【问题标题】:Stacked Bar Chart with Centered Labels带有居中标签的堆积条形图
【发布时间】:2017-05-08 20:33:24
【问题描述】:

我正在尝试在堆积条形图中“稳健地”将数据标签居中。下面给出了一个简单的代码示例和结果。如您所见,数据标签并没有真正在所有矩形中居中。我错过了什么?

import numpy as np
import matplotlib.pyplot as plt

A = [45, 17, 47]
B = [91, 70, 72]

fig = plt.figure(facecolor="white")

ax = fig.add_subplot(1, 1, 1)
bar_width = 0.5
bar_l = np.arange(1, 4)
tick_pos = [i + (bar_width / 2) for i in bar_l]

ax1 = ax.bar(bar_l, A, width=bar_width, label="A", color="green")
ax2 = ax.bar(bar_l, B, bottom=A, width=bar_width, label="B", color="blue")
ax.set_ylabel("Count", fontsize=18)
ax.set_xlabel("Class", fontsize=18)
ax.legend(loc="best")
plt.xticks(tick_pos, ["C1", "C2", "C3"], fontsize=16)
plt.yticks(fontsize=16)

for r1, r2 in zip(ax1, ax2):
    h1 = r1.get_height()
    h2 = r2.get_height()
    plt.text(r1.get_x() + r1.get_width() / 2., h1 / 2., "%d" % h1, ha="center", va="bottom", color="white", fontsize=16, fontweight="bold")
    plt.text(r2.get_x() + r2.get_width() / 2., h1 + h2 / 2., "%d" % h2, ha="center", va="bottom", color="white", fontsize=16, fontweight="bold")

plt.show()

【问题讨论】:

    标签: python pandas matplotlib seaborn bar-chart


    【解决方案1】:

    导入和测试数据帧

    import pandas as pd
    import matplotlib.pyplot as plt
    
    A = [45, 17, 47]
    B = [91, 70, 72]
    C = [68, 43, 13]
    
    # pandas dataframe
    df = pd.DataFrame(data={'A': A, 'B': B, 'C': C})
    df.index = ['C1', 'C2', 'C3']
    
         A   B   C
    C1  45  91  68
    C2  17  70  43
    C3  47  72  13
    

    更新为matplotlib v3.4.2

    • 使用matplotlib.pyplot.bar_label
      • 将自动将条中的值居中。
      • 有关.bar_label() 的更多详细信息,请参阅此answer
    • 有关其他格式选项,请参阅 matplotlib: Bar Label Demo 页面。
    • 使用pandas v1.2.4 测试,使用matplotlib 作为绘图引擎。
    • 如果条形图的某些部分为零,请参阅我的answer,它显示了如何为.bar_label() 自定义labels
    • 如果需要,ax.bar_label(c, fmt='%0.0f', label_type='center') 将更改数字格式以不显示小数位。
    ax = df.plot(kind='bar', stacked=True, figsize=(8, 6), rot=0, xlabel='Class', ylabel='Count')
    for c in ax.containers:
    
        # Optional: if the segment is small or 0, customize the labels
        labels = [v.get_height() if v.get_height() > 0 else '' for v in c]
        
        # remove the labels parameter if it's not needed for customized labels
        ax.bar_label(c, labels=labels, label_type='center')
    

    注释资源 - 来自matplotlib v3.4.2


    原答案

    • 使用.patches 方法解压缩matplotlib.patches.Rectangle 对象列表,每个对象对应堆叠条形的每个部分。
      • 每个.Rectangle 都有用于提取定义矩形的各种值的方法。
      • 每个.Rectangle 的顺序是从左到右,从下到上,因此在遍历.patches 时,每个级别的所有.Rectangle 对象都会按顺序出现。
    • 标签使用f-stringlabel_text = f'{height}',因此可以根据需要添加任何其他文本,例如label_text = f'{height}%'
      • label_text = f'{height:0.0f}' 将显示不带小数位的数字。

    情节

    plt.style.use('ggplot')
    
    ax = df.plot(stacked=True, kind='bar', figsize=(12, 8), rot='horizontal')
    
    # .patches is everything inside of the chart
    for rect in ax.patches:
        # Find where everything is located
        height = rect.get_height()
        width = rect.get_width()
        x = rect.get_x()
        y = rect.get_y()
        
        # The height of the bar is the data value and can be used as the label
        label_text = f'{height}'  # f'{height:.2f}' to format decimal values
        
        # ax.text(x, y, text)
        label_x = x + width / 2
        label_y = y + height / 2
    
        # plot only when height is greater than specified value
        if height > 0:
            ax.text(label_x, label_y, label_text, ha='center', va='center', fontsize=8)
        
    ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)    
    ax.set_ylabel("Count", fontsize=18)
    ax.set_xlabel("Class", fontsize=18)
    plt.show()
    

    • 绘制水平条:
      • kind='barh'
      • label_text = f'{width}'
      • if width > 0:
    • 署名:jsoma/chart.py

    【讨论】:

      【解决方案2】:

      你为什么写va="bottom"?您必须使用va="center"

      【讨论】:

        猜你喜欢
        • 2015-10-18
        • 1970-01-01
        • 1970-01-01
        • 2013-12-22
        • 2016-04-26
        相关资源
        最近更新 更多