Mi piacerebbe sapere come invertire semplicemente l'ordine dei colori di una data mappa per poterlo utilizzare con plot_surface.Inverti mappa colori in matplotlib
risposta
Anche i colori standard hanno tutte le versioni invertite. Hanno lo stesso nome con _r
attaccato alla fine. (Documentation here.)
Questo non funziona con "amfhot": "ValueError: Colormap amfhot_r non è riconosciuto". Suppongo che "hot_r" debba essere sufficiente. – shockburner
Analogamente, "ValueError: Colormap red_r non è riconosciuto." –
In matplotlib una mappa colori non è un elenco, ma contiene l'elenco dei suoi colori come colormap.colors
. E il modulo matplotlib.colors
fornisce una funzione ListedColormap()
per generare una mappa dei colori da un elenco. Così si può invertire qualsiasi mappa colore effettuando
colormap_r = ListedColormap(colormap.colors[::-1])
+1. Tuttavia, questo non invertirà genericamente alcuna mappa dei colori. Solo 'ListedColormap's (cioè discreto, piuttosto che interpolato) hanno un attributo' colors'. L'inversione di 'LinearSegmentedColormaps' è un po 'più complessa. (È necessario invertire ogni voce nel dettato '_segmentdata'.) –
Per quanto riguarda l'inversione di' LinearSegmentedColormaps', l'ho appena fatto per alcuni colori. [Ecco un Quaderno IPython su di esso.] (Http://nbviewer.ipython.org/github/kwinkunks/notebooks/blob/master/Matteo_colourmaps.ipynb) – kwinkunks
@kwinkunks penso che la funzione nel tuo quaderno non sia corretta, vedi risposta sotto – Mattijn
Come LinearSegmentedColormaps
si basa su un dizionario di rosso, verde e blu, è necessario invertire ogni voce:
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
vedere che funziona:
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')
ED IT
non capisco il commento di user3445587. Funziona benissimo sulla mappa di colori dell'arcobaleno:
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')
Ma funziona particolarmente piacevole per la personalizzazione mappe di colore dichiarato, in quanto non v'è un difetto _r
per la personalizzazione mappe di colore dichiarato. Seguendo l'esempio tratto da 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')
Questo esempio non è completo nel senso che i dati dei segmenti non devono essere inclusi negli elenchi, quindi non è necessariamente reversibile (ad es. colormap standard arcobaleno). Penso che in linea di principio tutte le LinearSegmentedColormaps dovrebbero essere in grado di essere reversibili usando una funzione lambda come nella colormap arcobaleno? – overseas
@ user3445587 Aggiungo qualche altro esempio, ma penso che funzioni perfettamente sulla colormap dell'arcobaleno standard – Mattijn
Poiché era troppo lungo, ho aggiunto una nuova risposta, che dovrebbe funzionare per tutti i tipi di LinearSegmentData. Il problema è che per rainbow, _segmentdata è implementato in modo diverso. Quindi il tuo codice, almeno sulla mia macchina, non funziona con la mappa colori dell'arcobaleno. – overseas
Ci sono due tipi di LinearSegmentedColormaps. In alcuni, il _segmentdata è dato esplicitamente, ad esempio, per il 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))}
per Rainbow, _segmentdata è dato come segue:
>>> cm.rainbow._segmentdata
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>}
possiamo trovare le funzioni nella fonte di matplotlib, dove sono dati come
_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)
}
Tutto ciò che si desidera è già stato fatto in matplotlib, basta chiamare cm.revcmap, che inverte entrambi i tipi di segmentdata, così
01.235.164,106174 millionsdovrebbe fare il lavoro - si può semplicemente creare un nuovo LinearSegmentData da quello.Nel revcmap, l'inversione della funzione di base SegmentData è fatto con
def _reverser(f):
def freversed(x):
return f(1 - x)
return freversed
mentre le altre liste sono invertiti come al solito
valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)]
Quindi in realtà il tutto si desidera, è
def reverse_colourmap(cmap, name = 'my_cmap_r'):
return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata))
La soluzione è piuttosto semplice. Supponiamo di voler utilizzare lo schema della mappa dei colori "autunnale". La versione standard:
cmap = matplotlib.cm.autumn
Per invertire lo spettro dei colori mappa di colori, utilizzare get_cmap() la funzione e aggiungere '_r' al titolo colormap in questo modo:
cmap_reversed = matplotlib.cm.get_cmap('autumn_r')
Non c'è modo integrato (ancora) di invertire colormaps arbitrarie, ma una soluzione semplice è quella di non modificare la realtà colorbar ma per creare un oggetto invertente Normalizzazione:
from matplotlib.colors import Normalize
class InvertedNormalize(Normalize):
def __call__(self, *args, **kwargs):
return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)
è possibile utilizzare questo con plot_surface
e altre funzioni di tracciamento Matlotlib eseguendo ad es.
inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)
Questo funzionerà con qualsiasi colormap Matplotlib.
C'è ora! https://matplotlib.org/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormap.reversed –
A partire dal Matplotlib 2.0, c'è un metodo per reversed()
ListedColormap
e LinearSegmentedColorMap
oggetti, quindi si può solo fare
cmap_reversed = cmap.reverse()
Vedere here per la documentazione.
Il titolo deve essere "Ripristina" non "Inverti". C'è una differenza! –