使用Seaborn绘制多组子图面板遇空网格问题求助
子图绘制异常问题分析与解决
问题重现
尝试在单个画布中绘制3组各含3个绘图的子图面板,但最终得到一个空网格和3个独立的子图面板,效果如下:
相关代码如下:
绘图函数
def plot_qc_metrics(adata, key): pg.qc_metrics(adata, min_genes=100, mito_prefix='MT-') pg.filter_data(adata) fig, ax = plt.subplots(1, 3, figsize=(15, 5), sharey=True) fig.suptitle(key, fontsize=16) sns.histplot(data = adata.obs, x = 'n_counts', bins=50, log_scale=True, ax=ax[0]) ax[0].set(xlim=(1, 100000), xlabel='log nUMI') data = adata.obs['n_genes'] sns.histplot(data = adata.obs, x = 'n_genes', bins=50, log_scale=True, ax=ax[1]) ax[1].set(xlim=(1, 100000), xlabel='log nGenes') data = np.log2(adata.obs['percent_mito']) sns.histplot(data = data, x=data, bins=100, ax=ax[2]) ax[2].xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: '$2^{%.0f}$' % x)) return fig, ax
主调用代码
adata_dict = { 'org_1': org_1, 'org_2': org_2, 'org_3': org_3 } fig, ax = plt.subplots(nrows = 3, ncols = len(adata_dict), figsize=(15, 5), sharey=True) for i, (key, adata) in enumerate(adata_dict.items()): subfig, subax = plot_qc_metrics(adata, key) ax[i] = subax plt.tight_layout() plt.show()
问题原因
- 重复创建画布:
plot_qc_metrics函数内部每次都会执行fig, ax = plt.subplots(1, 3),这会生成新的独立画布,而非在你预先创建的大画布的子轴上绘图。 - 无效的轴赋值:尝试将
subax赋值给ax[i]完全不起作用——matplotlib的轴对象无法通过这种方式替换,只会让预先创建的大画布轴保持空白,而函数里生成的新画布会单独显示。
修改方案
让绘图函数复用外部创建的轴对象,不再自行生成画布。具体修改如下:
修改后的绘图函数
def plot_qc_metrics(adata, key, ax_list): pg.qc_metrics(adata, min_genes=100, mito_prefix='MT-') pg.filter_data(adata) # 直接使用传入的轴列表绘图 sns.histplot(data=adata.obs, x='n_counts', bins=50, log_scale=True, ax=ax_list[0]) ax_list[0].set(xlim=(1, 100000), xlabel='log nUMI') sns.histplot(data=adata.obs, x='n_genes', bins=50, log_scale=True, ax=ax_list[1]) ax_list[1].set(xlim=(1, 100000), xlabel='log nGenes') data = np.log2(adata.obs['percent_mito']) sns.histplot(data=data, x=data, bins=100, ax=ax_list[2]) ax_list[2].xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: '$2^{%.0f}$' % x))
修改后的主调用代码
adata_dict = { 'org_1': org_1, 'org_2': org_2, 'org_3': org_3 } # 创建3行3列的子图网格,调整画布大小适配布局 fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(15, 12), sharey='row') for i, (key, adata) in enumerate(adata_dict.items()): # 将当前行的3个轴传入绘图函数 plot_qc_metrics(adata, key, ax[i]) # 给每行添加数据集标题 ax[i][0].set_ylabel(key, fontsize=14) # 调整布局避免标题重叠 plt.tight_layout() plt.subplots_adjust(top=0.92) # 添加总标题 fig.suptitle('样本QC指标汇总', fontsize=18) plt.show()
修改说明
- 移除绘图函数内部创建画布的代码,改为接收外部传入的轴列表
ax_list,直接在指定轴上绘图,避免生成独立画布。 - 主代码创建3行3列的轴网格,每行对应一个数据集的3个QC图,将每行的轴传入函数完成绘图。
- 调整画布大小和布局参数,确保标题与子图不重叠,提升可视化效果。
内容的提问来源于stack exchange,提问作者Carmen Sandoval
相关产品推荐
相关产品推荐

