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

如何在Matplotlib中渲染尺寸均匀的子图?

问题描述

我想要制作包含5个水平条形图(barh)的图形,要求图例放在底部,添加注释线和总标题,但遇到子图尺寸不均的问题:第二行子图高度和其他行不一致,第三行的子图(第5个)宽度也不对。我尝试调整constrained_layout和subplot_adjust()都没效果,换成tight_layout手动调整也无法正确渲染。

目标图形示意图:
目标条形图布局

我的代码如下:

import numpy as np
import matplotlib
import matplotlib.pyplot as plt

fig = plt.figure(constrained_layout=True)

temps = ['1', '2', '3']
colour=['#ffffff','#29d639']

subfigs = fig.subfigures(nrows=3, ncols=1)
subfigs[1].suptitle('Open defects')


[ax14, ax9] = subfigs[0].subplots(nrows=1, ncols=2)


d14_4= [15000000,15000000,15000000]
b14 = ax14.barh(temps, d14_4,height= 1, linewidth=0.5,edgecolor='black', color=colour[0])
ax14.set_xscale('log')
ax14.set_xlim(1,15000000)
ax14.margins(x=0,y=0)


d9_4= [1500000,1500000,1500000]
b9_4 = ax9.barh(temps, d9_4,height= 1, linewidth=0.5,edgecolor='black', color=colour[0])
ax9.set_xscale('log')
ax9.set_xlim(1,1500000)
ax9.margins(x=0,y=0)

ax14.annotate('', xy=(0, -0.32), xycoords='axes fraction', xytext=(2.07, -0.32), arrowprops=dict(arrowstyle="-", linestyle='-', linewidth=1.5, color='grey'))


[ax1, ax8] = subfigs[1].subplots(nrows=1, ncols=2)

d1_5= [4000,4000,4000]
b1_5 = ax1.barh(temps, d1_5,height= 1, linewidth=0.5,edgecolor='black',color=colour[1])
ax1.set_xscale('log')
ax1.set_xlim(1,4000)
ax1.margins(x=0,y=0)

d8_3= [60000000, 60000000, 0]
b8_3 = ax8.barh(temps, d8_3,height= 1, linewidth=0.5,edgecolor='black', color=colour[1])
ax8.set_xscale('log')
ax8.set_xlim(1,60000000)
ax8.margins(x=0,y=0)

[ax15, ax18] = subfigs[2].subplots(nrows=1, ncols=2)

d15_5= [0, 0, 5000000]
b15 = ax15.barh(temps, d15_5,height= 1, linewidth=0.5,edgecolor='black',color=colour[1])
ax15.set_xscale('log')
ax15.set_xlim(1,5000000)
ax15.margins(x=0,y=0)

ax18.remove()

labels=["1","2"]
lines=[b15,b14]

leg=fig.legend(lines, labels, loc = (0.7, 0.035), ncol=3,frameon=False)

# plt.savefig('output1.pdf', format='pdf')
plt.show()
解决方案

问题出在使用subfigures的方式,每个subfig会自动分配高度,且第三行删除子图后布局失衡。改用GridSpec精确控制子图位置和尺寸,可保证所有子图高度一致,同时第三行单个子图宽度与上方匹配。

修改后的代码:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

fig = plt.figure(figsize=(10, 8), constrained_layout=True)
# 添加总标题
fig.suptitle('Total Title', y=0.98, fontsize=12)

# 划分3行2列网格,强制所有行高度相同
gs = GridSpec(3, 2, figure=fig, height_ratios=[1, 1, 1])

temps = ['1', '2', '3']
colour=['#ffffff','#29d639']

# 第一行子图
ax14 = fig.add_subplot(gs[0, 0])
ax9 = fig.add_subplot(gs[0, 1])

d14_4= [15000000,15000000,15000000]
b14 = ax14.barh(temps, d14_4, height=1, linewidth=0.5, edgecolor='black', color=colour[0])
ax14.set_xscale('log')
ax14.set_xlim(1,15000000)
ax14.margins(x=0,y=0)

d9_4= [1500000,1500000,1500000]
b9_4 = ax9.barh(temps, d9_4, height=1, linewidth=0.5, edgecolor='black', color=colour[0])
ax9.set_xscale('log')
ax9.set_xlim(1,1500000)
ax9.margins(x=0,y=0)

# 添加注释线(适配新布局调整坐标)
ax14.annotate('', xy=(0, -0.3), xycoords='axes fraction', xytext=(2.1, -0.3), 
              arrowprops=dict(arrowstyle="-", linestyle='-', linewidth=1.5, color='grey'))

# 第二行子图
ax1 = fig.add_subplot(gs[1, 0])
ax8 = fig.add_subplot(gs[1, 1])
# 在第二行中间上方添加标题
fig.text(0.5, 0.67, 'Open defects', ha='center', fontsize=10)

d1_5= [4000,4000,4000]
b1_5 = ax1.barh(temps, d1_5, height=1, linewidth=0.5, edgecolor='black', color=colour[1])
ax1.set_xscale('log')
ax1.set_xlim(1,4000)
ax1.margins(x=0,y=0)

d8_3= [60000000, 60000000, 0]
b8_3 = ax8.barh(temps, d8_3, height=1, linewidth=0.5, edgecolor='black', color=colour[1])
ax8.set_xscale('log')
ax8.set_xlim(1,60000000)
ax8.margins(x=0,y=0)

# 第三行仅创建需要的子图,避免布局失衡
ax15 = fig.add_subplot(gs[2, 0])

d15_5= [0, 0, 5000000]
b15 = ax15.barh(temps, d15_5, height=1, linewidth=0.5, edgecolor='black', color=colour[1])
ax15.set_xscale('log')
ax15.set_xlim(1,5000000)
ax15.margins(x=0,y=0)

# 添加底部右侧图例
labels=["1","2"]
lines=[b15,b14]
fig.legend(lines, labels, loc='lower right', ncol=2, frameon=False, bbox_to_anchor=(0.95, 0.02))

plt.savefig('output1.pdf', format='pdf')
plt.show()

关键修改点:

  • 用GridSpec替代subfigures,通过height_ratios=[1,1,1]强制所有行高度一致
  • 第三行直接创建单个子图,避免删除子图导致的布局错乱
  • 调整注释线坐标参数适配新布局
  • 用fig.text()添加第二行标题,保证位置居中
  • 优化图例位置参数,让布局更合理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:58:15