Step 39:複数のグラフを配置しよう

🎨 ステップ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

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE