在 matplotlib 中更改颜色条渐变 [英] Change colorbar gradient in matplotlib

查看:56
本文介绍了在 matplotlib 中更改颜色条渐变的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a grid of weights (Y) evolving with time (X):

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

I cannot distinguish correctly the variations of weights as the distribution is asymmetric between positive and negative weights; the null weights should be recognized as it means the given variables are not used.

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

For these reasons, I would like to change the color gradient to get something like those (either a or b):

知道如何解决这个问题吗?

Any idea on how to approach this?

推荐答案

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

A colorbar in matplotlib maps number between 0 and 1 to a color. In order to map other numbers to colors you need a normalization to the range [0,1] first. This is usually done automatically from the minimum and maximum data, or by using vmin and vmax arguments to the respective plotting function. Internally a normalization instance matplotlib.colors.Normalize is used to perform the normalization and by default a linear scale between vmin and vmax is assumed.

在这里您需要一个非线性刻度,该刻度(a)将中点移动到某个指定值,并且(b)挤压该值周围的颜色.

Here you want a nonlinear scale, which (a) shifts the middle point to some specified value, and (b) squeezes the colors around that value.

现在的想法是将 matplotlib.colors.Normalize 子类化,并使其返回满足条件(a)和(b)的映射.

The idea can now be to subclass matplotlib.colors.Normalize and let it return a a mapping which fulfills the criteria (a) and (b).

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

An option might be the combination of two root functions as shown below.

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

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

The function is chosen such that independent of its parameters it will map any range onto the range [0,1], such that a colormap can be used. The parameter mid determines which value should be mapped to the middle of the colormap. This would be 0 in this case. The parameters s1 and s2 determine how squeezed the colormap is in both directions.

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

Setting mid = np.mean(vmin, vmax), s1=1, s2=1 would recover the original scaling.

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

In order to choose good parameters, one may use some Sliders to see the live updated plot.

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)

这篇关于在 matplotlib 中更改颜色条渐变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