Definizione del punto medio di una mappa di colori in matplotlib


88

Voglio impostare il punto medio di una mappa di colori, cioè i miei dati vanno da -5 a 10, voglio che zero sia il centro. Penso che il modo per farlo sia normalizzare le sottoclassi e usare la norma, ma non ho trovato alcun esempio e non mi è chiaro cosa esattamente devo implementare.


questa è chiamata mappa dei colori "divergente" o "bipolare", dove il punto centrale della mappa è importante ei dati vanno sopra e sotto questo punto. sandia.gov/~kmorel/documents/ColorMaps
endolith

3
Tutte le risposte in questo thread sembrano piuttosto complicate. La soluzione facile da usare è mostrata in questa eccellente risposta , che nel frattempo è stata inserita anche nella documentazione di matplotlib, sezione Normalizzazione personalizzata: due intervalli lineari .
ImportanceOfBeingErnest

Risposte:


15

Si noti che in matplotlib versione 3.1 del DivergingNorm è stato aggiunto di classe. Penso che copra il tuo caso d'uso. Può essere usato in questo modo:

from matplotlib import colors
colors.DivergingNorm(vmin=-4000., vcenter=0., vmax=10000)

In matplotlib 3.2 la classe è stata rinominata TwoSlopesNorm


Sembra interessante, ma sembra che debba essere usato per trasformare i dati prima della stampa. La legenda della barra dei colori si riferirà ai dati trasformati, non a quello originale.
bli

3
@bli non è così. la normfa la normalizzazione per la vostra immagine. normsandare di pari passo con le mappe dei colori.
Paul H

1
Fastidiosamente questo è deprecato a partire dalla 3.2 senza alcun documento su come sostituirlo: matplotlib.org/3.2.0/api/_as_gen/…
daknowles

1
Sì, i documenti non sono chiari. Penso che sia stato rinominato in TwoSlopeNorm: matplotlib.org/3.2.0/api/_as_gen/…
macKaiver

91

So che è tardi per il gioco, ma ho appena seguito questo processo e ho trovato una soluzione che forse meno robusta della normalizzazione delle sottoclassi, ma molto più semplice. Ho pensato che sarebbe stato bello condividerlo qui per i posteri.

La funzione

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import AxesGrid

def shiftedColorMap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'):
    '''
    Function to offset the "center" of a colormap. Useful for
    data with a negative min and positive max and you want the
    middle of the colormap's dynamic range to be at zero.

    Input
    -----
      cmap : The matplotlib colormap to be altered
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower offset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to 
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax / (vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highest point in the colormap's range.
          Defaults to 1.0 (no upper offset). Should be between
          `midpoint` and 1.0.
    '''
    cdict = {
        'red': [],
        'green': [],
        'blue': [],
        'alpha': []
    }

    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)

    # shifted index to match the data
    shift_index = np.hstack([
        np.linspace(0.0, midpoint, 128, endpoint=False), 
        np.linspace(midpoint, 1.0, 129, endpoint=True)
    ])

    for ri, si in zip(reg_index, shift_index):
        r, g, b, a = cmap(ri)

        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))

    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)

    return newcmap

Un esempio

biased_data = np.random.random_integers(low=-15, high=5, size=(37,37))

orig_cmap = matplotlib.cm.coolwarm
shifted_cmap = shiftedColorMap(orig_cmap, midpoint=0.75, name='shifted')
shrunk_cmap = shiftedColorMap(orig_cmap, start=0.15, midpoint=0.75, stop=0.85, name='shrunk')

fig = plt.figure(figsize=(6,6))
grid = AxesGrid(fig, 111, nrows_ncols=(2, 2), axes_pad=0.5,
                label_mode="1", share_all=True,
                cbar_location="right", cbar_mode="each",
                cbar_size="7%", cbar_pad="2%")

# normal cmap
im0 = grid[0].imshow(biased_data, interpolation="none", cmap=orig_cmap)
grid.cbar_axes[0].colorbar(im0)
grid[0].set_title('Default behavior (hard to see bias)', fontsize=8)

im1 = grid[1].imshow(biased_data, interpolation="none", cmap=orig_cmap, vmax=15, vmin=-15)
grid.cbar_axes[1].colorbar(im1)
grid[1].set_title('Centered zero manually,\nbut lost upper end of dynamic range', fontsize=8)

im2 = grid[2].imshow(biased_data, interpolation="none", cmap=shifted_cmap)
grid.cbar_axes[2].colorbar(im2)
grid[2].set_title('Recentered cmap with function', fontsize=8)

im3 = grid[3].imshow(biased_data, interpolation="none", cmap=shrunk_cmap)
grid.cbar_axes[3].colorbar(im3)
grid[3].set_title('Recentered cmap with function\nand shrunk range', fontsize=8)

for ax in grid:
    ax.set_yticks([])
    ax.set_xticks([])

Risultati dell'esempio:

inserisci qui la descrizione dell'immagine


Molte grazie per il tuo fantastico contributo! Tuttavia, il codice non è stato in grado di entrambe ritaglio e spostando la stessa mappa dei colori, e le tue istruzioni erano un po 'impreciso e fuorviante. Ora l'ho risolto e mi sono preso la libertà di modificare il tuo post. Inoltre, l'ho incluso in una delle mie librerie personali e ti ho aggiunto come autore. Spero non ti dispiaccia.
TheChymera

@TheChymera la mappa dei colori nell'angolo in basso a destra è stata sia ritagliata che ricentrata. Sentiti libero di usarlo come meglio credi.
Paul H

Sì, è vero, purtroppo sembra solo approssimativamente giusto come una coincidenza. Se starte stopnon sono rispettivamente 0 e 1, dopo averlo fatto reg_index = np.linspace(start, stop, 257), non puoi più presumere che il valore 129 sia il punto medio del cmap originale, quindi l'intero ridimensionamento non ha senso ogni volta che ritagli. Inoltre, startdovrebbe essere compreso tra 0 e 0,5 e stoptra 0,5 e 1, non entrambi tra 0 e 1 come da istruzioni.
TheChymera

@TheChymera Ho provato la tua versione e ho avuto due pensieri al riguardo. 1) mi sembra che gli indici che hai creato siano tutti di lunghezza 257, e in matplotlib è predefinito a 256 presumo? 2) supponiamo che i miei dati siano compresi tra -1 e 1000, è dominato da positivi e quindi più livelli / strati dovrebbero andare al ramo positivo. Ma la tua funzione fornisce 128 livelli sia ai negativi che ai positivi, quindi sarebbe più "giusto" dividere i livelli in modo non uniforme, credo.
Jason

Questa è una soluzione eccellente, ma fallisce se il valore midpointdei dati è uguale a 0 o 1. Vedere la mia risposta di seguito per una semplice soluzione a quel problema.
DaveTheScientist

22

Ecco una soluzione sottoclasse Normalize. Per usarlo

norm = MidPointNorm(midpoint=3)
imshow(X, norm=norm)

Ecco la classe:

import numpy as np
from numpy import ma
from matplotlib import cbook
from matplotlib.colors import Normalize

class MidPointNorm(Normalize):    
    def __init__(self, midpoint=0, vmin=None, vmax=None, clip=False):
        Normalize.__init__(self,vmin, vmax, clip)
        self.midpoint = midpoint

    def __call__(self, value, clip=None):
        if clip is None:
            clip = self.clip

        result, is_scalar = self.process_value(value)

        self.autoscale_None(result)
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if not (vmin < midpoint < vmax):
            raise ValueError("midpoint must be between maxvalue and minvalue.")       
        elif vmin == vmax:
            result.fill(0) # Or should it be all masked? Or 0.5?
        elif vmin > vmax:
            raise ValueError("maxvalue must be bigger than minvalue")
        else:
            vmin = float(vmin)
            vmax = float(vmax)
            if clip:
                mask = ma.getmask(result)
                result = ma.array(np.clip(result.filled(vmax), vmin, vmax),
                                  mask=mask)

            # ma division is very slow; we can take a shortcut
            resdat = result.data

            #First scale to -1 to 1 range, than to from 0 to 1.
            resdat -= midpoint            
            resdat[resdat>0] /= abs(vmax - midpoint)            
            resdat[resdat<0] /= abs(vmin - midpoint)

            resdat /= 2.
            resdat += 0.5
            result = ma.array(resdat, mask=result.mask, copy=False)                

        if is_scalar:
            result = result[0]            
        return result

    def inverse(self, value):
        if not self.scaled():
            raise ValueError("Not invertible until scaled")
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if cbook.iterable(value):
            val = ma.asarray(value)
            val = 2 * (val-0.5)  
            val[val>0]  *= abs(vmax - midpoint)
            val[val<0] *= abs(vmin - midpoint)
            val += midpoint
            return val
        else:
            val = 2 * (value - 0.5)
            if val < 0: 
                return  val*abs(vmin-midpoint) + midpoint
            else:
                return  val*abs(vmax-midpoint) + midpoint

È possibile utilizzare questa classe oltre al ridimensionamento log o sym-log senza dover creare più sottoclassi? Il mio attuale caso d'uso utilizza già "norm = SymLogNorm (linthresh = 1)"
AnnanFay

Perfetto, questo è esattamente quello che stavo cercando. Forse dovresti aggiungere un'immagine per dimostrare la differenza? Qui il punto medio è centrato nella barra, contrariamente ad altri normalizzatori del punto medio in cui il punto medio può essere trascinato verso le estremità.
gaborous

18

