堆叠的条形图意外地用条形图高度的总和注释

Stacked bars are unexpectedly annotated with the sum of bar heights

我的数据:

names_col = ['Count','Freq']
dat = [['Matching', 56935],['Mismatching', 100587]]
plot_df = pd.DataFrame(data=dat,columns=names_col)

我正在尝试显示值的 plot stacked catplot,这是我的代码:

plt.figure(figsize=(16,9))
p=plot_df.set_index('Count').T.plot(kind='bar', stacked=True)
p.bar_label(p.containers[0])
p.bar_label(p.containers[1])
plt.show();

首先,输出的图形大小不是(16,9),有什么问题吗? 第二个情节显示价值为:

而不是 matching 的值 - 56935(这里没问题)和 mismatching - 100587,绘图显示总计(157522)。 我如何访问和显示 Mismatching 值?

您可以将figsize设置为绘图参数。然后为每个容器添加条形标签和您自己的文本:

p=plot_df.set_index('Count').T.plot(kind='bar', stacked=True, figsize=(16,9)) 
for x in p.containers:
    p.bar_label(x)
    p.text(0, x[0].get_y() + x[0].get_height()*0.5, x.datavalues[0], ha='center', color='w', weight='bold')

plt.show()

输出:

  • 使用matplotlib.pyplot.bar_label两次
    • 根据标签是在条形的中心还是在条形的边缘来确定注释值。
    • 另一个答案使用 x[0].,因为只有一组堆积条,但如果 x 轴上有不止一组,那将不起作用。
    • 有关 .bar_label 的更多详细信息和示例,请参阅此 answer
  • 重塑数据框应该是独立于绘图的步骤
  • pandas.DataFrame.plot 使用 matplotlib 作为默认绘图后端,并且有许多参数,如 rotxlabelylabelfigsize,用于自定义绘图。
  • python 3.10pandas 1.3.4matplotlib 3.5.0
  • 中测试
df = pd.DataFrame(data=dat, columns=names_col)
dft = df.set_index('Count').T

axe = dft.plot(kind='bar', stacked=True, figsize=(16,9), rot=0)

for x in axe.containers:
    axe.bar_label(x, label_type='edge', weight='bold')
    axe.bar_label(x, label_type='center', weight='bold', color='white')

  • 这是一个包含多个组的更详尽的示例
    • 另一个答案没有为第二组条放置中间注释。
# test data 
data = {'Matching': [56935, 17610], 'Mismatching': [100587, 13794], 'Test': [33139, 23567]}
df = pd.DataFrame(data=data, index=['Freq', 'Freq2'])

axe = df.plot(kind='bar', stacked=True, figsize=(16,9), rot=0)

for x in axe.containers:
    axe.bar_label(x, label_type='edge', weight='bold')
    axe.bar_label(x, label_type='center', weight='bold', color='white')

仅将总数添加到条形图的顶部

  • 为行的总和添加一个新的冒号,用于注释
df['tot'] = df.sum(axis=1)

display(df)
       Matching  Mismatching   Test     tot
Freq      56935       100587  33139  190661
Freq2     17610        13794  23567   54971

# plot 
axe = df.iloc[:, :3].plot(kind='bar', stacked=True, figsize=(16,9), rot=0)

# annotate
for x in axe.containers:
    axe.bar_label(x, label_type='center', weight='bold', color='white')

# resuse x from the for loop, the last x is the top set of bar patches
axe.bar_label(x, labels=df['tot'], label_type='edge', weight='bold')