修改离散的LinearSegmentedColormap

时间:2013-10-05 15:23:33

标签: python matplotlib

我是一名气候学家,经常会出现异常现象。温度场使用“蓝色到白色到红色”的色彩图。为了使图表更具可读性,我使用我在互联网上“找到”的功能将颜色图在一定数量的级别(箱子)中离散化(但我真的不明白):

这样的事情:

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。有人可以帮我这个吗?

2 个答案:

答案 0 :(得分:5)

您找到的函数构建了一个数据结构(在cdict中),用于定义具有不执行任何插值的段的LinearSegmentedColormap(即行{{1}中的y1始终与行i中的y0相同,并且这给出了常量或离散的颜色“波段”)。

i+1是一个奇怪的数据结构,一个包含密钥cdict'red''green'的字典。每个键的值是包含'blue'形式的元组的列表结构。 (x, y0, y1)是颜色贴图坐标,它是0到1之间的某个浮点数。xy0“左侧”的颜色值,xy1“右侧”的颜色值。在连续值x之间的频带中线性插值颜色;如果第一个元组由x给出而第二个元组由(0, A, B)给出,则(X, C, D)t之间的点0的颜色将由X

出于您的目的,您的功能非常好,但需要将颜色贴图中间附近的“波段”替换为白色。您可以尝试以下内容:

(t - 0) / (X - 0) * (C - B) + B

答案 1 :(得分:3)

让我们首先浏览您的代码

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

所以现在的问题是如何在中间创建一个带有“加倍”白色条带的彩色地图。我会改变功能位,让它接收两个颜色图(顶部和底部)

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

enter image description here

您可以轻松修改此选项以分割两个以上的彩色地图。