2010-07-19 9 views
138

Mi piacerebbe sapere come invertire semplicemente l'ordine dei colori di una data mappa per poterlo utilizzare con plot_surface.Inverti mappa colori in matplotlib

+0

Il titolo deve essere "Ripristina" non "Inverti". C'è una differenza! –

risposta

268

Anche i colori standard hanno tutte le versioni invertite. Hanno lo stesso nome con _r attaccato alla fine. (Documentation here.)

+0

Questo non funziona con "amfhot": "ValueError: Colormap amfhot_r non è riconosciuto". Suppongo che "hot_r" debba essere sufficiente. – shockburner

+0

Analogamente, "ValueError: Colormap red_r non è riconosciuto." –

12

In matplotlib una mappa colori non è un elenco, ma contiene l'elenco dei suoi colori come colormap.colors. E il modulo matplotlib.colors fornisce una funzione ListedColormap() per generare una mappa dei colori da un elenco. Così si può invertire qualsiasi mappa colore effettuando

colormap_r = ListedColormap(colormap.colors[::-1]) 
+7

+1. Tuttavia, questo non invertirà genericamente alcuna mappa dei colori. Solo 'ListedColormap's (cioè discreto, piuttosto che interpolato) hanno un attributo' colors'. L'inversione di 'LinearSegmentedColormaps' è un po 'più complessa. (È necessario invertire ogni voce nel dettato '_segmentdata'.) –

+3

Per quanto riguarda l'inversione di' LinearSegmentedColormaps', l'ho appena fatto per alcuni colori. [Ecco un Quaderno IPython su di esso.] (Http://nbviewer.ipython.org/github/kwinkunks/notebooks/blob/master/Matteo_colourmaps.ipynb) – kwinkunks

+0

@kwinkunks penso che la funzione nel tuo quaderno non sia corretta, vedi risposta sotto – Mattijn

6

Come LinearSegmentedColormaps si basa su un dizionario di rosso, verde e blu, è necessario invertire ogni voce:

import matplotlib.pyplot as plt 
import matplotlib as mpl 
def reverse_colourmap(cmap, name = 'my_cmap_r'): 
    """ 
    In: 
    cmap, name 
    Out: 
    my_cmap_r 

    Explanation: 
    t[0] goes from 0 to 1 
    row i: x y0 y1 -> t[0] t[1] t[2] 
       /
       /
    row i+1: x y0 y1 -> t[n] t[1] t[2] 

    so the inverse should do the same: 
    row i+1: x y1 y0 -> 1-t[0] t[2] t[1] 
       /
       /
    row i: x y1 y0 -> 1-t[n] t[2] t[1] 
    """   
    reverse = [] 
    k = [] 

    for key in cmap._segmentdata:  
     k.append(key) 
     channel = cmap._segmentdata[key] 
     data = [] 

     for t in channel:      
      data.append((1-t[0],t[2],t[1]))    
     reverse.append(sorted(data))  

    LinearL = dict(zip(k,reverse)) 
    my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL) 
    return my_cmap_r 

vedere che funziona:

my_cmap   
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518> 

my_cmap_r = reverse_colourmap(my_cmap) 

fig = plt.figure(figsize=(8, 2)) 
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15]) 
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15]) 
norm = mpl.colors.Normalize(vmin=0, vmax=1) 
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal') 
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal') 

enter image description here

ED IT


non capisco il commento di user3445587. Funziona benissimo sulla mappa di colori dell'arcobaleno:

cmap = mpl.cm.jet 
cmap_r = reverse_colourmap(cmap) 

fig = plt.figure(figsize=(8, 2)) 
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15]) 
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15]) 
norm = mpl.colors.Normalize(vmin=0, vmax=1) 
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal') 
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal') 

enter image description here

Ma funziona particolarmente piacevole per la personalizzazione mappe di colore dichiarato, in quanto non v'è un difetto _r per la personalizzazione mappe di colore dichiarato. Seguendo l'esempio tratto da http://matplotlib.org/examples/pylab_examples/custom_cmap.html:

cdict1 = {'red': ((0.0, 0.0, 0.0), 
        (0.5, 0.0, 0.1), 
        (1.0, 1.0, 1.0)), 

     'green': ((0.0, 0.0, 0.0), 
        (1.0, 0.0, 0.0)), 

     'blue': ((0.0, 0.0, 1.0), 
        (0.5, 0.1, 0.0), 
        (1.0, 0.0, 0.0)) 
     } 

blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1) 
blue_red1_r = reverse_colourmap(blue_red1) 

fig = plt.figure(figsize=(8, 2)) 
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15]) 
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15]) 

norm = mpl.colors.Normalize(vmin=0, vmax=1) 
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal') 
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal') 

enter image description here

+0

Questo esempio non è completo nel senso che i dati dei segmenti non devono essere inclusi negli elenchi, quindi non è necessariamente reversibile (ad es. colormap standard arcobaleno). Penso che in linea di principio tutte le LinearSegmentedColormaps dovrebbero essere in grado di essere reversibili usando una funzione lambda come nella colormap arcobaleno? – overseas

+0

@ user3445587 Aggiungo qualche altro esempio, ma penso che funzioni perfettamente sulla colormap dell'arcobaleno standard – Mattijn

+0

Poiché era troppo lungo, ho aggiunto una nuova risposta, che dovrebbe funzionare per tutti i tipi di LinearSegmentData. Il problema è che per rainbow, _segmentdata è implementato in modo diverso. Quindi il tuo codice, almeno sulla mia macchina, non funziona con la mappa colori dell'arcobaleno. – overseas

1

Ci sono due tipi di LinearSegmentedColormaps. In alcuni, il _segmentdata è dato esplicitamente, ad esempio, per il jet:

>>> cm.jet._segmentdata 
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))} 

per Rainbow, _segmentdata è dato come segue:

>>> cm.rainbow._segmentdata 
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>} 

possiamo trovare le funzioni nella fonte di matplotlib, dove sono dati come

_rainbow_data = { 
     'red': gfunc[33], # 33: lambda x: np.abs(2 * x - 0.5), 
     'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi), 
     'blue': gfunc[10], # 10: lambda x: np.cos(x * np.pi/2) 
} 

Tutto ciò che si desidera è già stato fatto in matplotlib, basta chiamare cm.revcmap, che inverte entrambi i tipi di segmentdata, così

01.235.164,106174 millions

dovrebbe fare il lavoro - si può semplicemente creare un nuovo LinearSegmentData da quello.Nel revcmap, l'inversione della funzione di base SegmentData è fatto con

def _reverser(f): 
    def freversed(x): 
     return f(1 - x) 
    return freversed 

mentre le altre liste sono invertiti come al solito

valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)] 

Quindi in realtà il tutto si desidera, è

def reverse_colourmap(cmap, name = 'my_cmap_r'): 
    return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata)) 
2

La soluzione è piuttosto semplice. Supponiamo di voler utilizzare lo schema della mappa dei colori "autunnale". La versione standard:

cmap = matplotlib.cm.autumn 

Per invertire lo spettro dei colori mappa di colori, utilizzare get_cmap() la funzione e aggiungere '_r' al titolo colormap in questo modo:

cmap_reversed = matplotlib.cm.get_cmap('autumn_r') 
1

Non c'è modo integrato (ancora) di invertire colormaps arbitrarie, ma una soluzione semplice è quella di non modificare la realtà colorbar ma per creare un oggetto invertente Normalizzazione:

from matplotlib.colors import Normalize 

class InvertedNormalize(Normalize): 
    def __call__(self, *args, **kwargs): 
     return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs) 

è possibile utilizzare questo con plot_surface e altre funzioni di tracciamento Matlotlib eseguendo ad es.

inverted_norm = InvertedNormalize(vmin=10, vmax=100) 
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm) 

Questo funzionerà con qualsiasi colormap Matplotlib.

+0

C'è ora! https://matplotlib.org/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormap.reversed –

0

A partire dal Matplotlib 2.0, c'è un metodo per reversed()ListedColormap e LinearSegmentedColorMap oggetti, quindi si può solo fare

cmap_reversed = cmap.reverse()

Vedere here per la documentazione.