matplotlib imshow绘制分类栅格时ListedColormap颜色显示错误
问题根因
图例显示正常但栅格渲染颜色和自定义色带不符,核心是ListedColormap搭配imshow的默认映射逻辑不符合离散分类栅格的渲染要求:
- 默认规则下,
imshow会自动把栅格值的最小值、最大值线性拉伸到色带的0到N-1索引区间,中间值按线性插值匹配颜色,不会按照「像素值=色带位置」的逻辑一一对应 earthpy.draw_legend是直接根据传入的classes列表按顺序匹配色带颜色生成图例,不受默认拉伸规则影响,因此会出现图例正确、图面错误的错位问题。
如果分类值不是从0开始的连续整数,这种错位会尤其明显。
修复方案
引入BoundaryNorm手动指定离散值的映射规则,让每个分类值精准匹配预设颜色,修改后的完整代码如下:
## 加载TIF文件 import rioxarray as rxr import numpy as np import matplotlib.pyplot as plt import earthpy.plot as ep from matplotlib.colors import ListedColormap, BoundaryNorm data_path = 'folder/test_img.tif' lctif_1km_20530 = rxr.open_rasterio(data_path, masked=True).squeeze() lctif_1km_20530 = lctif_1km_20530.astype('int') ### 提取分类值、定义色带与图例名称 classes_20530 = list(np.unique(lctif_1km_20530).astype('int')) color_list_20530 = ['#FAF5E4', '#006400', '#45C2A5', '#B8AF4F', '#fff3bf', '#0000FF'] class_names_20530 = ['Out of buffer','Forest Formation','Wetlands','Grassland', 'Mosaic Agriculture and Pasture','River, Lake and Ocean'] # 构造自定义色带 cmap_20530 = ListedColormap(color_list_20530) # 生成分类边界:边界数量比分类数多1,按整数分类值±0.5设置避免浮点匹配误差 bounds = [val - 0.5 for val in classes_20530] + [classes_20530[-1] + 0.5] # 构造离散归一化器,固定值到颜色的映射关系 norm = BoundaryNorm(bounds, cmap_20530.N) # 绘图 f, ax = plt.subplots(figsize=(10,5)) # 传入norm参数,禁用默认线性拉伸 im = ax.imshow(lctif_1km_20530, cmap=cmap_20530, norm=norm) ax.set(title="Landcover classes") ep.draw_legend(im, titles=class_names_20530, classes=classes_20530) ax.set_axis_off() plt.show()
注意事项
BoundaryNorm会将落在两个相邻边界区间内的像素值,固定映射到色带对应索引的颜色,不会做线性插值,完全适配土地覆盖这类离散分类栅格的渲染需求- 边界值设置为分类值±0.5是针对整数型分类值的通用处理方式,可以避免浮点精度问题导致的像素值匹配错误
- 后续如果调整分类,只需要同步更新分类值列表、色带列表、图例名称列表即可,边界与归一化器的生成逻辑无需改动
内容的提问来源于stack exchange,提问作者fernando schuh
相关产品推荐
相关产品推荐

