seaborn

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

MAX

スケールの異なるデータを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())))
スポンサーリンク
ABOUT ME
MAX
MAX
ITエンジニア、データサイエンティスト
新卒でSIerに入社し、フリーランスになってWEB系へ転向。
その後AIの世界へ足を踏み入れ、正社員に戻る。 テーブルデータの分析がメイン。
スポンサーリンク
記事URLをコピーしました