如何在Python Matplotlib中修正带Colorbar的子图尺寸:解决3×2子图第三行图像缩小问题
解决3×2子图中带Colorbar行的图像尺寸不一致问题
这个问题的核心原因很明确:当你调用fig.colorbar()并指定ax=ax3[0]/ax3[1]时,matplotlib会直接从对应的子图轴域里挤占空间来放置水平colorbar,导致第三行的子图本身被压缩,自然就比前两行的图像小了。
要解决这个问题,我们需要让colorbar占用独立的布局空间,而不是挤压原图像的区域。下面提供两种可靠的实现方案:
方法一:用GridSpec精准规划全局布局
GridSpec可以把画布拆分成更精细的网格,我们可以给第三行的colorbar单独分配一行空间,这样第三行的子图就能和前两行保持相同的高度。
修改后的代码如下:
import matplotlib.pyplot as plt import matplotlib.image as image import matplotlib.colors from matplotlib.gridspec import GridSpec # 读取图像 bird = image.imread('Desktop/bird.jpeg') # 创建GridSpec:总共4行(前3行放子图,第4行放第三行的colorbar),2列 fig = plt.figure(figsize=(5, 6)) # 微调高度,给colorbar预留空间 gs = GridSpec(4, 2, figure=fig, height_ratios=[1, 1, 1, 0.1]) # 第4行高度占比小,专门放colorbar # 第一行子图 ax1_0 = fig.add_subplot(gs[0, 0]) ax1_0.imshow(bird) ax1_0.set_ylabel('Row 1', size=8) ax1_0.set_yticks([]) ax1_0.set_xticks([]) ax1_1 = fig.add_subplot(gs[0, 1]) ax1_1.imshow(bird) ax1_1.set_yticks([]) ax1_1.set_xticks([]) # 第二行子图 ax2_0 = fig.add_subplot(gs[1, 0]) ax2_0.imshow(bird) ax2_0.set_ylabel('Row 2', size=8) ax2_0.set_yticks([]) ax2_0.set_xticks([]) ax2_1 = fig.add_subplot(gs[1, 1]) ax2_1.imshow(bird) ax2_1.set_yticks([]) ax2_1.set_xticks([]) # 第三行子图(占用第3行网格) ax3_0 = fig.add_subplot(gs[2, 0]) cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["Red","Green","Blue"]) bird_4 = ax3_0.imshow(bird, cmap=cmap) ax3_0.set_ylabel('Row 3', size=8) ax3_0.set_yticks([]) ax3_0.set_xticks([]) bird_4.set_clim(vmin=-1, vmax=1) ax3_1 = fig.add_subplot(gs[2, 1]) bird_3 = ax3_1.imshow(bird, cmap=cmap) ax3_1.set_yticks([]) ax3_1.set_xticks([]) bird_3.set_clim(vmin=-1, vmax=1) # 为第三行的两个子图分别创建colorbar,放在第4行对应的列 cbar0 = fig.colorbar(bird_4, orientation='horizontal', cax=fig.add_subplot(gs[3, 0])) cbar0.set_label('CBar', size=8, rotation=0) cbar0.ax.tick_params(labelsize=8) cbar1 = fig.colorbar(bird_3, orientation='horizontal', cax=fig.add_subplot(gs[3, 1])) cbar1.set_label('CBar', size=8, rotation=0) cbar1.ax.tick_params(labelsize=8) plt.tight_layout() plt.show()
方法二:用make_axes_locatable为子图附加独立colorbar轴
这个方法会自动为每个子图创建一个相邻的轴域来放置colorbar,从根源上避免原图像被挤压。
修改后的代码如下:
import matplotlib.pyplot as plt import matplotlib.image as image import matplotlib.colors from mpl_toolkits.axes_grid1 import make_axes_locatable # 读取图像 bird = image.imread('Desktop/bird.jpeg') fig, (ax1, ax2, ax3) = plt.subplots(3,2,figsize=(5,6)) # 第一行子图 ax1[0].imshow(bird) ax1[0].set_ylabel('Row 1', size=8) ax1[0].set_yticks([]) ax1[0].set_xticks([]) ax1[1].imshow(bird) ax1[1].set_yticks([]) ax1[1].set_xticks([]) # 第二行子图 ax2[0].imshow(bird) ax2[0].set_ylabel('Row 2', size=8) ax2[0].set_yticks([]) ax2[0].set_xticks([]) ax2[1].imshow(bird) ax2[1].set_yticks([]) ax2[1].set_xticks([]) # 生成色图 cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["Red","Green","Blue"]) # 第三行左图:用make_axes_locatable创建colorbar轴 bird_4 = ax3[0].imshow(bird, cmap=cmap) ax3[0].set_ylabel('Row 3', size=8) ax3[0].set_yticks([]) ax3[0].set_xticks([]) bird_4.set_clim(vmin=-1, vmax=1) # 分割ax3[0]的轴域,在下方添加一个用于colorbar的轴 divider = make_axes_locatable(ax3[0]) cax0 = divider.append_axes("bottom", size="10%", pad=0.3) # size是colorbar高度,pad是间距 cbar0 = fig.colorbar(bird_4, orientation='horizontal', cax=cax0) cbar0.set_label('CBar', size=8, rotation=0) cbar0.ax.tick_params(labelsize=8) # 第三行右图:同样的处理 bird_3 = ax3[1].imshow(bird, cmap=cmap) ax3[1].set_yticks([]) ax3[1].set_xticks([]) bird_3.set_clim(vmin=-1, vmax=1) divider = make_axes_locatable(ax3[1]) cax1 = divider.append_axes("bottom", size="10%", pad=0.3) cbar1 = fig.colorbar(bird_3, orientation='horizontal', cax=cax1) cbar1.set_label('CBar', size=8, rotation=0) cbar1.ax.tick_params(labelsize=8) plt.tight_layout() plt.show()
这两种方法都能保证第三行的子图尺寸和前两行完全一致,同时让colorbar有独立的展示空间。你可以根据需求选择:GridSpec适合全局布局的精细调控,make_axes_locatable则更适合快速给单个子图追加colorbar的场景。
内容的提问来源于stack exchange,提问作者user199663
相关产品推荐
相关产品推荐

