在 matplotlib 中更改颜色条渐变 [英] Change colorbar gradient in 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
.参数 s1
和 s2
确定颜色图在两个方向上的压缩程度.
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屋!