【Seaborn】2軸のグラフを作成する【Matplotlib】
スケールの異なるデータを1つのグラフにまとめたい時などは、y軸を左右の両方に作成すると見やすくなる。
軸の設定が重要になってくる。また、左右の軸のグリッド線を合わせるなどの小技も、見やすいグラフを作るのには必要になる。
グラフ自体は、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は直線ではないことが分かる。
なお、左右の軸の範囲はset_ylim()
で設定しているが、この場合、左右で目盛りのグリッド線が合わなくなる。ax.grid(False)
でどちらか一方のグリッド線を消すことができる。
グリッド線を合わせたい場合はax.set_yticks()
を使うと良い。
左右の目盛り線を合わせたグラフ
y軸の目盛り設定時にax.set_yticks()
を使う。
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_yticks(np.linspace(ax1.get_yticks()[0], ax1.get_yticks()[-1], len(ax2.get_yticks())))
14ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))
15# 凡例を取得
16handler1, label1 = ax1.get_legend_handles_labels()
17handler2, label2 = ax2.get_legend_handles_labels()
18# ax1で凡例をまとめて表示
19ax1.legend(handler1 + handler2, label1 + label2, loc="upper center")
20# ax2の凡例は削除
21ax2.get_legend().remove()
22
23plt.title("2軸グラフ例")
24plt.tight_layout()
25plt.show()
set_yticks()で値を指定する時に、np.linspace()でy軸の値をもう一方の軸の長さで分割することで、お互いに目盛りのグリッド線の位置が揃う。
棒グラフと折れ線グラフ
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_yticks(np.linspace(ax1.get_yticks()[0], ax1.get_yticks()[-1], len(ax2.get_yticks())))
14ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))
15# 凡例を取得
16handler1, label1 = ax1.get_legend_handles_labels()
17handler2, label2 = ax2.get_legend_handles_labels()
18# ax1で凡例をまとめて表示
19ax1.legend(handler1 + handler2, label1 + label2, loc="upper center")
20# ax2の凡例は削除
21ax2.get_legend().remove()
22
23plt.title("2軸グラフ例")
24plt.tight_layout()
25plt.show()
lineplotをbarplotに変えるだけ。
折れ線グラフの方が前面になるようにした方が見やすい。
また、棒グラフはalphaを0.5~0.8辺りに設定してあげると、前面の折れ線グラフが見やすくなる。
シンプルなグラフだと、matplotlibでも十分だが、複数の棒グラフを並べたり、エラーバーを付けたりなどの場合、seabornを使う方が簡単にグラフを作成できるので、seabornにも慣れておくと便利。
まとめ
ポイントはseabornのグラフ描画時に、引数axを指定すること。
グリッド線を合わせたい場合、ax.set_yticksとnp.linspaceを使う。
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)
8
9# 各y軸の範囲を設定
10ax1.set_yticks(np.linspace(ax1.get_yticks()[0], ax1.get_yticks()[-1], len(ax2.get_yticks())))
11ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))