2014-04-01 130 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