🎨 ステップ39: 複数のグラフを配置しよう
subplots()で複数のグラフを並べてダッシュボードを作ろう!
ステップ38で様々なグラフの描き方を学びました。今回は複数のグラフを1つの画面に並べて表示する方法を学びます。これができると、データを多角的に分析する「ダッシュボード」が作れるようになります。
📖 このステップで学ぶこと
・plt.subplots()の使い方
・グラフの配置(1行2列、2行2列など)
・サイズと間隔の調整
・実践例:ダッシュボード作成
🎯 1. なぜ複数のグラフを並べるのか?
データ分析では、複数の視点から同時にデータを見ることが大切です。1つの画面に複数のグラフを並べると、比較や分析がしやすくなります。
📌 複数グラフのメリット
比較しやすい:並べて見ることで違いがわかる
関連性が見える:複数の視点で理解が深まる
報告に便利:ダッシュボードとして使える
効率的:1つの画面で全体を把握できる
📐 2. subplots()の基本
plt.subplots()を使うと、複数のグラフを配置できます。まずは基本的な使い方を学びましょう。
🔰 2つのグラフを横に並べる(1行2列)
コード:1行2列の配置
import matplotlib.pyplot as plt
# データの準備
months = ['1月', '2月', '3月', '4月']
sales = [120, 150, 130, 180]
# 1行2列のグラフを作成
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 左側のグラフ(折れ線)
axes[0].plot(months, sales, marker='o')
axes[0].set_title('折れ線グラフ')
axes[0].set_ylabel('売上(万円)')
# 右側のグラフ(棒グラフ)
axes[1].bar(months, sales, color='skyblue')
axes[1].set_title('棒グラフ')
axes[1].set_ylabel('売上(万円)')
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説(重要!)
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
・plt.subplots(行数, 列数):複数グラフの枠を作る
・1, 2:1行2列(横に2つ並べる)
・fig:全体の図(Figure)を格納
・axes:各グラフ(Axes)の配列
・figsize=(12, 5):全体の幅12インチ、高さ5インチ
axes[0]:1番目(左側)のグラフ
axes[1]:2番目(右側)のグラフ
axes[0].plot():axes[0]に対してplot()を実行
・これまでのplt.plot()と同じ書き方ができる
・ただしplt.の代わりにaxes[番号].を使う
axes[0].set_title():plt.title()の代わり
axes[0].set_ylabel():plt.ylabel()の代わり
実行結果
横に2つのグラフが並んで表示されます。左は折れ線グラフ、右は棒グラフです。
📌 plt.〇〇() と axes[i].set_〇〇() の対応
| これまでの書き方 | subplotsでの書き方 |
| plt.title(‘タイトル’) | axes[i].set_title(‘タイトル’) |
| plt.xlabel(‘ラベル’) | axes[i].set_xlabel(‘ラベル’) |
| plt.ylabel(‘ラベル’) | axes[i].set_ylabel(‘ラベル’) |
| plt.xlim(0, 100) | axes[i].set_xlim(0, 100) |
| plt.ylim(0, 100) | axes[i].set_ylim(0, 100) |
| plt.grid(True) | axes[i].grid(True) |
| plt.legend() | axes[i].legend() |
📝 2つのグラフを縦に並べる(2行1列)
コード:2行1列の配置
import matplotlib.pyplot as plt
months = ['1月', '2月', '3月', '4月']
sales = [120, 150, 130, 180]
# 2行1列のグラフを作成
fig, axes = plt.subplots(2, 1, figsize=(8, 10))
# 上のグラフ
axes[0].plot(months, sales, marker='o', color='blue')
axes[0].set_title('売上推移')
axes[0].set_ylabel('売上(万円)')
axes[0].grid(True, alpha=0.3)
# 下のグラフ
axes[1].bar(months, sales, color='lightgreen')
axes[1].set_title('月別売上')
axes[1].set_ylabel('売上(万円)')
axes[1].grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
plt.subplots(2, 1)
・2行1列(縦に2つ並べる)
figsize=(8, 10)
・幅8インチ、高さ10インチ
・縦に並べるので高さを大きくする
axes[0]:上のグラフ
axes[1]:下のグラフ
🔢 3. 2×2のグリッド配置
2行2列にすると、4つのグラフを整然と並べられます。2次元配列で位置を指定します。
🔰 4つのグラフを配置
コード:2行2列の配置
import matplotlib.pyplot as plt
# データの準備
months = ['1月', '2月', '3月', '4月', '5月']
sales = [120, 150, 130, 180, 170]
costs = [80, 90, 85, 100, 95]
# 2行2列のグラフを作成
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 左上:折れ線グラフ(axes[0, 0])
axes[0, 0].plot(months, sales, marker='o', label='売上', color='blue')
axes[0, 0].plot(months, costs, marker='s', label='コスト', color='red')
axes[0, 0].set_title('売上とコストの推移')
axes[0, 0].set_ylabel('金額(万円)')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 右上:棒グラフ(axes[0, 1])
profit = [s - c for s, c in zip(sales, costs)]
axes[0, 1].bar(months, profit, color='lightgreen', edgecolor='black')
axes[0, 1].set_title('月別利益')
axes[0, 1].set_ylabel('利益(万円)')
axes[0, 1].grid(axis='y', alpha=0.3)
# 左下:円グラフ(axes[1, 0])
axes[1, 0].pie(sales, labels=months, autopct='%1.1f%%', startangle=90)
axes[1, 0].set_title('売上構成比')
# 右下:横棒グラフ(axes[1, 1])
axes[1, 1].barh(months, sales, color='skyblue', edgecolor='black')
axes[1, 1].set_title('売上ランキング')
axes[1, 1].set_xlabel('売上(万円)')
axes[1, 1].grid(axis='x', alpha=0.3)
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 2次元配列での位置指定
2行2列の場合、axes[行, 列]で位置を指定します:
axes[0, 0]:左上(0行目の0列目)
axes[0, 1]:右上(0行目の1列目)
axes[1, 0]:左下(1行目の0列目)
axes[1, 1]:右下(1行目の1列目)
📌 配置と番号の対応
| 位置 | 1行の場合 | 2行以上の場合 |
| 左上 | axes[0] | axes[0, 0] |
| 右上 | axes[1] | axes[0, 1] |
| 左下 | – | axes[1, 0] |
| 右下 | – | axes[1, 1] |
1行(または1列)の場合は1次元配列、2行以上の場合は2次元配列になります。
📝 利益の計算部分の解説
💡 リスト内包表記の解説
profit = [s – c for s, c in zip(sales, costs)]
・売上から費用を引いて利益を計算
・zip(sales, costs):2つのリストを同時にループ
・sはsalesの値、cはcostsの値
・結果:[40, 60, 45, 80, 75](各月の利益)
⚙️ 4. サイズと間隔の調整
📝 figsizeでサイズを変更
figsizeパラメータで、全体のサイズを調整できます。
コード:横長のサイズ
import matplotlib.pyplot as plt
months = ['1月', '2月', '3月']
sales = [120, 150, 130]
# 幅15、高さ5の横長サイズ
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 3つのグラフを描画
colors = ['red', 'blue', 'green']
for i in range(3):
axes[i].bar(months, sales, color=colors[i])
axes[i].set_title(f'グラフ{i+1}')
axes[i].set_ylabel('売上(万円)')
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 forループでグラフを描画
for i in range(3):
・i = 0, 1, 2 と3回ループ
・各ループでaxes[i]にグラフを描画
f’グラフ{i+1}’
・f文字列で「グラフ1」「グラフ2」「グラフ3」を生成
📝 間隔を調整する
コード:間隔の調整
import matplotlib.pyplot as plt
months = ['1月', '2月', '3月', '4月']
sales = [120, 150, 130, 180]
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# グラフを描く
axes[0, 0].plot(months, sales)
axes[0, 0].set_title('グラフ1')
axes[0, 1].bar(months, sales)
axes[0, 1].set_title('グラフ2')
axes[1, 0].scatter(range(len(months)), sales)
axes[1, 0].set_title('グラフ3')
axes[1, 1].pie(sales, labels=months)
axes[1, 1].set_title('グラフ4')
# 間隔を細かく調整
plt.subplots_adjust(hspace=0.3, wspace=0.3)
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
📌 間隔調整のパラメータ
| パラメータ | 説明 | 目安の値 |
| hspace | 縦方向の間隔(height space) | 0.2〜0.4 |
| wspace | 横方向の間隔(width space) | 0.2〜0.4 |
| plt.tight_layout() | 自動で良い感じに調整 | 推奨 |
plt.tight_layout()を使うと、自動で適切な間隔に調整してくれるので便利です。
🎨 5. 非対称なレイアウト(GridSpec)
上段を大きく、下段を小さくするなど、非対称なレイアウトを作りたい場合はGridSpecを使います。
📝 上段を広く使うレイアウト
コード:GridSpecでレイアウト
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# データの準備
months = ['1月', '2月', '3月', '4月', '5月']
sales = [120, 150, 130, 180, 170]
# 図を作成
fig = plt.figure(figsize=(12, 8))
# GridSpecで配置を定義(2行2列のグリッド)
gs = gridspec.GridSpec(2, 2, figure=fig)
# 上段を広く使う(1行目全体)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(months, sales, marker='o', linewidth=2)
ax1.set_title('売上推移(メイングラフ)', fontsize=14)
ax1.set_ylabel('売上(万円)')
ax1.grid(True, alpha=0.3)
# 下段左
ax2 = fig.add_subplot(gs[1, 0])
ax2.bar(months, sales, color='lightblue', edgecolor='black')
ax2.set_title('棒グラフ')
ax2.set_ylabel('売上(万円)')
# 下段右
ax3 = fig.add_subplot(gs[1, 1])
ax3.pie(sales, labels=months, autopct='%1.1f%%')
ax3.set_title('構成比')
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
import matplotlib.gridspec as gridspec
・GridSpecモジュールをインポート
gs = gridspec.GridSpec(2, 2, figure=fig)
・2行2列のグリッドを定義
fig.add_subplot(gs[0, :])
・gs[0, :]:0行目の全列(1行目全体)
・「:」はスライス表記で「すべて」を意味する
fig.add_subplot(gs[1, 0])
・gs[1, 0]:1行目の0列目(左下)
📌 GridSpecの位置指定
| 指定方法 | 意味 |
| gs[0, :] | 0行目の全列(上段全体) |
| gs[:, 0] | 全行の0列目(左側全体) |
| gs[0, 0] | 0行目の0列目(左上) |
| gs[1, 0:2] | 1行目の0〜1列目(下段全体) |
📊 6. 実践:ダッシュボードを作ろう
これまで学んだ技術を組み合わせて、売上分析ダッシュボードを作りましょう。
📝 まずはデータを準備
コード:データの準備
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
# データの準備
months = ['1月', '2月', '3月', '4月', '5月', '6月']
sales_2023 = [120, 135, 150, 140, 160, 175]
sales_2024 = [140, 155, 170, 165, 185, 200]
categories = ['商品A', '商品B', '商品C', '商品D']
category_sales = [450, 380, 320, 250]
※ 画面が小さい場合は、コードブロックを横にスクロールできます
📝 ダッシュボードを作成
コード:完成版ダッシュボード
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
# データの準備
months = ['1月', '2月', '3月', '4月', '5月', '6月']
sales_2023 = [120, 135, 150, 140, 160, 175]
sales_2024 = [140, 155, 170, 165, 185, 200]
categories = ['商品A', '商品B', '商品C', '商品D']
category_sales = [450, 380, 320, 250]
# ダッシュボード作成
fig = plt.figure(figsize=(15, 10))
fig.suptitle('📊 売上分析ダッシュボード', fontsize=20, fontweight='bold', y=0.98)
# レイアウト設定
gs = gridspec.GridSpec(2, 3, figure=fig, hspace=0.3, wspace=0.3)
# 1. 年別売上推移(大きく表示)
ax1 = fig.add_subplot(gs[0, :2])
ax1.plot(months, sales_2023, marker='o', linewidth=2, label='2023年', color='blue')
ax1.plot(months, sales_2024, marker='s', linewidth=2, label='2024年', color='red')
ax1.set_title('年別売上推移', fontsize=14, fontweight='bold')
ax1.set_ylabel('売上(万円)')
ax1.legend()
ax1.grid(True, alpha=0.3)
# 2. 前年比(%)
ax2 = fig.add_subplot(gs[0, 2])
growth_rate = [(s24 - s23) / s23 * 100 for s23, s24 in zip(sales_2023, sales_2024)]
colors = ['green' if g > 0 else 'red' for g in growth_rate]
ax2.bar(range(len(months)), growth_rate, color=colors, alpha=0.7)
ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)
ax2.set_title('前年比伸び率', fontsize=14, fontweight='bold')
ax2.set_ylabel('伸び率(%)')
ax2.set_xticks(range(len(months)))
ax2.set_xticklabels(months, rotation=45)
ax2.grid(axis='y', alpha=0.3)
# 3. 商品別売上
ax3 = fig.add_subplot(gs[1, 0])
ax3.barh(categories, category_sales, color='skyblue', edgecolor='black')
ax3.set_title('商品別売上', fontsize=14, fontweight='bold')
ax3.set_xlabel('売上(万円)')
ax3.grid(axis='x', alpha=0.3)
# 4. 商品別構成比
ax4 = fig.add_subplot(gs[1, 1])
colors_pie = ['gold', 'lightcoral', 'lightskyblue', 'lightgreen']
ax4.pie(category_sales, labels=categories, autopct='%1.1f%%',
colors=colors_pie, startangle=90)
ax4.set_title('商品別構成比', fontsize=14, fontweight='bold')
# 5. 月別売上分布(2024年)
ax5 = fig.add_subplot(gs[1, 2])
ax5.hist(sales_2024, bins=5, color='lightgreen', edgecolor='black', alpha=0.7)
ax5.set_title('売上分布(2024年)', fontsize=14, fontweight='bold')
ax5.set_xlabel('売上(万円)')
ax5.set_ylabel('月数')
ax5.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 新しいコードの解説
fig.suptitle(‘📊 売上分析ダッシュボード’, …)
・全体のタイトル(super title)を設定
・y=0.98で位置を微調整
growth_rate = [(s24 – s23) / s23 * 100 for …]
・前年比の伸び率を計算(%)
colors = [‘green’ if g > 0 else ‘red’ for g in growth_rate]
・プラスは緑、マイナスは赤で色分け
ax2.axhline(y=0, …)
・y=0の位置に水平線を引く(基準線)
ax2.set_xticklabels(months, rotation=45)
・X軸のラベルを45度回転(重ならないように)
✅ ダッシュボード作成のコツ
・メイングラフを大きく:最も重要なグラフを目立たせる
・色を統一:同じデータは同じ色にする
・タイトルを明確に:各グラフが何を示すか一目でわかるように
・グリッド線を活用:値を読み取りやすくする
・適度な余白:tight_layout()で見やすく配置
📝 練習問題
問題1:2つのグラフを横に並べる(初級)
📋 問題
以下のデータを使って、折れ線グラフと棒グラフを横に並べて表示してください。
days = ['月', '火', '水', '木', '金']
visitors = [120, 150, 130, 180, 200]
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import matplotlib.pyplot as plt
days = ['月', '火', '水', '木', '金']
visitors = [120, 150, 130, 180, 200]
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].plot(days, visitors, marker='o')
axes[0].set_title('来客数推移')
axes[0].set_ylabel('人数')
axes[0].grid(True, alpha=0.3)
axes[1].bar(days, visitors, color='skyblue')
axes[1].set_title('曜日別来客数')
axes[1].set_ylabel('人数')
axes[1].grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
問題2:2×2のグリッド配置(初級)
📋 問題
同じデータを4種類のグラフ(折れ線、棒、散布図、円グラフ)で2×2に配置してください。
categories = ['A', 'B', 'C', 'D']
values = [30, 40, 20, 10]
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import matplotlib.pyplot as plt
categories = ['A', 'B', 'C', 'D']
values = [30, 40, 20, 10]
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 折れ線グラフ
axes[0, 0].plot(categories, values, marker='o')
axes[0, 0].set_title('折れ線グラフ')
# 棒グラフ
axes[0, 1].bar(categories, values, color='lightgreen')
axes[0, 1].set_title('棒グラフ')
# 散布図
axes[1, 0].scatter(range(len(categories)), values, s=200)
axes[1, 0].set_title('散布図')
# 円グラフ
axes[1, 1].pie(values, labels=categories, autopct='%1.1f%%')
axes[1, 1].set_title('円グラフ')
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
問題3:3つのグラフを縦に配置(中級)
📋 問題
売上データを3つの視点(推移、比較、構成比)で表現し、縦に並べてください。
months = ['1月', '2月', '3月', '4月']
sales = [100, 120, 110, 140]
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import matplotlib.pyplot as plt
months = ['1月', '2月', '3月', '4月']
sales = [100, 120, 110, 140]
fig, axes = plt.subplots(3, 1, figsize=(10, 12))
# 推移
axes[0].plot(months, sales, marker='o', linewidth=2)
axes[0].set_title('売上推移')
axes[0].set_ylabel('売上(万円)')
axes[0].grid(True, alpha=0.3)
# 比較
axes[1].bar(months, sales, color='lightblue', edgecolor='black')
axes[1].set_title('月別売上比較')
axes[1].set_ylabel('売上(万円)')
axes[1].grid(axis='y', alpha=0.3)
# 構成比
axes[2].pie(sales, labels=months, autopct='%1.1f%%', startangle=90)
axes[2].set_title('月別売上構成比')
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
問題4:GridSpecでレイアウト(中級)
📋 問題
GridSpecを使って、上段に大きなグラフ1つ、下段に小さなグラフ2つを配置してください。
解答例を見る
コード
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
months = ['1月', '2月', '3月', '4月', '5月']
sales = [120, 150, 130, 180, 170]
fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(2, 2, figure=fig)
# 上段全体
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(months, sales, marker='o', linewidth=2)
ax1.set_title('売上推移(メイン)', fontsize=14)
ax1.grid(True, alpha=0.3)
# 下段左
ax2 = fig.add_subplot(gs[1, 0])
ax2.bar(months, sales, color='lightgreen')
ax2.set_title('棒グラフ')
# 下段右
ax3 = fig.add_subplot(gs[1, 1])
ax3.pie(sales, labels=months, autopct='%1.1f%%')
ax3.set_title('構成比')
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
問題5:ミニダッシュボード作成(上級)
📋 問題
学生の成績データを分析するダッシュボードを作成してください。以下の要素を含めてください:
・科目別平均点の棒グラフ
・2科目の相関を示す散布図
・科目別割合の円グラフ
解答例を見る
コード
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
# データ準備
subjects = ['国語', '数学', '英語', '理科', '社会']
avg_scores = [75, 80, 70, 85, 78]
math_scores = np.random.normal(80, 8, 30)
english_scores = np.random.normal(70, 10, 30)
# ダッシュボード作成
fig = plt.figure(figsize=(14, 8))
fig.suptitle('📚 学生成績分析', fontsize=18, fontweight='bold')
gs = gridspec.GridSpec(1, 3, figure=fig, wspace=0.3)
# 1. 科目別平均点
ax1 = fig.add_subplot(gs[0, 0])
ax1.bar(subjects, avg_scores, color='skyblue', edgecolor='black')
ax1.set_title('科目別平均点', fontsize=14)
ax1.set_ylabel('平均点')
ax1.set_ylim(0, 100)
ax1.grid(axis='y', alpha=0.3)
# 2. 数学と英語の相関
ax2 = fig.add_subplot(gs[0, 1])
ax2.scatter(math_scores, english_scores, s=100, alpha=0.6, edgecolors='black')
ax2.set_title('数学と英語の相関', fontsize=14)
ax2.set_xlabel('数学')
ax2.set_ylabel('英語')
ax2.grid(True, alpha=0.3)
# 3. 科目別構成比
ax3 = fig.add_subplot(gs[0, 2])
ax3.pie(avg_scores, labels=subjects, autopct='%1.1f%%', startangle=90)
ax3.set_title('科目別構成比', fontsize=14)
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
🎯 このステップのまとめ
✅ 学んだこと
✓ plt.subplots(行, 列)で複数のグラフを配置
✓ axes[i]またはaxes[行, 列]で個別のグラフを操作
✓ figsizeでサイズ調整
✓ GridSpecで複雑なレイアウト
✓ tight_layout()で見やすく配置
✓ ダッシュボードの作成方法
💡 次のステップに進む前に確認
以下のことができるようになったか確認しましょう:
□ 複数のグラフを並べて表示できる
□ 2×2のグリッド配置ができる
□ GridSpecで自由なレイアウトができる
□ 見やすいダッシュボードを作れる
これらができたら、次のステップに進みましょう!
❓ よくある質問
Q1: axesとaxの違いは何ですか?
A: axesは複数のグラフの集まり(配列)、axは1つのグラフを指します。subplots()で複数作るとaxes、add_subplot()で1つ作るとaxがよく使われます。
Q2: tight_layout()は必ず必要ですか?
A: 必須ではありませんが、強く推奨します。グラフ同士が重なったり、タイトルが切れたりするのを防げます。
Q3: 5つ以上のグラフを配置できますか?
A: はい、できます。plt.subplots(3, 3)なら9個まで配置できます。ただし、あまり多すぎると見づらくなるので注意しましょう。
Q4: グラフのサイズを個別に変えられますか?
A: GridSpecを使えば可能です。gs[0, :]のように範囲を指定すると、複数のセルを結合してより大きなグラフを作れます。
Q5: ダッシュボードを保存するにはどうすればいいですか?
A: plt.savefig(‘dashboard.png’)をplt.show()の前に書くと、画像として保存できます。dpi=300を追加すると高画質になります。
学習メモ
Pythonデータ分析入門 - Step 39