È più semplice usare gli argomenti vmine vmaxper imshow(supponendo che tu stia lavorando con i dati dell'immagine) piuttosto che sottoclasse matplotlib.colors.Normalize.

Per esempio

import numpy as np
import matplotlib.pyplot as plt

data = np.random.random((10,10))
# Make the data range from about -5 to 10
data = 10 / 0.75 * (data - 0.25)

plt.imshow(data, vmin=-10, vmax=10)
plt.colorbar()

plt.show()

inserisci qui la descrizione dell'immagine


1
È possibile aggiornare l'esempio a una curva gaussiana in modo da poter vedere meglio la gradazione del colore?
Dat Chu

3
Non mi piace questa soluzione, perché non utilizza l'intera gamma dinamica dei colori disponibili. Inoltre vorrei un esempio di normalizzazione per creare un tipo di normalizzazione symlog.
tillsten

2
@tillsten - Sono confuso, quindi ... Non puoi usare l'intera gamma dinamica della barra dei colori se vuoi 0 al centro, giusto? Allora vuoi una scala non lineare? Una scala per i valori superiori a 0, una per i valori inferiori? In tal caso, sì, dovrai creare una sottoclasse Normalize. Aggiungerò un esempio tra poco (supponendo che qualcun altro non mi abbia battuto ...).
Joe Kington

@ Joe: hai ragione, non è lineare (più esattamente, due parti lineari). Usando vmin / vmax, il colore per i valori inferiori a -5 non viene utilizzato (il che ha senso in alcune applicazioni, ma non il mio).
Tillsten

2
per i dati generici in Z:vmax=abs(Z).max(), vmin=-abs(Z).max()
endolith

13

Qui creo una sottoclasse di Normalizeseguita da un esempio minimo.

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


class MidpointNormalize(mpl.colors.Normalize):
    def __init__(self, vmin, vmax, midpoint=0, clip=False):
        self.midpoint = midpoint
        mpl.colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        normalized_min = max(0, 1 / 2 * (1 - abs((self.midpoint - self.vmin) / (self.midpoint - self.vmax))))
        normalized_max = min(1, 1 / 2 * (1 + abs((self.vmax - self.midpoint) / (self.midpoint - self.vmin))))
        normalized_mid = 0.5
        x, y = [self.vmin, self.midpoint, self.vmax], [normalized_min, normalized_mid, normalized_max]
        return np.ma.masked_array(np.interp(value, x, y))


vals = np.array([[-5., 0], [5, 10]]) 
vmin = vals.min()
vmax = vals.max()

norm = MidpointNormalize(vmin=vmin, vmax=vmax, midpoint=0)
cmap = 'RdBu_r' 

plt.imshow(vals, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

Risultato: pic-1

Lo stesso esempio con solo dati positivi vals = np.array([[1., 3], [6, 10]])

immagine 2

Proprietà:

  • Il punto medio ottiene il colore centrale.
  • Gli intervalli superiore e inferiore vengono ridimensionati dalla stessa trasformazione lineare.
  • Solo il colore che appare nell'immagine è mostrato nella barra dei colori.
  • Sembra funzionare bene anche se vminè più grande di midpoint(non ha testato tutti i casi limite).

Questa soluzione è ispirata da una classe con lo stesso nome di questa pagina


3
Migliore risposta per la sua semplicità. Le altre risposte sono migliori solo se sei già un esperto di Matplotlib che cerca di diventare un super esperto. La maggior parte dei cercatori di risposte matplotlib sta solo cercando di fare qualcosa per tornare a casa dal proprio cane e / o dalla famiglia, e per loro questa risposta è la migliore.
sapo_cosmico

Questa soluzione sembra davvero la migliore, ma non funziona! Ho appena eseguito lo script di test e il risultato è completamente diverso (inclusi solo i quadrati blu e non il rosso). @icemtel, puoi controllare? (a parte il problema con il rientro def __call__)
Filipe

Ok, ho trovato il problema (i): i numeri nel calcolo di normalized_mine normalized_maxsono presi come numeri interi. Mettili come 0,0. Inoltre, per ottenere l'output corretto della tua figura, ho dovuto usare vals = sp.array([[-5.0, 0.0], [5.0, 10.0]]) . Grazie comunque per la risposta!
Filipe

Ciao @Filipe, non riesco a riprodurre il tuo problema sulla mia macchina (Python 3.7, matplotlib 2.2.3 e penso che dovrebbe essere lo stesso sulle versioni più recenti). Quale versione hai? Ad ogni modo, ho apportato una piccola modifica rendendo l'array di tipo float e ho risolto il problema del rientro. Grazie per averlo segnalato
icemtel

Hmm .. Ho appena provato con python3 e funziona anche. Ma sto usando python2.7. Grazie per la correzione e per la risposta. È molto semplice da usare! :)
Filipe

5

Non sono sicuro se stai ancora cercando una risposta. Per me, provare a creare una sottoclasse Normalizenon ha avuto successo. Quindi mi sono concentrato sulla creazione manuale di un nuovo set di dati, tick e tick-label per ottenere l'effetto che penso tu stia mirando.

Ho trovato il scalemodulo in matplotlib che ha una classe usata per trasformare i grafici a linee secondo le regole 'syslog', quindi la uso per trasformare i dati. Quindi ridimensiono i dati in modo che vadano da 0 a 1 (cosa Normalizefa di solito), ma ridimensiono i numeri positivi in ​​modo diverso dai numeri negativi. Questo perché il tuo vmax e vmin potrebbero non essere gli stessi, quindi .5 -> 1 potrebbe coprire un intervallo positivo più ampio di .5 -> 0, l'intervallo negativo fa. Per me è stato più facile creare una routine per calcolare i valori di tick e label.

Di seguito è riportato il codice e una figura di esempio.

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

NDATA = 50
VMAX=10
VMIN=-5
LINTHRESH=1e-4

def makeTickLables(vmin,vmax,linthresh):
    """
    make two lists, one for the tick positions, and one for the labels
    at those positions. The number and placement of positive labels is 
    different from the negative labels.
    """
    nvpos = int(np.log10(vmax))-int(np.log10(linthresh))
    nvneg = int(np.log10(np.abs(vmin)))-int(np.log10(linthresh))+1
    ticks = []
    labels = []
    lavmin = (np.log10(np.abs(vmin)))
    lvmax = (np.log10(np.abs(vmax)))
    llinthres = int(np.log10(linthresh))
    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lavmin) = 0
    m = .5/float(llinthres-lavmin)
    b = (.5-llinthres*m-lavmin*m)/2
    for itick in range(nvneg):
        labels.append(-1*float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmin tick
    labels.append(vmin)
    ticks.append(b+(lavmin)*m)

    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lvmax) = 1
    m = .5/float(lvmax-llinthres)
    b = m*(lvmax-2*llinthres) 
    for itick in range(1,nvpos):
        labels.append(float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmax tick
    labels.append(vmax)
    ticks.append(b+(lvmax)*m)

    return ticks,labels


data = (VMAX-VMIN)*np.random.random((NDATA,NDATA))+VMIN

# define a scaler object that can transform to 'symlog'
scaler = scale.SymmetricalLogScale.SymmetricalLogTransform(10,LINTHRESH)
datas = scaler.transform(data)

# scale datas so that 0 is at .5
# so two seperate scales, one for positive and one for negative
data2 = np.where(np.greater(data,0),
                 .75+.25*datas/np.log10(VMAX),
                 .25+.25*(datas)/np.log10(np.abs(VMIN))
                 )

ticks,labels=makeTickLables(VMIN,VMAX,LINTHRESH)

cmap = mpl.cm.jet
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(data2,cmap=cmap,vmin=0,vmax=1)
cbar = plt.colorbar(im,ticks=ticks)
cbar.ax.set_yticklabels(labels)

fig.savefig('twoscales.png')

vmax = 10, vmin = -5 e linthresh = 1e-4

Sentiti libero di modificare le "costanti" (ad es. VMAX) All'inizio dello script per confermare che si comporta bene.


Grazie per il tuo suggerimento, come mostrato di seguito, ho avuto successo nella sottoclasse. Ma il tuo codice è ancora molto utile per rendere giuste le etichette.
tillsten

4

Stavo usando l'eccellente risposta di Paul H, ma ho riscontrato un problema perché alcuni dei miei dati andavano da negativi a positivi, mentre altri set andavano da 0 a positivi o da negativi a 0; in entrambi i casi volevo che 0 fosse colorato di bianco (il punto medio della mappa di colori che sto usando). Con l'implementazione esistente, se il midpointvalore è uguale a 1 o 0, le mappature originali non venivano sovrascritte. Puoi vederlo nella figura seguente: grafici prima della modifica La terza colonna sembra corretta, ma l'area blu scuro nella seconda colonna e l'area rosso scuro nelle colonne rimanenti dovrebbero essere tutte bianche (i loro valori di dati sono infatti 0). L'utilizzo della mia correzione mi dà: La grafici dopo la modifica mia funzione è essenzialmente la stessa di quella di Paul H, con le mie modifiche all'inizio del forciclo:

def shiftedColorMap(cmap, min_val, max_val, name):
    '''Function to offset the "center" of a colormap. Useful for data with a negative min and positive max and you want the middle of the colormap's dynamic range to be at zero. Adapted from /programming/7404116/defining-the-midpoint-of-a-colormap-in-matplotlib

    Input
    -----
      cmap : The matplotlib colormap to be altered.
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower ofset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax/(vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highets point in the colormap's range.
          Defaults to 1.0 (no upper ofset). Should be between
          `midpoint` and 1.0.'''
    epsilon = 0.001
    start, stop = 0.0, 1.0
    min_val, max_val = min(0.0, min_val), max(0.0, max_val) # Edit #2
    midpoint = 1.0 - max_val/(max_val + abs(min_val))
    cdict = {'red': [], 'green': [], 'blue': [], 'alpha': []}
    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)
    # shifted index to match the data
    shift_index = np.hstack([np.linspace(0.0, midpoint, 128, endpoint=False), np.linspace(midpoint, 1.0, 129, endpoint=True)])
    for ri, si in zip(reg_index, shift_index):
        if abs(si - midpoint) < epsilon:
            r, g, b, a = cmap(0.5) # 0.5 = original midpoint.
        else:
            r, g, b, a = cmap(ri)
        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))
    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)
    return newcmap

