2012-03-16 11 views
5

Estoy empezando con la pila scipy. Estoy usando el conjunto de datos del iris, en una versión CSV. Puedo cargarlo bien usando:Pylab: asignar etiquetas a los colores

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

y la trama que:

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

Ahora me gustaría trazar las clases, que se almacenan en iris.field(4):

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

¿Cuál es una manera elegante de asignar estas cadenas a los colores para trazar? scatter(iris.field(0), iris.field(1), c=iris.field(4)) no funciona (de los documentos espera valores flotantes o un mapa de colores). No he encontrado una manera elegante de generar automáticamente un mapa de color.

cols = {"versicolor": "blue", "virginica": "green", "setosa": "red"} 
scatter(iris.field(0), iris.field(1), c=map(lambda x:cols[x], iris.field(4))) 

hace aproximadamente lo que quiero, pero no me gusta demasiado la especificación de color manual.

Edición: versión ligeramente más elegante de la última línea:

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

Respuesta

4

Por si sirve de algo, normalmente se haría algo más parecido a esto en ese 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

No hay nada malo con lo que sugirió @Yann, pero scatter es más adecuado para la administración continua datos.

Es más fácil confiar en el ciclo de color de los ejes y simplemente llamar al trazado varias veces (también obtiene artistas separados en lugar de una colección, lo que es bueno para datos discretos como este).

Por defecto, el ciclo de color para un eje es: azul, verde, rojo, cian, magenta, amarillo, negro.

después de 7 llamadas a plot, que serán ciclo hacia atrás sobre esos colores, por lo que si usted tiene más elementos, que necesitará para set it manually (o simplemente especificar el color en cada llamada a plot utilizando una barra de colores interpolados similar a lo que @ Yann sugirió arriba).

+0

Gracias. Vi la opción de trazado múltiple, pero aún no sabía el elegante truco de condición que usaste aquí (+1). Tengo que estar en desacuerdo sobre 'scatter'. A mi entender, es exactamente para este tipo de tramas, donde los puntos son independientes y no están conectados (que se trabaja mediante el establecimiento de 'linestyle =" none "') –

+0

El punto 'plot' vs' scatter' es un desafortunado y Malentendido común. Usa 'plot' para trazar puntos, y usa' scatter' para trazar cosas cuando necesites variar continuamente el tamaño y/o el color de los marcadores basados ​​en una tercera o cuarta variable. 'scatter' devuelve una colección que es mucho más difícil de administrar. 'plot' _really is_ pretende trazar puntos desconectados, el valor predeterminado simplemente es una línea. Si quieres una llamada más concisa, 'plt.plot (x, y, 'o')' hará lo mismo que 'plt.plot (x, y, linestyle = 'none', marker = 'o')' . –

+0

Gracias. Yo uso 'np.unique (iris.field (4))' (ya que mi CSV no tiene una fila de etiqueta de columna). Pero aparte de eso, ahora esencialmente estoy usando tu código. Me gusta mucho el truco de la condición. –

5

Ya sea una manera elegante es o no es algo subjetivo. Personalmente, considero que su enfoque es mejor que el método 'matplotlib'. De color módulo de matplotlib:

asignación de color típicamente implica dos pasos: una matriz de datos es primero mapeadas a la gama de 0-1 usando una instancia de normalizar o de una subclase ; luego, este número en el rango 0-1 se asigna a un color usando una instancia de una subclase de Colormap.

Lo que tomo de esto con respecto a su problema es que necesita una subclase de Normalize que toma cadenas y las asigna a 0-1.

He aquí un ejemplo que hereda de Normalize para crear una subclase TextNorm, que se utiliza para convertir una cadena en un valor de 0 a 1. Esta normalización se utiliza para obtener un color correspondiente.

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() 

Esto produce:

enter image description here

Elegí el mapa de color 'RdYlGn' por lo que era fácil distinguir entre los tres tipos de puntos. No incluí la característica clip como parte de __call__, aunque es posible con algunas modificaciones.

Tradicionalmente se puede probar la normalización del método scatter usando la palabra clave norm, pero scatter pone a prueba la palabra clave c para ver si se almacena cadenas, y si lo hace, entonces se supone que está pasando en colores como sus valores de cadena, p.ej 'Rojo', 'Azul', etc. Por lo tanto, se produce un error al llamar al plt.scatter(iris.field(0), iris.field(1), c=iris.field(4), cmap='RdYlGn', norm=norm). En su lugar, simplemente uso el TextNorm y "opero" en el iris.field(4) para devolver una matriz de valores que van de 0 a 1.

Tenga en cuenta que se devuelve un valor de -1 para un sting no en la lista textvals. Aquí es donde el enmascaramiento sería útil.

+0

Estoy trabajando en un ejemplo .... – Yann

+0

Como acabo de hacer lo mismo en 'R' (tratando de hacer una descripción general de las herramientas), me preguntaba si existe un equivalente de' unclass' en ' scipy'. –

+0

@ Anony-Mousse No estoy seguro de lo que está preguntando en su comentario. ¿Cómo usarías 'unclass' y en qué lo usarías? – Yann

Cuestiones relacionadas