コンテンツにスキップ

3.4.2 Matplotlib 基礎

Matplotlib Figure と Axes の構造図

  • Figure と Axes のオブジェクトモデルを理解する
  • 5 種類の基本グラフの描き方を身につける
  • グラフ要素(タイトル、凡例、グリッドなど)をカスタマイズできるようになる
  • サブプロットのレイアウトを理解する

初めて Matplotlib を学ぶとき、いちばん安定した順番は「すべての関数を先に覚える」ことではなく、まず 1 枚の図がどうやって出来上がるのかを見通すことです。

flowchart LR
A["何を伝えたいかを先に考える"] --> B["グラフの種類を選ぶ"]
B --> C["Figure / Axes を作成する"]
C --> D["データを描画する"]
D --> E["タイトル・ラベル・凡例を追加する"]
E --> F["スタイル調整と保存をする"]

この節で本当に解決したいのは、次の 2 つです。

  • いちばん基本の描画操作は何か
  • なぜ Figure / Axes モデルが、これから出てくるすべての図の土台になるのか

「1 枚の図は千の言葉に勝る。」

同じデータでも、

  • 表で見せると:平均給与: 技術部 18667, 営業部 19000, 管理部 32500
  • グラフで見せると:管理部の給与が他の部署よりかなり高いことが、一目で分かる

データ可視化の目的は、データに語らせることです。 数秒で、その背景にある規則やストーリーを理解できるようにします。

初心者向けの分かりやすい比喩

Section titled “初心者向けの分かりやすい比喩”

Matplotlib は次のように考えると分かりやすいです。

  • いちばん基本的な描画ツールボックス

Seaborn のように、あらかじめ多くのデフォルトスタイルが整っているわけではありません。 でも、その分メリットがあります。

  • グラフがどうやって少しずつ組み立てられるのかを、ちゃんと見られる

なので Matplotlib を学ぶ価値は、ただグラフを描けるようになることだけではありません。 次の感覚を身につけることにもあります。

  • グラフは、データ・キャンバス・座標軸からどう作られているのか

# インストール(通常はすでに入っています)
# python -m pip install --upgrade matplotlib
import matplotlib.pyplot as plt
import numpy as np
# Jupyter Notebook でグラフを表示する
# %matplotlib inline

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]
plt.plot(x, y) # 折れ線グラフを描く
plt.title("最初のグラフ") # タイトル
plt.show() # グラフを表示する

これだけです! 左下から右上に伸びる直線が表示されます。

初めて描くときに、まず覚えたい順番

Section titled “初めて描くときに、まず覚えたい順番”

初めて何かのグラフを描くときは、次の順番がいちばん安定しています。

  1. まず xy を準備する
  2. まずは最小限の形で描く
  3. そのあとでタイトルとラベルを入れる
  4. 最後に凡例、色、見た目の調整をする

最初から配色やスタイルを細かく考えるより、この順番のほうがずっと進めやすいです。


Matplotlib のグラフは、次の 2 つの重要なオブジェクトでできています。

flowchart TD
F["Figure(キャンバス)<br/>グラフ全体の入れ物"] --> A1["Axes(サブプロット 1)<br/>実際に描画する領域"]
F --> A2["Axes(サブプロット 2)"]
F --> A3["Axes(サブプロット 3)"]
A1 --> T1["タイトル Title"]
A1 --> X1["X 軸 xlabel"]
A1 --> Y1["Y 軸 ylabel"]
A1 --> L1["凡例 Legend"]
A1 --> D1["データの線 / 点 / 棒"]
style F fill:#e3f2fd,stroke:#1565c0,color:#333
style A1 fill:#fff3e0,stroke:#e65100,color:#333
style A2 fill:#fff3e0,stroke:#e65100,color:#333
style A3 fill:#fff3e0,stroke:#e65100,color:#333
  • Figure:グラフ全体のキャンバス。複数のサブプロットを含められる
  • Axes:1 つの具体的なグラフ領域(注意:ここでの “Axes” は「軸」ではなく「サブプロット」に近い意味です)
# スタイル 1:plt を使った簡単な描画(シンプルな場面向け)
plt.plot([1, 2, 3], [4, 5, 6])
plt.title("簡単な描画")
plt.show()
# スタイル 2:オブジェクト指向スタイル(おすすめ、より柔軟)
fig, ax = plt.subplots() # キャンバスとサブプロットを作成
ax.plot([1, 2, 3], [4, 5, 6]) # サブプロット上に描画
ax.set_title("オブジェクト指向の描画") # タイトルを設定
plt.show()

まず関数名を暗記するより、「何を伝えるのに向いているか」を覚えよう

