Matplotlib & Seaborn 入門講座 | 09.Pythonを使った2軸グラフの作成方法

Matplotlib & Seaborn 入門講座 09.Pythonを使った2軸グラフの作成方法
Matplotlib & Seaborn入門講座
この記事の執筆者 キノコード キノコード

テクノロジーアンドデザインカンパニー株式会社のCEO。
日本最大級のプログラミング教育のYouTubeチャンネル「キノコード」や、プログラミング学習サービス「キノクエスト」を運営。
書籍「あなたの仕事が一瞬で片付くPythonによる自動化仕事術」の著者や、雑誌「日経ソフトウエア」の寄稿などの実績も多数。

挨拶

こんにちは。キノコードです。
Matplotlib & Seaborn入門講座の9回目です。
このレッスンでは、2軸グラフの作成方法について学びます。
2軸グラフとは、2つの異なるデータを1枚のグラフにプロットし、左のy軸には1つ目のデータのラベル、右側のy軸には2つ目のデータのラベルを表示させたグラフのことです。
2つのデータのスケールが異なる場合によく使用されるグラフです。
具体的には、数値とパーセントを同時に表示させたい時、整数と少数を同時に表示させたい時に使います。
例えば、売上金額と売上比率や、気温と湿度を同時に表示させいたい時です。
応用的な話になりますが、これを使えるようになれば自由自在にグラフを作成することができます。
復習と実践を通して、ぜひ習得してください。
また、キノコードでは、月額290円からキノコードを応援するYouTubeのメンバーシップを募集しています。
キノコードは、プログラミングやIT、テクノロジーの知識であったり、その活用を日本中に広めたいと思っています。
キノコードでのYouTubeの活動などを応援してくださる方は、チャンネル登録ボタンの横にある「メンバーになる」をクリックをお願いします。
メンバーシップをはじめた理由などの動画もありますので、そちらもご視聴ください。
概要欄にURLを貼っておきます。
それではレッスンスタートです。

レッスンで使ったファイルはこちら

■保存方法
Mac:右クリック⇒「リンク先を別名で保存」
Windows:右クリック⇒「名前を付けてリンク先を保存」

Jupyter Labのファイルはこちら
CSVファイル1はこちら
CSVファイル2はこちら

ライブラリインポート

import matplotlib.pyplot as plt
%matplotlib inline
import pandas as pd

まずは、ライブラリをインポートする記述をします。
matplotlibをpltという名前でインポート。
notebook上にグラフを表示させるための記述もします。
今回は、あらかじめ用意したcsvファイルを読み込んでグラフを作成します。
そのため、csvやExcelなどのデータを効率的に処理できるpandasもインポートしておきます。
実行します。
インポートが完了しました。

データ読み込み

data = pd.read_csv('1month_data.csv', index_col='売上日', parse_dates=True)

続いてpandasのread_csvメソッドを使って、csvデータを読み込む記述をします。
こちらのcsvファイルについては、キノコードのWebサイトからダウンロードできます。
csvファイルには、架空のアパレル会社の1ヶ月分の売上個数と売上金額が格納されています。
では、dataという変数にcsvデータを代入する記述をします。
売上日の列をインデックスにするために、indexアンダースコアcolと書いてイコール、シングルコーテーションの中に売上日と記述します。
また、時系列データを扱うにはインデックスを日付型に変更する必要があります。
従って、parseアンダースコアdatesという引数をTrueとします。
実行します。

data.head()

headで上位5件を表示させてみましょう。
実行します。
データが格納できているようです。

x = data.index
volume = data['数量(個)']
price = data['売上金額(円)']

続いて、データを扱いやすくするため、変数にデータのインデックスやカラムを代入します。
xには、日付型のインデックスに設定した売上日の列を代入します。
volumeには、数量の列を、priceには売上金額の列を代入します。
実行します。

2軸設定無しプロット

plt.bar(x, volume, color='darkcyan')
plt.plot(x, price, color='red')

plt.title('volume/price')
plt.show()

2軸設定をせずに2つのデータをプロットすると、どのようになるでしょうか。
ここでは、volumeに代入した数量を棒グラフ、priceに代入した売上金額を線グラフで表示させてみます。
また、volumeのカラーをダークシアン、priceのカラーをレッドとしておきます。
実行します。
このように、priceのみプロットされています。
これは、priceに対してvolumeのスケールが遥かに小さいために、グラフ上に表示できないからです。
このような状態を解消するため、2軸グラフを作成していきます。

fig, ax1 = plt.subplots()

ax1.bar(x, volume, color='darkcyan')

ax2 = ax1.twinx()
ax2.plot(x, price, color='red')

plt.show()

