【问题标题】:Pandas Bar plot, how to annotate grouped horizontal bar chartsPandas Bar plot,如何注释分组的水平条形图
【发布时间】:2016-03-21 09:53:15
【问题描述】:

我问这个问题是因为我还没有找到一个关于如何注释分组水平 Pandas 条形图的工作示例。我知道以下两个:

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

在解决这个问题几周后,我终于可以用示例代码提出问题,这几乎是我想要的,只是不是 100% 有效。需要您的帮助才能达到 100%。

我们来了,full code is uploaded here。结果如下所示:

您可以看到它几乎可以工作,只是标签没有放在我想要的位置,我自己无法将它们移动到更好的位置。此外,因为图表栏的顶部是用来显示错误栏的,所以我真正想要的是将注释文本移向 y 轴,整齐地排列在左侧或右侧y 轴,取决于 X 值。例如,这是我的同事可以使用 MS Excel 执行的操作:

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')             

请帮忙。谢谢。

【问题讨论】:

    标签: python pandas plot bar-chart


    【解决方案1】:

    所以,为了简单起见,我稍微改变了您构建数据的方式:

    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()
    

    给出:

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

    • width=0.85
    • +r.get_height()/5. # y
    • "pad":1
    • fontsize=10
    • "{:" "&gt;6.1f}%".format(r.get_width()*100) :设置标签中字符的总量(这里最少6个,如果小于6个字符,则在右侧填充空白)。它需要family="monospace"

    如果有什么不清楚的地方告诉我。

    HTH

    【讨论】:

    • @xpt,好的,如果您有不明白的地方,请告诉我。自从您发表评论后,我进行了一些修改。
    • 太棒了,太棒了!抱歉回复晚了。我唯一的问题是,从整个代码中我看不出它为什么需要import seaborn,但是当我注释掉该行时,它仍然有效,但图表看起来更丑。我想这回答了这个问题,但这是为什么呢?再次感谢。
    • @xpt,是的,见第 5 行 (sns.set_style...),我评论说这是出于审美目的。
    • 谢谢,第一次知道seaborn可以这样使用。即,没有使用单一的 seaborn 特定功能,而是在幕后进行美化。太好了。
    猜你喜欢
    • 2017-08-09
    • 2020-11-22
    • 1970-01-01
    • 2022-01-05
    • 2020-03-31
    • 2016-10-13
    • 1970-01-01
    • 2016-03-10
    • 1970-01-01
    相关资源
    最近更新 更多