Section titled “まず関数名を暗記するより、「何を伝えるのに向いているか」を覚えよう”
グラフまず覚えるべき用途
折れ線グラフ傾向を見る
棒グラフカテゴリを比較する
散布図関係を見る
ヒストグラム分布を見る
円グラフ割合を見る(ただしカテゴリは少なめ)

この表は初心者にとても大事です。 「関数名」を、もう一度「何を表現したいか」に戻してくれます。

適した場面: 時間や連続変数に沿った変化の傾向を示すとき

import matplotlib.pyplot as plt
import numpy as np
# 12 か月の売上データを作る
months = np.arange(1, 13)
sales_2023 = [120, 135, 150, 180, 200, 210, 195, 188, 220, 250, 280, 310]
sales_2024 = [140, 155, 170, 195, 230, 245, 225, 210, 260, 290, 320, 350]
fig, ax = plt.subplots(figsize=(10, 6)) # キャンバスサイズを設定
ax.plot(months, sales_2023, marker="o", label="2023年", color="#2196F3", linewidth=2)
ax.plot(months, sales_2024, marker="s", label="2024年", color="#FF5722", linewidth=2)
ax.set_title("月ごとの売上推移", fontsize=16, fontweight="bold")
ax.set_xlabel("", fontsize=12)
ax.set_ylabel("売上(万元)", fontsize=12)
ax.set_xticks(months)
ax.set_xticklabels([f"{m}月" for m in months])
ax.legend(fontsize=12) # 凡例を表示
ax.grid(True, alpha=0.3) # グリッド線を表示
plt.tight_layout() # 余白を自動調整
plt.show()

重要なパラメータ:

パラメータ役割
markerデータ点の印"o" 丸, "s" 四角, "^" 三角
linestyle線の種類"-" 実線, "--" 破線, ":" 点線
linewidth線の太さ2
color"red", "#FF5722", "C0"
label凡例のラベル"2023年"
alpha透明度0.7(0 は完全透明、1 は不透明)

適した場面: いくつかのカテゴリの大きさを比較するとき

# 各部署の給与比較
departments = ["技術部", "営業部", "管理部", "財務部", "人事部"]
avg_salary = [18500, 16200, 28000, 15800, 14500]
fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(departments, avg_salary, color=["#4CAF50", "#2196F3", "#FF9800", "#9C27B0", "#607D8B"])
# 棒の上に数値を表示する
for bar, val in zip(bars, avg_salary):
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 300,
f{val:,}", ha="center", fontsize=10)
ax.set_title("各部署の平均給与", fontsize=14)
ax.set_ylabel("給与(円)")
ax.set_ylim(0, max(avg_salary) * 1.15) # Y 軸に数値ラベルの余白を確保
plt.tight_layout()
plt.show()

横棒グラフ(ラベルが長いときに見やすい):

fig, ax = plt.subplots(figsize=(8, 5))
ax.barh(departments, avg_salary, color="#4CAF50")
ax.set_xlabel("給与(円)")
ax.set_title("各部署の平均給与")
plt.tight_layout()
plt.show()

グループ棒グラフ:

# 2 年比較
x = np.arange(len(departments))
width = 0.35
fig, ax = plt.subplots(figsize=(10, 5))
ax.bar(x - width/2, [17000, 15000, 26000, 14500, 13000], width, label="2023", color="#64B5F6")
ax.bar(x + width/2, avg_salary, width, label="2024", color="#1565C0")
ax.set_xticks(x)
ax.set_xticklabels(departments)
ax.legend()
ax.set_title("各部署の給与比較(2023 vs 2024)")
plt.tight_layout()
plt.show()

適した場面: 2 つの変数の関係を観察するとき

rng = np.random.default_rng(seed=42)
# 身長と体重のデータをシミュレーション
height = rng.normal(170, 8, 100)
weight = height * 0.65 - 40 + rng.normal(0, 5, 100)
fig, ax = plt.subplots(figsize=(8, 6))
scatter = ax.scatter(height, weight, c=weight, cmap="RdYlGn_r",
s=50, alpha=0.7, edgecolors="white", linewidth=0.5)
ax.set_title("身長と体重の関係", fontsize=14)
ax.set_xlabel("身長(cm)")
ax.set_ylabel("体重(kg)")
plt.colorbar(scatter, label="体重") # カラーバー
plt.tight_layout()
plt.show()

重要なパラメータ:

パラメータ役割
s点の大きさ50、または配列を渡して大きさを変える
c点の色"red"、または配列を渡して色を割り当てる
cmapカラーマップ"viridis", "RdYlGn", "Blues"
alpha透明度0.7

適した場面: データの分布を確認するとき

