如何在带hue的Seaborn factorplot箱线图上显示样本量
在带Hue的Seaborn箱线图上添加样本数量标注
我明白你遇到的问题了——当用Seaborn的catplot(注意factorplot已经被官方弃用,推荐用catplot替代)加上hue参数后,每个x类别下会有多个分组的箱线,原来单x轴时直接取刻度位置的方法就失效了。下面我用tips数据集给你两套完整的解决方案,你可以按需选择:
方法一:手动计算Hue分组的位置偏移
这种方法适合你明确知道hue类别数量的场景,逻辑清晰,容易理解:
import seaborn as sns import matplotlib.pyplot as plt import numpy as np sns.set_style("whitegrid") # 加载tips数据集 tips = sns.load_dataset("tips") # 绘制带hue的箱线图,用catplot替代弃用的factorplot g = sns.catplot(x="day", y="total_bill", hue="sex", kind="box", data=tips) ax = g.ax # 获取绘图的轴对象 # 计算每个(x类别, hue类别)组合的样本数量 counts = tips.groupby(['day', 'sex']).size().reset_index(name='count') # 获取x轴的刻度位置和对应的类别 x_ticks = ax.get_xticks() x_categories = tips['day'].unique() # 遍历每个x类别,给对应的两个hue分组添加标注 for i, day in enumerate(x_categories): # 筛选当前x类别下的所有hue分组计数 day_counts = counts[counts['day'] == day] # 男性分组的位置:x刻度位置 - 0.2(因为箱线默认宽度0.8,两个分组各占0.4) ax.text(x_ticks[i] - 0.2, ax.get_ylim()[1] * 0.98, f'n={day_counts[day_counts["sex"]=="Male"]["count"].values[0]}', ha='center', va='top', fontsize=10) # 女性分组的位置:x刻度位置 + 0.2 ax.text(x_ticks[i] + 0.2, ax.get_ylim()[1] * 0.98, f'n={day_counts[day_counts["sex"]=="Female"]["count"].values[0]}', ha='center', va='top', fontsize=10) plt.tight_layout() plt.show()
方法二:自动获取箱线位置(更通用)
如果你的hue类别数量不确定,或者想让代码更灵活,可以直接获取箱线图的矩形patch对象,自动提取位置信息:
import seaborn as sns import matplotlib.pyplot as plt import numpy as np sns.set_style("whitegrid") tips = sns.load_dataset("tips") g = sns.catplot(x="day", y="total_bill", hue="sex", kind="box", data=tips) ax = g.ax # 计算每个分组的样本数量,注意顺序要和箱线图的绘制顺序一致 counts = tips.groupby(['day', 'sex']).size().values # 筛选出所有箱线对应的矩形patch(排除其他辅助元素) boxes = [patch for patch in ax.patches if isinstance(patch, plt.Rectangle)] # 遍历每个箱线,添加样本数量标注 for box, count in zip(boxes, counts): # 获取箱线的中心x坐标 x_center = box.get_x() + box.get_width() / 2 # 获取箱线的顶部y坐标(也可以放在中位数位置,看你需求) y_top = box.get_y() + box.get_height() # 添加文本标注 ax.text(x_center, y_top, f'n={count}', ha='center', va='bottom', fontsize=10) plt.tight_layout() plt.show()
关键说明
- 为什么原来的方法失效?因为添加
hue后,Seaborn会在同一个x刻度位置左右偏移绘制多个箱线,不再是刚好对齐x刻度,所以直接用ax.get_xticks()的位置会对应到分组中间,不是单个箱线的位置。 - 如果你想把标注放在中位数位置,可以通过
ax.lines获取中位数线的位置,不过上面两种方法放在箱线顶部已经足够清晰直观。
内容的提问来源于stack exchange,提问作者sqlnewbie1979
相关产品推荐
相关产品推荐