第2軸を設定するには、matplotlibの中のtwinxというメソッドを使います。
twinxメソッドを使用するには、まずaxisオブジェクトを生成します。
さらに、axisオブジェクトを生成するには、その土台となるfigureオブジェクトが必要です。
従って、subplotsメソットでfigureオブジェクトとaxisオブジェクトを同時に生成する記述をします。
また、volumeの棒グラフをax1、priceの線グラフをax2とします。
ax2に、ax1ドットtwinx丸括弧を代入することで、ax2を第2軸にプロットさせることができます。
実行します。
2軸グラフを作成できました。

グラフサイズ変更

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.bar(x, volume, color='darkcyan')

ax2 = ax1.twinx()
ax2.plot(x, price, color='red')

plt.show()

続いて、グラフのサイズを変更しましょう。
subplotsメソッドの丸括弧の中で、引数figsizeを設定します。
今回は9対6とします。
実行します。
グラフのサイズを変更できました。

軸ラベル、タイトル追加

import japanize_matplotlib

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.bar(x, volume, color='darkcyan')
ax1.set_ylabel('数量(個)', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(x, price, color='red')
ax2.set_ylabel('売上金額(円)', fontsize=14)

plt.title('東京/売上金額', fontsize=16)
plt.show()

さらに、グラフタイトルと軸ラベルを追加しましょう。
まず、日本語を表示させるためのjapanize matplotlibをインポートします。
続いて、axisのsetメソッドのylabelで軸ラベルを追加します。
axドット、setアンダースコアylabelと記述します。
丸括弧の中で表示させたい軸の名前をシングルコーテーションでくくります。
fontsizeは14としておきます。
ax2の、priceにも同様の記述をします。
グラフタイトルは、pltドットtitleで設定しましょう。
実行します。
グラフタイトルと軸ラベルを追加できました。

x軸日付表示変更

import matplotlib.dates as dt

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.bar(x, volume, color='darkcyan')
ax1.set_ylabel('数量(個)', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(x, price, color='red')
ax2.set_ylabel('売上金額(円)', fontsize=14)

ax2.xaxis.set_major_formatter(dt.DateFormatter('%m/%d'))

plt.title('1月 東京/売上金額', fontsize=15)
plt.show()

x軸の日付のラベルが少し見づらいので、整えてみましょう。
まずは、matplotlibのdatesをdtという名前でインポートします。
datesを使うことで、時系列グラフのx軸の表示を自由に変更することができます。
そして、axis setメソッドの、major_formatterと記述した丸括弧の中に、インポートしたdatesの省略名dt、ドット、DateFoematterと記述します。
ここではax2に記述をしていますが、ax1でも同じように表示されます。
さらに丸括弧の中で、x軸ラベルの表示形式を設定できます。
パーセントの後に、小文字のm、スラッシュを挟んで、dを指定してみます。
ちなみに、mはmonth、dはdayの頭文字です。
実行します。
x軸の日付が先ほどよりも、とても見やすくなりました。

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.bar(x, volume, color='darkcyan')
ax1.set_ylabel('数量(個)', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(x, price, color='red')
ax2.set_ylabel('売上金額(円)', fontsize=14)

ax2.xaxis.set_major_formatter(dt.DateFormatter('%d'))

plt.title('1月 東京/売上金額', fontsize=15)
plt.show()

パーセントdのみにしてみたらどうでしょうか。
実行します。
このように、日付のみの表示になりました。

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.bar(x, volume, color='darkcyan')
ax1.set_ylabel('数量(個)', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(x, price, color='red')
ax2.set_ylabel('売上金額(円)', fontsize=14)

ax2.xaxis.set_major_locator(dt.DayLocator(interval=7))

plt.title('1月 東京/売上金額', fontsize=15)
plt.show()

さらに、 axis setメソッドのmajor_locatorを使って、指定した間隔で日付ラベルを表示させてみます。
DayLocatorと記述した丸括弧の中の、引数intervalで間隔を指定できます。
ここでは1週間ごとの7を設定してみましょう。
実行します。
1週間ごとで日付のラベルが表示されました。
このように、matplotlibのdatesというライブラリを使うことで、時系列グラフのx軸ラベルを自由に変更できます。
お好きな方法を試してみてください。

気温と湿度の2軸グラフ

続いて、データを変えて2軸グラフを作成してみましょう。
ある日の東京の、1日の気温と湿度の時系列データを2軸グラフにしてみます。

データ読み込み

kion_data = pd.read_csv('kion_data.csv', index_col='Date', parse_dates=True)

まずは、pandasのread_csvメソッドを使ってデータを読み込む記述をします。
kionアンダースコアdata という変数に、csvデータを代入します。
こちらのcsvデータも、キノコードのサイトからダウンロードできます。
引数index_colで、Dateの列をインデックスに指定します。
さらに、parse_dates をTrueとすることで、インデックスに指定したDateの列が、日付型に変換されます。
実行します。

kion_data.head()

headで中身を確認してみましょう。
データが格納できているようです。

date = kion_data.index
temp = kion_data['気温(℃)']
humid = kion_data['湿度(%)']

続いてデータを扱いやすいように、変数に代入しましょう。
dateという変数には、日付型のインデックスに指定した列を代入します。
tempには気温の列を、humidには湿度の列を代入します。
実行します。

temp.plot()

まずは、気温のみプロットして見てみましょう。
このようなグラフになっています。

humid.plot()

湿度のグラフはこのようになっています。
これらのグラフを、同時に2軸グラフにプロットします。

気温と湿度を2軸でプロット

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp, color='coral')

ax2 = ax1.twinx()
ax2.plot(humid)

plt.show()

先ほどと同様、まずはsubplotsでfigureオブジェクトとaxisオブジェクトを同時に生成します。
figsizeは9対6としておきます。
ax1には気温のtempをプロットします。
従って、丸括弧の中の第一引数にはtempと記述し、区別をしやすいようにカラーはコーラルとしておきます。
ax2にはtwinxを記述し、第2軸にする設定をします。
こちらは、湿度のhumidをプロットします。
実行します。
2軸グラフを作成できました。

湿度のy軸を0-100に

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp, color='coral')

ax2 = ax1.twinx()
ax2.plot(humid)
ax2.set_ylim(0,100)

plt.show()

湿度はパーセントなので、第2軸のラベルの最小を0、最大を100と表示させましょう。
軸の範囲を変更するには、axis setメソッドのylimで設定できます。
丸括弧の中に、指定したい数値の最小値と最大値を記述します。
実行します。
右側の軸ラベルを0から100の範囲に変更できました。

気温0-20に

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp, color='coral')
ax1.set_ylim(0,20)

ax2 = ax1.twinx()
ax2.plot(humid)
ax2.set_ylim(0,100)

plt.show()

気温の軸も0から20としてみましょう。
ax1にset_ylimを設定します。
実行します。
気温のラベルも変更できました。

軸ラベル、タイトル追加

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp, color='coral')
ax1.set_ylim(0,20)
ax1.set_ylabel('気温[℃]', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(humid)
ax2.set_ylim(0,100)
ax2.set_ylabel('湿度[%]', fontsize=14)

plt.title('Tokyo Temperature/Humid', fontsize=16)
plt.show()

続いて、軸の名前とグラフタイトルを追加しましょう。
軸の名前を表示するには、axis setメソッドのylabelで設定できます。
丸括弧の中に、表示させたい名前をシングルコーテーションでくくります。
fontsizeは14としておきます。
ax2の湿度グラフにも同様に設定します。
グラフのタイトルはpltドット、titleで設定しましょう。
こちらのfontsizeは少し大きめの16としておきます。
実行します。
タイトルとラベルが追加されました。

グリッド追加

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp, color='coral')
ax1.set_ylim(0,20)
ax1.set_ylabel('気温[℃]', fontsize=14)
ax1.grid()

