You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

设置Colorbar中点值:如何让数值0对应白色

问题:Matplotlib颜色条无法让数值0对应白色的排查

以下代码用于生成指定范围的随机整数,为其分配RGBA颜色并绘制成patch:

import numpy
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.colors as mcolors
import matplotlib.colorbar as cbar
from matplotlib import cm
import random

class MidpointNormalize(mpl.colors.Normalize):
    def __init__(self,vmin=None,vmax=None,midpoint=None,clip=False):
        self.midpoint=midpoint
        mpl.colors.Normalize.__init__(self,vmin,vmax,clip)
    def __call__(self,value,clip=None):
        x,y=[self.vmin,self.midpoint,self.vmax],[0,0.5,1]
        return numpy.ma.masked_array(numpy.interp(value,x,y),numpy.isnan(value))

colors=plt.cm.RdBu(numpy.linspace(0,1,256))
colormap=mcolors.LinearSegmentedColormap.from_list('colormap',colors)
normalisecolors=MidpointNormalize(vmin=-50,midpoint=0,vmax=100)
scalecolors=cm.ScalarMappable(norm=normalisecolors,cmap=colormap) 

fig,ax=plt.subplots(figsize=(8,8))
ax.set_xlim(0,100)
ax.set_ylim(0,100)

for x in range(0,100):
    for y in range(0,100):
        val=random.randint(-50,100)
        rgbacolor=scalecolors.to_rgba(val)
        ax.add_patch(patches.Polygon([(x,y),(x,y+1),(x+1,y+1),(x+1,y)],fill=True,facecolor=rgbacolor))

cax,_=cbar.make_axes(ax,orientation='horizontal',aspect=50,pad=0.12)
cb=cbar.ColorbarBase(cax,cmap=colormap,norm=normalisecolors,orientation='horizontal')

我希望让数值0对应颜色条的白色,本来以为第20行的MidpointNormalize设置(将midpoint设为0)能实现,但实际并未生效——当前颜色条里0对应的不是白色,而是偏蓝的色调。

恳请帮忙排查问题。另外请勿建议其他绘图方式,我实际场景需要处理数值模型输出文件,代码量很大,这里只是用随机数简化了示例。


解决方案

问题根源很简单:你用的RdBu默认色板的中点(0.5位置)不是白色,而是淡紫色。你写的MidpointNormalize确实把数值0映射到了色板的0.5位置,但这个位置本身就不是白色,所以才会出现不符合预期的结果。

要解决这个问题,你需要自己构建一个红-白-蓝的渐变色板,明确让色板的中点对应白色,再配合你的MidpointNormalize逻辑,就能让数值0准确对应白色了。

修改步骤:

  • 替换原有的色板创建代码,手动定义颜色节点:红色(对应最小值-50)、白色(对应中点0)、蓝色(对应最大值100)
  • 其余代码保持不变,你的MidpointNormalize逻辑是正确的

修改后的关键代码段:

# 替换原有的colormap创建部分
color_nodes = [
    (0.0, '#FF0000'),   # 红色对应vmin=-50
    (0.5, '#FFFFFF'),   # 白色对应midpoint=0
    (1.0, '#0000FF')    # 蓝色对应vmax=100
]
colormap = mcolors.LinearSegmentedColormap.from_list('custom_RdBu', color_nodes, N=256)

把这段代码替换掉原来的colors=plt.cm.RdBu(...)和colormap=mcolors.LinearSegmentedColormap.from_list(...)两行即可。

完整修改后的代码如下:

import numpy
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.colors as mcolors
import matplotlib.colorbar as cbar
from matplotlib import cm
import random

class MidpointNormalize(mpl.colors.Normalize):
    def __init__(self,vmin=None,vmax=None,midpoint=None,clip=False):
        self.midpoint=midpoint
        mpl.colors.Normalize.__init__(self,vmin,vmax,clip)
    def __call__(self,value,clip=None):
        x,y=[self.vmin,self.midpoint,self.vmax],[0,0.5,1]
        return numpy.ma.masked_array(numpy.interp(value,x,y),numpy.isnan(value))

# 自定义红-白-蓝colormap
color_nodes = [
    (0.0, '#FF0000'),
    (0.5, '#FFFFFF'),
    (1.0, '#0000FF')
]
colormap = mcolors.LinearSegmentedColormap.from_list('custom_RdBu', color_nodes, N=256)

normalisecolors=MidpointNormalize(vmin=-50,midpoint=0,vmax=100)
scalecolors=cm.ScalarMappable(norm=normalisecolors,cmap=colormap) 

fig,ax=plt.subplots(figsize=(8,8))
ax.set_xlim(0,100)
ax.set_ylim(0,100)

for x in range(0,100):
    for y in range(0,100):
        val=random.randint(-50,100)
        rgbacolor=scalecolors.to_rgba(val)
        ax.add_patch(patches.Polygon([(x,y),(x,y+1),(x+1,y+1),(x+1,y)],fill=True,facecolor=rgbacolor))

cax,_=cbar.make_axes(ax,orientation='horizontal',aspect=50,pad=0.12)
cb=cbar.ColorbarBase(cax,cmap=colormap,norm=normalisecolors,orientation='horizontal')

plt.show()

运行修改后的代码,数值0就会正确显示为白色,颜色条的渐变也会符合你的预期。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 09:08:10