在matplotlib中更改colorbar渐变

JrC*_*ian 2 python matplotlib colormap

我有一个随时间(X)演变的权重网格(Y): 在此输入图像描述

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

出于这些原因,我想改变颜色渐变以获得类似的东西(a或b): 在此输入图像描述

有关如何处理此问题的任何想法?

Imp*_*est 6

matplotlib中的颜色条将0到1之间的数字映射到一种颜色.要将其他数字映射到颜色,您需要[0,1]首先对范围进行标准化.这通常是由最小和最大的数据,或通过使用自动完成vminvmax参数到相应的绘图功能.在内部,标准化实例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")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

选择该函数使得其独立于其参数将任何范围映射到该范围上[0,1],使得可以使用色图.该参数mid确定应将哪个值映射到色彩映射的中间.这将是0在这种情况下.参数s1s2确定色彩图在两个方向上的挤压方式.

设置mid = np.mean(vmin, vmax), s1=1, s2=1将恢复原始缩放.

在此输入图像描述

为了选择好的参数,可以使用一些滑块来查看实时更新的图.

在此输入图像描述

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)
Run Code Online (Sandbox Code Playgroud)