EDIT: Mi sono imbattuto in un problema simile ancora una volta quando alcuni dei miei dati andavano da un piccolo valore positivo a un valore positivo più grande, dove i valori molto bassi erano colorati di rosso invece che di bianco. L'ho risolto aggiungendo una riga Edit #2nel codice sopra.


Sembra carino, ma sembra che gli argomenti siano cambiati dalla risposta di Paul H (e dai commenti) ... Puoi aggiungere una chiamata di esempio alla tua risposta?
Filipe

1

Se non ti dispiace calcolare il rapporto tra vmin, vmax e zero, questa è una mappa lineare piuttosto semplice dal blu al bianco al rosso, che imposta il bianco in base al rapporto z:

def colormap(z):
    """custom colourmap for map plots"""

    cdict1 = {'red': ((0.0, 0.0, 0.0),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),
              'green': ((0.0, 0.0, 0.0),
                        (z,   1.0, 1.0),
                        (1.0, 0.0, 0.0)),
              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, 0.0, 0.0))
              }

    return LinearSegmentedColormap('BlueRed1', cdict1)

Il formato cdict è abbastanza semplice: le righe sono punti nel gradiente che viene creato: la prima voce è il valore x (il rapporto lungo il gradiente da 0 a 1), la seconda è il valore finale per il segmento precedente e il terzo è il valore iniziale per il segmento successivo: se vuoi sfumature uniformi, gli ultimi due sono sempre gli stessi. Vedi i documenti per maggiori dettagli.


