使用Matplotlib实现非线性颜色映射

6

我有一些数据想要用contourf/tricontourf绘制,并使用非线性的颜色映射。

我找到了一个脚本(见下文),它提供了一个很好的解决方案,只要级别在0到正数之间。

然而,我的数据是负数(级别在-50到0之间)。不幸的是,调整级别到我的情况根本不起作用(见图,子图3)。那么有什么需要考虑的吗?有人对我有什么建议,或者甚至面临同样的问题吗?

我真的很感谢你的帮助。

from pylab import *
from numpy import *
from matplotlib.colors import LinearSegmentedColormap

class nlcmap(LinearSegmentedColormap):
    """A nonlinear colormap"""

    name = 'nlcmap'

    def __init__(self, cmap, levels):
        self.cmap = cmap
        self.monochrome = self.cmap.monochrome
        self.levels = asarray(levels, dtype='float64')
        self._x = self.levels/ self.levels.max()
        self.levmax = self.levels.max()
        self.levmin = self.levels.min()
        self._y = linspace(self.levmin, self.levmax, len(self.levels))

    def __call__(self, xi, alpha=1.0, **kw):
        yi = interp(xi, self._x, self._y)
        return self.cmap(yi/self.levmax, alpha)

if __name__ == '__main__':

    y, x = mgrid[0.0:3.0:100j, 0.0:5.0:100j]
    H = 50.0 * exp( -(x**2 + y**2) / 4.0 )
    levels = [0, 1, 2, 3, 6, 9, 20, 50]

    H1 = -50.0 * exp( -(x**2 + y**2) / 4.0 )
    levels1 = [-50, -20, -9, -6, -3, -2, -1, 0]

    cmap_lin = cm.jet
    cmap_nonlin = nlcmap(cmap_lin, levels)
    cmap_lin1 = cm.jet
    cmap_nonlin1 = nlcmap(cmap_lin1, levels1)

    subplot(4,1,1)
    contourf(x, y, H, levels, cmap=cmap_nonlin)
    colorbar()
    subplot(4,1,2)
    contourf(x, y, H, levels, cmap=cmap_lin)
    colorbar()
    subplot(4,1,3)
    contourf(x, y, H1, levels1, cmap=cmap_nonlin1)
    colorbar()
    subplot(4,1,4)
    contourf(x, y, H1, levels1, cmap=cmap_lin1)
    colorbar()

    plt.show()  

contourf plot with nonlinear colormap

3个回答

3
在例子中,当levels1 = [-50, -20, -9, -6, -3, -2, -1, 0]时,你在self._x = self.levels/ self.levels.max()这里除以了零。似乎像pcolorcontourf这样的函数在将输入数据传递给色图之前会将其重新缩放到0到1之间。因此,您还需要将您的级别重新缩放到该范围内,您的代码对第一个示例进行了处理,但未对第二个示例进行处理。这似乎可以解决问题:
class nlcmap(LinearSegmentedColormap):
    """A nonlinear colormap"""

    name = 'nlcmap'

    def __init__(self, cmap, levels):
        self.cmap = cmap
        self.monochrome = self.cmap.monochrome
        self.levels = asarray(levels, dtype='float64')
        self._x = self.levels-self.levels.min()
        self._x/= self._x.max()
        self._y = linspace(0, 1, len(self.levels))

    def __call__(self, xi, alpha=1.0, **kw):
        yi = interp(xi, self._x, self._y)
        return self.cmap(yi, alpha)

3

与其修改色图,更简单的方法是定义一种新的规范化类型,以将数据映射到[0,1]范围内。

这里我修改了先前回答中的一个示例:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

class PiecewiseNorm(Normalize):
    def __init__(self, levels, clip=False):
        # the input levels
        self._levels = np.sort(levels)
        # corresponding normalized values between 0 and 1
        self._normed = np.linspace(0, 1, len(levels))
        Normalize.__init__(self, None, None, clip)

    def __call__(self, value, clip=None):
        # linearly interpolate to get the normalized value
        return np.ma.masked_array(np.interp(value, self._levels, self._normed))

例如:

y, x = np.mgrid[0.0:3.0:100j, 0.0:5.0:100j]
H = 50.0 * np.exp( -(x**2 + y**2) / 4.0 )
levels = [0, 1, 2, 3, 6, 9, 20, 50]

H1 = -50.0 * np.exp( -(x**2 + y**2) / 4.0 )
levels1 = [-50, -20, -9, -6, -3, -2, -1, 0]

fig, ax = plt.subplots(2, 2, gridspec_kw={'width_ratios':(20, 1), 'wspace':0.05})

im0 = ax[0, 0].contourf(x, y, H, levels, cmap='jet', norm=PiecewiseNorm(levels))
cb0 = fig.colorbar(im0, cax=ax[0, 1])

im1 = ax[1, 0].contourf(x, y, H1, levels1, cmap='jet', norm=PiecewiseNorm(levels1))
cb1 = fig.colorbar(im1, cax=ax[1, 1])

plt.show()

enter image description here

这种方法的一个优点是可以与任何色图一起使用相同的规范化处理。

2

问题似乎在于您试图通过除以最大值来将值投影到[0,1]范围内,这对于max的正值有效,但对于负值无效...请尝试以下操作:

from pylab import *
from numpy import *
from matplotlib.colors import LinearSegmentedColormap

class nlcmap(LinearSegmentedColormap):
    """A nonlinear colormap"""

    name = 'nlcmap'

    def __init__(self, cmap, levels):
        self.cmap = cmap
        self.monochrome = self.cmap.monochrome
        self.levels = asarray(levels, dtype='float64')
        self.levmax = self.levels.max()
        self.levmin = self.levels.min()
        self._x = (self.levels - self.levmin) / (self.levmax - self.levmin)
        self._y = linspace(0, 1, len(self.levels))

    def __call__(self, xi, alpha=1.0, **kw):
        yi = interp(xi, self._x, self._y)
        return self.cmap(yi, alpha)

if __name__ == '__main__':

    y, x = mgrid[0.0:3.0:100j, 0.0:5.0:100j]
    H = 50.0 * exp( -(x**2 + y**2) / 4.0 )
    levels = [0, 1, 2, 3, 6, 9, 20, 50]

    H1 = -50.0 * exp( -(x**2 + y**2) / 4.0 )
    levels1 = [-50, -20, -9, -6, -3, -2, -1, 0]

    cmap_lin = cm.jet
    cmap_nonlin = nlcmap(cmap_lin, levels)
    cmap_lin1 = cm.jet
    cmap_nonlin1 = nlcmap(cmap_lin1, levels1)

    subplot(4,1,1)
    contourf(x, y, H, levels, cmap=cmap_nonlin)
    colorbar()
    subplot(4,1,2)
    contourf(x, y, H, levels, cmap=cmap_lin)
    colorbar()
    subplot(4,1,3)
    contourf(x, y, H1, levels1, cmap=cmap_nonlin1)
    colorbar()
    subplot(4,1,4)
    contourf(x, y, H1, levels1, cmap=cmap_lin1)
    colorbar()

    plt.show()  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接