添加误差线时如何注释条形图
Posted
技术标签:
【中文标题】添加误差线时如何注释条形图【英文标题】:How to annotate bar plots when adding error bars 【发布时间】:2022-01-16 20:46:37 【问题描述】:我有一个这样的数据框字典
'region': 0: 'R0',1: 'R1',2: 'R2',3: 'R3',4: 'R4',5: 'R5',6: 'R6',
'DT': 0: 0.765, 1: 0.694, 2: 0.778, 3: 0.694, 4: 0.629, 5: 0.67, 6: 0.668,
'GB': 0: 0.714, 1: 0.741, 2: 0.752, 3: 0.741, 4: 0.683, 5: 0.706, 6: 0.656,
'KNN': 0: 0.625, 1: 0.641, 2: 0.628, 3: 0.641, 4: 0.552, 5: 0.544, 6: 0.578,
'LR': 0: 0.624, 1: 0.662, 2: 0.634, 3: 0.662, 4: 0.581, 5: 0.629, 6: 0.649,
'lstm': 0: 0.803,1: 0.633,2: 0.845,3: 0.668,4: 0.717,5: 0.726,6: 0.674
格式简洁
region DT GB KNN LR lstm
0 R0 0.765 0.714 0.625 0.624 0.803
1 R1 0.694 0.741 0.641 0.662 0.633
2 R2 0.778 0.752 0.628 0.634 0.845
3 R3 0.694 0.741 0.641 0.662 0.668
4 R4 0.629 0.683 0.552 0.581 0.717
5 R5 0.67 0.706 0.544 0.629 0.726
6 R6 0.668 0.656 0.578 0.649 0.674
我想绘制带有误差线的堆积条形图。这个数据框没有关于标准差的信息,但我有另一个标准差数据框。
假设有两个数据框的均值和标准差
我试过这段代码
fig, ax = plt.subplots()
width=0.5
clfs=['DT', 'KNN', 'LR', 'GB', 'lstm']
ax.bar(mean_df['region'], mean_df[clfs[0]], width,yerr=std_df[clfs[0]], label=clfs[0])
for i in range(1,5):
ax.bar(mean_df['region'], mean_df[clfs[i]], width,yerr=std_df[clfs[i]], label=clfs[i],bottom=mean_df[clfs[i-1]])
plt.xticks(rotation=90)
plt.legend()
plt.show()
但是条形图没有正确堆叠。我也在寻找一种在每个条形段上写入值的方法,以增加绘图的可读性
编辑: 解决方案是在绘制第三个列表时在底部添加前两个列表。
fig, ax = plt.subplots()
ax.bar(mean_df['region'], mean_df[clfs[0]], width,yerr=std_df[clfs[0]], label=clfs[0])
ax.bar(mean_df['region'], mean_df[clfs[1]], width,yerr=std_df[clfs[1]], label=clfs[1],bottom=mean_df[clfs[0]])
ax.bar(mean_df['region'], mean_df[clfs[2]], width,yerr=std_df[clfs[2]], label=clfs[2],
bottom=mean_df[clfs[0]]+mean_df[clfs[1]])
但我正在寻找一种优雅的方式来做到这一点,以及如何在栏的片段上写入值
编辑 2: 我来了
ax = mean_df.plot(kind='bar', stacked=True, figsize=(8, 6),yerr=std_df, rot=0, xlabel='region', ylabel='DT')
但现在我正在寻找编写文本的方法。 我试过这个
for c in ax.containers:
ax.bar_label(c, label_type='center')
但我得到了这个错误
AttributeError: 'ErrorbarContainer' object has no attribute 'patches'
编辑 3
这个错误是因为yerr=std_df
,但我也想保留错误栏
【问题讨论】:
【参考方案1】: 堆积条形图并不是呈现数据的理想方式。使用误差线时,堆叠的条形图更难阅读,可能与给定堆栈中的误差线和注释重叠,这可能会导致可视化混乱。stacked=True
或stacked=False
会出现此问题,它适用于使用matplotlib.axes.Axes.bar
后跟matplotlib.axes.Axes.errorbar
。
此答案也适用于水平条。
这不适用于 ci=True
的 seaborn 条形图
pandas.DataFrame.plot
返回一个Axes
,可以从中提取containers
。
添加yerr
会导致containers
包含ErrorbarContainer object
和BarContainer object
有关使用 matplotlib.pyplot.bar_label
的详细说明以及其他示例,请参阅此 answer。
在python 3.10
、pandas 1.3.4
、matplotlib 3.5.0
、seaborn 0.11.2
中测试
ax.containers
[<ErrorbarContainer object of 3 artists>,
<BarContainer object of 2 artists>,
<ErrorbarContainer object of 3 artists>,
<BarContainer object of 2 artists>,
<ErrorbarContainer object of 3 artists>,
<BarContainer object of 2 artists>]
.bar_label
使用label_type='center'
时会标注patch 值,使用label_type='edge'
时会使用patch 的cumsum
pandas.DataFrame.plot
与 yerr
BarContainer
对象位于奇数索引处,可以使用 ax.containers[1::2]
提取
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# load same dataframe
pen = sns.load_dataset('penguins')
# create the aggregated dataframe (mean)
pen_mean = pen.pivot_table(index='sex', columns='species', values='bill_depth_mm', aggfunc='mean')
# create the dataframe for the error bars with (std)
pen_std = pen.pivot_table(index='sex', columns='species', values='bill_depth_mm', aggfunc='std')
# plot the dataframe and add yerr
ax = pen_mean.plot(kind='bar', stacked=True, figsize=(9, 6), rot=0, yerr=pen_std)
# move the legend
ax.legend(bbox_to_anchor=(1, 1.02), loc='upper left')
# iterate through every other container; the even containers are ErrorbarContainer
for c in ax.containers[1::2]:
# add the annotation
ax.bar_label(c, label_type='center')
水平条
# plot the dataframe and add yerr
ax = pen_mean.plot(kind='barh', stacked=True, figsize=(9, 6), rot=0, xerr=pen_std)
# move the legend
ax.legend(bbox_to_anchor=(1, 1.02), loc='upper left')
# iterate through every other container; the even containers are ErrorbarContainer
for c in ax.containers[1::2]:
# add the annotation
ax.bar_label(c, label_type='center')
Axes.bar
和 Axes.errorbar
BarContainer 对象位于偶数索引处,可以使用ax.containers[0::2]
提取
data = pen_mean
cols = pen_mean.columns
rows = pen_mean.index
# Get some pastel shades for the colors
colors = ['tab:blue', 'tab:green']
n_rows = len(data)
index = np.arange(len(cols))
bar_width = 0.4
# Initialize the vertical-offset for the stacked bar chart.
y_offset = np.zeros(len(cols))
# Plot bars and create text labels for the table
fig, ax = plt.subplots(figsize=(8, 5))
for i, row in enumerate(rows):
ax.bar(cols, data.loc[row], bar_width, bottom=y_offset, color=colors[i])
ax.errorbar(cols, y_offset+data.loc[row], pen_std.loc[row], color='k', ls='none')
y_offset = y_offset + data.loc[row]
# note the order of the container objects is different
for c in ax.containers[0::2]:
ax.bar_label(c, label_type='center')
plt.show()
海生酒吧
默认ci=True
的seaborn 条形图不会在containers
中返回ErrorbarContainer objects
。
sns.catplot
与 kind='bar'
请参阅此answer,了解有关注释 seaborn 图形级条形图的其他示例。
p = sns.catplot(kind='bar', data=pen, x='sex', y='bill_depth_mm', hue='species', height=4.5, aspect=1.5)
# since this is a single subplot of a figure
ax = p.axes.flat[0]
for c in ax.containers:
# add the annotation
ax.bar_label(c, label_type='center')
sns.barplot
fig = plt.figure(figsize=(9, 6))
p = sns.barplot(data=pen, x='sex', y='bill_depth_mm', hue='species')
p.legend(bbox_to_anchor=(1, 1.02), loc='upper left')
for c in p.containers:
# add the annotation
p.bar_label(c, label_type='center')
【讨论】:
以上是关于添加误差线时如何注释条形图的主要内容,如果未能解决你的问题,请参考以下文章
R语言ggplot2可视化条形图(bar plot)并为条形图添加误差条(error bar)自定义设置误差条(error bar)的颜色/色彩( Barplots with Error bar)