2010-07-19 2 views
138

Je voudrais savoir comment inverser simplement l'ordre des couleurs d'une carte de couleurs donnée afin de l'utiliser avec plot_surface.Inverser la palette de couleurs dans matplotlib

+0

Le titre doit être "Revenir" et non "Inverser". Il existe une différence! –

Répondre

268

Les colormaps standard ont également tous des versions inversées. Ils ont les mêmes noms avec _r collés à la fin. (Documentation here.)

+0

Cela ne fonctionne pas avec "amfhot": "ValueError: Colormap amfhot_r n'est pas reconnu". Je suppose que "hot_r" devra suffire. – shockburner

+0

De même, "ValueError: Colormap red_r n'est pas reconnu." –

12

Dans matplotlib une carte en couleur n'est pas une liste, mais elle contient la liste de ses couleurs comme colormap.colors. Et le module matplotlib.colors fournit une fonction ListedColormap() pour générer une carte de couleurs à partir d'une liste. Vous pouvez donc annuler toute carte de couleur en faisant

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

+1. Cependant, cela n'inversera pas de façon générique toute colormap. Seul 'ListedColormap' (c'est-à-dire discret, plutôt que interpolé) possède un attribut' colors'. Inverser 'LinearSegmentedColormaps' est un peu plus complexe. (Vous devez inverser chaque élément de la dict '_segmentdata'.) –

+3

En ce qui concerne l'inversion de' LinearSegmentedColormaps', je l'ai fait pour certaines cartes de couleurs. [Voici un IPython Notebook à ce sujet.] (Http://nbviewer.ipython.org/github/kwinkunks/notebooks/blob/master/Matteo_colourmaps.ipynb) – kwinkunks

+0

@kwinkunks Je pense que la fonction dans votre cahier n'est pas bonne, voir la réponse ci-dessous – Mattijn

6

En tant que 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

ED IT


Je ne comprends pas le commentaire de user3445587. Il fonctionne très bien sur la palette de couleurs arc-en-:

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 agréable pour colormaps a déclaré la coutume, car il n'y a pas un défaut _r pour a déclaré la coutume colormaps. L'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

+0

Cet exemple n'est pas complet en ce sens que les données de segment ne doivent pas figurer dans des listes, elles ne sont donc pas nécessairement réversibles (par exemple, carte de couleurs arc-en-ciel standard). Je pense en principe que tous les LinearSegmentedColormaps devraient être réversibles en utilisant une fonction lambda comme dans la palette de couleurs arc-en-ciel? – overseas

+0

@ user3445587 J'ajoute quelques autres exemples, mais je pense que cela fonctionne très bien sur la palette de couleurs arc-en-ciel standard – Mattijn

+0

Depuis trop longtemps, j'ai ajouté une nouvelle réponse, qui devrait fonctionner pour toutes sortes de LinearSegmentData. Le problème est que pour arc-en-ciel, _segmentdata est implémenté différemment. Donc, votre code - au moins sur ma machine - ne fonctionne pas avec la palette de couleurs arc-en-ciel. – overseas

1

Il existe deux types de LinearSegmentedColormaps. Dans certains pays, la _segmentdata est donnée 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 arc en ciel, _segmentdata est donnée 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ù ils sont donnés à titre

_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, il suffit d'appeler cm.revcmap, qui inverse les deux types de segmentdata, si

cm.revcmap(cm.rainbow._segmentdata) 

devrait faire le travail - vous pouvez simplement créer un nouveau LinearSegmentData à partir de cela.En revcmap, le renversement de la fonction basée SegmentData est fait 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 la chose que vous voulez, est

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

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 des couleurs de palette de couleurs, utilisez la fonction get_cmap() et ajouter '_r' au titre de colormap comme ceci:

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

Il n'y a pas moyen intégré (encore) d'inverser colormaps arbitraires, mais une solution simple est de ne pas modifier le fait colorbar mais pour créer un objet Normaliser inversante:

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 avec plot_surface et d'autres fonctions de traçage de Matplotlib en faisant par ex.

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

Ceci fonctionnera avec n'importe quelle carte de couleurs Matplotlib.

+0

Il y a maintenant! https://matplotlib.org/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormap.reversed –

0

Au Matplotlib 2.0, il existe une méthode reversed() pour les objets ListedColormap et LinearSegmentedColorMap, de sorte que vous pouvez juste faire

cmap_reversed = cmap.reverse()

Voir here pour la documentation.

Questions connexes