如何向条形图添加多个注释

7

我想在我的pandas柱状图中添加百分比值 - 除了计数之外。但是,我无法这样做。我的代码如下,到目前为止,我只能显示计数值。请问有人可以帮助我在每个条形图显示的计数值旁边/下面添加相对百分比值吗?

import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')

import seaborn as sns
sns.set_style("white")

fig = plt.figure()
fig.set_figheight(5)
fig.set_figwidth(10)

ax = fig.add_subplot(111)

counts = [29227, 102492,  53269, 504028, 802994]

y_ax = ('A','B','C','D','E')
y_tick = np.arange(len(y_ax))

ax.barh(range(len(counts)), counts, align = "center", color = "tab:blue")
ax.set_yticks(y_tick)
ax.set_yticklabels(y_ax, size = 8)

#annotate bar plot with values
for i in ax.patches:
    ax.text(i.get_width()+.09, i.get_y()+.3, str(round((i.get_width()), 1)), fontsize=8)

sns.despine()
plt.show();

下面是我的代码输出。如何在每个显示的计数值旁边添加%值?

enter image description here

1个回答

9
  • python 3.11pandas 1.5.3matplotlib 3.7.1 中进行了测试

导入和加载数据

import pandas as pd
import matplotlib.pyplot as plt

# create the dataframe from values in the OP
counts = [29227, 102492,  53269, 504028, 802994]
df = pd.DataFrame(data=counts, columns=['counts'], index=['A','B','C','D','E'])

# add a percent column
df['%'] = df.counts.div(df.counts.sum()).mul(100).round(2)

# display(df)
   counts      %
A   29227   1.96
B  102492   6.87
C   53269   3.57
D  504028  33.78
E  802994  53.82

使用 matplotlib 版本 3.4.2 绘制图表

  • 使用 matplotlib.pyplot.bar_label
    • 有关使用 .bar_label 的详细信息和示例,请参见 如何在条形图上添加值标签
    • 如果使用垂直条形图,请改用 v.get_height() 而不是 v.get_width()
    • 可以使用 fmt 参数进行一些格式设置,但更复杂的格式设置应使用 labels 参数。
  • pandas 使用 matplotlib 作为默认的绘图后端。
    • 使用 kind='bar' 绘制垂直条形图。
ax = df.plot(kind='barh', y='counts', figsize=(10, 5), legend=False, width=.75,
             title='This is the plot generated by all code examples in this answer')

# customize the label to include the percent
labels = [f' {v.get_width()}\n {df.iloc[i, 1]}%' for i, v in enumerate(ax.containers[0])]

# set the bar label
ax.bar_label(ax.containers[0], labels=labels, label_type='edge', size=13)

ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
plt.show()

enter image description here


在 matplotlib 版本 3.4.2 之前使用 matplotlib 绘图

# plot the dataframe
ax = df.plot(kind='barh', y='counts', figsize=(10, 5), legend=False, width=.75)
for i, y in enumerate(ax.patches):

    # get the percent label
    label_per = df.iloc[i, 1]
    
    # add the value label
    ax.text(y.get_width()+.09, y.get_y()+.3, str(round((y.get_width()), 1)), fontsize=10)
    
    # add the percent label here
    ax.text(y.get_width()+.09, y.get_y()+.1, str(f'{round((label_per), 2)}%'), fontsize=10)

ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
plt.show()

没有使用 pandas 的原始答案

  • 已测试通过 matplotlib v3.3.4
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(10, 5))

counts = [29227, 102492,  53269, 504028, 802994]

# calculate percents
percents = [100*x/sum(counts) for x in counts]

y_ax = ('A','B','C','D','E')
y_tick = np.arange(len(y_ax))

ax.barh(range(len(counts)), counts, align = "center", color = "tab:blue")
ax.set_yticks(y_tick)
ax.set_yticklabels(y_ax, size = 8)

#annotate bar plot with values
for i, y in enumerate(ax.patches):
    label_per = percents[i]
    ax.text(y.get_width()+.09, y.get_y()+.3, str(round((y.get_width()), 1)), fontsize=10)
    # add the percent label here
    # ax.text(y.get_width()+.09, y.get_y()+.3, str(round((label_per), 2)), ha='right', va='center', fontsize=10)
    ax.text(y.get_width()+.09, y.get_y()+.1, str(f'{round((label_per), 2)}%'), fontsize=10)

ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
plt.show()
  • 您可以调整位置。
  • JohanC 提到了其他格式选项。
  • 将文本的两个部分打印在一个字符串中,\n 之间以获得 "自然" 行间距:
  • str(f'{round((y.get_width()), 1)}\n{round((label_per), 2)}%')
  • 使用 ax.text(..., va='center') 竖直居中并能够使用稍大的字体。
  • 使用 ax.set_xlim(0, max(counts) * 1.18) 获得更多文本空间。
  • 每行文本都以空格开头,以获得自然的 "水平" 填充。
  • 注意 { 前面的空格:str(f' {round((label_per), 2)}%')
  • 当这些值处于万位数时,y.get_width()+.09y.get_width() 几乎相同。

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接