2012-01-19 10 views
53

Come si imposta il colore di una linea in matplotlib con i valori scalari forniti in fase di esecuzione utilizzando una mappa di colori (ad esempio jet)? Ho provato un paio di approcci diversi qui e penso di essere perplesso. values[] è una matrice storta di scalari. le curve sono un insieme di matrici 1-d e le etichette sono un array di stringhe di testo. Ciascuno degli array ha la stessa lunghezza.Utilizzo di Colormaps per impostare il colore della linea in matplotlib

fig = plt.figure() 
ax = fig.add_subplot(111) 
jet = colors.Colormap('jet') 
cNorm = colors.Normalize(vmin=0, vmax=values[-1]) 
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet) 
lines = [] 
for idx in range(len(curves)): 
    line = curves[idx] 
    colorVal = scalarMap.to_rgba(values[idx]) 
    retLine, = ax.plot(line, color=colorVal) 
    #retLine.set_color() 
    lines.append(retLine) 
ax.legend(lines, labels, loc='upper right') 
ax.grid() 
plt.show() 

risposta

66

L'errore che si riceve è dovuto al modo in cui si definisce jet. Stai creando la classe base Colormap con il nome 'jet', ma questo è molto diverso dall'ottenere la definizione predefinita della mappa colori 'jet'. Questa classe base non dovrebbe mai essere creata direttamente, e solo le sottoclassi dovrebbero essere istanziate.

Quello che hai trovato con il tuo esempio è un comportamento bacato in Matplotlib. Ci dovrebbe essere un messaggio di errore più chiaro generato quando viene eseguito questo codice.

Si tratta di una versione aggiornata del vostro esempio:

import matplotlib.pyplot as plt 
import matplotlib.colors as colors 
import matplotlib.cm as cmx 
import numpy as np 

# define some random data that emulates your indeded code: 
NCURVES = 10 
np.random.seed(101) 
curves = [np.random.random(20) for i in range(NCURVES)] 
values = range(NCURVES) 

fig = plt.figure() 
ax = fig.add_subplot(111) 
# replace the next line 
#jet = colors.Colormap('jet') 
# with 
jet = cm = plt.get_cmap('jet') 
cNorm = colors.Normalize(vmin=0, vmax=values[-1]) 
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet) 
print scalarMap.get_clim() 

lines = [] 
for idx in range(len(curves)): 
    line = curves[idx] 
    colorVal = scalarMap.to_rgba(values[idx]) 
    colorText = (
     'color: (%4.2f,%4.2f,%4.2f)'%(colorVal[0],colorVal[1],colorVal[2]) 
     ) 
    retLine, = ax.plot(line, 
         color=colorVal, 
         label=colorText) 
    lines.append(retLine) 
#added this to get the legend to work 
handles,labels = ax.get_legend_handles_labels() 
ax.legend(handles, labels, loc='upper right') 
ax.grid() 
plt.show() 

conseguente:

enter image description here

Utilizzando un ScalarMappable è un miglioramento rispetto all'approccio presentato nella mia risposta correlato: creating over 20 unique legend colors using matplotlib

35

Ho pensato che sarebbe stato utile includere w mi considero un metodo più semplice che usa lo spionaggio di numpy accoppiato con l'oggetto di tipo cm di matplotlib. È possibile che la soluzione di cui sopra sia per una versione precedente. Sto usando python 3.4.3, matplotlib 1.4.3 e numpy 1.9.3. E la mia soluzione è la seguente.

import matplotlib.pyplot as plt 

from matplotlib import cm 
from numpy import linspace 

start = 0.0 
stop = 1.0 
number_of_lines= 1000 
cm_subsection = linspace(start, stop, number_of_lines) 

colors = [ cm.jet(x) for x in cm_subsection ] 

for i, color in enumerate(colors): 
    plt.axhline(i, color=color) 

plt.ylabel('Line Number') 
plt.show() 

Ciò provoca 1000 linee univocamente colorate che coprono l'intera mappa colori cm.jet come illustrato di seguito. Se esegui questo script, scoprirai che puoi ingrandire le singole linee.

cm.jet between 0.0 and 1.0 with 1000 graduations

Ora dicono Voglio che i miei 1000 colori di linea per appena coprono la porzione di verde tra le linee 400 e 600. Ho semplicemente cambiare il mio start e stop valori di 0,4 e 0,6 e questo si traduce in utilizzando solo il 20% la mappa dei colori cm.jet tra 0,4 e 0,6.

cm.jet between 0.4 and 0.6 with 1000 graduations

Quindi, in una sintesi di una linea che si può creare un elenco di colori RGBA da un matplotlib.cm colormap di conseguenza:

colors = [ cm.jet(x) for x in linspace(start, stop, number_of_lines) ] 

In questo caso io uso la carta di nome del getto comunemente invocato ma è possibile trovare l'elenco completo delle mappe di colori disponibili nella versione matplotlib invocando:

>>> from matplotlib import cm 
>>> dir(cm) 
+0

Funziona solo perché il tuo 'stop' è 1 – Eric

+1

Ovviamente 1 è il valore migliore. Se vuoi una gamma di colori più ampia, tutto ciò che devi fare è aumentare "numero_di_linea". E nel caso in cui si desideri solo una parte dei colori nella banda si riduce 'stop' e si aumenta' start' secondo necessità. – Parousia

+0

Una domanda veloce: come aggiungere la colorbar invece della legenda alla trama? –

7

Una combinazione di linea stili, pennarelli, colori e qualitativi da matplotlib:

import itertools 
import matplotlib as mpl 
import matplotlib.pyplot as plt 
N = 8*4+10 
l_styles = ['-','--','-.',':'] 
m_styles = ['','.','o','^','*'] 
colormap = mpl.cm.Dark2.colors # Qualitative colormap 
for i,(marker,linestyle,color) in zip(range(N),itertools.product(m_styles,l_styles, colormap)): 
    plt.plot([0,1,2],[0,2*i,2*i], color=color, linestyle=linestyle,marker=marker,label=i) 
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.,ncol=4); 

enter image description here

Problemi correlati