ax2 = ax1.twinx()
ax2.plot(humid)
ax2.set_ylim(0,100)
ax2.set_ylabel('湿度[%]', fontsize=14)

plt.title('Tokyo Temperature/Humid', fontsize=16)

plt.show()

続いて、グラフにグリッド線を追加してみましょう。
gridメソッドを使って、グラフにグリッドを追加します。
ax1の後に付けることで、気温の軸を基準としたグリッド線になります。
実行します。
グリッドを追加できました。

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp, color='coral')
ax1.set_ylim(0,20)
ax1.set_ylabel('気温[℃]', fontsize=14)
ax1.grid(axis='y')

ax2 = ax1.twinx()
ax2.plot(humid)
ax2.set_ylim(0,100)
ax2.set_ylabel('湿度[%]', fontsize=14)

plt.title('Tokyo Temperature/Humid', fontsize=16)

plt.show()

gridメソッドの丸括弧の中に、引数axisを記述しイコール、yをシングルコーテーションでくくることで横線のみのグリッドになります。
実行します。
グリッドが横線のみになりました。

x軸時間表記変更

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp, color='coral')
ax1.set_ylim(0,20)
ax1.set_ylabel('気温[℃]', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(humid)
ax2.set_ylim(0,100)
ax2.set_ylabel('湿度[%]', fontsize=14)
ax2.xaxis.set_major_formatter(dt.DateFormatter('%H:%M'))

plt.title('Tokyo Temperature/Humid', fontsize=16)
plt.grid()
plt.show()

続いて、x軸の時間表記を変更しましょう。
ここでは、時刻のみの表示にしてみます。
先ほどもご紹介した、axis setメソッドの、major formatterを使用します。
丸括弧の中には、インポートしたdatesの省略名dt、ドット、DateFormatterと記述します。
時刻の表示にするには、パーセントの後に大文字のHと、コロンを挟んで大文字のMです。
Hはhour、Mはminuteの頭文字です。
この記述は、ax1とax2のどちらに記述をしても同じように表示されます。
実行します。
x軸を、時刻の表記に変更できました。

凡例追加

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp,color='coral', label='temp')
ax1.set_ylim(0,20)
ax1.set_ylabel('気温[℃]', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(humid, label='humid')
ax2.set_ylim(0,100)
ax2.set_ylabel('湿度[%]', fontsize=14)
ax2.xaxis.set_major_formatter(dt.DateFormatter('%H:%M'))

ax1.legend(bbox_to_anchor=(1, 1), loc='upper right', frameon=False, fontsize=14)
ax2.legend(bbox_to_anchor=(1, 0.9), borderaxespad=0, frameon=False, fontsize=14)

plt.title('Tokyo Temperature/Humid', fontsize=16)
plt.grid()
plt.show()

続いて、それぞれのグラフが何のデータを示しているのか分かりやすいように、凡例を追加しましょう。
まず、それぞれのplotメソッドの丸括弧の中に引数labelを記述し、凡例に表示させたい名前をシングルコーテーションでくくります。
次に、ax1とax2のそれぞれでlegendを作成し、丸括弧の中で凡例の設定をします。
何も設定しないデフォルトでは、2つの凡例が重なってしまうので、引数locやbbox_to_anchorで互いの凡例の位置をずらす設定をします。
まず、ax1の凡例tempを、引数locでupper right、つまりグラフ右上に固定します。
さらに、ax2のbbox_to_anchorは、locで固定したax1の凡例を基準にした位置を数値で設定します。
ax1よりも少し下に表示させたいので、xの位置は1、yの位置は0.9としてみます。
borderaxespad(ボーダーaxisパッド)イコールゼロとすることで、凡例同士の余白を無くすことができます。
また、デフォルトでは凡例に枠線が表示されてしまうので、frameon(フレームオン)をFalseにします。
fontsizeはどちらも14としておきましょう。
実行します。
凡例が表示されました。

補助目盛り追加

from matplotlib.ticker import MultipleLocator

fig, ax1 = plt.subplots(figsize=(9,6))

ax1.plot(temp,color='coral', label='temp')
ax1.set_ylim(0,20)
ax1.set_ylabel('気温[℃]', fontsize=14)

ax2 = ax1.twinx()
ax2.plot(humid, label='humid')
ax2.set_ylim(0,100)
ax2.set_ylabel('湿度[%]', fontsize=14)
ax2.xaxis.set_major_formatter(dt.DateFormatter('%H:%M'))

ax1.legend(bbox_to_anchor=(1, 1), loc='upper right', frameon=False, fontsize=14)
ax2.legend(bbox_to_anchor=(1, 0.9), borderaxespad=0, frameon=False, fontsize=14)

ax1.yaxis.set_minor_locator(MultipleLocator(0.5))
ax2.yaxis.set_minor_locator(MultipleLocator(5))

plt.title('Tokyo Temperature/Humid', fontsize=16)
plt.grid()
plt.show()

最後は、y軸の目盛りに補助目盛りを追加してみましょう。
まず、matplotlibのtickerというライブラリからMultipleLocatorをインポートします。
axis setメソッドのminor_locatorを使って、補助目盛りの設定をします。
インポートしたMultipleLocatorを記述し丸括弧、補助目盛りの間隔を数値で設定します。
ax1の気温の補助目盛りは0.5度ごと、湿度は5パーセントごととしましょう。
実行します。
補助目盛りを追加できました。

挨拶

キノコードではmatplotlibやSeabornのレッスンだけではなく、仕事の自動化のレッスン、人工知能のレッスンなども配信しています。
キノコードの新着動画はチャンネル登録をしていただければ、通知が届きますので、ぜひチャンネル登録をお願いします。
それでは、次のレッスンでお会いしましょう。

レッスンで使ったファイルはこちら

■保存方法
Mac:右クリック⇒「リンク先を別名で保存」
Windows:右クリック⇒「名前を付けてリンク先を保存」

Jupyter Labのファイルはこちら
CSVファイル1はこちら
CSVファイル2はこちら