中央揃え帯グラフ
帯グラフで中央で揃える方法を紹介した。英語では diverging stacked bar chart というらしい。divergingは両側に伸びる意味だが、適訳がない。
t検定で使ったLumleyのデータを中央揃え帯グラフにしてみよう。
import numpy as np
import pandas as pd
from collections import Counter
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
x = [1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1]
y = [3, 3, 4, 3, 1, 2, 3, 1, 1, 5, 4]
df = pd.DataFrame([Counter(x), Counter(y)], index=["x", "y"])
df = df.fillna(0).astype(int)
df = df.reindex(columns=range(min(x+y), max(x+y)+1), fill_value=0)
df = df[::-1]
n = len(df.columns)
def get_offset(row):
mid_idx = n // 2
if n % 2 == 1:
return -(row.iloc[:mid_idx].sum() + row.iloc[mid_idx] / 2)
else:
return -row.iloc[:mid_idx].sum()
offsets = df.apply(get_offset, axis=1)
fig, ax = plt.subplots(figsize=(6.4, 2))
cmap = plt.get_cmap("coolwarm")
colors = cmap(np.linspace(0, 1, n))
y_pos = np.arange(len(df.index))
for i, col in enumerate(df.columns):
widths = df[col]
lefts = offsets + df.iloc[:, :i].sum(axis=1)
ax.barh(y_pos, widths, left=lefts, color=colors[i], edgecolor="black", label=col)
ax.set_yticks(y_pos)
ax.set_yticklabels(df.index)
# ax.axvline(0, color='black', linewidth=1, linestyle='--')
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
min_x = offsets.min()
max_x = (offsets + df.sum(axis=1)).max()
# ax.set_xlim(min_x, max_x)
ax.set_xlim(min_x - 1, max_x + 1)
# 目盛を整数に限る
ax.xaxis.set_major_locator(MaxNLocator(integer=True))
# 見やすい位置に移動
plt.tight_layout()
plt.show()