Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 更改matplotlib中的颜色条渐变_Python_Matplotlib_Colormap - Fatal编程技术网

Python 更改matplotlib中的颜色条渐变

Python 更改matplotlib中的颜色条渐变,python,matplotlib,colormap,Python,Matplotlib,Colormap,我有一个权重(Y)随时间(X)变化的网格: 我无法正确区分权重的变化,因为正权重和负权重之间的分布是不对称的;应识别空权重,因为它意味着不使用给定的变量 出于这些原因,我想更改颜色渐变以获得类似以下内容(a或b): 您知道如何实现这一点吗?您可以使用自定义的规范化器。很方便,文档中的示例已经是一个“可选中点”规范化器。这个例子是由乔·金顿做的,所以所有的功劳都归功于他 请参见本页底部: 自定义规范化类: class MidpointNormalize(mpl.colors.Normaliz

我有一个权重(Y)随时间(X)变化的网格:

我无法正确区分权重的变化,因为正权重和负权重之间的分布是不对称的;应识别空权重,因为它意味着不使用给定的变量

出于这些原因,我想更改颜色渐变以获得类似以下内容(a或b):


您知道如何实现这一点吗?

您可以使用自定义的
规范化器。很方便,文档中的示例已经是一个“可选中点”规范化器。这个例子是由乔·金顿做的,所以所有的功劳都归功于他

请参见本页底部:

自定义规范化类:

class MidpointNormalize(mpl.colors.Normalize):
    ## class from the mpl docs:
    # https://matplotlib.org/users/colormapnorms.html

    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        super().__init__(vmin, vmax, clip)

    def __call__(self, value, clip=None):
        # I'm ignoring masked values and all kinds of edge cases to make a
        # simple example...
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y))    
结果是:

data = np.linspace(-5,1,100)[None,:]

fig, axs = plt.subplots(2,1, figsize=(5,2), facecolor='w', subplot_kw=dict(xticks=[], yticks=[]))

props = dict(aspect=15, cmap=plt.cm.coolwarm)

axs[0].imshow(data, **props)
axs[1].imshow(data, norm=MidpointNormalize(midpoint=0), **props)


这是一个相对简单的示例,但在类似的情况下可以实现更复杂的缩放

matplotlib中的颜色栏将0到1之间的数字映射为一种颜色。为了将其他数字映射到颜色,首先需要对范围进行标准化
[0,1]
。这通常是从最小和最大数据自动完成的,或者通过对相应的绘图函数使用
vmin
vmax
参数来完成。内部使用规范化实例
matplotlib.colors.Normalize
执行规范化,默认情况下,假定
vmin
vmax
之间存在线性比例

这里您需要一个非线性比例,它(a)将中点移动到某个指定值,并且(b)围绕该值挤压颜色

现在可以将
matplotlib.colors.Normalize
子类化,让它返回满足条件(a)和(b)的映射

一个选项可能是两个根函数的组合,如下所示

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

class SqueezedNorm(matplotlib.colors.Normalize):
    def __init__(self, vmin=None, vmax=None, mid=0, s1=2, s2=2, clip=False):
        self.vmin = vmin # minimum value
        self.mid  = mid  # middle value
        self.vmax = vmax # maximum value
        self.s1=s1; self.s2=s2
        f = lambda x, zero,vmax,s: np.abs((x-zero)/(vmax-zero))**(1./s)*0.5
        self.g = lambda x, zero,vmin,vmax, s1,s2: f(x,zero,vmax,s1)*(x>=zero) - \
                                             f(x,zero,vmin,s2)*(x<zero)+0.5
        matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        r = self.g(value, self.mid,self.vmin,self.vmax, self.s1,self.s2)
        return np.ma.masked_array(r)


fig, (ax, ax2, ax3) = plt.subplots(nrows=3, 
                                   gridspec_kw={"height_ratios":[3,2,1], "hspace":0.25})

x = np.linspace(-13,4, 110)
norm=SqueezedNorm(vmin=-13, vmax=4, mid=0, s1=1.7, s2=4)

line, = ax.plot(x, norm(x))
ax.margins(0)
ax.set_ylim(0,1)

im = ax2.imshow(np.atleast_2d(x).T, cmap="Spectral_r", norm=norm, aspect="auto")
cbar = fig.colorbar(im ,cax=ax3,ax=ax2, orientation="horizontal")
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors

class SqueezedNorm(matplotlib.colors.Normalize):
    def __init__(self, vmin=None, vmax=None, mid=0, s1=2, s2=2, clip=False):
        self.vmin = vmin # minimum value
        self.mid  = mid  # middle value
        self.vmax = vmax # maximum value
        self.s1=s1; self.s2=s2
        f = lambda x, zero,vmax,s: np.abs((x-zero)/(vmax-zero))**(1./s)*0.5
        self.g = lambda x, zero,vmin,vmax, s1,s2: f(x,zero,vmax,s1)*(x>=zero) - \
                                             f(x,zero,vmin,s2)*(x<zero)+0.5
        matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        r = self.g(value, self.mid,self.vmin,self.vmax, self.s1,self.s2)
        return np.ma.masked_array(r)


fig, (ax, ax2, ax3) = plt.subplots(nrows=3, 
                                   gridspec_kw={"height_ratios":[3,2,1], "hspace":0.25})

x = np.linspace(-13,4, 110)
norm=SqueezedNorm(vmin=-13, vmax=4, mid=0, s1=1.7, s2=4)

line, = ax.plot(x, norm(x))
ax.margins(0)
ax.set_ylim(0,1)

im = ax2.imshow(np.atleast_2d(x).T, cmap="Spectral_r", norm=norm, aspect="auto")
cbar = fig.colorbar(im ,cax=ax3,ax=ax2, orientation="horizontal")
from matplotlib.widgets import Slider

midax = plt.axes([0.1, 0.04, 0.2, 0.03], facecolor="lightblue")
s1ax = plt.axes([0.4, 0.04, 0.2, 0.03], facecolor="lightblue")
s2ax = plt.axes([0.7, 0.04, 0.2, 0.03], facecolor="lightblue")

mid = Slider(midax, 'Midpoint', x[0], x[-1], valinit=0)
s1 = Slider(s1ax, 'S1', 0.5, 6, valinit=1.7)
s2 = Slider(s2ax, 'S2', 0.5, 6, valinit=4)


def update(val):
    norm=SqueezedNorm(vmin=-13, vmax=4, mid=mid.val, s1=s1.val, s2=s2.val)
    im.set_norm(norm)
    cbar.update_bruteforce(im) 
    line.set_ydata(norm(x))
    fig.canvas.draw_idle()

mid.on_changed(update)
s1.on_changed(update)
s2.on_changed(update)

fig.subplots_adjust(bottom=0.15)