修改离散LinearSegmentedColormap

2024-04-27 03:30:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我是个气候学家,经常用“蓝到白到红”的彩色地图绘制温度场的异常。为了使绘图更具可读性,我用我在互联网上“找到”的一个函数将colormap分为若干个级别(bin)(但我并不真正理解):

像这样:

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()

这导致

enter image description here

现在我想把最中间的两段(即接近0的那两段)设置为白色,因为我不想显示非常小的偏差。在

我的目标是最终得到类似的结果:

enter image description here

我真的很难弄清楚这些LinearSegmentedColormap是如何被相应地修改的。有人能帮我吗?在


Tags: fromimportnumpymatplotlibasnpcmplt
2条回答

您找到的函数构建了一个数据结构(在cdict)中,用不执行任何插值的段定义{a1}(即第i行中的y1总是与第i+1行中的y0相同,这就给出了常量或离散的颜色“带”)。在

cdict是一种奇怪的数据结构,是一个包含键'red''green'和{}的字典。每个键的值都是一个包含(x, y0, y1)形式的元组的列表结构。x是颜色贴图坐标,它是介于0和1之间的某个浮点数。^左边{cd11>的值是^{cd11>x的连续值之间线性插值;如果第一个元组由(0, A, B)给出,第二个元组由(X, C, D)给出,则0和{}之间的点{}的颜色将由(t - 0) / (X - 0) * (C - B) + B给出。在

出于您的目的,您的函数运行得很好,但需要将颜色图中间附近的“带”替换为白色。您可以尝试以下方法:

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)

让我们从浏览现有代码开始

# get some uniformly sampled data, padded out a bit
colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
# sample the input colormap at our sample points
colors_rgba = cmap(colors_i)
# indices for color map
indices = np.linspace(0, 1., N+1)
# dict to pass to the LinearSegmentedColormap
cdict = {}
# loop over the colors
for ki,key in enumerate(('red','green','blue')):
    # in each color assemble a list that looks like
    #[...,
    # (indices[2], colors_rgba[1,ki], colors_rgba[2,ki]),
    # (indices[3], colors_rgba[2,ki], colors_rgba[3,ki]),
    # ....]
    cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
    # The color for a number between [indices[2], indices[3]] are interpolated
    # between colors_rgba[2,ki] and colors_rgba[2,ki] which are the same
    # which is what gives you the discrete blocks.
# Construct and return colormap object.
return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)
现在的问题是如何在中间创建一个“双”白色带的彩色地图。我会改变功能位,让它接受两个彩色地图(顶部和底部)

^{pr2}$

enter image description here

您可以轻松地修改此选项,以便在两个以上的颜色贴图之间分割。在

相关问题 更多 >