解决Seaborn catplot子图合并后保存为单个图像文件时的空白问题
解决Seaborn Catplot子图合并后保存空白的问题
这个问题的核心原因是你混淆了Seaborn中图级函数和轴级函数的区别——catplot是图级函数,它会自动创建独立的FacetGrid和图形实例,并不会直接在你用plt.subplots预先创建的axs子图上绘制内容。这就导致你最后保存的fig其实是空的,真正的绘图内容在catplot生成的独立图形窗口里,自然导出后显示空白。
解决方案:改用轴级的countplot函数
要在自定义子图上绘制计数图,应该使用seaborn.countplot(轴级函数),它支持直接指定ax参数,在你预先创建的子图轴上完成绘图。下面是修正后的完整代码:
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # Read data df1 = pd.read_csv("df1.csv") df2 = pd.read_csv("df2.csv") # 创建我们要使用的主图形和子图轴 fig, axs = plt.subplots(2, 1, figsize=(10, 7)) category_order = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] # 顶部子图:使用countplot指定ax=axs[0] sns.countplot(x="Month", hue="Day of Week", data=df1, hue_order=category_order, ax=axs[0]) # 为柱子添加数值标注(居中显示) for p in axs[0].patches: axs[0].text(p.get_x() + p.get_width()/2, p.get_height()*1.02, f"{p.get_height():.0f}", color="black", ha='center', size="small") # 格式调整 axs[0].set(ylim=(0, 18)) sns.despine(ax=axs[0], top=False, right=False) axs[0].legend_.remove() # 移除顶部子图的图例 # 底部子图:同样用countplot指定ax=axs[1] sns.countplot(x="Month", hue="Day of Week", data=df2, hue_order=category_order, ax=axs[1]) # 为柱子添加数值标注(居中显示) for p in axs[0].patches: axs[1].text(p.get_x() + p.get_width()/2, p.get_height()*1.02, f"{p.get_height():.0f}", color="black", ha='center', size="small") # 格式调整 axs[1].set(ylim=(0, 18)) axs[1].set_xlabel("Date") sns.despine(ax=axs[1], top=False, right=False) # 统一调整整个图形的布局 fig.tight_layout() # 保存图形(此时保存的是我们创建的fig,包含所有子图内容) fig.savefig("fig.pdf", dpi=200, bbox_inches="tight") plt.show()
关键改动说明
- 替换
catplot为countplot:countplot是轴级函数,支持ax参数,直接在你指定的子图轴上绘图,不会生成额外的图形实例。 - 图例处理更直接:通过
axs[0].legend_.remove()直接移除顶部子图的图例,无需操作FacetGrid对象。 - 优化标注位置:调整了文本的x坐标为
p.get_x() + p.get_width()/2,让数值标注居中显示在柱子上方,避免偏移。 - 统一布局管理:用
fig.tight_layout()替代原代码中的g.tight_layout(),直接操作我们创建的主图形对象,布局更可控。 - 无需关闭额外图形:因为所有绘图都在预先创建的
fig中完成,没有多余的图形窗口,所以不需要plt.close(1)。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

