seaborn

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

スケールの異なるデータを1つのグラフにまとめたい時などは、y軸を左右の両方に作成すると見やすくなる。

2軸グラフを作成する場合、matplotlibでも作成可能だが、seabornの方がより簡単に見やすいグラフを作成できるため、seabornで作成する。

データ準備

以下のようなスケールの異なるデータを例とする。

import pandas as pd

import matplotlib.pyplot as plt
import seaborn as sns

sns.set(font="meiryo")

date_list = ["2020/1/1", "2020/2/1", "2020/3/1", "2020/4/1", "2020/5/1"]
values = [[1, 150], [2, 140], [3, 130], [5, 120], [8, 110]]

df = pd.DataFrame(data=values, index=date_list, columns=["colA", "colB"])
# インデックスを日付型に変換
df.index = pd.to_datetime(df.index)
print(df)
>>
            colA  colB
2020-01-01     1   150
2020-02-01     2   140
2020-03-01     3   130
2020-04-01     5   120
2020-05-01     8   110

colAはフィボナッチ数列。colBは10ずつ減少。

スケールの異なるグラフ(1軸)

特にy軸の設定を何もしなければ、2つのcolAとcolBを同じグラフに描画すると、以下のようになる。

fig = plt.figure(figsize=(12, 6.75), facecolor="w")
# x軸の値設定
x = df.index.strftime("%Y-%m").to_list()
# 折れ線グラフ描画
sns.lineplot(data=df, x=x, y="colA", color="red", label="colA")
sns.lineplot(data=df, x=x, y="colB", color="blue",label="colB")
plt.title("スケールの違うグラフ例")
plt.tight_layout()
plt.show()

一方は0付近、もう一方は100ちょいにあることは分かるが、分かりにくい。

2軸グラフ

y軸を左右でcolAとcolBに分ける。

subplots()で作成されたaxをtwinx()でコピーする。

seabornでグラフを作成する時に、引数axにそれぞれax1、ax2を設定する。

fig = plt.figure(figsize=(12, 6.75), facecolor="w")

ax1 = fig.subplots()
# ax1のx軸をコピー
ax2 = ax1.twinx()
# x軸の値設定
x = df.index.strftime("%Y-%m").to_list()
# 折れ線グラフ描画
sns.lineplot(data=df, x=x, y="colA", ax=ax1, color="red", label="colA")
sns.lineplot(data=df, x=x, y="colB", ax=ax2, color="blue",label="colB")

# 各y軸の範囲を設定
ax1.set_ylim(0, 10)
ax2.set_ylim(100, 180)
# ax2のグリッド線を非表示にする
ax2.grid(False)
# 凡例を取得
handler1, label1 = ax1.get_legend_handles_labels()
handler2, label2 = ax2.get_legend_handles_labels()
# ax1で凡例をまとめて表示
ax1.legend(handler1 + handler2, label1 + label2, loc="upper center")
# ax2の凡例は削除
ax2.get_legend().remove()

plt.title("2軸グラフ例")
plt.tight_layout()
plt.show()

y軸を分けたことで、colBは直線だが、colAは直線ではないことが分かる。

なお、左右の軸のグリッド線を合わせるためには、目盛の設定を合わせる必要があるため、どうしても必要という場合でなければ、どちらか一方のグリッド線を消す方がラク。

無理にグリッド線を合わせるよりも、2種類のグラフの特徴がよく分かるような目盛に設定する方が良い。

2軸グラフ(棒グラフと折れ線グラフ)

2軸グラフを作成する場合、2種類のグラフが混じるため、グラフの種類を変えた方が分かりやすいことが多い。

fig = plt.figure(figsize=(12, 6.75), facecolor="w")

ax1 = fig.subplots()
# ax1のx軸をコピー
ax2 = ax1.twinx()
# x軸の値設定
x = df.index.strftime("%Y-%m").to_list()
# 折れ線グラフ描画
sns.barplot(data=df, x=x, y="colA", ax=ax1, color="orange", label="colA", alpha=0.7)
sns.lineplot(data=df, x=x, y="colB", ax=ax2, color="blue",label="colB")

# 各y軸の範囲を設定
ax1.set_ylim(0, 10)
ax2.set_ylim(100, 180)
# ax2のグリッド線を非表示にする
ax2.grid(False)
# 凡例を取得
handler1, label1 = ax1.get_legend_handles_labels()
handler2, label2 = ax2.get_legend_handles_labels()
# ax1で凡例をまとめて表示
ax1.legend(handler1 + handler2, label1 + label2, loc="upper center")
# ax2の凡例は削除
ax2.get_legend().remove()

plt.title("2軸グラフ例")
plt.tight_layout()
plt.show()

lineplotをbarplotに変えるだけ。

折れ線グラフの方が前面になるようにした方が見やすい。

また、棒グラフはalphaを0.5~0.8辺りに設定してあげると、前面の折れ線グラフが見やすくなる。

シンプルなグラフだと、matplotlibでも十分だが、複数の棒グラフを並べたり、エラーバーを付けたりなどの場合、seabornを使う方が簡単にグラフを作成できるので、seabornにも慣れておくと便利。

まとめ

ポイントはseabornのグラフ描画時に、引数axを指定すること。

ax1 = fig.subplots()
# ax1のx軸をコピー
ax2 = ax1.twinx()

# グラフ描画。axにそれぞれax1、ax2を指定する
sns.barplot(data=data, x=x, y=y, ax=ax1)
sns.lineplot(data=data, x=x, y=y, ax=ax2)