2014-04-01 50 views
3

我有一个多指标一个大熊猫数据帧:组标签使用熊猫多指标

group subgroup obs_1 obs_2 
GroupA Elem1  4  0 
     Elem2  34  2 
     Elem3  0  10 
GroupB Elem4  5  21 

等。如this SO question所述,这在matplotlib中实际上是可行的,但我宁愿(如果可能)使用我已经知道层次结构的事实(感谢MultiIndex)。目前发生的情况是索引显示为一个元组。

这样的事情可能吗?

回答

5

如果您在MultiIdex只有两个级别,我相信下面将简单:

plt.figure() 
ax=plt.gca() 
DF.plot(kind='bar', ax=ax) 
plt.grid(True, 'both') 
minor_XT=ax.get_xaxis().get_majorticklocs() 
DF['XT_V']=minor_XT 
major_XT=DF.groupby(by=DF.index.get_level_values(0)).first()['XT_V'].tolist() 
DF.__delitem__('XT_V') 
ax.set_xticks(minor_XT, minor=True) 
ax.set_xticklabels(DF.index.get_level_values(1), minor=True) 
ax.tick_params(which='major', pad=15) 
_=plt.xticks(major_XT, (DF.index.get_level_values(0)).unique(), rotation=0) 

enter image description here

,有点涉及,但更普遍的解决方案(没有多么你有很多级别):

def cvt_MIdx_tcklab(df): 
    Midx_ar=np.array(df.index.tolist()) 
    Blank_ar=Midx_ar.copy() 
    col_idx=np.arange(Midx_ar.shape[0]) 
    for i in range(Midx_ar.shape[1]): 
     val,idx=np.unique(Midx_ar[:,i], return_index=True) 
     Blank_ar[idx, i]=val 
     idx=~np.in1d(col_idx, idx) 
     Blank_ar[idx, i]='' 
    return map('\n'.join, np.fliplr(Blank_ar)) 

plt.figure() 
ax=plt.gca() 
DF.plot(kind='bar', ax=ax) 
ax.set_xticklabels(cvt_MIdx_tcklab(DF),rotation=0) 
+0

了“更通用的”解决方案没有解决的一些问题:1次刻度标记可能是重复的,但它们也是空白的。 2.它返回一个导致“TypeError:映射类型为'map'的对象没有len()”的映射。通过更改为“返回列表(地图('\ n'.join,np.fliplr(Blank_ar)))”来解决它。“3.使用该解决方案旋转标签是不可能的。我会坚持2级索引解决方案,这是非常好的。谢谢 – wuppi

1

我认为没有一个很好的标准方式绘制多索引数据框。我发现@斯坦的following solution美观宜人。我已经适应了你的数据他的榜样:

import pandas as pd 
import matplotlib.pyplot as plt 
from itertools import groupby 
import numpy as np 
%matplotlib inline 

group = ('Group_A', 'Group_B') 
subgroup = ('elem1', 'elem2', 'elem3', 'elem4') 
obs = ('obs_1', 'obs_2') 
index = pd.MultiIndex.from_tuples([('Group_A','elem1'),('Group_A','elem2'),('Group_A','elem3'),('Group_B','elem4')], 
    names=['group', 'subgroup']) 
values = np.array([[4,0],[43,2],[0,10],[5,21]]) 
df = pd.DataFrame(index=index) 
df['obs_1'] = values[:,0] 
df['obs_2'] = values[:,1] 

def add_line(ax, xpos, ypos): 
    line = plt.Line2D([xpos, xpos], [ypos + .1, ypos], 
         transform=ax.transAxes, color='gray') 
    line.set_clip_on(False) 
    ax.add_line(line) 

def label_len(my_index,level): 
    labels = my_index.get_level_values(level) 
    return [(k, sum(1 for i in g)) for k,g in groupby(labels)] 

def label_group_bar_table(ax, df): 
    ypos = -.1 
    scale = 1./df.index.size 
    for level in range(df.index.nlevels)[::-1]: 
     pos = 0 
     for label, rpos in label_len(df.index,level): 
      lxpos = (pos + .5 * rpos)*scale 
      ax.text(lxpos, ypos, label, ha='center', transform=ax.transAxes) 
      add_line(ax, pos*scale, ypos) 
      pos += rpos 
     add_line(ax, pos*scale , ypos) 
     ypos -= .1 

ax = df.plot(kind='bar',stacked=False) 
#Below 2 lines remove default labels 
ax.set_xticklabels('') 
ax.set_xlabel('') 
label_group_bar_table(ax, df) 

主要生产:

enter image description here