【问题标题】:How to add multiple data labels in a bar chart in matplotlib如何在 matplotlib 的条形图中添加多个数据标签
【发布时间】:2021-11-13 05:25:56
【问题描述】:

我有两个分组的条形图,用于显示以下 3 组中两个系统的案例之间的值变化。在这里,我可以使用下面的代码向条形添加数据标签(附图)

我想要做的是在顶部(或底部对于值的负变化情况),添加一个额外的数据标签来捕获值变化的百分比,如第二个图所示,红色的 33%(I手动编辑)。我如何从这段代码中实现这一点?提前谢谢你。

import matplotlib.pyplot as plt
import numpy as np

value_case0_system1 = np.array([30, 20, 40])
value_case1_system1 = np.array([20, 25, 50])
value_case2_system1 = np.array([10, 35, 45])

value_case1_system2 = np.array([60, 50, 40])
value_case2_system2 = np.array([50, 40, 55])

change_case0_to_case1_system1 = np.subtract(value_case1_system1,value_case0_system1)
change_case1_to_case2_system1 = np.subtract(value_case2_system1,value_case1_system1)
change_case1_to_case2_system2 = np.subtract(value_case2_system2,value_case1_system2)

fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(18,10))
labels = ['Group 1', 'Group 2', 'Group 3']
x = np.arange(len(labels))
ax0.set_ylabel('Change in Values', va='center', rotation='vertical',
         fontsize=17, fontweight='bold')
width = 0.28
ax0.set_title('System 1', fontsize=17, fontweight='bold')
ax0.axhline(y=0, color='black', ls=':', lw=2)
ax0.set_xticks(x)
ax0.set_xticklabels(labels,fontsize=15)
rects1 = ax0.bar(x-width/2, change_case0_to_case1_system1, width, label='Case 0 to Case 1',
        color='#292929', edgecolor='black', linewidth=1)
rects2 = ax0.bar(x+width/2, change_case1_to_case2_system1, width, label='Case 1 to Case 2',
        color='#7f6d5f', edgecolor='black', linewidth=1)
ax0.bar_label(rects1, padding=3, fontsize=11)
ax0.bar_label(rects2, padding=3, fontsize=11)
leg = ax0.legend(loc="upper left", bbox_to_anchor=[0, 1],
                 ncol=1, fancybox=True)
ax0.legend(fontsize=15)

ax1.set_title('System 2', fontsize=17, fontweight='bold')
ax1.axhline(y=0, color='black', ls=':', lw=2)
ax1.set_xticks(x)
ax1.set_xticklabels(labels,fontsize=15)

rects3 = ax1.bar(x, change_case1_to_case2_system2, width, label='Case 1 to Case 2',
        color='#7f6d5f', edgecolor='black', linewidth=1)
ax1.legend(shadow=True, fancybox=True)
ax1.bar_label(rects3, padding=3, fontsize=11)
leg = ax1.legend(loc="upper left", bbox_to_anchor=[0, 1],
                 ncol=1, fancybox=True)
ax1.legend(fontsize=15)
plt.tight_layout()
plt.show()

【问题讨论】:

    标签: python matplotlib annotations bar-chart


    【解决方案1】:
    • 额外绘图格式的代码已被省略,因为它与答案无关。可以根据您的要求添加回来。
    • 每个.bar_label 为标签全局着色,因此与answer 不同,需要添加第二个.bar_label 以实现百分比变化,并使用不同的colorpadding
    • 对于每个case-to-case,计算百分比变化,并在列表理解中设置字符串格式。
      • 将字符串格式的计算列表设置为.bar_label中的labels参数。
    • 给定 OP 中的代码,需要添加 6 行代码,其中 3 行用于创建标签列表,3 行用于将标签添加到绘图中。
    • 其他资源:
    • python 3.8.11matplotlib 3.4.3 测试
    change_case0_to_case1_system1 = np.subtract(value_case1_system1, value_case0_system1)
    # add list of string formatted percent change calculation
    per_change_case0_to_case1_system1 = [f'({v}%)' for v in (change_case0_to_case1_system1 / value_case0_system1).round(2)*100]
    
    change_case1_to_case2_system1 = np.subtract(value_case2_system1, value_case1_system1)
    # add list of string formatted percent change calculation
    per_change_case1_to_case2_system1 = [f'({v}%)' for v in (change_case1_to_case2_system1 / value_case1_system1).round(2)*100]
    
    change_case1_to_case2_system2 = np.subtract(value_case2_system2, value_case1_system2)
    # add list of string formatted percent change calculation
    per_case1_to_case2_system2 = [f'({v}%)' for v in (change_case1_to_case2_system2 / value_case1_system2).round(2)*100]
    
    fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(18,10))
    labels = ['Group 1', 'Group 2', 'Group 3']
    x = np.arange(len(labels))
    
    width = 0.28
    
    ax0.set_xticks(x)
    ax0.set_xticklabels(labels, fontsize=15)
    
    rects1 = ax0.bar(x-width/2, change_case0_to_case1_system1, width, label='Case 0 to Case 1', color='#292929', edgecolor='black', linewidth=1)
    rects2 = ax0.bar(x+width/2, change_case1_to_case2_system1, width, label='Case 1 to Case 2', color='#7f6d5f', edgecolor='black', linewidth=1)
    
    ax0.bar_label(rects1, padding=3, fontsize=11)
    # add a second annotation with the string formatted labels
    ax0.bar_label(rects1, labels=per_change_case0_to_case1_system1, padding=15, fontsize=11, color='red')
    
    ax0.bar_label(rects2, padding=3, fontsize=11)
    # add a second annotation with the string formatted labels
    ax0.bar_label(rects2, labels=per_change_case1_to_case2_system1, padding=15, fontsize=11, color='red')
    
    rects3 = ax1.bar(x, change_case1_to_case2_system2, width, label='Case 1 to Case 2', color='#7f6d5f', edgecolor='black', linewidth=1)
    
    ax1.set_xticks(x)
    ax1.set_xticklabels(labels,fontsize=15)
    
    ax1.bar_label(rects3, padding=3, fontsize=11)
    # add a second annotation with the string formatted labels
    ax1.bar_label(rects3, labels=per_case1_to_case2_system2, padding=15, fontsize=11, color='red')
    
    plt.tight_layout()
    plt.show()
    

    【讨论】:

    • 非常感谢!这就是我要找的。我不知道我可以像这样使用 ax.bar_label。
    • @user496181 不客气。很高兴它对你有用。起初我没有想到要使用.bar_label 两次。我想用ax.text添加第二个注释,但后来我想试试padding
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    • 2015-05-09
    相关资源
    最近更新 更多