Pandas Bar图,如何注释分组的水平条形图

时间:2015-12-15 14:43:24

标签: python pandas plot bar-chart

我问这个问题,因为我还没有在如何注释分组水平Pandas条形图上找到一个有效的例子。我知道以下两点:

但他们都是关于垂直条形图。即,要么没有水平条形图的解决方案,要么它没有完全正常工作。

在这个问题上工作了几个星期之后,我终于能够用一个示例代码提出问题,这几乎就是我想要的,而不是100%工作。需要你的帮助才能实现100%的目标。

我们走了full code is uploaded here。结果如下:

Pandas chart

你可以看到它几乎正常工作,只是标签没有放在我想要的地方,我不能把它们移到一个更好的地方。此外,因为图表栏的顶部用于显示错误栏,所以我真正想要的是将注释文本移向y轴,在左侧或右侧很好地排列 y轴,取决于X值。例如,这是我的同事可以用MS Excel做的事情:

MS Excel chart

Python可以用Pandas图表做到这一点吗?

我将上面的网址中的代码包含在注释中,一个是我的全能,我可以做,另一个是参考(来自In [23]):

# my all-that-I-can-do
def autolabel(rects):
    #if height constant: hbars, vbars otherwise
    if (np.diff([plt.getp(item, 'width') for item in rects])==0).all():
        x_pos = [rect.get_x() + rect.get_width()/2. for rect in rects]
        y_pos = [rect.get_y() + 1.05*rect.get_height() for rect in rects]
        scores = [plt.getp(item, 'height') for item in rects]
    else:
        x_pos = [rect.get_width()+.3 for rect in rects]
        y_pos = [rect.get_y()+.3*rect.get_height() for rect in rects]
        scores = [plt.getp(item, 'width') for item in rects]
    # attach some text labels
    for rect, x, y, s in zip(rects, x_pos, y_pos, scores):
        ax.text(x, 
                y,
                #'%s'%s,
                str(round(s, 2)*100)+'%',
                ha='center', va='bottom')

# for the reference 
ax.bar(1. + np.arange(len(xv)), xv, align='center')
# Annotate with text
ax.set_xticks(1. + np.arange(len(xv)))
for i, val in enumerate(xv):
    ax.text(i+1, val/2, str(round(val, 2)*100)+'%', va='center',
ha='center', color='black')             

请帮忙。感谢。

1 个答案:

答案 0 :(得分:3)

因此,为了简单起见,我改变了构建数据的方式:

source = new FileInputStream(currentDB).getChannel();
destination = new FileOutputStream(backupDB).getChannel();
destination.transferFrom(source, 0, source.size());
source.close();
destination.close();

给出:

barh plot error bar annotated

我根据平均值绘制标签,并将其放在0行的另一侧,这样您就可以确定它永远不会与其他内容重叠,有时除了错误栏。我在文本后面设置了一个框,以便反映平均值。 根据您的图形大小,您需要调整一些值,以便标签适合,例如:

  • import numpy as np import matplotlib.pyplot as plt import pandas as pd import seaborn as sns sns.set_style("white") #for aesthetic purpose only # fake data df = pd.DataFrame({'A': np.random.choice(['foo', 'bar'], 100), 'B': np.random.choice(['one', 'two', 'three'], 100), 'C': np.random.choice(['I1', 'I2', 'I3', 'I4'], 100), 'D': np.random.randint(-10,11,100), 'E': np.random.randn(100)}) p = pd.pivot_table(df, index=['A','B'], columns='C', values='D') e = pd.pivot_table(df, index=['A','B'], columns='C', values='E') ax = p.plot(kind='barh', xerr=e, width=0.85) for r in ax.patches: if r.get_x() < 0: # it it's a negative bar ax.text(0.25, # set label on the opposite side r.get_y() + r.get_height()/5., # y "{:" ">7.1f}%".format(r.get_x()*100), # text bbox={"facecolor":"red", "alpha":0.5, "pad":1}, fontsize=10, family="monospace", zorder=10) else: ax.text(-1.5, # set label on the opposite side r.get_y() + r.get_height()/5., # y "{:" ">6.1f}%".format(r.get_width()*100), bbox={"facecolor":"green", "alpha":0.5, "pad":1}, fontsize=10, family="monospace", zorder=10) plt.tight_layout()
  • width=0.85
  • +r.get_height()/5. # y
  • "pad":1
  • fontsize=10:设置标签中的char总量(此处为6最小值,如果小于6个字符,则在右侧填充空格)。它需要"{:" ">6.1f}%".format(r.get_width()*100)

告诉我某些事情是否不清楚。

HTH