Matplotlib多imshow子图colorbar范围统一与位置调整实现
问题核心修复方案
1. 实现同组子图色标映射统一
同组色标不统一的核心原因是代码在循环内为每张子图单独创建LogNorm()实例,每个norm会自动适配当前子图的数值范围生成独立的色阶映射,后续单独修改colorbar的clim仅能作用于最后一次循环生成的mappable,无法同步所有同组子图。
修复方式:
- 提前为两组数据分别固定数值范围,创建全局共享的norm实例
- 所有同组的
imshow调用都传入这个共享的norm,从根源上保证数值到颜色的映射规则完全一致 - 不需要后续对colorbar单独设置clim,因为固定的norm会同步所有子图和colorbar的映射范围
2. 实现第二组colorbar在后两列上方水平居中
原代码仅将第一行的两个轴作为colorbar的依附对象,无法锚定整组列的总宽度范围,容易出现位置偏移。
修复方式:
- 给colorbar的
ax参数传入对应列组的所有行轴对象,而非仅第一行的轴 - matplotlib会自动计算整组轴的包围盒,将顶部放置的colorbar调整为与整组轴等宽,自然实现水平居中对齐
- 调整合理的pad参数,避免colorbar过近压到子图内容
附带修复的原代码bug
- 索引越界:原代码定义的
cm = ['hot', 'viridis']仅包含2个元素(索引0、1),但实际调用时使用了cm[2],会触发数组越界报错,需修正为cm[1] - 变量覆盖:原代码在循环内重复对外部列表类型的
data变量重新赋值,会覆盖原有预设的分类列表,需调整内部变量名避免混淆
修正后的可运行测试代码
import matplotlib.pyplot as plt import matplotlib as mpl import numpy as np # 用于生成测试随机矩阵 a = 5 b = 4 fig, axs = plt.subplots(a, b , figsize=(8.27, 11.69), tight_layout=True, sharey=True, sharex=True, gridspec_kw = {'wspace':0, 'hspace':0}) gasf = ['fg10', 'fg20', 'fg30', 'fg50', 'fg70'] dire = ['x', 'z', 'x', 'z'] cm = ['hot', 'viridis'] # 提前定义共享的固定范围的norm,实现同组色标统一 norm_sm = mpl.colors.LogNorm(vmin=1E2, vmax=1E9) norm_dens = mpl.colors.LogNorm(vmin=1E-5, vmax=1E0) # 生成测试用随机矩阵替换eval(data)的逻辑 test_data_sm = np.random.uniform(low=1E2, high=1E9, size=(100,100)) test_data_dens = np.random.uniform(low=1E-5, high=1E0, size=(100,100)) for col in range(b): for row in range(a): ax = axs[row, col] if col ==0: ax.set_ylabel('x (kpc)', fontsize=13) if col < 2: # 所有sm组的图都使用同一个共享norm pcm = ax.imshow(test_data_sm, norm=norm_sm, cmap=cm[0], interpolation='none', extent=[-17.5,17.5,-17.5,17.5]) else: # 所有dens组的图都使用同一个共享norm,修正原cm[2]的越界问题 pcm2 = ax.imshow(test_data_dens, norm=norm_dens, cmap=cm[1], interpolation='none', extent=[-17.5,17.5,-17.5,17.5]) if row ==4: if col == 0: ax.set_xlabel('z (kpc)', fontsize=13) if col == 1: ax.set_xlabel('y (kpc)', fontsize=13) if col == 2: ax.set_xlabel('z (kpc)', fontsize=13) if col == 3: ax.set_xlabel('y (kpc)', fontsize=13) # colorbar传入整列组的所有轴对象,自动实现水平居中,调整合理pad值 cb1 = fig.colorbar(pcm, ax=axs[:, :2], location='top', pad=0.15) cb2 = fig.colorbar(pcm2, ax=axs[:, 2:4], location='top', pad=0.15) plt.show()
内容的提问来源于stack exchange,提问作者Vloer
相关产品推荐
相关产品推荐

