簡體   English   中英

在matplotlib中更改colorbar漸變

[英]Change colorbar gradient in matplotlib

我有一個隨時間(X)演變的權重網格(Y): 在此輸入圖像描述

我無法正確區分權重的變化,因為分布在正負權重之間是不對稱的; 應該識別空權重,因為這意味着不使用給定的變量。

出於這些原因,我想改變顏色漸變以獲得類似的東西(a或b): 在此輸入圖像描述

有關如何處理此問題的任何想法?

matplotlib中的顏色條將0到1之間的數字映射到一種顏色。 為了將其他數字映射到顏色,首先需要對范圍[0,1]進行歸一化。 這通常通過最小和最大數據自動完成,或者通過使用相應繪圖功能的vminvmax參數完成。 在內部,標准化實例matplotlib.colors.Normalize用於執行標准化,默認情況下,假定vminvmax之間的線性標度。

在這里你需要一個非線性比例,它(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")

在此輸入圖像描述

選擇該函數使得它獨立於其參數將任何范圍映射到范圍[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)

您可以使用自定義normalizer 方便的是,文檔中的示例已經是“替代中點”規范化器。 這個例子是由Joe Kington制作的,所以所有的歸功於他。

請參閱本頁底部: https//matplotlib.org/users/colormapnorms.html

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

自定義規范化類:

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)

在此輸入圖像描述

這是一個相對簡單的例子,但在類似的事情中可以實現更復雜的縮放。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM