【Seaborn】2軸のグラフを作成する

スケールの異なるデータを1つのグラフにまとめたい時などは、y軸を左右の両方に作成すると見やすくなる。
2軸グラフを作成する場合、matplotlibでも作成可能だが、seabornの方がより簡単に見やすいグラフを作成できるため、seabornで作成する。
データ準備
以下のようなスケールの異なるデータを例とする。
1import pandas as pd
2
3import matplotlib.pyplot as plt
4import seaborn as sns
5
6sns.set(font="meiryo")
7
8date_list = ["2020/1/1", "2020/2/1", "2020/3/1", "2020/4/1", "2020/5/1"]
9values = [[1, 150], [2, 140], [3, 130], [5, 120], [8, 110]]
10
11df = pd.DataFrame(data=values, index=date_list, columns=["colA", "colB"])
12# インデックスを日付型に変換
13df.index = pd.to_datetime(df.index)
14print(df)
15
16# colA colB
17# 2020-01-01 1 150
18# 2020-02-01 2 140
19# 2020-03-01 3 130
20# 2020-04-01 5 120
21# 2020-05-01 8 110
colAはフィボナッチ数列。colBは10ずつ減少。
スケールの異なるグラフ(1軸)
特にy軸の設定を何もしなければ、2つのcolAとcolBを同じグラフに描画すると、以下のようになる。
1fig = plt.figure(figsize=(12, 6.75), facecolor="w")
2# x軸の値設定
3x = df.index.strftime("%Y-%m").to_list()
4# 折れ線グラフ描画
5sns.lineplot(data=df, x=x, y="colA", color="red", label="colA")
6sns.lineplot(data=df, x=x, y="colB", color="blue",label="colB")
7plt.title("スケールの違うグラフ例")
8plt.tight_layout()
9plt.show()

一方は0付近、もう一方は100ちょいにあることは分かるが、分かりにくい。
2軸グラフ
y軸を左右でcolAとcolBに分ける。
subplots()で作成されたaxをtwinx()でコピーする。
seabornでグラフを作成する時に、引数axにそれぞれax1、ax2を設定する。
1fig = plt.figure(figsize=(12, 6.75), facecolor="w")
2
3ax1 = fig.subplots()
4# ax1のx軸をコピー
5ax2 = ax1.twinx()
6# x軸の値設定
7x = df.index.strftime("%Y-%m").to_list()
8# 折れ線グラフ描画
9sns.lineplot(data=df, x=x, y="colA", ax=ax1, color="red", label="colA")
10sns.lineplot(data=df, x=x, y="colB", ax=ax2, color="blue",label="colB")
11
12# 各y軸の範囲を設定
13ax1.set_ylim(0, 10)
14ax2.set_ylim(100, 180)
15# ax2のグリッド線を非表示にする
16ax2.grid(False)
17# 凡例を取得
18handler1, label1 = ax1.get_legend_handles_labels()
19handler2, label2 = ax2.get_legend_handles_labels()
20# ax1で凡例をまとめて表示
21ax1.legend(handler1 + handler2, label1 + label2, loc="upper center")
22# ax2の凡例は削除
23ax2.get_legend().remove()
24
25plt.title("2軸グラフ例")
26plt.tight_layout()
27plt.show()

y軸を分けたことで、colBは直線だが、colAは直線ではないことが分かる。
なお、左右の軸のグリッド線を合わせるためには、目盛の設定を合わせる必要があるため、どうしても必要という場合でなければ、どちらか一方のグリッド線を消す方がラク。
無理にグリッド線を合わせるよりも、2種類のグラフの特徴がよく分かるような目盛に設定する方が良い。
2軸グラフ(棒グラフと折れ線グラフ)
2軸グラフを作成する場合、2種類のグラフが混じるため、グラフの種類を変えた方が分かりやすいことが多い。
1fig = plt.figure(figsize=(12, 6.75), facecolor="w")
2
3ax1 = fig.subplots()
4# ax1のx軸をコピー
5ax2 = ax1.twinx()
6# x軸の値設定
7x = df.index.strftime("%Y-%m").to_list()
8# 折れ線グラフ描画
9sns.barplot(data=df, x=x, y="colA", ax=ax1, color="orange", label="colA", alpha=0.7)
10sns.lineplot(data=df, x=x, y="colB", ax=ax2, color="blue",label="colB")
11
12# 各y軸の範囲を設定
13ax1.set_ylim(0, 10)
14ax2.set_ylim(100, 180)
15# ax2のグリッド線を非表示にする
16ax2.grid(False)
17# 凡例を取得
18handler1, label1 = ax1.get_legend_handles_labels()
19handler2, label2 = ax2.get_legend_handles_labels()
20# ax1で凡例をまとめて表示
21ax1.legend(handler1 + handler2, label1 + label2, loc="upper center")
22# ax2の凡例は削除
23ax2.get_legend().remove()
24
25plt.title("2軸グラフ例")
26plt.tight_layout()
27plt.show()

lineplotをbarplotに変えるだけ。
折れ線グラフの方が前面になるようにした方が見やすい。
また、棒グラフはalphaを0.5~0.8辺りに設定してあげると、前面の折れ線グラフが見やすくなる。
シンプルなグラフだと、matplotlibでも十分だが、複数の棒グラフを並べたり、エラーバーを付けたりなどの場合、seabornを使う方が簡単にグラフを作成できるので、seabornにも慣れておくと便利。
まとめ
ポイントはseabornのグラフ描画時に、引数axを指定すること。
1ax1 = fig.subplots()
2# ax1のx軸をコピー
3ax2 = ax1.twinx()
4
5# グラフ描画。axにそれぞれax1、ax2を指定する
6sns.barplot(data=data, x=x, y=y, ax=ax1)
7sns.lineplot(data=data, x=x, y=y, ax=ax2)