2012-01-19 40 views
53

¿Cómo se establece el color de una línea en matplotlib con valores escalares proporcionados en tiempo de ejecución usando un mapa de color (digamos jet)? Probé un par de enfoques diferentes aquí y creo que estoy perplejo. values[] es una matriz almacenada de escalares. las curvas son un conjunto de matrices de 1-d, y las etiquetas son una matriz de cadenas de texto. Cada una de las matrices tiene la misma longitud.Uso de Colormaps para establecer el color de la línea en 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() 

Respuesta

66

El error que está recibiendo es debido a cómo se defina jet. Está creando la clase base Colormap con el nombre 'jet', pero esto es muy diferente de obtener la definición predeterminada del mapa de colores 'jet'. Esta clase base nunca se debe crear directamente, y solo se deben crear instancias de las subclases.

Lo que ha encontrado con su ejemplo es un comportamiento con errores en Matplotlib. Debería haber un mensaje de error más claro generado cuando se ejecuta este código.

Ésta es una versión actualizada de su ejemplo:

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

lo que resulta en:

enter image description here

El uso de un ScalarMappable es una mejora sobre el enfoque presentado en mi respuesta relacionada: creating over 20 unique legend colors using matplotlib

35

Pensé que sería beneficioso incluir w Creo que es un método más simple que usa el linspace de numpy junto con el objeto de tipo cm de matplotlib. Es posible que la solución anterior sea para una versión anterior. Estoy usando python 3.4.3, matplotlib 1.4.3 y numpy 1.9.3., Y mi solución es la siguiente.

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

Esto da como resultado 1000 líneas de colores únicos que abarcan todo el mapa de colores cm.jet como se muestra a continuación. Si ejecuta este script, verá que puede acercarse a las líneas individuales.

cm.jet between 0.0 and 1.0 with 1000 graduations

Ahora dicen que quiero que mis colores de las líneas 1000 a solo abarcan la parte verdosa entre las líneas 400 a 600. Simplemente cambiar mis valores inicial y final de 0,4 y 0,6 y esto se traduce en el uso de sólo el 20% de el mapa de color cm.jet entre 0,4 y 0,6.

cm.jet between 0.4 and 0.6 with 1000 graduations

Así que en un resumen de una línea puede crear una lista de colores RGBA de un matplotlib.cm mapa de colores en consecuencia:

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

En este caso utilizo el mapa llamado chorro comúnmente invocado pero se puede encontrar la lista completa de mapas de colores disponibles en su versión matplotlib invocando:

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

Esto solo funciona porque tu 'stop' es 1 – Eric

+1

Por supuesto que 1 es el mejor valor. Si desea una gama más amplia de colores, todo lo que necesita hacer es aumentar 'number_of_lines'. Y en el caso de que solo desee una porción de los colores en la banda, reducirá 'stop' e incrementará' start' según sea necesario. – Parousia

+0

Una pregunta rápida: ¿cómo agregar barra de color en lugar de leyenda a su trazado? –

7

Una combinación de línea estilos, marcadores, colores y cualitativos de 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

Cuestiones relacionadas