matplotlib+pandas로 계층적 축 레이블 그리기

계층 구조의 인덱스를 가진 Matplotlib의 데이터 프레임을 그대로 플롯하면 축 라벨이 튜플 그대로의 표시가 되어 약간 유감스러운 느낌이 됩니다.
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

a = pd.DataFrame(np.random.random([6, 2]),
                 index=pd.MultiIndex.from_product([['group1', 'group2'],['item1', 'item2', 'item3']]),
                 columns=['data1', 'data2'])

a.plot.bar()



계층 구조의 데이터인 것이 보기 쉬운 축 라벨이 붙고 싶다고 생각해 보았습니다만, 우선 아래와 같은 방법으로 할 수 있는 모양.
def set_hierarchical_xlabels(index, ax=None,
                             bar_xmargin=0.1, # 線の左右両端のマージン、X軸のスケール
                             bar_yinterval=0.1, # 線の上下の間隔、Y軸の長さを1とした相対値?
                            ):
    from itertools import groupby
    from matplotlib.lines import Line2D

    ax = ax or plt.gca()

    assert isinstance(index, pd.MultiIndex)
    labels = ax.set_xticklabels([s for *_, s in index])
    for lb in labels:
        lb.set_rotation(0)

    transform = ax.get_xaxis_transform()

    for i in range(1, len(index.codes)):
        xpos0 = -0.5 # 対象グループの左側の座標
        for (*_, code), codes_iter in groupby(zip(*index.codes[:-i])):
            xpos1 = xpos0 + sum(1 for _ in codes_iter) # 対象グループの右側の座標
            ax.text((xpos0+xpos1)/2, (bar_yinterval * (-i-0.1)),
                    index.levels[-i-1][code],
                    transform=transform,
                    ha="center", va="top")
            ax.add_line(Line2D([xpos0+bar_xmargin, xpos1-bar_xmargin],
                               [bar_yinterval * -i]*2,
                               transform=transform,
                               color="k", clip_on=False))
            xpos0 = xpos1

a.plot.bar()
set_hierarchical_xlabels(a.index)




세세한 디자인은 목적이나 취향에 따라 달라진다고 생각하기 때문에, 상기를 참고에 적당하게 변경하면 OK.
3계층 이상의 MultiIndex에서도 플롯할 수 있습니다.

좋은 웹페이지 즐겨찾기