LoginSignup
2
3

More than 3 years have passed since last update.

matplotlib+pandasで階層的な軸ラベルを描く

Posted at

階層構造のインデックスを持った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()

img1.png

階層構造のデータであることが見やすいような軸ラベルが付けたいと思って調べてみましたが、とりあえず下記のような方法でできる模様。

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)

img2.png

細かいデザインは目的や好みによって変わると思うので、上記を参考に適当に改変すればOK。
3階層以上のMultiIndexでもプロットできます。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3