带居中标签的堆叠条形图
- 2024-12-24 08:55:00
- admin 原创
- 89
问题描述:
我正在尝试“稳健地”将数据标签置于堆叠条形图中的中心。下面给出了一个简单的代码示例和结果。如您所见,数据标签实际上并未在所有矩形中居中。我遗漏了什么?
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()
解决方案 1:
以下方法更简洁,并且易于扩展。
将数据放入
pandas.DataFrame
是绘制堆积条形图的最简单方法。使用
pandas.DataFrame.plot.bar(stacked=True)
或 是pandas.DataFrame.plot(kind='bar', stacked=True)
绘制堆积条形图的最简单方法。此方法返回其中的一个
matplotlib.axes.Axes
或一个。numpy.ndarray
由于
seaborn
只是 的高级 APImatplotlib
,这些解决方案也适用于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.barplot
API 没有堆叠选项,但它“可以”用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"
。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)