- 以下方法更简洁,并且易于扩展。
- 将数据放入
pandas.DataFrame
是绘制堆积条形图的最简单方法。
- Using pandas.DataFrame.plot.bar(stacked=True) https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.bar.html, or pandas.DataFrame.plot(kind='bar', stacked=True) https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.html, is the easiest way to plot a stacked bar plot.
- 该方法返回一个
matplotlib.axes.Axes
or a numpy.ndarray
其中。
- Since
seaborn
只是一个高级 APImatplotlib
,这些解决方案也适用于seaborn
绘图,如图所示如何使用聚合值注释seaborn条形图 https://stackoverflow.com/a/64797097/7758804.
- 对于水平堆叠条,请参见水平堆叠条形图并向每个部分添加标签 https://stackoverflow.com/a/64202669/7758804
- 测试于
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
- Use matplotlib.pyplot.bar_label https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.bar_label.html,这将自动将条中的值居中。
- See 如何在条形图上添加值标签 https://stackoverflow.com/a/67561982/7758804有关更多详细信息和示例,请使用
.bar_label
.
- 测试用
pandas v1.2.4
,正在使用matplotlib
作为情节引擎。
- 如果条形图的某些部分为零,请参阅我的answer https://stackoverflow.com/a/64202669/7758804,它展示了如何自定义
labels
for .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 更新 https://matplotlib.org/stable/users/prev_whats_new/whats_new_3.7.0.html#additional-format-string-options-in-bar-label, the
fmt
的论证bar_label
现在接受 {} 样式格式字符串。
fmt=lambda x: f'{x:.0f}' if x > 0 else ''
-
fmt=lambda x: np.where(x > 0, f'{x:.0f}', '')
with np.where https://numpy.org/doc/stable/reference/generated/numpy.where.html
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
是一个高级 APImatplotlib
- The seaborn.barplot https://seaborn.pydata.org/generated/seaborn.barplot.htmlapi 没有堆叠选项,但它“可以”通过以下方式实现sns.histplot https://seaborn.pydata.org/generated/seaborn.histplot.html, or sns.displot https://seaborn.pydata.org/generated/seaborn.displot.html.
Seaborn 数据帧格式
# 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')
原答案
- Using the
.patches
method unpacks a list of matplotlib.patches.Rectangle https://matplotlib.org/api/_as_gen/matplotlib.patches.Rectangle.html?highlight=rectangle#matplotlib.patches.Rectangle objects, one for each of the sections of the stacked bar.
- Each
.Rectangle
具有提取定义矩形的各种值的方法。
- Each
.Rectangle
是从左到右、从下到上的顺序,所以所有的.Rectangle
迭代时,每个级别的对象按顺序出现.patches
.
- The labels are made using an f-string https://www.python.org/dev/peps/pep-0498/,
label_text = f'{height}'
, so any additional text can be added as needed, such as label_text = f'{height}%'
-
label_text = f'{height:0.0f}'
将显示没有小数位的数字。
Plot
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()
- To plot a horizontal bar:
kind='barh'
label_text = f'{width}'
if width > 0:
- 归因:jsoma/chart.py https://gist.github.com/jsoma/c61e56819e4ae315ad5d194a630ccb23