1
C'è anche la possibilità di specificare all'interno delle LinearSegmentedColormap.from_list()tuple (val,color)e passarle come lista colorall'argomento di questo metodo dove val0=0<val1<...<valN==1.
maurizio

0

Ho avuto un problema simile, ma volevo che il valore più alto fosse rosso pieno e tagliasse i valori bassi di blu, facendo sembrare essenzialmente che la parte inferiore della barra dei colori fosse stata tagliata. Questo ha funzionato per me (include la trasparenza opzionale):

def shift_zero_bwr_colormap(z: float, transparent: bool = True):
    """shifted bwr colormap"""
    if (z < 0) or (z > 1):
        raise ValueError('z must be between 0 and 1')

    cdict1 = {'red': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),

              'green': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                        (z,   1.0, 1.0),
                        (1.0, max(2*z-1,0),  max(2*z-1,0))),

              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, max(2*z-1,0), max(2*z-1,0))),
              }
    if transparent:
        cdict1['alpha'] = ((0.0, 1-max(-2*z+1, 0), 1-max(-2*z+1, 0)),
                           (z,   0.0, 0.0),
                           (1.0, 1-max(2*z-1,0),  1-max(2*z-1,0)))

    return LinearSegmentedColormap('shifted_rwb', cdict1)

cmap =  shift_zero_bwr_colormap(.3)

x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2*np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 5 + 5
plt.plot([0, 10*np.pi], [0, 20*np.pi], color='c', lw=20, zorder=-3)
plt.imshow(Z, interpolation='nearest', origin='lower', cmap=cmap)
plt.colorbar()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.