rng = np.random.default_rng(seed=42)
scores = rng.normal(75, 12, 500) # 500 人の学生の成績
fig, ax = plt.subplots(figsize=(8, 5))
# ヒストグラムを描画
n, bins, patches = ax.hist(scores, bins=20, color="#42A5F5", edgecolor="white",
alpha=0.8)
# 平均線を追加
mean_val = scores.mean()
ax.axvline(mean_val, color="red", linestyle="--", linewidth=2, label=f"平均: {mean_val:.1f}")
ax.set_title("学生の成績分布", fontsize=14)
ax.set_xlabel("点数")
ax.set_ylabel("人数")
ax.legend()
plt.tight_layout()
plt.show()

適した場面: 全体に対する各部分の割合を示すとき(カテゴリは 5〜6 個以内)

labels = ["Python", "JavaScript", "Java", "C++", "その他"]
sizes = [35, 25, 20, 10, 10]
colors = ["#4CAF50", "#FFC107", "#2196F3", "#FF5722", "#9E9E9E"]
explode = (0.05, 0, 0, 0, 0) # Python を強調
fig, ax = plt.subplots(figsize=(7, 7))
ax.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct="%1.1f%%", startangle=90, shadow=False,
textprops={"fontsize": 12})
ax.set_title("AI 分野におけるプログラミング言語の使用割合", fontsize=14)
plt.tight_layout()
plt.show()

flowchart TD
A["何を表示したい?"] --> B{"データの種類"}
B -->|"傾向の変化"| C["折れ線グラフ 📈"]
B -->|"カテゴリ比較"| D["棒グラフ 📊"]
B -->|"2 変数の関係"| E["散布図 🔵"]
B -->|"データの分布"| F["ヒストグラム 📉"]
B -->|"割合の構成"| G["円グラフ 🥧"]
C --> C1["時系列<br/>株価の動き<br/>売上の推移"]
D --> D1["部署比較<br/>商品比較<br/>ランキング"]
E --> E1["身長 vs 体重<br/>価格 vs 売上<br/>相関分析"]
F --> F1["成績分布<br/>年齢分布<br/>収入分布"]
G --> G1["市場シェア<br/>支出の割合<br/>(カテゴリは 6 個以内)"]

初学者がまず覚えるとよい最小チェックリスト

Section titled “初学者がまず覚えるとよい最小チェックリスト”

見た目を整える前に、まず次の 4 つを確認しましょう。

  1. タイトルは、この図が何を表しているかを伝えているか?
  2. X 軸と Y 軸にラベルと単位はあるか?
  3. 凡例は本当に必要か?
  4. 色は理解を助けているか、それとも邪魔しているか?

この 4 つができていれば、多くの場合、すでに「動くけれど見づらい図」よりずっと分かりやすくなっています。

Matplotlib はデフォルトでは日本語表示に対応していないため、設定が必要です。

