You need to enable JavaScript to run this app. Matplotlib自定义ListedColormap实现烈度值与颜色固定映射
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib自定义ListedColormap实现烈度值与颜色固定映射

问题根因

当前映射逻辑失效的核心原因是 仅创建了离散色表,但没有固定烈度值和色标区间的一一绑定关系,matplotlib会默认根据传入GeoDataFrame的 Intensity 字段实际取值范围动态计算归一化边界:

  • 多值场景下,实际取值的上下限刚好覆盖预设烈度分级区间,所以映射结果碰巧符合预期
  • 单值场景下,Intensity 字段的最小值和最大值完全相等,动态计算的归一化区间发生退化,导致所有值直接映射到色表的起始位(也就是定义的第一个颜色 #f3f3f3)
修复实现方案

要实现固定的单个烈度值对应唯一专属颜色的映射规则,不需要依赖matplotlib的动态归一化逻辑,需要把烈度值和色标的绑定关系写死,分三步调整代码:

  1. 明确固定所有的烈度取值集合,不把分级逻辑藏在颜色数组里
# 预设的9级地震烈度固定取值,顺序与自定义颜色一一对应
intensity_levels = [1, 2, 3, 4, 5, 5.5, 6, 6.5, 7]
# 每个烈度值对应的专属自定义颜色
color_map = [
    '#f3f3f3',
    '#1aff1a',
    '#ffff00',
    '#ff8900',
    '#ff5500',
    '#b64100',
    '#993300',
    '#aa3c00',
    '#800080'
]
cm = matplotlib.colors.ListedColormap(color_map)
  1. 构造固定的色标映射边界,替代matplotlib的动态范围计算
    用BoundaryNorm实现硬绑定,让每个烈度值独占一个颜色的映射区间,不受传入数据的取值范围影响:
# 构造固定边界:在相邻烈度值之间取中点,确保每个烈度值落在独立区间内
bounds = [
    intensity_levels[0] - 0.5,  # 区间下界,覆盖所有可能的最小烈度
    1.5,   # 分隔1和2的中点
    2.5,   # 分隔2和3的中点
    3.5,   # 分隔3和4的中点
    4.5,   # 分隔4和5的中点
    5.25,  # 分隔5和5.5的中点
    5.75,  # 分隔5.5和6的中点
    6.25,  # 分隔6和6.5的中点
    6.75,  # 分隔6.5和7的中点
    intensity_levels[-1] + 0.5  # 区间上界,覆盖所有可能的最大烈度
]
# 生成固定规则的归一化器,完全锁定映射逻辑
norm = matplotlib.colors.BoundaryNorm(bounds, ncolors=cm.N)
  1. 绘图时传入固定归一化规则,覆盖默认的动态计算逻辑
draw_area.plot(
    "Intensity",
    ax=axes,
    cmap=cm,
    norm=norm,  # 传入固定归一化规则,替代默认的动态范围计算
    legend=True
)
可选优化:匹配自定义图例展示

默认BoundaryNorm生成的图例是按照数值区间展示的,如果需要直接显示对应烈度值作为标签,可以在绘图后手动调整图例刻度:

# 获取自动生成的图例对象
leg = axes.get_legend()
# 把图例的刻度位置替换为真实烈度值
leg.set_ticks(intensity_levels)
# 把图例标签替换为对应烈度的字符串
leg.set_ticklabels([str(x) for x in intensity_levels])
效果验证

调整完成后:

  • 单值场景下(比如全区域Intensity为2),会按照固定规则映射到对应的专属颜色#1aff1a,不会再出现统一映射到色表首色的问题
  • 多值场景下,每个烈度值都会严格匹配预先配置的自定义颜色,不会因为数据范围变化发生色标偏移

内容的提问来源于stack exchange,提问作者Lambertchen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.28 18:36:10