帯グラフ

帯グラフに相当する英語は stacked bar chart つまり積み重ね棒グラフである。特に日本の帯グラフは割合を表すので (horizontal) proportional stacked bar chart あるいは具体的に stacked bar chart showing the proportion of ... ということになる。

import pandas as pd

df = pd.DataFrame({"反対": [10, 40],
                   "やや反対": [20, 30],
                   "やや賛成": [30, 20],
                   "賛成": [40, 10]},
                  index = ["男", "女"])

df[::-1].plot(figsize=(6.4, 2), kind="barh", stacked=True,
              xlim=[0, 100], colormap="coolwarm", edgecolor="black")
帯グラフ1

df[::-1] を付けるのは逆順にするためである。これがなければ下から上に「男」「女」が並ぶ。

凡例を消したければ plot()legend=False、凡例を逆に「賛成」から始めるには legend="reverse" を付ける。

黒い輪郭線 edgecolor="black" は、場合によっては白のほうがいいかも。

帯の左端にヒゲ(tick mark)が付くのが嫌なら、次のようにする:

ax = df[::-1].plot(figsize=(6.4, 2), kind="barh", stacked=True,
                   xlim=[0, 100], colormap="coolwarm")
ax.tick_params(left=False)

この ax とMatplotlibの機能を使えばいろいろなことができる。例えば凡例を図の下に移動してみよう:

import matplotlib.pyplot as plt

ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.15), ncol=4)
plt.tight_layout()
帯グラフ2

こちらに倣って補助線を付けてみよう:

for i in range(len(ax.patches)-len(df)-1):
    if (i + 1) % len(df) != 0:
        dn = ax.patches[i].get_corners()[2]
        up = ax.patches[i+1].get_corners()[1]
        ax.plot([dn[0], up[0]], [dn[1], up[1]], c='gray', lw=0.5)
帯グラフ3

反対と賛成の中央で揃える方法もある:

left = df.iloc[::-1, :2].sum(axis=1)
df[::-1].plot(figsize=(6.4, 2), kind="barh", stacked=True,
              left=-left, xlim=[-max(left),100-min(left)],
              colormap="coolwarm", edgecolor="black", legend="reverse")
帯グラフ4

選択肢が奇数個の場合は中央の「どちらでもない」の中央を揃える。一般に「無回答」は省くので帯の長さは必ずしも100%にならない。


Matplotlibだけで描くこともできる:

plt.figure(figsize=(6.4, 2))

df1 = df[::-1]
cmap = plt.get_cmap("coolwarm")
bottom = 0
for i in range(4):
    plt.barh(df1.index, df1.iloc[:,i], left=bottom, color=cmap(i/3))
    bottom += df1.iloc[:,i]
plt.xlim(0, 100)
帯グラフ5