web-dev-qa-db-fra.com

Inverser la palette de couleurs dans matplotlib

J'aimerais savoir comment inverser simplement l'ordre des couleurs d'une palette de couleurs donnée afin de l'utiliser avec plot_surface.

202
Mermoz

Les cartes de couleurs standard ont également toutes des versions inversées. Ils ont les mêmes noms avec _r cloué à la fin. ( Documentation ici. )

384
ptomato

Dans matplotlib, une carte de couleurs n'est pas une liste, mais elle contient la liste de ses couleurs sous la forme colormap.colors. Et le module matplotlib.colors fournit une fonction ListedColormap() pour générer une palette de couleurs à partir d'une liste. Ainsi, vous pouvez inverser n’importe quelle carte couleur en faisant

colormap_r = ListedColormap(colormap.colors[::-1])
15
Gilles

Comme un LinearSegmentedColormaps est basé sur un dictionnaire de rouge, vert et bleu, il est nécessaire d'inverser chaque élément:

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

Voir que cela fonctionne:

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

EDIT


Je ne comprends pas le commentaire de user3445587. Cela fonctionne très bien sur la palette de couleurs Rainbow:

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

Mais cela fonctionne particulièrement bien pour les tables de couleurs déclarées personnalisées, car il n'y a pas de valeur par défaut _r pour les tables de couleurs déclarées personnalisées. Exemple suivant tiré de 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

10
Mattijn

Depuis Matplotlib 2.0, il existe une méthode reversed() pour les objets ListedColormap et LinearSegmentedColorMap. Vous pouvez donc simplement faire

cmap_reversed = cmap.reversed()

Ici est la documentation.

7
David Stansby

La solution est assez simple. Supposons que vous souhaitiez utiliser le schéma de couleurs "automne". La version standard:

cmap = matplotlib.cm.autumn

Pour inverser le spectre de couleurs de la palette de couleurs, utilisez la fonction get_cmap () et ajoutez '_r' au titre de la palette de couleurs de la manière suivante:

cmap_reversed = matplotlib.cm.get_cmap('autumn_r')
7
Jm M

Il existe deux types de LinearSegmentedColormaps. Dans certains cas, le _segmentdata est donné explicitement, par exemple pour 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))}

Pour Rainbow, _segmentdata est donné comme suit:

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

Nous pouvons trouver les fonctions dans la source de matplotlib, où elles sont données comme

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

Tout ce que vous voulez est déjà fait dans matplotlib, appelez simplement cm.revcmap, qui inverse les deux types de données de segment,

cm.revcmap(cm.Rainbow._segmentdata)

devrait faire le travail - vous pouvez simplement créer un nouveau LinearSegmentData à partir de cela. Dans revcmap, l’inversion de SegmentData basée sur une fonction s’effectue avec

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

tandis que les autres listes sont inversées comme d'habitude

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

Donc en fait tout ce que vous voulez, c'est

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

Il n’existe pas (encore) de méthode invoquée pour inverser les cartouches de couleurs arbitraires, mais une solution simple consiste à ne pas modifier la barre de couleurs, mais à créer un objet de normalisation inversé:

from matplotlib.colors import Normalize

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

Vous pouvez ensuite utiliser cela avec plot_surface et d'autres fonctions de traçage de Matplotlib en effectuant par exemple.

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

Cela fonctionnera avec n'importe quelle palette de couleurs Matplotlib.

1
astrofrog