2010-07-19 25 views
138

Me gustaría saber cómo invertir el orden de color de un mapa de colores determinado para usarlo con plot_surface.Invertir mapa de colores en matplotlib

+0

El título debe ser "Revertir" no "Invertir". ¡Hay una diferencia! –

Respuesta

268

Los mapas de color estándar también tienen versiones inversas. Tienen los mismos nombres con _r añadidos al final. (Documentation here.)

+0

Esto no funciona con "amfhot": "ValueError: Colormap amfhot_r no se reconoce". Supongo que "hot_r" tendrá que ser suficiente. – shockburner

+0

Del mismo modo, "ValueError: Colormap red_r no se reconoce". –

12

En matplotlib un mapa de colores no es una lista, pero contiene la lista de sus colores como colormap.colors. Y el módulo matplotlib.colors proporciona una función ListedColormap() para generar un mapa de colores de una lista. Por lo que puede revertir cualquier mapa de color haciendo

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

+1. Sin embargo, esto no revertirá genéricamente ningún mapa de color. Solo 'ListedColormap's (es decir, discreto, en lugar de interpolado) tiene un atributo' colors'. Invertir 'LinearSegmentedColormaps' es un poco más complejo. (Es necesario invertir cada elemento en el dict '_segmentdata') –

+3

En cuanto a la inversión de' LinearSegmentedColormaps', acabo de hacer esto para algunos mapas de colores. [Este es un cuaderno de IPython al respecto.] (Http://nbviewer.ipython.org/github/kwinkunks/notebooks/blob/master/Matteo_colourmaps.ipynb) – kwinkunks

+0

@kwinkunks Creo que la función en su computadora portátil no es correcta, vea la respuesta debajo de – Mattijn

6

Como LinearSegmentedColormaps se basa en un diccionario de rojo, verde y azul, es necesario invertir cada elemento:

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 

ver que funciona:

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 TI


no consigo el comentario de user3445587. Funciona bien en el mapa de colores del arco iris:

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

Pero sobre todo funciona bien para encargo declaró mapas de colores, ya que no es un defecto _r por encargo declaró mapas de colores. Siguiendo el ejemplo tomado 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

Este ejemplo no está completo en el sentido de que los datos de segmento no están en las listas, por lo que no es necesariamente reversible (por ejemplo, mapa de colores de arco iris estándar). Creo que en principio todos los LinearSegmentedColormaps deberían en principio ser reversibles usando una función lambda como en el mapa de colores del arco iris? – overseas

+0

@ user3445587 Agrego algunos ejemplos más, pero creo que funciona bien en el mapa de colores del arcoíris estándar – Mattijn

+0

Dado que era demasiado largo, agregué una nueva respuesta, que debería funcionar para todo tipo de LinearSegmentData. El problema es que para rainbow, _segmentdata se implementa de forma diferente. Entonces su código, al menos en mi máquina, no funciona con el mapa de colores del arco iris. – overseas

1

Hay dos tipos de LinearSegmentedColormaps. En algunos, la _segmentdata se da de forma explícita, por ejemplo, para 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))} 

para el arco iris, se da _segmentdata de la siguiente manera:

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

podemos encontrar las funciones de la fuente de matplotlib, donde se dan como

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

Todo lo que quiere ya que se hace en matplotlib, simplemente llame cm.revcmap, que invierte los dos tipos de segmentdata, por lo

cm.revcmap(cm.rainbow._segmentdata) 

debería hacer el trabajo; simplemente puede crear un nuevo LinearSegmentData a partir de eso.En revcmap, la inversión de la función basada SegmentData se realiza con

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

mientras que las otras listas se invierten como de costumbre

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

Así que en realidad todo lo que desea, es

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

La solución es bastante simple. Supongamos que desea utilizar el esquema de mapa de colores "otoñal". La versión estándar:

cmap = matplotlib.cm.autumn 

Para invertir el espectro de color mapa de colores, utilice get_cmap() y anexar '_r' al título de mapa de colores de esta manera:

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

No hay manera integrada (aún) de revertir mapas de colores arbitrarios, pero una solución simple es en realidad no se modifique la barra de colores, pero para crear un objeto de inversión Normalizar:

from matplotlib.colors import Normalize 

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

a continuación, puede utilizar esto con plot_surface y otras funciones de trazado de Matplotlib haciendo, p.

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

Esto funcionará con cualquier mapa de color Matplotlib.

+0

¡Ahora hay! https://matplotlib.org/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormap.reversed –

0

A partir de Matplotlib 2.0, hay un método para reversed()ListedColormap y LinearSegmentedColorMap objetos, por lo que sólo puede hacer

cmap_reversed = cmap.reverse()

Ver here para la documentación.

Cuestiones relacionadas