You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为分面分组条形图的sns.catplot添加自定义误差棒?

用预计算误差棒绘制Seaborn柱状图(两种实现方式)

环境依赖:pandas 1.5.3、seaborn 0.12.2


方法一:直接用Seaborn的errorbar参数(推荐)

Seaborn 0.12+版本支持在catplot(kind='bar')中通过errorbar参数传入自定义误差逻辑,刚好适配你预计算的val_lo(下限)和val_hi(上限)。只需定义一个lambda函数,返回每个数据点的上下误差范围即可。

修改后完整代码

import pandas as pd
import re
import seaborn as sns
from matplotlib.ticker import PercentFormatter
import matplotlib.pyplot as plt

df = pd.DataFrame([
    ['C', 'G1', 'gbt',    'auc', 0.7999, 0.7944, 0.8032],
    ['C', 'G1', 'gbtv2',  'auc', 0.8199, 0.8144, 0.8232],
    ['C', 'G1', 'gbt',  'pr@2%', 0.0883, 0.0841, 0.0909],
    ['C', 'G1', 'gbt', 'pr@10%', 0.0430, 0.0416, 0.0435],
    ['C', 'G2', 'gbt',    'auc', 0.7554, 0.7506, 0.7573],
    ['C', 'G2', 'gbt',  'pr@2%', 0.0842, 0.0795, 0.0872],
    ['C', 'G2', 'gbt', 'pr@10%', 0.0572, 0.0556, 0.0585],
    ['C', 'G3', 'gbt',    'auc', 0.7442, 0.7404, 0.7460],
    ['C', 'G3', 'gbt',  'pr@2%', 0.0894, 0.0836, 0.0913],
    ['C', 'G3', 'gbt', 'pr@10%', 0.0736, 0.0714, 0.0742],
    ['E', 'G1', 'gbt',    'auc', 0.7988, 0.7939, 0.8017],
    ['E', 'G1', 'gbt',  'pr@2%', 0.0810, 0.0770, 0.0832],
    ['E', 'G1', 'gbt', 'pr@10%', 0.0354, 0.0342, 0.0361],
    ['E', 'G1', 'gbtv3','pr@10%',0.0454, 0.0442, 0.0461],
    ['E', 'G2', 'gbt',    'auc', 0.7296, 0.7253, 0.7311],
    ['E', 'G2', 'gbt',  'pr@2%', 0.1071, 0.1034, 0.1083],
    ['E', 'G2', 'gbt', 'pr@10%', 0.0528, 0.0508, 0.0532],
    ['E', 'G3', 'gbt',    'auc', 0.6958, 0.6914, 0.6978],
    ['E', 'G3', 'gbt',  'pr@2%', 0.1007, 0.0961, 0.1030],
    ['E', 'G3', 'gbt', 'pr@10%', 0.0536, 0.0518, 0.0541],
  ], columns=["src","grp","model","metric","val","val_lo","val_hi"])

sns.reset_defaults()
sns.set(style="whitegrid", font_scale=1.)

# 核心修改:添加errorbar参数,传入自定义误差计算逻辑
g = sns.catplot(data=df, x="grp", y="val", hue="model", 
                col="metric", row="src", kind="bar", sharey=False,
                errorbar=lambda x: (x['val'] - x['val_lo'], x['val_hi'] - x['val']))

for ax in g.axes.flat:
  ax.yaxis.set_major_formatter(PercentFormatter(1))
  if re.search("metric = auc",ax.get_title(),re.IGNORECASE):
    _ = ax.set_ylim((.5,1.))
plt.show()

说明

lambda函数接收每个分组的子DataFrame,返回元组:第一个元素是下限误差(val - val_lo),第二个是上限误差(val_hi - val),Seaborn会自动将这些误差值对应到每个柱状图上。


方法二:手动用Matplotlib的errorbar添加误差棒

如果需要更灵活控制误差棒样式(如颜色、帽宽),可以先绘制基础柱状图,再遍历每个子轴手动添加误差棒。

修改后完整代码

import pandas as pd
import re
import seaborn as sns
from matplotlib.ticker import PercentFormatter
import matplotlib.pyplot as plt

