【问题标题】:How to set 0 to white at a uneven color ramp?如何在不均匀的色带上将 0 设置为白色?
【发布时间】:2020-04-25 12:49:58
【问题描述】:

我的色带不均匀,我希望 0 为白色。所有负片必须是蓝色的,所有正片必须是红色的。 我当前的尝试显示 0 蓝色和 0.7 白色。

有没有办法将 0 设置为白色?

import numpy as np
import matplotlib.colors as colors 
from matplotlib import pyplot as m

bounds_min = np.arange(-2, 0, 0.1)
bounds_max = np.arange(0, 4.1, 0.1)
bounds = np.concatenate((bounds_min, bounds_max), axis=None)       
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)      # I found this on the internet and thought this would solve my problem. But it doesn't...
m.pcolormesh(xx, yy, interpolated_grid_values, norm=norm, cmap='RdBu_r')

【问题讨论】:

    标签: python matplotlib plot colors matplotlib-basemap


    【解决方案1】:

    为了获得所需的标准,在负片上设置与正片相同数量的颜色。

    或者,您可以使用未修改的规范,并创建一个特殊的颜色图。这样的颜色图将具有 1/3rd 的蓝色到白色和 2/3rd 白色到红色的颜色。一个好处是颜色条看起来更好。这种方法只有在负数和正数之间的平衡不太极端的情况下才有效。

    这是带有生成数据的演示代码。 zz 被选为围绕中心旋转的正弦曲线,并缩放为从 -2 到 4,因此围绕 1 对称。左侧的图像显示了修改后的颜色图。在右侧,范数更改为强制白色为零。

    由于所有正值都是红色的,因此红色带比蓝色更宽。在没有改变规范或颜色图的图像中,条带将具有相等的宽度。颜色条表示零为白色。

    import numpy as np
    import matplotlib.colors as colors
    from matplotlib import pyplot as plt
    
    x = np.linspace(-20, 20, 500)
    y = np.linspace(-20, 20, 500)
    xx, yy = np.meshgrid(x, y)
    zz = np.sin(np.sqrt(xx * xx + yy * yy)) * 3 + 1
    
    negatives = -2.0
    positives = 4.0
    
    bounds_min = np.linspace(negatives, 0, 129)
    bounds_max = np.linspace(0, positives, 129)[1:]
        # the zero is only needed once
        # in total there will be 257 bounds, so 256 bins
    bounds = np.concatenate((bounds_min, bounds_max), axis=None)
    norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
    
    num_neg_colors = int(256 / (positives - negatives) * (-negatives))
    num_pos_colors = 256 - num_neg_colors
    cmap_BuRd = plt.cm.RdBu_r
    colors_2neg_4pos = [cmap_BuRd(0.5*c/num_neg_colors) for c in range(num_neg_colors)] +\
                       [cmap_BuRd(1-0.5*c/num_pos_colors) for c in range(num_pos_colors)][::-1]
    cmap_2neg_4pos = colors.LinearSegmentedColormap.from_list('cmap_2neg_4pos', colors_2neg_4pos, N=256)
    
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
    
    mesh1 = ax1.pcolormesh(xx, yy, zz, cmap=cmap_2neg_4pos)
    ax1.set_aspect('equal')
    ax1.set_title('using a modified cmap')
    fig.colorbar(mesh1, ax=ax1)
    
    mesh2 = ax2.pcolormesh(xx, yy, zz, norm=norm, cmap='RdBu_r')
    ax2.set_aspect('equal')
    ax2.set_title('using a special norm')
    ticks = np.append(np.arange(-2.0, 0, 0.25), np.arange(0, 4.001, 0.5))
    fig.colorbar(mesh2, ax=ax2, ticks=ticks)
    
    plt.show()
    

    以下代码绘制了范数,看起来像一个阶梯函数。只有 257 个边界,这个阶跃函数在任何地方都有正确的形状(在 -2、0 和 4 处缩放到 x)。

    nx = np.linspace(-3,5,10000)
    plt.plot(nx, norm(nx))
    

    PS:有一个alternative method 可以创建类似的颜色图。但是尝试一下,很明显RdBu 颜色图经过了微调,可以生成更好看的图。

    norm_2neg_4pos = mcolors.Normalize(negatives, positives)
    colors_2neg_4pos = [[0, 'blue'],
                        [norm_2neg_4pos(0.0), "white"],
                        [1, 'red']]
    cmap_2neg_4pos = mcolors.LinearSegmentedColormap.from_list("", colors_2neg_4pos)
    

    还有一个简单的解决方案是在 -4 和 4 之间重新调整所有内容。但是,这会丢失较深的蓝色。 'RdBu_r' 的替代方案是 'seismic',它以不同的方式从红色到白色再到蓝色。

    ax.pcolormesh(xx, yy, zz, vmin=-positives, vmax=positives, cmap='RdBu_r')
    

    【讨论】:

    • 感谢您的帮助!我花了一段时间才把它弄好,但现在它可以工作了。你知道是否可以让负条比正条短吗?
    • 是的,也可以这样做。在这种情况下,不需要规范,只需要重新计算颜色图。如果负数和正数之间存在巨大差异,它将无法正常工作,但如果系数为 2,则效果会很好。给我一些时间来创建一个例子。
    【解决方案2】:

    另一个答案使它比需要的复杂一些。为了使颜色图的中点位于 0,请使用 DivergingNormvcenter=0

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.colors import DivergingNorm
    
    x, y = np.meshgrid(np.linspace(0,50,51), np.linspace(0,50,51))
    z = np.linspace(-2,4,50*50).reshape(50,50)
    
    norm = DivergingNorm(vmin=z.min(), vcenter=0, vmax=z.max())
    pc = plt.pcolormesh(x,y,z, norm=norm, cmap="RdBu_r")
    plt.colorbar(pc)
    
    plt.show()
    

    注意:从 matplotlib 3.2 起,DivergingNorm 将重命名为 TwoSlopeNorm

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-28
      • 2021-10-01
      • 2020-01-26
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多