2012-03-16 11 views
5

Sto appena iniziando con lo stack scipy. Sto usando il set di dati dell'iride, in una versione CSV. Posso caricarlo bene con:Pylab: mappare le etichette sui colori

iris=numpy.recfromcsv("iris.csv") 

e tracciarla:

pylab.scatter(iris.field(0), iris.field(1)) 
pylab.show() 

Ora vorrei tracciare anche le classi, che sono immagazzinati in iris.field(4):

chararray(['setosa', ...], dtype='|S10') 

Qual è un modo elegante per mappare queste stringhe a colori per la stampa? scatter(iris.field(0), iris.field(1), c=iris.field(4)) non funziona (dai documenti si aspetta valori float o una mappa di colori). Non ho trovato un modo elegante per generare automaticamente una mappa dei colori.

fa approssimativamente quello che voglio, ma non mi piace troppo le specifiche del colore manuale.

Edit: un po 'la versione più elegante dell'ultima riga:

scatter(iris.field(0), iris.field(1), c=map(cols.get, iris.field(4))) 

risposta

4

Per quel che vale, tipicamente si dovrebbe fare qualcosa di più simile in questo caso:

import numpy as np 
import matplotlib.pyplot as plt 

iris = np.recfromcsv('iris.csv') 
names = set(iris['class']) 

x,y = iris['sepal_length'], iris['sepal_width'] 

for name in names: 
    cond = iris['class'] == name 
    plt.plot(x[cond], y[cond], linestyle='none', marker='o', label=name) 

plt.legend(numpoints=1) 
plt.show() 

enter image description here

Non c'è niente di sbagliato in quello che @Yann suggerito, ma scatter è più adatto per continua dati.

È più semplice fare affidamento sul ciclo del colore degli assi e basta chiamare la trama più volte (si ottengono anche artisti separati anziché una raccolta, il che è una buona cosa per dati discreti come questo).

Per impostazione predefinita, il ciclo del colore per un asse è: blu, verde, rosso, ciano, magenta, giallo, nero.

dopo 7 chiamate a plot, sarà ciclo di ripercorrere quei colori, quindi se avete più elementi, è necessario set it manually (o semplicemente specificare il colore in ogni chiamata a plot utilizzando un colorbar interpolato simile a quello che @ Yann ha suggerito sopra).

+0

Grazie. Ho visto l'opzione del plottaggio multiplo, ma non ero ancora a conoscenza dell'elegante trucco di condizione che hai usato qui (+1). Non sono d'accordo su 'scatter'. A mio modo di vedere, è esattamente inteso per questo tipo di trame, dove i punti sono indipendenti e non connessi (che si aggira impostando 'linestyle =" none "') –

+0

Il punto 'plot' vs' scatter' è uno sfortunato e malinteso comune. Usa 'trama' per tracciare i punti, e usa solo' scatter' per tracciare le cose quando hai bisogno di variare continuamente le dimensioni e/o il colore dei marcatori in base a una 3a o 4a variabile. 'scatter' restituisce una collezione che è molto più difficile da gestire. 'plot' _really is_ ha lo scopo di tracciare punti disconnessi, l'impostazione predefinita è una linea. Se vuoi una chiamata più concisa, 'plt.plot (x, y, 'o')' farà la stessa cosa di 'plt.plot (x, y, linestyle = 'none', marker = 'o')' . –

+0

Grazie. Io uso 'np.unique (iris.field (4))' (dato che il mio CSV non ha una riga di etichetta di colum). Ma a parte questo, ora sto usando essenzialmente il tuo codice. Mi piace molto il trucco delle condizioni. –

5

Che modo è elegante o non è un po' soggettiva. Personalmente trovo i tuoi approcci migliori rispetto al modo "matplotlib". Dal modulo di matplotlib color:

color mapping tipicamente comprende due fasi: una schiera di dati è il primo mappata sulla gamma 0-1 utilizzando un'istanza Normalizza o di una sottoclasse ; quindi questo numero nell'intervallo 0-1 viene mappato su un colore usando un'istanza di una sottoclasse di Colormap.

quello che prendo da questo per quanto riguarda il vostro problema è che hai bisogno di una sottoclasse di Normalize che prende le stringhe e li mappa per 0-1.

Ecco un esempio che eredita da Normalize per creare una sottoclasse TextNorm, che viene utilizzata per convertire una stringa in un valore compreso tra 0 e 1. Questa normalizzazione viene utilizzata per ottenere un colore corrispondente.

import matplotlib.pyplot as plt 
from matplotlib.colors import Normalize 
import numpy as np 
from numpy import ma 

class TextNorm(Normalize): 
    '''Map a list of text values to the float range 0-1''' 

    def __init__(self, textvals, clip=False): 
     self.clip = clip 
     # if you want, clean text here, for duplicate, sorting, etc 
     ltextvals = set(textvals) 
     self.N = len(ltextvals) 
     self.textmap = dict(
      [(text, float(i)/(self.N-1)) for i, text in enumerate(ltextvals)]) 
     self.vmin = 0 
     self.vmax = 1 

    def __call__(self, x, clip=None): 
     #Normally this would have a lot more to do with masking 
     ret = ma.asarray([self.textmap.get(xkey, -1) for xkey in x]) 
     return ret 

    def inverse(self, value): 
     return ValueError("TextNorm is not invertible") 

iris = np.recfromcsv("iris.csv") 
norm = TextNorm(iris.field(4)) 

plt.scatter(iris.field(0), iris.field(1), c=norm(iris.field(4)), cmap='RdYlGn') 
plt.savefig('textvals.png') 
plt.show() 

Questo produce:

enter image description here

ho scelto il 'RdYlGn' mappa dei colori in modo che fosse facile distinguere tra i tre tipi di punti. Non ho incluso la funzione clip come parte di __call__, sebbene sia possibile con alcune modifiche.

Tradizionalmente si può testare la normalizzazione del metodo scatter utilizzando la parola chiave norm, ma scatter test la parola c per vedere se memorizza le stringhe, e se lo fa, allora assume siete di passaggio in colori come i loro valori di stringa, per esempio 'Rosso', 'Blu', ecc. Quindi chiamare plt.scatter(iris.field(0), iris.field(1), c=iris.field(4), cmap='RdYlGn', norm=norm) fallisce. Invece uso semplicemente lo TextNorm e "opero" sullo iris.field(4) per restituire un array di valori compreso tra 0 e 1.

Si noti che un valore di -1 viene restituito per una puntura non nell'elenco textvals. Questo è dove il mascheramento sarebbe utile.

+0

Sto lavorando a un esempio .... – Yann

+0

Poiché ho appena fatto lo stesso in 'R' (cercando di fare una panoramica degli strumenti), mi chiedevo se c'è un equivalente di' unclass' in ' scipy'. –

+0

@ Anony-Mousse Non sono sicuro di cosa stai chiedendo nel tuo commento. Come useresti 'unclass' e su cosa lo useresti. – Yann

Problemi correlati