DataScience

【Python】【Seaborn】複数の棒グラフを並べて表示する

棒グラフでグループ毎に値を並べて表示したい場合などがある。

matplotlibだと多少面倒だが、seabornのbarplotの引数hueを使うと、少しデータ整形が必要になるが、簡単にグラフを作成することができる。

ポイントは、hueを使えるようにするために、x軸となる列をインデックスに設定し、並べたい列をstackで積み上げることである。

データ作成

以下のデータを対象とする。

import pandas as pd

data1 = [30, 35, 40]
data2 = [24, 28, 31]
data3 = [20, 25, 25]
index = ["Aさん", "Bさん", "Cさん"]
df = pd.DataFrame(data={"額面": data1, "手取り": data2, "支出": data3}, index=index)
print(df)
     額面  手取り  支出
Aさん  30   24  20
Bさん  35   28  25
Cさん  40   31  25

Aさん、Bさん、Cさん毎に、額面、手取り、支出を並べて棒グラフに表示する。

データ整形

seabornのbarplotのhueを指定できるような形に整形する。

一気にやると以下のようなコードになる。

# 以下の処理を行う
# stack
# index名の設定
# nameの設定
# reset_index

data = df.stack().rename_axis(["name", "category"]).reset_index().rename(columns={0: "金額(万円)"})
# 以下のようなコードでも可能
data = df.stack().rename("金額(万円)").rename_axis(["name", "category"]).reset_index()
# index名はreset_index前にしておく
# nameの設定はreset_indexの前後どちらでもOK

print(data)
  name category  金額(万円)
0  Aさん       額面      30
1  Aさん      手取り      24
2  Aさん       支出      20
3  Bさん       額面      35
4  Bさん      手取り      28
5  Bさん       支出      25
6  Cさん       額面      40
7  Cさん      手取り      31
8  Cさん       支出      25

これで、hueにcategoryを指定することで、Aさん、Bさん、Cさん毎に棒グラフを並べて表示することが可能となる。

上記の処理を細かく分解すると以下のようになる。

stackでデータを縦にする

stackでインデックスに対し、列を全て縦にする。

df.stack()
Aさん  額面     30
     手取り    24
     支出     20
Bさん  額面     35
     手取り    28
     支出     25
Cさん  額面     40
     手取り    31
     支出     25

df.stack()の結果はマルチインデックスのSeriesとなる。

「Aさん、Bさん、Cさん」の列と「額面、手取り、支出」の列は両方ともインデックス列。

数値の列が値の列となる。

列名を全て変更する

rename_axisでインデックス名を変更する。

df.stack().rename_axis(["name", "category"])
name  category
Aさん   額面          30
      手取り         24
      支出          20
Bさん   額面          35
      手取り         28
      支出          25
Cさん   額面          40
      手取り         31
      支出          25

なお、この時もまだ、Seriesであることに注意。

インデックスをリセットする

reset_indexでインデックスを解除する。

df.stack().rename_axis(["name", "category"]).reset_index()
  name category   0
0  Aさん       額面  30
1  Aさん      手取り  24
2  Aさん       支出  20
3  Bさん       額面  35
4  Bさん      手取り  28
5  Bさん       支出  25
6  Cさん       額面  40
7  Cさん      手取り  31
8  Cさん       支出  25

ここでようやく型がDataFrameになる。

Seriesの時にname属性を設定していない場合、reset_indexすると列名は「0」になる。

値の列名を変更する

「0」となっている列名を変更する。

df.stack().rename_axis(["name", "category"]).reset_index().rename(columns={0: "金額(万円)"})
  name category  金額(万円)
0  Aさん       額面      30
1  Aさん      手取り      24
2  Aさん       支出      20
3  Bさん       額面      35
4  Bさん      手取り      28
5  Bさん       支出      25
6  Cさん       額面      40
7  Cさん      手取り      31
8  Cさん       支出      25

もちろん、reset_index前のSeriesの状態でnameを設定してから、reset_indexしてもOK。

df.stack().rename("金額(万円)").rename_axis(["name", "category"]).reset_index()

これで上記と同じ形に整形される。

棒グラフを並べて表示

seabornのbarplotにhueを指定して棒グラフを並べて表示する。

# 日本語の文字化けを防ぐ
sns.set(font="meiryo")
# グラフサイズ設定。
# facecolor="w"に設定しておくことで、グラフ保存時にグラフ外部分が見えなくなるのを防ぐ。
plt.figure(figsize=(16, 9), facecolor="w")
sns.barplot(data=data, x="name", y="金額(万円)", hue="category")
title = "額面と手取と支出"
plt.title(title)
plt.legend(loc="upper left", bbox_to_anchor=(1,1))
plt.show()

Aさん、Bさん、Cさん毎にまとまって棒グラフが表示される。