Respuestas:
Los mapas de color estándar también tienen versiones invertidas. Tienen los mismos nombres con _r
tachuelas hasta el final. ( Documentación aquí. )
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 color a partir de una lista. Para que pueda revertir cualquier mapa de color haciendo
colormap_r = ListedColormap(colormap.colors[::-1])
ListedColormap
s (es decir, discreto, en lugar de interpolado) tienen un colors
atributo. Revertir LinearSegmentedColormaps
es un poco más complejo. (Debe revertir cada elemento en el _segmentdata
dict.)
LinearSegmentedColormaps
, acabo de hacer esto para algunos mapas de colores. Aquí hay un cuaderno de IPython al respecto.
La solución es bastante sencilla. Supongamos que desea utilizar el esquema de mapa de colores "otoño". La versión estándar:
cmap = matplotlib.cm.autumn
Para invertir el espectro de colores del mapa de colores, use la función get_cmap () y agregue '_r' al título del mapa de colores de esta manera:
cmap_reversed = matplotlib.cm.get_cmap('autumn_r')
Como LinearSegmentedColormaps
se basa en un diccionario de rojo, verde y azul, es necesario revertir 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')
EDITAR
No recibo el comentario del usuario3445587. 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')
Pero funciona especialmente bien para mapas de color declarados personalizados, ya que no hay un valor predeterminado _r
para mapas de color declarados personalizados. 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')
A partir de Matplotlib 2.0, hay un reversed()
método para ListedColormap
y LinearSegmentedColorMap
objetos, por lo que puede hacer
cmap_reversed = cmap.reversed()
Aquí está la documentación.
Hay dos tipos de LinearSegmentedColormaps. En algunos, los _segmentdata se dan explícitamente, 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 rainbow, _segmentdata se da 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 en 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 desea ya está hecho en matplotlib, solo llame a cm.revcmap, que invierte ambos tipos de datos de segmento, por lo que
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 SegmentData basada en funciones 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)]
Entonces, en realidad, todo lo que quieres es
def reverse_colourmap(cmap, name = 'my_cmap_r'):
return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata))
No existe una forma integrada (todavía) de invertir mapas de colores arbitrarios, pero una solución simple es no modificar la barra de colores sino crear un objeto Normalizar invertido:
from matplotlib.colors import Normalize
class InvertedNormalize(Normalize):
def __call__(self, *args, **kwargs):
return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)
Luego puede usar esto con plot_surface
y otras funciones de trazado de Matplotlib haciendo, por ejemplo,
inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)
Esto funcionará con cualquier mapa de colores Matplotlib.