import matplotlib.pyplot as plt
# 方法 1:グローバル設定(おすすめ)
plt.rcParams["font.sans-serif"] = ["SimHei", "Arial Unicode MS", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False # マイナス記号の表示問題を解決
# macOS の場合
# plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]
# Linux の場合
# plt.rcParams["font.sans-serif"] = ["WenQuanYi Micro Hei"]
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title("メインタイトル", fontsize=16, fontweight="bold", color="#333")
ax.set_xlabel("X 軸ラベル", fontsize=12)
ax.set_ylabel("Y 軸ラベル", fontsize=12)
ax.plot(x, y1, label="データ A")
ax.plot(x, y2, label="データ B")
ax.legend(loc="upper left", fontsize=10, frameon=True, shadow=True)
# loc のよく使う値:
# "best" (自動), "upper left", "upper right", "lower left", "lower right", "center"
ax.grid(True, alpha=0.3, linestyle="--") # 半透明の破線グリッド
# 事前定義スタイルを使う(グローバル設定)
plt.style.use("seaborn-v0_8-whitegrid") # すっきりした白背景グリッド
# 他にも見やすいスタイル:
# "ggplot", "seaborn-v0_8", "fivethirtyeight", "bmh"

使用できるすべてのスタイルを確認するには:

print(plt.style.available)
fig, ax = plt.subplots(figsize=(8, 5))
x = np.arange(1, 13)
y = [120, 135, 150, 180, 200, 210, 195, 188, 220, 250, 280, 310]
ax.plot(x, y, marker="o")
# 最大値に注釈を付ける
max_idx = np.argmax(y)
ax.annotate(f"最高点: {y[max_idx]}",
xy=(x[max_idx], y[max_idx]), # 矢印の指す先
xytext=(x[max_idx]-2, y[max_idx]+20), # 文字の位置
arrowprops=dict(arrowstyle="->", color="red"),
fontsize=12, color="red")
plt.show()

subplots:複数のサブプロットを作る

Section titled “subplots:複数のサブプロットを作る”
# 2 行 2 列 = 4 つのサブプロット
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# axes は 2×2 の配列
axes[0, 0].plot([1, 2, 3], [1, 4, 9])
axes[0, 0].set_title("折れ線グラフ")
axes[0, 1].bar(["A", "B", "C"], [3, 7, 5])
axes[0, 1].set_title("棒グラフ")
rng = np.random.default_rng(seed=42)
axes[1, 0].scatter(rng.random(50), rng.random(50))
axes[1, 0].set_title("散布図")
axes[1, 1].hist(rng.standard_normal(200), bins=15)
axes[1, 1].set_title("ヒストグラム")
fig.suptitle("4 種類の基本グラフ", fontsize=16, fontweight="bold")
plt.tight_layout()
plt.show()
fig = plt.figure(figsize=(12, 5))
# 左側は幅の 2/3
ax1 = fig.add_axes([0.05, 0.1, 0.6, 0.8]) # [left, bottom, width, height]
ax1.plot([1, 2, 3, 4], [10, 20, 25, 30])
ax1.set_title("メイン図")
# 右側は幅の 1/3
ax2 = fig.add_axes([0.72, 0.1, 0.25, 0.8])
ax2.bar(["A", "B"], [15, 25])
ax2.set_title("補助図")
plt.show()

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title("保存の例")
# PNG として保存(最もよく使う)
fig.savefig("my_chart.png", dpi=150, bbox_inches="tight")
# SVG として保存(ベクター画像、拡大してもぼやけない)
fig.savefig("my_chart.svg", bbox_inches="tight")
# PDF として保存
fig.savefig("my_chart.pdf", bbox_inches="tight")
パラメータ役割推奨値
dpi解像度150(通常), 300(印刷)
bbox_inches余白の切り取り"tight" 自動で切り取る
transparent背景を透明にするTrue(PPT 向け)

このページを終えたら、この evidence card を残します。

質問
このグラフが答える比較、分布、傾向、または関係
グラフ選択
折れ線、棒、散布図、ヒストグラム、箱ひげ図、ヒートマップ、またはインタラクティブダッシュボード
成果物
保存した chart 画像/html と、そのデータスライス
失敗確認
誤解を招くスケール、情報過多のグラフ、誤った集計、またはラベル不足
期待される成果
1文で示唆を説明するチャートのアーティファクト
グラフ関数適した場面
折れ線グラフax.plot()傾向、時系列
棒グラフax.bar() / ax.barh()カテゴリ比較
散布図ax.scatter()2 変数の関係
ヒストグラムax.hist()データ分布
円グラフax.pie()割合(慎重に使う)

基本のワークフロー:

fig, ax = plt.subplots(figsize=(8, 5)) # 1. キャンバスを作る
ax.plot(x, y) # 2. データを描画する
ax.set_title("タイトル") # 3. タイトル / ラベルを設定する
ax.legend() # 4. 凡例を追加する
plt.tight_layout() # 5. レイアウトを整える
plt.show() # 6. 表示する

この節でいちばん持ち帰ってほしいこと

Section titled “この節でいちばん持ち帰ってほしいこと”
  • Matplotlib の大事な点は、関数の多さではなく、グラフがどう組み上がるかを理解できること
  • 何を伝えたいかを先に考え、それから図を選び、最後にコードを書くと、API を暗記するよりずっと安定する
  • Figure / Axes は、その後のほぼすべての Python 可視化ライブラリで必要になる、土台の感覚です

# sin(x) と cos(x) の曲線を描く
# x は 0 から 2π まで、100 点取る
# 条件:色と線の種類を変える、凡例を付ける、グリッドを付ける、タイトルを付ける
# 6 つの都市の住宅価格データと 1 人当たり収入データがある
# グループ棒グラフを描いて比較する
# 条件:棒の上に数値を表示する
# 1000 個の正規分布の乱数を生成する
# 2×2 のサブプロットでそれぞれ次を表示する:
# 1. 折れ線グラフ(最初の 100 個のデータの推移)
# 2. ヒストグラム(分布)
# 3. 散布図(隣り合う 2 つのデータ点の関係)
# 4. 棒グラフ(区間ごとの出現回数)
参考実装と解説
  • 正弦と余弦のグラフには、ラベル付きの 2 本の線、タイトル、軸ラベル、凡例、薄いグリッドを入れます。比較しにくい場合は、装飾より先に色と線種を調整します。
  • グループ棒グラフでは x 位置を明示的に計算し、読者がコードを見なくても理解できるように棒や軸をラベル付けします。
  • 複数グラフでは fig, ax = plt.subplots() を使い、fig.savefig(...) で保存します。保存画像は証拠の一部であり、後回しのおまけではありません。