如何在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
相关产品推荐
相关产品推荐

