如何使用matplotlib subplots实现多行多列的子图布局
实现方案
核心是创建2行n列的子图网格后,分别给两行的对应列分配绘图内容,修改后的可运行代码如下:
import pandas as pd import matplotlib.pyplot as plt # 示例数据 data = pd.DataFrame({ 'corpus': ['fairview', 'i2b2', 'mipacq'], 'group': ['all', 'all', 'all'], 'mono p': [49, 46, 44], 'non p': [51, 54, 56], 'plus p': [49, 46, 43], 'minus p': [0, 0, 1] }) semgroups = ['all'] for sg in semgroups: i = semgroups.index(sg) ix = i + 7 ncols = data['corpus'].nunique() # 核心修改1:创建2行n列的子图,共享y轴 fig, axs = plt.subplots(2, ncols, sharey=True, figsize=(12, 6)) # 遍历每一列(每个corpus对应一列) for col_idx, (idx, row) in enumerate(data.iterrows()): # 第一行绘制mono p、non p ax_top = axs[0, col_idx] row[['mono p', 'non p']].plot.bar(ax=ax_top, color=['C0','C1']) # 第二行绘制plus p、minus p ax_bottom = axs[1, col_idx] row[['plus p', 'minus p']].plot.bar(ax=ax_bottom, color=['C0','C1']) # 标题规则调整,第一行加前缀,第二行用原规则 if row['corpus'] == 'fairview': corpus_name = 'Fairview' top_label = '(a) ' bottom_label = '(d) ' elif row['corpus'] == 'mipacq': corpus_name = 'MiPACQ' top_label = '(c) ' bottom_label = '(f) ' else: corpus_name = 'i2b2' top_label = '(b) ' bottom_label = '(e) ' ax_top.set_title(top_label + corpus_name) ax_bottom.set_title(bottom_label + corpus_name) # 统一设置x轴刻度旋转 ax_top.tick_params(axis='x', labelrotation=45) ax_bottom.tick_params(axis='x', labelrotation=45) if sg == 'all': sg_name = 'All groups' # 统一设置y轴范围 custom_ylim = (0, 60) plt.setp(axs, ylim=custom_ylim) fig.suptitle(f'Figure {ix} {sg_name}', y=1.02) # 自动调整布局避免重叠 plt.tight_layout() plt.show()
关键修改说明
- 把原本的
plt.subplots(1, ncols, sharey=True)改为plt.subplots(2, ncols, sharey=True),生成2行3列的子图网格 - 每一列对应同一个corpus的两组数据,分别在第一行和第二行的对应子图上绘图
- 新增
tight_layout()避免子图标题、标签重叠,y=1.02调整总标题位置避免和子图标题冲突
内容的提问来源于stack exchange,提问作者horcle_buzz
相关产品推荐
相关产品推荐

