matplotlib热图colorbar调整:兼容极小值并展示数值细微差异
问题根源
问题核心是色条的动态范围被离群值抢占,主数据区间的映射分辨率不足。默认使用线性归一化色阶时,1e-9的离群极小值会把色条的动态范围拉得极宽,占比最高的614~620主数值区间仅占色条总长度的不到1%,完全无法展示细微数值差异。
注意:不要直接使用普通
LogNorm对数归一化,普通对数刻度下600~620区间的对数值差异极小,依然无法清晰展示数值波动。

方案1:SymLog对称对数归一化(实现最简单)
使用matplotlib内置的SymLogNorm做色阶映射,在指定阈值内使用线性刻度、阈值外使用对数刻度,既完整覆盖1e-9极小值,又能把主数值区间完全展开:
import numpy as np from numpy import NaN import matplotlib.pyplot as plt from matplotlib.colors import SymLogNorm from mpl_toolkits.axes_grid1 import make_axes_locatable T = np.array([[6.19314835e+02, 6.19229656e+02, 6.19220233e+02], [6.14626547e+02, 6.18217141e+02, 6.19029892e+02], [1.00000000e-09, NaN, NaN]]) fig, ax = plt.subplots() # *linthresh是核心参数*:-1~1区间使用对数刻度压缩,大于1的区间使用线性刻度展开 # 显式指定vmin/vmax避免自动归一化出现偏差 im = ax.imshow( T, norm=SymLogNorm(linthresh=1, vmin=1e-9, vmax=np.nanmax(T)) ) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) plt.colorbar(im, cax=cax) plt.show()
效果说明:1e-9到1的区间被对数压缩,仅占色条很小一部分长度,1620的主值区间线性展开,614620之间的数值差异可以清晰分辨。
方案2:自定义分段归一化(读值最直观)
如果觉得对数刻度读值不便,可以用BoundaryNorm自定义色段边界,单独给1e-9极小值分配一个独立色段,剩余所有色条长度都用来展示主数值区间的波动:
import numpy as np from numpy import NaN import matplotlib.pyplot as plt from matplotlib.colors import BoundaryNorm from mpl_toolkits.axes_grid1 import make_axes_locatable T = np.array([[6.19314835e+02, 6.19229656e+02, 6.19220233e+02], [6.14626547e+02, 6.18217141e+02, 6.19029892e+02], [1.00000000e-09, NaN, NaN]]) # 自定义色段边界:第一个区间单独留给1e-9极小值,后续按主数值范围细分 bounds = [1e-9, 614, 615, 616, 617, 618, 618.5, 619, 619.5, 620] cmap = plt.get_cmap('viridis').copy() norm = BoundaryNorm(bounds, cmap.N) fig, ax = plt.subplots() im = ax.imshow(T, cmap=cmap, norm=norm) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) # 按自定义边界设置色条刻度,按比例分配色段长度 plt.colorbar(im, cax=cax, ticks=bounds, spacing='proportional') plt.show()
效果说明:1e-9的异常点单独使用色条最下端的颜色标识,其余色段全部分配给614~620区间,刻度为线性,读值直观,微小数值差异展示最清晰。
补充说明
- 两种方案都默认自动忽略NaN值,不需要额外对NaN做遮罩处理
- 可以根据实际数据的波动范围调整
linthresh参数或者分段边界的密度,主数值波动越小,主值区间的边界可以设得越密,差异展示效果越好 - 如果需要突出1e-9的异常点,可以手动修改对应色段的颜色为高对比度色(如红色),和正常数值做区分
内容的提问来源于stack exchange,提问作者Wiz123
相关产品推荐
相关产品推荐

