Matplotlib BoundaryNorm将等于上边界的值映射至set_over颜色问题
BoundaryNorm中1.0被识别为over值的问题分析
问题描述
我需要将0.1~1.0之间的值映射为离散颜色,小于0.1的用白色,大于1的用hotpink。但使用matplotlib.colors.BoundaryNorm时,发现1.0被映射到了set_over定义的hotpink,只有把1.0改成0.999999才能得到预期效果。同时疑惑文档中“大于等于上边界的值将被映射到最高索引”的描述是否有误。
测试代码
import matplotlib.colors as colors from matplotlib.cm import get_cmap import numpy as np import matplotlib.pyplot as plt ncolors=11 vmin = 0.1 vmax = 1.0 cmap = get_cmap('RdYlBu_r',10).copy() cmap.set_bad(color='gray',alpha=0) cmap.set_under(color='white') cmap.set_over(color='hotpink') boundaries = list(np.arange(vmin, vmax, 0.1))+[vmax] norm = colors.BoundaryNorm(boundaries, ncolors=ncolors, clip=False,extend='both') print(norm(boundaries)) data=boundaries.copy() data.insert(0,0) data.append(1.5) bar=np.repeat([data],5,axis=0).repeat(5,axis=1) fig=plt.figure(figsize=(10,10)) img=plt.imshow(bar,cmap=cmap,norm=norm) img.axes.get_xaxis().set_visible(False) img.axes.get_yaxis().set_visible(False) plt.colorbar(orientation='horizontal', extend='both') plt.show()
问题原因
BoundaryNorm的区间划分逻辑:当设置
extend='both'时,BoundaryNorm的映射规则为:- 值小于第一个边界→under颜色(索引0)
- 值落在
[boundaries[i], boundaries[i+1})区间→对应中间颜色索引(i+1) - 值大于等于最后一个边界→over颜色(索引
len(boundaries))
你的边界最后一个值是1.0,所以1.0会被判定为大于等于上边界,直接映射到over颜色。文档描述的“最高索引”指的是未开启extend时的中间区间最高索引,开启extend后,大于等于上边界会被分配到额外的over索引,这是描述歧义导致的误解。
颜色数与区间数不匹配:你的边界列表有10个元素,对应9个离散区间,但你创建的colormap有10个颜色,颜色数和区间数不匹配,进一步加剧了映射混乱。
解决方案
调整边界和colormap的设置,让1.0落在最后一个离散区间内:
import matplotlib.colors as colors from matplotlib.cm import get_cmap import numpy as np import matplotlib.pyplot as plt vmin = 0.1 vmax = 1.0 # 区间数是9,对应9个离散颜色 cmap = get_cmap('RdYlBu_r', 9).copy() cmap.set_bad(color='gray', alpha=0) cmap.set_under(color='white') cmap.set_over(color='hotpink') # 调整最后一个边界为略大于1.0的值,让1.0落在最后一个区间内 boundaries = list(np.arange(vmin, vmax, 0.1)) + [vmax + 1e-8] # ncolors = 区间数 + 2(under和over) norm = colors.BoundaryNorm(boundaries, ncolors=9+2, clip=False, extend='both') print(norm(boundaries)) data = boundaries.copy() data.insert(0, 0) data.append(1.5) bar = np.repeat([data],5,axis=0).repeat(5,axis=1) fig = plt.figure(figsize=(10,10)) img = plt.imshow(bar, cmap=cmap, norm=norm) img.axes.get_xaxis().set_visible(False) img.axes.get_yaxis().set_visible(False) plt.colorbar(orientation='horizontal', extend='both') plt.show()
说明
- 将colormap的颜色数改为9,和区间数(
len(boundaries)-1=9)一致 - 把最后一个边界设为
1.0+1e-8,这样1.0会落在[0.9, 1.0+1e-8)区间内,被映射到最后一个离散颜色 - 大于
1.0+1e-8的值依然会被映射到over的hotpink颜色
内容的提问来源于stack exchange,提问作者Axel
相关产品推荐
相关产品推荐

