matplotlib多不同范围子图如何设置全局统一colorbar范围
matplotlib多子图共用全局范围colorbar的实现方法
问题出现的核心机制
- 循环绘制散点图时,
plt.scatter()默认会根据当前子图输入的颜色值,自动计算颜色映射的数值上下限(vmin/vmax)。 - 最后调用
plt.colorbar()时,接口会默认读取当前活动坐标轴(即循环结束后最后绘制的巴西子图)的颜色映射配置,自然就只采用了巴西区域的温度范围。俄罗斯的低温数据远低于这个范围,全部被映射到色阶的最高值,看起来和高温数据配色完全一致。
具体修改步骤
- 绘图循环启动前,计算全量数据的全局数值范围,避免手动硬编码数值,适配后续数据变动:
# 提取所有温度数据的全局最小、最大值 temp_min = df['Temperature'].min() temp_max = df['Temperature'].max() - 每次循环绘制散点图时,强制所有散点使用同一套全局上下限做颜色映射:
在原有plt.scatter()调用中追加vmin、vmax参数:plt.scatter( data['Depth'], data['%TOC'], c=data['Temperature'], s=50, edgecolors='k', vmin=temp_min, vmax=temp_max ) - 生成colorbar时,指定绑定所有子图,避免colorbar宽度只匹配最后一个子图的高度,出现比例失调:
将原有cbar = plt.colorbar()修改为:# 传入所有子图组成的数组,colorbar会自动适配总高度对齐 cbar = plt.colorbar(ax=axs) cbar.ax.set_ylabel('Temperature, degrees C')
可选等价实现方式
如果需要更灵活的颜色映射配置,可以在绘图前手动初始化全局归一化对象,所有散点图共用同一个对象即可,和上面传vmin/vmax的效果完全一致:
from matplotlib.colors import Normalize # 初始化全局统一的归一化配置 global_norm = Normalize(vmin=df['Temperature'].min(), vmax=df['Temperature'].max()) # 循环内调用scatter时,直接传入norm参数即可 plt.scatter(..., norm=global_norm)
修改后的完整可运行代码
import numpy as np import pandas as pd import matplotlib.pyplot as plt core_list = ['Russia', 'Brazil'] core_depth = [0, 2, 4, 6, 8, 10] lo = [-33, 28] hi = [10, 38] df = pd.DataFrame([], columns = ['Location', 'Depth', '%TOC', 'Temperature']) # 填充测试数据 for ii, name in enumerate(core_list): for jj in core_depth: df.loc[len(df.index)] = [name, jj, (np.random.randint(1, 20))/10, np.random.randint(lo[ii], hi[ii])] # 提前计算全局温度范围 temp_min = df['Temperature'].min() temp_max = df['Temperature'].max() # 绘制子图 fig, axs = plt.subplots(nrows = 1, ncols = 2, sharey = True) for nn, name in enumerate(core_list): core_mask = df['Location'] == name data = df.loc[core_mask] plt.sca(axs[nn]) # 传入统一的vmin/vmax plt.scatter(data['Depth'], data['%TOC'], c = data['Temperature'], s = 50, edgecolors = 'k', vmin=temp_min, vmax=temp_max) axs[nn].set_xlabel('%TOC') plt.text(1.25*min(data['%TOC']), 1.75, name) if nn == 0: axs[nn].set_ylabel('Depth') # 绑定所有子图生成colorbar cbar = plt.colorbar(ax=axs) cbar.ax.set_ylabel('Temperature, degrees C') plt.show()
运行上述代码后,colorbar的范围会完整覆盖从俄罗斯最低的零下三十余度到巴西最高的近四十度的全区间,俄罗斯的低温点会正确映射到冷色色阶,巴西的高温点映射到暖色色阶,不会再出现配色错位的问题。
内容的提问来源于stack exchange,提问作者brosenheim
相关产品推荐
相关产品推荐

