带居中标签的堆叠条形图

2024-12-24 08:55:00
admin
原创
89
摘要:问题描述:我正在尝试“稳健地”将数据标签置于堆叠条形图中的中心。下面给出了一个简单的代码示例和结果。如您所见,数据标签实际上并未在所有矩形中居中。我遗漏了什么?import numpy as np import matplotlib.pyplot as plt A = [45, 17, 47] B = [9...

问题描述:

我正在尝试“稳健地”将数据标签置于堆叠条形图中的中心。下面给出了一个简单的代码示例和结果。如您所见,数据标签实际上并未在所有矩形中居中。我遗漏了什么?

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

IT科技


解决方案 1:

  • 以下方法更简洁,并且易于扩展。

  • 将数据放入pandas.DataFrame是绘制堆积条形图的最简单方法。

  • 使用pandas.DataFrame.plot.bar(stacked=True)或 是pandas.DataFrame.plot(kind='bar', stacked=True)绘制堆积条形图的最简单方法。

    • 此方法返回其中的一个matplotlib.axes.Axes或一个。numpy.ndarray

  • 由于seaborn只是 的高级 API matplotlib,这些解决方案也适用于seaborn图表,如如何使用聚合值注释 seaborn 条形图中所示。

  • 对于水平堆叠条形图,请参阅水平堆叠条形图并为每个部分添加标签

  • 已在python 3.10, pandas 1.4.2, matplotlib 3.5.1,测试seaborn 0.11.2

导入并测试 DataFrame

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}, 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

  • 已使用 进行测试pandas v1.2.4,它被用作matplotlib情节引擎。

  • 如果条形图的某些部分为零,请参阅我的回答,其中展示了如何自labels定义.bar_label()

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

在此处输入图片描述

可以使用其他选项来删除小段的标签fmt

  • 随着matplotlib 3.7 更新,fmt的参数bar_label现在接受 {} 样式的格式字符串。

  • fmt=lambda x: f'{x:.0f}' if x > 0 else ''

  • fmt=lambda x: np.where(x > 0, f'{x:.0f}', '')np.where

ax = df.plot(kind='bar', stacked=True, figsize=(8, 6), rot=0, xlabel='Class', ylabel='Count')
for c in ax.containers:
    ax.bar_label(c, fmt=lambda x: f'{x:.0f}' if x > 0 else '', label_type='center')

Seaborn 选项

  • seaborn是一个高级 API,用于matplotlib

  • seaborn.barplotAPI 没有堆叠选项,但它“可以”用sns.histplot、 或来实现sns.displot

Seaborn DataFrame 格式

# create the data frame
df = pd.DataFrame(data={'A': A, 'B': B, 'C': C, 'cat': ['C1', 'C2', 'C3']})

    A   B   C cat
0  45  91  68  C1
1  17  70  43  C2
2  47  72  13  C3

# convert the dataframe to a long form
df = df.melt(id_vars='cat')

  cat variable  value
0  C1        A     45
1  C2        A     17
2  C3        A     47
3  C1        B     91
4  C2        B     70
5  C3        B     72
6  C1        C     68
7  C2        C     43
8  C3        C     13

轴层图

# plot
ax = sns.histplot(data=df, x='cat', hue='variable', weights='value', discrete=True, multiple='stack')

# iterate through each container
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')

在此处输入图片描述

图形级绘图

# plot
g = sns.displot(data=df, x='cat', hue='variable', weights='value', discrete=True, multiple='stack')

# iterate through each axes
for ax in g.axes.flat:

    # iterate through each container
    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')

在此处输入图片描述


原始答案

  • 使用该.patches方法解包一个对象列表matplotlib.patches.Rectangle,堆叠条形图的每个部分对应一个对象。

    • 每种.Rectangle方法都有提取定义矩形的各种值的方法。

    • 每个.Rectangle都是从左到右、从下到上的顺序,因此.Rectangle在迭代时,每个级别的所有对象都按顺序出现.patches

  • 标签使用f 字符串,制作label_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"
在此处输入图片描述

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1124  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   79  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   70  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   82  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   74  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用