¿Cómo obtener diferentes líneas de color para diferentes parcelas en una sola figura?

202

Estoy usando matplotlibpara crear las tramas. Tengo que identificar cada parcela con un color diferente que Python debería generar automáticamente.

¿Me puede dar un método para poner diferentes colores para diferentes parcelas en la misma figura?

pottigopi
fuente

Respuestas:

424

Matplotlib hace esto por defecto.

P.ej:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.show()

Parcela básica que muestra el ciclo del color.

Y, como ya sabrá, puede agregar fácilmente una leyenda:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

Trama básica con leyenda

Si desea controlar los colores que se recorrerán a través de:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.gca().set_color_cycle(['red', 'green', 'blue', 'yellow'])

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

Gráfico que muestra control sobre el ciclo de color predeterminado

Si no está familiarizado con matplotlib, el tutorial es un buen lugar para comenzar .

Editar:

En primer lugar, si tiene muchas (> 5) cosas que desea trazar en una figura, ya sea:

  1. Póngalos en diferentes parcelas (considere usar algunas subtramas en una figura), o
  2. Use algo que no sea color (es decir, estilos de marcador o grosor de línea) para distinguir entre ellos.

De lo contrario, terminarás con un muy trama desordenada! ¡Sé amable con quien va a leer lo que sea que estés haciendo y no intentes meter 15 cosas diferentes en una sola figura!

Más allá de eso, muchas personas son daltónicas en diversos grados, y distinguir entre numerosos colores sutilmente diferentes es difícil para más personas de lo que puede imaginar.

Dicho esto, si realmente quieres poner 20 líneas en un eje con 20 colores relativamente distintos, aquí hay una forma de hacerlo:

import matplotlib.pyplot as plt
import numpy as np

num_plots = 20

# Have a look at the colormaps here and decide which one you'd like:
# http://matplotlib.org/1.2.1/examples/pylab_examples/show_colormaps.html
colormap = plt.cm.gist_ncar
plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))

# Plot several different functions...
x = np.arange(10)
labels = []
for i in range(1, num_plots + 1):
    plt.plot(x, i * x + 5 * i)
    labels.append(r'$y = %ix + %i$' % (i, 5*i))

# I'm basically just demonstrating several different legend options here...
plt.legend(labels, ncol=4, loc='upper center', 
           bbox_to_anchor=[0.5, 1.1], 
           columnspacing=1.0, labelspacing=0.0,
           handletextpad=0.0, handlelength=1.5,
           fancybox=True, shadow=True)

plt.show()

Colores únicos para 20 líneas basadas en un mapa de colores dado

Joe Kington
fuente
17
Tenga en cuenta para el último ejemplo, en las versiones más recientes de matplotlib, el set_color_cycleha quedado en desuso, por lo que esa línea debería ser plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))y solo cambiarla plt.cm.YOUR_PREFERED_COLOR_MAPpara satisfacer sus necesidades.
Nate
1
@ JoeKington: La explicación fue maravillosa, muchas gracias
Rika
esto es genial. ¿Hay alguna manera de hacerlos interactivos? por ejemplo, en RI, convierta ggplot en ggplotly (), y la trama se vuelve interactiva html
kRazzy R
Estoy convencido de que el OP sabía que Matplotlib colorea apropiadamente diferentes curvas en una sola parcela (en una sola axes) y me preguntó sobre la variación del color de una sola línea en diferentes parcelas (diferentes axes) ... Dicho esto, excelente respuesta a una importante pregunta (posiblemente diferente de lo que OP preguntó, ¡pero nadie puede decirlo porque hicieron esta sola pregunta y desaparecieron!) - +1
gboffi
37

Poniéndolos luego

Si no sabe el número de parcelas que va a trazar, puede cambiar los colores una vez que los haya trazado recuperando el número directamente de la trama usando .lines, utilizo esta solución:

Algunos datos al azar

import matplotlib.pyplot as plt
import numpy as np

fig1 = plt.figure()
ax1 = fig1.add_subplot(111)


for i in range(1,15):
    ax1.plot(np.array([1,5])*i,label=i)

El código que necesitas:

colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired   
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]
for i,j in enumerate(ax1.lines):
    j.set_color(colors[i])
  

ax1.legend(loc=2)

El resultado es el siguiente:ingrese la descripción de la imagen aquí

GM
fuente
8

TL; DR No, no se puede hacer automáticamente . Sí, es posible.

import matplotlib.pyplot as plt
my_colors = plt.rcParams['axes.prop_cycle']() # <<< note that we CALL the prop_cycle
fig, axes = plt.subplots(2,3)
for ax in axes.flatten(): ax.plot((0,1), (0,1), **next(my_colors))

ingrese la descripción de la imagen aquí Cada gráfico ( axes) en una figura ( figure) tiene su propio ciclo de colores: si no fuerza un color diferente para cada gráfico, todos los gráficos comparten el mismo orden de colores pero, si estiramos un poco, qué significa "automáticamente" , se puede hacer.


El OP escribió

[...] Tengo que identificar cada parcela con un color diferente que debería ser generado automáticamente por [Matplotlib].

Pero ... Matplotlib genera automáticamente diferentes colores para cada curva diferente

In [10]: import numpy as np
    ...: import matplotlib.pyplot as plt

In [11]: plt.plot((0,1), (0,1), (1,2), (1,0));
Out[11]:

ingrese la descripción de la imagen aquí

Entonces, ¿por qué la solicitud de OP? Si continuamos leyendo, tenemos

¿Me puede dar un método para poner diferentes colores para diferentes parcelas en la misma figura?

y tiene sentido, porque cada trama (cada axes en el lenguaje de Matplotlib) tiene su propia color_cycle(o más bien, en 2018, su prop_cycle) y cada trama ( axes) reutiliza los mismos colores en el mismo orden.

In [12]: fig, axes = plt.subplots(2,3)

In [13]: for ax in axes.flatten():
    ...:     ax.plot((0,1), (0,1))

ingrese la descripción de la imagen aquí

Si este es el significado de la pregunta original, una posibilidad es nombrar explícitamente un color diferente para cada parcela.

Si las parcelas (como sucede a menudo) se generan en un bucle, debemos tener una variable de bucle adicional para anular el color elegido automáticamente por Matplotlib.

In [14]: fig, axes = plt.subplots(2,3)

In [15]: for ax, short_color_name in zip(axes.flatten(), 'brgkyc'):
    ...:     ax.plot((0,1), (0,1), short_color_name)

ingrese la descripción de la imagen aquí

Otra posibilidad es instanciar un objeto ciclador

from cycler import cycler
my_cycler = cycler('color', ['k', 'r']) * cycler('linewidth', [1., 1.5, 2.])
actual_cycler = my_cycler()

fig, axes = plt.subplots(2,3)
for ax in axes.flat:
    ax.plot((0,1), (0,1), **next(actual_cycler))

ingrese la descripción de la imagen aquí

Tenga en cuenta que type(my_cycler)es cycler.Cyclerperotype(actual_cycler) es itertools.cycle.

gboffi
fuente
3

Me gustaría ofrecer una mejora menor en la última respuesta de bucle dada en la publicación anterior (esa publicación es correcta y aún debe ser aceptada). La suposición implícita hecha al etiquetar el último ejemplo es que plt.label(LIST)coloca el número de etiqueta X en LISTla línea correspondiente a la Xa vez que plotse llamó. Me he encontrado con problemas con este enfoque antes. La forma recomendada de construir leyendas y personalizar sus etiquetas según la documentación de matplotlibs ( http://matplotlib.org/users/legend_guide.html#adjusting-the-order-of-legend-item ) es tener una sensación cálida de que las etiquetas se van junto con las tramas exactas que crees que hacen:

...
# Plot several different functions...
labels = []
plotHandles = []
for i in range(1, num_plots + 1):
    x, = plt.plot(some x vector, some y vector) #need the ',' per ** below
    plotHandles.append(x)
    labels.append(some label)
plt.legend(plotHandles, labels, 'upper left',ncol=1)

**: Matplotlib Legends no funciona

Tommy
fuente
3
Solo para tu información: también puedes usar la "etiqueta" kwarg para trazar y luego llamar a la leyenda sin ningún argumento.
Joe Kington