6. Matplotlibでデータの可視化(40分)#
この章では、第5章で加工した売上データを使用し、Matplotlibでの基本的なグラフの描画方法と、グラフの使い分けについて学びます。
注釈
入力が遅れた場合などに、この章のNotebookをダウンロードできます。ダウンロードしたファイルを作業フォルダに置き、JupyterLabのファイルブラウザでダブルクリックして開いてください。
ダウンロードしたNotebookには、この章の説明の文章も入っています。図などの一部の書き方は、JupyterLabでは記号のまま表示されます。
自分で作った6_matplotlib.ipynbと同じ名前のため、上書きしないように注意してください。
6.1. 可視化とは#
可視化とは、データをグラフなどの図にして、傾向やパターンを目で見て分かるようにすることです。
第5章のdescribe()メソッドのような数値の要約だけでは、データの特徴が分からないことがあります。
その例として、統計学者のアンスコムが示した4組のデータ(アンスコムの例)があります[1]。 4組(I〜IV)は、それぞれxとyの11組の値からなります。 次の表のとおり、4組のxとyの平均、分散、xとyの相関は、ほぼ同じです。
組 |
xの平均 |
xの分散 |
yの平均 |
yの分散 |
相関 |
|---|---|---|---|---|---|
I |
9.00 |
11.00 |
7.50 |
4.13 |
0.82 |
II |
9.00 |
11.00 |
7.50 |
4.13 |
0.82 |
III |
9.00 |
11.00 |
7.50 |
4.12 |
0.82 |
IV |
9.00 |
11.00 |
7.50 |
4.12 |
0.82 |
ところが、4組のデータを散布図(xとyの値を点で表したグラフ)にすると、形がまったく違います。
アンスコムの例の4組のデータの散布図#
I:点が直線の周りにばらついている
II:点が曲線の上に並んでいる
III:1点を除いて、点が直線の上に並んでいる
IV:1点を除いて、xの値がすべて同じ
このように、グラフに可視化することで、数値の要約だけでは分からない形や、ほかから離れた値(外れ値)に気付けます。
出典: Anscombe, F. J. (1973). Graphs in Statistical Analysis. The American Statistician, 27(1), 17–21.
6.2. さまざまな可視化ライブラリ#
Matplotlibは、Pythonでグラフを描画するための基本的なライブラリです。 折れ線グラフ、棒グラフ、散布図など、さまざまなグラフを描画できます。 Pythonの可視化の基礎となるライブラリで、Matplotlibの上に作られたライブラリも多くあります。
Matplotlib公式サイト:https://matplotlib.org/
ここでは、Matplotlibのほかによく使われる2つの可視化ライブラリを紹介します。
Seabornは、Matplotlibの上に作られたライブラリで、統計的なグラフを少ないコードで描画できます。
Seaborn公式サイト:https://seaborn.pydata.org/
SeabornのExample gallery(https://seaborn.pydata.org/examples/index.html)#
Plotlyは、拡大・縮小や、マウスを重ねて値を表示するなどの操作ができる、インタラクティブなグラフを描画できるライブラリです。
Plotly公式サイト:https://plotly.com/python/
PlotlyのPython向けのページ(https://plotly.com/python/)#
講座の環境にはSeabornとPlotlyをインストールしていません。 ここではMatplotlibを可視化ライブラリとして使用します。
6.3. 売上データの折れ線グラフを描画する#
第4章のJupyterLabを起動するの手順で、作業フォルダでJupyterLabを起動してください。
新しいNotebookを作成し、名前を6_matplotlib.ipynbに変更します。
ここではグラフ描画用のデータとして、第5章で作成した加工済みの売上データsales_clean.csvを使います。
sales_clean.csvを作業フォルダの直下(6_matplotlib.ipynbと同じ場所)に置いてください。
第5章のコードを実行できなかった場合は、sales_clean.csvをダウンロードして作業フォルダに置いてください。
売上データの読み込み#
第5章と同じく、pd.read_csv()関数で日付の列を日付の型として読み込みます。
import pandas as pd
df = pd.read_csv("sales_clean.csv", parse_dates=["date"])
df.head()
| date | store | item | quantity | price | amount | |
|---|---|---|---|---|---|---|
| 0 | 2026-04-01 | 東京店 | コーヒー | 38 | 400 | 15200 |
| 1 | 2026-04-01 | 東京店 | 紅茶 | 24 | 450 | 10800 |
| 2 | 2026-04-01 | 東京店 | ケーキ | 19 | 500 | 9500 |
| 3 | 2026-04-01 | 大阪店 | コーヒー | 35 | 400 | 14000 |
| 4 | 2026-04-01 | 大阪店 | 紅茶 | 20 | 450 | 9000 |
第5章で追加した売上金額(amount)の列があることを確認してください。
Matplotlibでグラフに日本語を表示するには、フォントの設定が必要です。
そのため、この章ではしばらく、店舗名(store)を英語に書き換えたデータを使います。
日本語を表示する方法は、日本語の表示の節で説明します。
商品名(item)は、グラフに表示しないため日本語のままです。
# storeを英語に書き換える
df["store"] = df["store"].replace({"東京店": "Tokyo", "大阪店": "Osaka", "名古屋店": "Nagoya"})
df.head()
| date | store | item | quantity | price | amount | |
|---|---|---|---|---|---|---|
| 0 | 2026-04-01 | Tokyo | コーヒー | 38 | 400 | 15200 |
| 1 | 2026-04-01 | Tokyo | 紅茶 | 24 | 450 | 10800 |
| 2 | 2026-04-01 | Tokyo | ケーキ | 19 | 500 | 9500 |
| 3 | 2026-04-01 | Osaka | コーヒー | 35 | 400 | 14000 |
| 4 | 2026-04-01 | Osaka | 紅茶 | 20 | 450 | 9000 |
Matplotlibで折れ線グラフを描画#
Matplotlibでグラフを描画するには、matplotlib.pyplotをインポートします。
pyplotは、Matplotlibでグラフを描画するための機能をまとめたモジュールです。
pltという別名でインポートするのが慣例です。
import matplotlib.pyplot as plt
第5章のgroupby()メソッドで、日ごとの売上金額の合計を求めます。
# 日ごとの売上金額の合計を計算
df_daily = df.groupby("date")["amount"].sum()
df_daily.head()
date
2026-04-01 86900
2026-04-02 80050
2026-04-03 73500
2026-04-04 80550
2026-04-05 84500
Name: amount, dtype: int64
日ごとの売上金額の合計を、折れ線グラフにします。 折れ線グラフは、値を線で結んだグラフで、時間とともに値がどう変わるか(推移)を見るために使います。
fig, ax = plt.subplots() # 描画オブジェクトとサブプロットを生成
ax.plot(df_daily) # 折れ線グラフを描画
plt.show() # グラフを表示
Matplotlibのグラフは、描画オブジェクトとサブプロットからできています。
描画オブジェクト(Figure):グラフ全体を描画する領域
サブプロット(Axes):描画オブジェクトの中で、グラフを描画する領域
plt.subplots()関数で描画オブジェクト(fig)とサブプロット(ax)を生成し、サブプロットのplot()メソッドで折れ線グラフを描画します。
plot()メソッドにSeriesを渡すと、インデックス(日付)が横軸、値(売上金額の合計)が縦軸になります。
最後のplt.show()関数でグラフを表示します。
これだけのプログラムでシンプルな折れ線グラフが描画できます。 ただ、このグラフには、何のグラフか、横軸と縦軸が何を表すかが書かれていません。 次の節でグラフをカスタマイズして、より意味がわかりやすいグラフにします。
6.4. グラフをカスタマイズする#
まずは、このグラフが何を表すものかわかりやすくするために、タイトルと軸ラベルを付けます。
タイトル:グラフの上に表示する、グラフの名前
軸ラベル:横軸と縦軸に表示する、軸が表す値の名前
タイトルはサブプロットのset_title()メソッド、軸ラベルはset_xlabel()メソッド(横軸)とset_ylabel()メソッド(縦軸)で付けます。
ここでは英語のタイトルと軸ラベルを設定します。
fig, ax = plt.subplots()
ax.plot(df_daily)
ax.set_title("Daily sales") # タイトル
ax.set_xlabel("Date") # 横軸のラベル
ax.set_ylabel("Sales (yen)") # 縦軸のラベル
plt.show()
タイトルと軸ラベルが付きました。 ただし、横軸の日付の目盛りが重なっていて読みにくくなっています。
描画オブジェクトのautofmt_xdate()メソッドを使うと、日付の目盛りが斜めになり、重ならなくなります。
前のセルのコードをコピーして、plt.show()の前に1行追加します。
fig, ax = plt.subplots()
ax.plot(df_daily)
ax.set_title("Daily sales")
ax.set_xlabel("Date")
ax.set_ylabel("Sales (yen)")
fig.autofmt_xdate() # 日付の目盛りを斜めにする
plt.show()
グラフから、日ごとの売上は約6.7万〜8.8万円で推移していることが分かります。 4月8日が最も少なくなっています。 これは、第5章で欠損値を0にした名古屋店のコーヒーの行がある日です。
コラム:pyplotインタフェースとオブジェクト指向インタフェース#
Matplotlibのグラフの書き方には、2つの種類があります。
この章で使っている、plt.subplots()関数で描画オブジェクトとサブプロットを生成し、サブプロットのメソッドで描画する書き方を、オブジェクト指向インタフェースといいます。
オブジェクト指向インタフェースでは、次のように1つの描画オブジェクトに複数のサブプロットを配置して、それぞれにグラフを描画できます。
fig, axes = plt.subplots(2, 2) # 2行2列のサブプロットを配置
plt.show()
一方、Webで見つかるMatplotlibのコードでは、描画オブジェクトとサブプロットを生成せずに、pltの関数で描画するpyplotインタフェースもよく見られます。
次のコードでも、タイトルと軸ラベルを付けた最初のグラフと同じグラフが描画できます。
plt.plot(df_daily)
plt.title("Daily sales")
plt.xlabel("Date")
plt.ylabel("Sales (yen)")
plt.show()
この講座では、オブジェクト指向インタフェースを使います。
6.5. 棒グラフで比較する#
棒グラフは、項目ごとの値を棒の高さで表したグラフで、項目どうしを比べるために使います。 ここでは、店舗ごとの売上金額の合計を比べます。
日ごとの売上金額の合計と同じくgroupby()メソッドで、店舗ごとの売上金額の合計を求めます。
# 店舗ごとの売上金額の合計を計算
df_store = df.groupby("store")["amount"].sum()
df_store
store
Nagoya 641850
Osaka 815050
Tokyo 988500
Name: amount, dtype: int64
店舗ごとの売上金額の合計を、棒グラフにします。
fig, ax = plt.subplots()
ax.bar(df_store.index, df_store) # 棒グラフを描画
ax.set_title("Sales by store")
ax.set_xlabel("Store")
ax.set_ylabel("Sales (yen)")
plt.show()
サブプロットのbar()メソッドには、横軸の項目(インデックスの店舗名)と、棒の高さ(売上金額の合計)を渡します。
縦軸の左上の1e6は、目盛りの値に100万(10の6乗)を掛けることを表します。
たとえば、Tokyoの棒は約1.0なので、約100万円です。
グラフから、Tokyoの売上が最も多く、Nagoyaが最も少ないことが分かります。
サブプロットのbarh()メソッドを使うと、棒を横向きにした棒グラフを描画できます。
項目の名前が長い場合や、項目が多い場合に便利です。
横向きのため、横軸が売上金額、縦軸が店舗になります。
fig, ax = plt.subplots()
ax.barh(df_store.index, df_store) # 横向きの棒グラフを描画
ax.set_title("Sales by store")
ax.set_xlabel("Sales (yen)")
ax.set_ylabel("Store")
plt.show()
6.6. 散布図で関係を見る#
散布図は、2つの値を横軸と縦軸にとって点で表したグラフで、2つの値の関係を見るために使います。 可視化とはのアンスコムの例で見たグラフです。 ここでは、コーヒーとケーキの数量の関係を見ます。
第5章と同じく条件を指定して、コーヒーの行とケーキの行をそれぞれ抽出します。
# コーヒーの行を抽出
df_coffee = df[df["item"] == "コーヒー"]
df_coffee.head()
| date | store | item | quantity | price | amount | |
|---|---|---|---|---|---|---|
| 0 | 2026-04-01 | Tokyo | コーヒー | 38 | 400 | 15200 |
| 3 | 2026-04-01 | Osaka | コーヒー | 35 | 400 | 14000 |
| 6 | 2026-04-01 | Nagoya | コーヒー | 19 | 400 | 7600 |
| 9 | 2026-04-02 | Tokyo | コーヒー | 38 | 400 | 15200 |
| 12 | 2026-04-02 | Osaka | コーヒー | 30 | 400 | 12000 |
# ケーキの行を抽出
df_cake = df[df["item"] == "ケーキ"]
df_cake.head()
| date | store | item | quantity | price | amount | |
|---|---|---|---|---|---|---|
| 2 | 2026-04-01 | Tokyo | ケーキ | 19 | 500 | 9500 |
| 5 | 2026-04-01 | Osaka | ケーキ | 16 | 500 | 8000 |
| 8 | 2026-04-01 | Nagoya | ケーキ | 13 | 500 | 6500 |
| 11 | 2026-04-02 | Tokyo | ケーキ | 14 | 500 | 7000 |
| 14 | 2026-04-02 | Osaka | ケーキ | 14 | 500 | 7000 |
2つの表を見比べると、どちらも行が同じ日・同じ店舗の順に並んでいることが分かります。
そのため、2つの表のquantity列を同じ順で組にすると、同じ日・同じ店舗のコーヒーとケーキの数量の組になります。
コーヒーの数量を横軸、ケーキの数量を縦軸にして、散布図を描画します。
fig, ax = plt.subplots()
ax.scatter(df_coffee["quantity"], df_cake["quantity"]) # 散布図を描画
ax.set_title("Coffee and cake")
ax.set_xlabel("Coffee (quantity)")
ax.set_ylabel("Cake (quantity)")
plt.show()
サブプロットのscatter()メソッドには、横軸の値と縦軸の値を渡します。
同じ順に並んだ値の組が、1つの点になります。
一方の値が多いともう一方の値も多い(または少ない)という、2つの値の関係を相関といいます。
グラフから、点が右上がりに並んでいて、コーヒーが多い日・店舗はケーキも多い傾向(相関)があることが分かります。 また、ほかの点から離れた0の点が2つあります。 横軸が0の点は4月8日の名古屋店のコーヒー、縦軸が0の点は4月3日の大阪店のケーキです。 どちらも第5章で欠損値を0にした行で、外れ値です。
6.7. ヒストグラムで分布を見る#
ヒストグラムは、値をいくつかの範囲に区切り、範囲ごとの個数を棒の高さで表したグラフです。 値の分布(どの値がどれだけあるか)を見るために使います。 区切った範囲をビンといいます。 ここでは、コーヒーの数量の分布を見ます。
fig, ax = plt.subplots()
ax.hist(df_coffee["quantity"]) # ヒストグラムを描画
ax.set_title("Coffee quantity")
ax.set_xlabel("Quantity")
ax.set_ylabel("Count")
plt.show()
サブプロットのhist()メソッドには、分布を見たい値を渡します。
デフォルトでは、値の範囲を10個のビンに分けます。
棒グラフは項目どうしを比べるグラフで、ヒストグラムは1つの値の分布を見るグラフです。 ヒストグラムの横軸は項目ではなく値の範囲のため、棒の間にすき間がありません。
binsでビンの数を指定すると、より細かく区切ったヒストグラムを描画できます。
bins=20は、値の範囲を20個のビンに分ける指定です。
fig, ax = plt.subplots()
ax.hist(df_coffee["quantity"], bins=20) # ビンの数を指定
ax.set_title("Coffee quantity")
ax.set_xlabel("Quantity")
ax.set_ylabel("Count")
plt.show()
グラフから、コーヒーの数量の多くは20〜40個であることが分かります。 また、0の外れ値がほかから離れて現れています。
orientation="horizontal"を指定すると、棒を横向きにしたヒストグラムを描画できます。
横向きのため、横軸が個数、縦軸が数量になります。
fig, ax = plt.subplots()
ax.hist(
df_coffee["quantity"],
bins=20,
orientation="horizontal", # 棒を横向きにする
)
ax.set_title("Coffee quantity")
ax.set_xlabel("Count")
ax.set_ylabel("Quantity")
plt.show()
6.8. そのほかのグラフ#
Matplotlibでは、ほかにもさまざまなグラフを描画できます。 描画できるグラフの種類は、公式サイトの「Plot types」のページで確認できます。
MatplotlibのPlot typesのページ#
ここでは、箱ひげ図と円グラフを描画します。
箱ひげ図#
箱ひげ図は、グループごとの値の散らばりと外れ値を比べるためのグラフです。 ここでは、店舗ごとのコーヒーの数量を比べます。
散布図で抽出したコーヒーの行(df_coffee)から、店舗ごとの数量を抽出します。
# 店舗ごとのコーヒーの数量を抽出
coffee_tokyo = df_coffee[df_coffee["store"] == "Tokyo"]["quantity"]
coffee_osaka = df_coffee[df_coffee["store"] == "Osaka"]["quantity"]
coffee_nagoya = df_coffee[df_coffee["store"] == "Nagoya"]["quantity"]
fig, ax = plt.subplots()
ax.boxplot( # 箱ひげ図を描画
[coffee_tokyo, coffee_osaka, coffee_nagoya],
tick_labels=["Tokyo", "Osaka", "Nagoya"],
)
ax.set_title("Coffee quantity by store")
ax.set_xlabel("Store")
ax.set_ylabel("Quantity")
plt.show()
サブプロットのboxplot()メソッドには、グループごとの値をリストにして渡します。
tick_labelsで、横軸の目盛りのラベル(店舗名)を指定します。
箱ひげ図は、次のように読みます。
箱:中央の50%の値の範囲
箱の中の線:中央値
ひげ:外れ値を除いた最小値から最大値までの範囲
点:外れ値
グラフから、コーヒーの数量はTokyoが最も多いことが分かります。 また、Nagoyaの0が外れ値として点で現れています。
円グラフ#
円グラフは、全体を円で表し、項目ごとの割合を扇形の大きさで表したグラフで、全体に対する割合を見るために使います。
ここでは、棒グラフで比べた店舗ごとの売上金額の合計(df_store)の割合を見ます。
fig, ax = plt.subplots()
ax.pie(df_store, labels=df_store.index) # 円グラフを描画
ax.set_title("Sales share by store")
plt.show()
サブプロットのpie()メソッドには、割合を見たい値を渡し、labelsで項目のラベルを指定します。
円グラフには軸がないため、軸ラベルは付けません。
デフォルトでは、円の右(時計の3時の位置)から反時計回りに項目を配置します。
上(時計の12時の位置)から配置を始めるにはstartangle=90(90度の位置)、時計回りに配置するにはcounterclock=Falseを指定します。
fig, ax = plt.subplots()
ax.pie(
df_store,
labels=df_store.index,
startangle=90, # 12時の位置から配置
counterclock=False, # 時計回りに配置
)
ax.set_title("Sales share by store")
plt.show()
autopctを指定すると、それぞれの扇形に割合を表示できます。
"%.1f%%"は、割合を小数第1位までの%で表示する書式です。
fig, ax = plt.subplots()
ax.pie(
df_store,
labels=df_store.index,
startangle=90,
counterclock=False,
autopct="%.1f%%", # 割合を表示
)
ax.set_title("Sales share by store")
plt.show()
グラフから、売上金額の割合はTokyoが約40%であることが分かります。
6.9. 日本語の表示#
この章ではここまで、店舗名を英語に書き換えたデータを使ってきました。 Matplotlibでグラフに日本語を表示するには、フォントの設定が必要です。
フォントを指定せずにグラフのタイトルなどで日本語を表示すると、次のように日本語の文字が四角になります(豆腐化とも呼ばれます)。 Matplotlibの標準のフォント(DejaVu Sans)には日本語の文字がないため、豆腐化が起こります。
フォントを指定せずに日本語を表示した棒グラフ#
グラフを作成するときに、次のような警告のメッセージが出力されます。 メッセージの内容は「DejaVu Sansというフォントに、この文字(Glyph)が存在しない」という意味です。
UserWarning: Glyph 22770 (\N{CJK UNIFIED IDEOGRAPH-58F2}) missing from font(s) DejaVu Sans.
それでは、日本語のフォントを指定します。
platform.system()関数は、OSの名前を返します(Windowsは"Windows"、macOSは"Darwin")。
plt.rcParamsはMatplotlibの設定で、"font.family"にフォント名を指定すると、それ以降のグラフの文字がそのフォントで表示されます。
WindowsとmacOSでは入っている日本語のフォントが違うため、OSを判定して指定します。
1つのコードでWindowsでもmacOSでも日本語フォントが正しく設定できます。
import platform
import matplotlib.pyplot as plt
# OSに合わせて日本語のフォントを指定
if platform.system() == "Windows":
plt.rcParams["font.family"] = "Yu Gothic"
elif platform.system() == "Darwin":
plt.rcParams["font.family"] = "Hiragino Sans"
else:
plt.rcParams["font.family"] = "IPAPGothic"
LinuxでIPAPGothicがない場合は、OSにある日本語のフォント名に書き換えてください。
注釈
カーネルを再起動すると、フォントの設定も消えます。 カーネルを再起動した場合は、この節のセルを上から順にもう一度実行してください。
店舗名を日本語に戻すため、売上データを読み込み直します。 売上データの読み込みの最初のセルと同じコードです。
# 売上データを読み込み直す
import pandas as pd
df = pd.read_csv("sales_clean.csv", parse_dates=["date"])
「棒グラフで比較する」と同じく、店舗ごとの売上金額の合計を求めます。 店舗名が日本語になっていることを確認してください。
# 店舗ごとの売上金額の合計を計算
df_store = df.groupby("store")["amount"].sum()
df_store
store
名古屋店 641850
大阪店 815050
東京店 988500
Name: amount, dtype: int64
「棒グラフで比較する」のグラフを、日本語の店舗名、タイトル、軸ラベルで描画し直します。
fig, ax = plt.subplots()
ax.bar(df_store.index, df_store)
ax.set_title("店舗ごとの売上金額")
ax.set_xlabel("店舗")
ax.set_ylabel("売上金額(円)")
plt.show()
日本語の店舗名、タイトル、軸ラベルが表示されました。
6.10. pandasからグラフを描画する#
pandasのplot()メソッドは、内部でMatplotlibを使用してグラフを描画します。
plot.bar()メソッドを使うと、棒グラフを描画できます。
日本語の表示で求めた店舗ごとの売上金額の合計(df_store)から、棒グラフを描画します。
df_store.plot.bar() # pandasから棒グラフを描画
plt.show()
描画オブジェクトとサブプロットの生成を必要とせず、plot.bar()メソッドを1行呼び出すだけで棒グラフを描画できます。
横軸にはインデックスの店舗名が、横軸のラベルにはインデックスの名前(store)が自動で設定されます。
タイトルや軸ラベルなどを指定する引数は、pandasのリファレンスで調べられます。
pandas.Series.plot.bar:https://pandas.pydata.org/docs/reference/api/pandas.Series.plot.bar.html
また、棒グラフ以外のグラフを描画するためのメソッドとドキュメントへのリンクを以下に示します。
グラフ名 |
メソッド |
|---|---|
折れ線グラフ |
|
散布図 |
|
ヒストグラム |
|
箱ひげ図 |
|
円グラフ |
6.11. この章のまとめ#
この章では以下を行いました。
節 |
行ったこと |
グラフ |
使った関数・メソッドなど |
|---|---|---|---|
売上データの折れ線グラフを描画する |
日ごとの売上金額の推移を見る |
折れ線グラフ |
|
グラフをカスタマイズする |
タイトルと軸ラベルを付け、日付の目盛りを斜めにする |
折れ線グラフ |
|
棒グラフで比較する |
店舗ごとの売上金額を比較する |
棒グラフ |
|
散布図で関係を見る |
コーヒーとケーキの数量の関係を見る |
散布図 |
|
ヒストグラムで分布を見る |
コーヒーの数量の分布を見る |
ヒストグラム |
|
そのほかのグラフ |
店舗ごとのコーヒーの数量の散らばりを比較する、店舗ごとの売上金額の割合を見る |
箱ひげ図、円グラフ |
|
日本語の表示 |
日本語のフォントを指定し、棒グラフを日本語で描画する |
棒グラフ |
|
pandasからグラフを描画する |
pandasの集計結果から棒グラフを描画する |
棒グラフ |
|
次の第7章では、機械学習やスクレイピングなど、データ分析の応用を紹介します。 また、気象庁のページから取得したデータを、第5章と第6章の方法で加工してグラフにする実演を見ます。