如何修改离散线性分段颜色图

我是气象学家,经常使用例如“蓝-白色-红色”的颜色图绘制温度场距平值。为了使图表更具可读性,我使用在互联网上“找到”的函数对颜色图进行一定数量的级别(箱)离散化(但我并不完全理解它):

import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import matplotlib.colors as cols
from numpy.random import randn

def cmap_discretize(cmap, N):
    colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
    colors_rgba = cmap(colors_i)
    indices = np.linspace(0, 1., N+1)
    cdict = {}
    for ki,key in enumerate(('red','green','blue')):
        cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
    # Return colormap object.
    return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)


cmap_disc= cmap_discretize(cm.RdBu_r,12)


fig, ax = plt.subplots()
data = np.clip(randn(250, 250), -1, 1)

cax = ax.pcolor(data, cmap=cmap_disc)
plt.colorbar(cax)

plt.show()

这将导致以下结果:

[图片]

现在,我想将最中间的两个片段(即接近 0 的两个片段)设置为白色,因为我不想显示非常小的偏差。
我的目标是最终得到类似于此的结果:

[图片]

我真的很难以理解这些 LinearSegmentedColormap 如何能够相应地进行修改。有人可以帮助我解决这个问题吗?

2、解决方案

方法 1:

第一个回答者提供了以下解决方案:

def cmap_discretize(cmap, N):
    colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
    colors_rgba = cmap(colors_i)
    indices = np.linspace(0, 1., N+1)
    cdict = {}
    for ki,key in enumerate(('red','green','blue')):
        cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
    # "white out" the bands closest to the middle
    num_middle_bands = 2 - (N % 2)
    middle_band_start_idx = (N - num_middle_bands) // 2
    for middle_band_idx in range(middle_band_start_idx,
                                 middle_band_start_idx + num_middle_bands):
        for key in cdict.keys():
            old = cdict[key][middle_band_idx]
            cdict[key][middle_band_idx] = old[:2] + (1.,)
            old = cdict[key][middle_band_idx + 1]
            cdict[key][middle_band_idx + 1] = old[:1] + (1.,) + old[2:]
    # Return colormap object.
    return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)

方法 2:

第二个回答者提供了以下解决方案:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import matplotlib.colors as cols
from numpy.random import randn

def cmap_double_discretize(cmap_bottom, cmap_top, N, split=.5):
    """
    Generates a descritized color map using two existing color maps

    Parameters
    ----------
    cmap_bottom : cmap
        The bottom cmap

    cmap_top : cmap
        The top cmap

    N : int
       The number of bins in each color map

    split : float, optional
       Where to join the maps, must be in [0, 1]
    """
    # sanity check
    assert split < 1 and split > 0
    # set up the data structure
    cdict = {lab: [] for lab in ('red','green','blue')}
    # do this in a fancy loop to a) save typing, b) make it easy to
    # retrofit to do arbitrary splits
    for cmap, ends in zip((cmap_bottom, cmap_top), ((0, split), (split, 1))):

        # run over the _whole_ range for each color map
        colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
        # map the color
        colors_rgba = cmap(colors_i)
        # get the values 
        indices = np.linspace(ends[0], ends[1], N+1, endpoint=True)

        for ki,key in enumerate(('red','green','blue')):
            cdict[key].extend((indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1))
            #    print cdict
    # Return colormap object.
    return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)

red_cdict = {'red': [(0, 0, 1),
                     (1, 1, 0)],
            'blue': [(0, 0, 0),
                     (1, 1, 0)],
            'green': [(0, 0, 0),
                     (1, 1, 0)]}

blue_cdict = {'blue': [(0, 0, 1),
                       (1, 1, 0),],
            'red': [(0, 0, 1),
                    (1, 0, 0)],
            'green': [(0, 0, 1),
                     (1, 0, 0)]}
red_cmap = cols.LinearSegmentedColormap('red', red_cdict, 1024)
blue_cmap = cols.LinearSegmentedColormap('blue', blue_cdict, 1024)

test_cmap = cmap_double_discretize(red_cmap, blue_cmap, 6)
# these don't actually go to white!
# test_cmap = cmap_double_discretize(cm.get_cmap('Reds_r'), cm.get_cmap('Blues'), 6)


fig, ax = plt.subplots()
data = np.clip(randn(250, 250), -1, 1)

cax = ax.pcolor(data, cmap=test_cmap)
plt.colorbar(cax)

plt.show()

你也可以很容易地修改它来跨越两个以上的颜色图。

### Matplotlib 热力颜色方案最佳实践 为了使热力更加美观并有效传达信息,选择合适的颜色方案至关重要。以下是几种推荐的颜色方案及其应用场景: #### 使用预定义的色彩映射表 (Colormap) Matplotlib 提供了许多内置的色彩映射表,适用于不同类型的数据集和视觉需求。 对于连续变量,可以选择 `viridis` 或者 `plasma` 这样的感知均匀线性 colormap 来表示数值的变化[^1]。 ```python import matplotlib.pyplot as plt import numpy as np data = np.random.rand(10, 10) plt.imshow(data, cmap='viridis') plt.colorbar() plt.show() ``` 当处理离散类别时,则应考虑使用分段型colormap 如 `tab20c`, 它能提供清晰区分度高的颜色组合[^2]. ```python from matplotlib.colors import ListedColormap discrete_cmap = ListedColormap(['red', 'green', 'blue']) plt.imshow(np.array([[0, 1], [2, 3]]), cmap=discrete_cmap) plt.colorbar(ticks=[0, 1, 2]) plt.show() ``` 针对正负值对比强烈的场景,建议采用双极化colormap比如 `RdBu_r` 或 `coolwarm`. 这些colormap 中间色调接近白色,在两端分别向冷暖两极过渡,非常适合强调差异性的场合[^3]. ```python correlation_matrix = np.corrcoef(np.random.randn(10, 20)) plt.imshow(correlation_matrix, cmap='RdBu_r', vmin=-1, vmax=1) plt.colorbar(label='Correlation Coefficient') plt.title('Heatmap with Diverging Colormap') plt.show() ``` #### 自定义颜色范围与边界 除了选用现成的colormap外,还可以根据具体业务逻辑设定特定的颜色区间及界限,从而更好地突出重点区域或异常情况[^4]. 例如设置不同的透明度(alpha)参数来增强某些部分的表现效果;或是利用 `BoundaryNorm` 函数创建不规则间隔的颜色分级标准. ```python from matplotlib.colors import BoundaryNorm bounds = [-1, -0.5, 0, 0.5, 1] norm = BoundaryNorm(bounds, ncolors=plt.cm.RdBu.N, clip=True) plt.imshow(correlation_matrix, cmap='RdBu', norm=norm) plt.colorbar(boundaries=bounds) plt.title('Customized Color Range and Boundaries') plt.show() ``` 通过上述方法,可以根据实际项目的需求灵活调整热力颜色配置,达到既科学又具美感的效果[^5].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值