2010-07-19 31 views
138

Ich würde gerne wissen, wie man einfach die Farbreihenfolge einer bestimmten Colormap umkehren, um es mit Plot_Surface zu verwenden.Invert Colormap in Matplotlib

+0

Der Titel sollte "Revert" nicht "Invert" sein. Da ist ein Unterschied! –

Antwort

268

Die Standard-Colormaps haben auch alle umgekehrte Versionen. Sie haben die gleichen Namen mit _r bis zum Ende angeheftet. (Documentation here.)

+0

Dies funktioniert nicht mit "amfhot": "ValueError: Colormap amfhot_r wird nicht erkannt". Ich nehme an, "hot_r" muss ausreichen. – shockburner

+0

In ähnlicher Weise wird "ValueError: Colormap red_r nicht erkannt." –

12

In Matplotlib ist eine Farbkarte keine Liste, aber es enthält die Liste seiner Farben als colormap.colors. Und das Modul matplotlib.colors bietet eine Funktion , um eine Farbkarte aus einer Liste zu generieren. So können Sie jede Farbe Karte umkehren, indem

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

+1. Dies wird jedoch keine Colormap generisch rückgängig machen. Nur "ListedColormaps" (d. H. Diskret statt interpoliert) haben ein Attribut "colors". Das Umkehren von 'LinearSegmentedColormaps' ist etwas komplexer. (Sie müssen jedes Element im '_segmentdata'-Diktat rückgängig machen.) –

+3

In Bezug auf die Umkehrung von' LinearSegmentedColormaps' habe ich dies für einige Farbmaps getan. [Hier ist ein IPython-Notebook darüber.] (Http://nbviewer.ipython.org/github/kwinkunks/notebooks/blob/master/Matteo_colourmaps.ipynb) – kwinkunks

+0

@kwinkunks Ich denke, die Funktion in Ihrem Notebook ist nicht richtig, siehe Antwort unter – Mattijn

6

Als LinearSegmentedColormaps tun basiert auf einem Wörterbuch von Rot, Grün und Blau, ist es notwendig, jedes Element zu umkehren:

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 

Sehen Sie, dass es funktioniert:

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


ich nicht bekommen, den Kommentar von user3445587. Es funktioniert gut auf dem Regenbogen colormap:

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

Aber es funktioniert besonders schön für benutzerdefinierte Farbtabellen erklärt, da es keinen Standard ist _r für benutzerdefinierte Farbtabellen erklärt. Das folgende Beispiel aus http://matplotlib.org/examples/pylab_examples/custom_cmap.html genommen:

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

Dieses Beispiel ist nicht vollständig in dem Sinne, dass die Segmentdaten nicht in Listen enthalten sind, so dass sie nicht unbedingt reversibel sein müssen (zB Standard-Rainbow-Colormap). Ich denke, im Prinzip sollten alle LinearSegmentedColormaps mit einer Lambda-Funktion reversibel sein wie in der Regenbogen-Colormap? – overseas

+0

@ user3445587 Ich füge einige weitere Beispiele hinzu, aber ich denke, es funktioniert gut auf dem Standard-Regenbogen colormap – Mattijn

+0

Da es zu lang war, fügte ich eine neue Antwort, die für alle Arten von LinearSegmentData funktionieren sollte. Das Problem ist, dass für Rainbow, _segmentdata anders implementiert wird. Also funktioniert dein Code - zumindest auf meinem Rechner - nicht mit der Regenbogenfarbkarte. – overseas

1

Es gibt zwei Arten von LinearSegmentedColormaps. In einigen, wird die _segmentdata explizit, zB für Düsentrieb gegeben:

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

Für Regenbogen, _segmentdata wird wie folgt angegeben:

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

wir die Funktionen in der Quelle der matplotlib finden, wo sie

_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) 
} 

Alles, was Sie wollen, ist bereits getan in matplotlib als

gegeben, nur nennen cm.revcmap, die beide Arten von segmentdata umkehrt, so

cm.revcmap(cm.rainbow._segmentdata) 

sollte den Job erledigen - Sie können einfach eine neue LinearSegmentData daraus erstellen.In revcmap wird die Umkehrung der Funktion basiert SegmentData mit

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

während die anderen Listen wie üblich umgekehrt sind

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

Also eigentlich das Ganze, was Sie wollen, ist

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

Die Lösung ist ziemlich einfach. Angenommen, Sie möchten das Colormap-Schema "Herbst" verwenden. Die Standardversion:

cmap = matplotlib.cm.autumn 

das colormap Farbspektrum umzukehren, verwenden get_cmap() Funktion und hängen ‚_r‘ an den colormap Titel wie folgt aus:

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

Es gibt keine integrierte Möglichkeit (noch) beliebige Farbtabellen der Umkehr, aber eine einfache Lösung ist eigentlich nicht die colorbar zu ändern, sondern eine Invertierung Normalisieren-Objekt zu erstellen:

from matplotlib.colors import Normalize 

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

Sie dann diese mitverwenden könnenund andere Matplotlib-Zeichenfunktionen, z.

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

Dies funktioniert mit jeder Matplotlib Colormap.

+0

Es gibt jetzt! https://matplotlib.org/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormap.reversed –

0

Ab Matplotlib 2.0 gibt es eine reversed() Methode für ListedColormap und LinearSegmentedColorMap Objekte, so können Sie einfach tun

cmap_reversed = cmap.reverse()

here für die Dokumentation.

Verwandte Themen