Matplotlib散点图跨子图标准化色阶与公共colorbar配置实现
问题根源
你现在的代码会生成两套完全独立的颜色映射规则:Matplotlib的scatter接口默认会拿当前传入的z值数组的最小/最大值,自动计算颜色对应的数值跨度,哪怕两个子图用了一模一样的色卡名字,相同z值的颜色根本对不上。
比如你的示例数据里,左图z值范围是1-4,右图是2-6:z=3在左图是色卡中间色,在右图是偏浅的低数值色,跨图对比完全没有意义。
修正逻辑
要让两个子图的颜色和z值一一对应,只需要给两个散点图用完全相同的数值归一化规则,把色阶的上下边界固定死,不让每个子图自己算范围就行。
具体步骤:
- 把两组数据的所有z值拼到一起,找全局的最小、最大值,作为统一色阶的两个端点
- 生成全局通用的归一化对象,调用
scatter的时候把这个对象传进去,替代默认的自动范围计算 - 加统一colorbar的时候,让它自动适配整个子图组的布局,不要挤在某一个子图边上
修正后可直接运行的代码
import numpy as np import matplotlib.pyplot as plt import matplotlib.colors as mcolors # 原始测试数据 vals1 = np.array([[1,1,1],[2,2,4]]) vals2 = np.array([[1,1,2],[2,2,6]]) # 计算全局统一的色阶上下限 all_z = np.concatenate([vals1[:, 2], vals2[:, 2]]) global_norm = mcolors.Normalize(vmin=all_z.min(), vmax=all_z.max()) fig, ax = plt.subplots(1, 2, constrained_layout=True) # 两个散点图传入完全相同的norm参数,保证色彩映射对齐 g1 = ax[0].scatter( x=vals1[:,0], y=vals1[:,1], c=vals1[:,2], cmap='RdBu', norm=global_norm ) g2 = ax[1].scatter( x=vals2[:,0], y=vals2[:,1], c=vals2[:,2], cmap='RdBu', norm=global_norm ) # 生成跨子图的统一colorbar,指定ax=ax让布局自动适配 fig.colorbar(g1, ax=ax, label='关联z值')
容易踩的坑
- 别以为用同一个
cmap名就够了:映射比例是每个scatter调用独立计算的,和色卡本身没有关系 - 色阶范围别只拿单组数据算:不然另一组超出范围的z值会被硬塞成色卡的边界极端色,和实际数值对不上
- 用
constrained_layout自动排版的时候,给colorbar加ax=ax参数:不然colorbar会吃掉某一个子图的宽度,让两个子图宽度不一致
内容的提问来源于stack exchange,提问作者StephB
相关产品推荐
相关产品推荐

