A veces, me llegan ficheros de datos con datos cada hora o cada día y los quiero representar en un plot. Para ello, podría acumular los ficheros en uno solo y luego pintarlo pero como lo debo hacer en ‘tiempo casi-real’ se puede meter todo en un bucle while
que espera los ficheros cada hora/día/lo que sea y va pintando cada variable por tramos. Por ejemplo, una aproximación podría ser la siguiente:
import numpy as np import matplotlib.pyplot as plt plt.style.use('bmh') %matplotlib inline plt.figure(figsize = (12, 6)) for i in range(10): x = np.arange(i * 10, i * 10 + 10) y_var1 = np.random.randint(1, 5, 10) y_var2 = np.random.randint(5, 8, 10) plt.plot(x, y_var1, color = 'k', label = 'variable1') plt.plot(x, y_var2, color = 'g', label = 'variable2') plt.legend() plt.ylim(, 9)
Como véis, en la gráfica anterior hay varios problemas pero como esta es una MicroEntrada solo nos vamos a centrar en el problema de las etiquetas repetidas en la leyenda.
¿Cómo podríamos evitar el meter tantas veces una etiqueta repetida?¶
Mi problema es que el bucle es o podría ser ‘infinito’ y tengo que inicializar las etiquetas de alguna forma. Si miro en esta respuesta encontrada en Stackoverflow dice que en la documentación se indica que “If label attribute is empty string or starts with “_”, those artists will be ignored.” pero si busco aquí o en el enlace que indican en la respuesta en Stackoverflow no veo esa funcionalidad indicada en ningún sitio. Eso es porque aparecía en la versión 1.3.1 pero luego desapareció… Sin embargo podemos seguir usando esa funcionalidad aunque actualmente no esté documentada:
plt.figure(figsize = (12, 6)) for i in range(10): x = np.arange(i * 10, i * 10 + 10) y_var1 = np.random.randint(1, 5, 10) y_var2 = np.random.randint(5, 8, 10) plt.plot(x, y_var1, color = 'k', label = 'variable1' if i == else "_esto_no_se_pintará") plt.plot(x, y_var2, color = 'g', label = 'variable2' if i == else "_esto_tampoco") plt.legend() plt.ylim(, 9)
Espero que a alguien le resulte útil.
He seguido la pista y he encontrado la información en el método legend() de Axes (http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.legend). Lo interesante es que indica que es el comportamiento por defecto, por lo que, en lugar de pasar al “artista” las etiquetas como argumentos, puede ser mejor asignárselas a través del método set_label únicamente para las dos primeras líneas:
(Por si no se ve bien, dejo también el código en https://gist.github.com/chemacortes/74a238cd5ae19fd78bf320581fe4d126)
Tu forma es más POO y, considero, más correcta, solo he indicado un ejemplo rápido y práctico para indicar el comportamiento.
En el enlace que indicas sigo sin encontrar la información completa de este comportamiento. Supongo que te refieres a esta línea: “Specific lines can be excluded from the automatic legend element selection by defining a label starting with an underscore.”, pero ahí no indica nada de strings vacios.
Tambien se podría usar el método “Axes.get_legend_handles_labels” (http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.get_legend_handles_labels) pero no permitiría hacerlo a priori o dinámicamente, solo una vez que ya dispones de todas las labels para legend o, si se hace dinámico, supongo que sería bastante costoso obtener los ‘handles’ y ‘labels’ en cada iteración. Aunque si esperas una hora/día a que te llegue el fichero igual no es un problema 😛
No, qué va. Más POO sería así:
Ya, ya, me refería a que usas los métodos de los objetos de matplotlib en lugar de usar, principalmente, el estilo de funciones de
pyplot