df = pd.DataFrame([
    ['C', 'G1', 'gbt',    'auc', 0.7999, 0.7944, 0.8032],
    ['C', 'G1', 'gbtv2',  'auc', 0.8199, 0.8144, 0.8232],
    ['C', 'G1', 'gbt',  'pr@2%', 0.0883, 0.0841, 0.0909],
    ['C', 'G1', 'gbt', 'pr@10%', 0.0430, 0.0416, 0.0435],
    ['C', 'G2', 'gbt',    'auc', 0.7554, 0.7506, 0.7573],
    ['C', 'G2', 'gbt',  'pr@2%', 0.0842, 0.0795, 0.0872],
    ['C', 'G2', 'gbt', 'pr@10%', 0.0572, 0.0556, 0.0585],
    ['C', 'G3', 'gbt',    'auc', 0.7442, 0.7404, 0.7460],
    ['C', 'G3', 'gbt',  'pr@2%', 0.0894, 0.0836, 0.0913],
    ['C', 'G3', 'gbt', 'pr@10%', 0.0736, 0.0714, 0.0742],
    ['E', 'G1', 'gbt',    'auc', 0.7988, 0.7939, 0.8017],
    ['E', 'G1', 'gbt',  'pr@2%', 0.0810, 0.0770, 0.0832],
    ['E', 'G1', 'gbt', 'pr@10%', 0.0354, 0.0342, 0.0361],
    ['E', 'G1', 'gbtv3','pr@10%',0.0454, 0.0442, 0.0461],
    ['E', 'G2', 'gbt',    'auc', 0.7296, 0.7253, 0.7311],
    ['E', 'G2', 'gbt',  'pr@2%', 0.1071, 0.1034, 0.1083],
    ['E', 'G2', 'gbt', 'pr@10%', 0.0528, 0.0508, 0.0532],
    ['E', 'G3', 'gbt',    'auc', 0.6958, 0.6914, 0.6978],
    ['E', 'G3', 'gbt',  'pr@2%', 0.1007, 0.0961, 0.1030],
    ['E', 'G3', 'gbt', 'pr@10%', 0.0536, 0.0518, 0.0541],
  ], columns=["src","grp","model","metric","val","val_lo","val_hi"])

sns.reset_defaults()
sns.set(style="whitegrid", font_scale=1.)

# 先绘制基础柱状图,关闭默认误差棒
g = sns.catplot(data=df, x="grp", y="val", hue="model", 
                col="metric", row="src", kind="bar", sharey=False,
                errorbar=None)

# 遍历每个子图添加自定义误差棒
for ax in g.axes.flat:
    # 获取当前子图对应的src和metric
    row_val = g.row_names[ax.get_subplotspec().rowspan.start]
    col_val = g.col_names[ax.get_subplotspec().colspan.start]
    subset = df[(df['src'] == row_val) & (df['metric'] == col_val)]
    
    # 按grp和model排序,确保和bar的绘制顺序一致
    subset_sorted = subset.sort_values(by=['grp', 'model'])
    bars = ax.patches
    
    # 逐个匹配bar和误差值
    for bar, (_, row) in zip(bars, subset_sorted.iterrows()):
        x_center = bar.get_x() + bar.get_width() / 2  # bar的中心x坐标
        y_val = row['val']
        # 上下误差需用嵌套列表格式
        y_err = [[row['val'] - row['val_lo']], [row['val_hi'] - row['val']]]
        ax.errorbar(x_center, y_val, yerr=y_err, fmt='none', c='black', capsize=3)
    
    # 保留原有的格式设置
    ax.yaxis.set_major_formatter(PercentFormatter(1))
    if re.search("metric = auc", ax.get_title(), re.IGNORECASE):
        ax.set_ylim((.5,1.))

plt.show()

说明

通过ax.patches获取每个柱状图的位置信息,再匹配对应数据行的误差值,调用ax.errorbar添加误差棒。可以通过修改c(颜色)、capsize(帽宽)等参数自定义样式。


内容的提问来源于stack exchange,提问作者ironv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 12:30:02