Microentradas: Evitar ciertas etiquetas en la leyenda en Matplotlib

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(0, 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 == 0 else "_esto_no_se_pintará")
    plt.plot(x, y_var2, color = 'g', label = 'variable2' if i == 0 else "_esto_tampoco")
    plt.legend()
    plt.ylim(0, 9)
Espero que a alguien le resulte útil.

Microentrada: Rendimiento de scatterplots en matplotlib

Normalmente, si vas a dibujar pocos puntos en un scatter plot lo normal es usar scatter en matplotlib. Sin embargo, si tienes que dibujar una cantidad considerable de puntos, el rendimiento puede ser un factor importante. Como alternativa se puede usar plot en lugar de scatter.

Veamos un ejemplo muy sencillo de esto y el rendimiento obtenido. vamos a dibujar 100.000 puntos aleatorios y ver los tiempos que obtenemos usando scatter y plot.

Primero importamos las librerías a usar:

import numpy as np
import matplotlib.pyplot as plt
%%matplotlib inline

Creamos 100.000 puntos aleatorios:

x = np.random.rand(100000)
y = np.random.rand(100000)

Veamos lo que tarda un scatter plot

plt.scatter(x,y)
1 loops, best of 3: 598 ms per loop

Y ahora lo mismo pero con un plot normal

plt.plot(x,y, 'bo')
100 loops, best of 3: 9.09 ms per loop

La diferencia entre ambas opciones es:

\(Rendimiento = \frac{scatter}{plot} = \frac{598}{9.09} \approx 65 \)

Motivación de esta entrada: hoy en el trabajo he tenido que escribir unos cuantos paneles de figuras 8x8, es decir, 64 figuras en cada panel, con más de 50.000 datos en cada figura y me ha parecido interesante compartir este pequeño truco que tengo por ahí guardado para estos casos :-)

De matplotlib a la web con plotly

(También podéis seguir las explicaciones de este post con este Notebook)

En esta entrada trataremos de dar a conocer plotly, un servicio web gratuito para generar gráficos interactivos y que permite la creación de proyectos colaborativos.

Los paquetes que vamos a emplear son,

  • pandas 0.14.0, para importar y analizar estructuras de datos en Python.
  • matplotlib 1.3.1, para generar diversisos tipos de gráficos con calidad de imprenta.
  • plotly 1.1.2, para generar gráficos interactivos para la web.

Empezaremos por importar los datos con pandas. Podeis encontrar una introducción a pandas en éste post de Pybonacci.

Datos

La estructura de datos con la que vamos a trajar es un CSV con datos de telemetría correspondientes a un BMW Z4 GT3 compitiendo en el circuito Brands Hatch Indy. El paquete de datos nos lo ha proporcionado Steve Barker, un mecánico que pasa la mayor parte de su tiempo en la GP2. Pero aquí sólo vamos a trabajar con los datos de la vuelta 27 de la primera carrera.

Sigue leyendo!

Dibujando una rosa de frecuencias (reloaded)

Esta entrada es una actualización a la entrada Dibujando una rosa de frecuencias dónde se rehace el código para usar nuevas funcionalidades de matplotlib que simplifica el script.
Imaginaos que estáis de vacaciones en Agosto en la playa y la única preocupación que tenéis es observar las nubes. Como sois un poco frikis y no podéis desconectar de vuestra curiosidad científica decidís apuntar las ocurrencias de la procedencia de las nubes y al final de las vacaciones decidís representar esos datos. La forma más normal de hacerlo sería usando una rosa de frecuencias.
Primero de todo vamos a importar los módulos que nos harán falta:
In [2]:
import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import math

%matplotlib inline

print('Versión de Python usada: ', sys.version)
print('Versión de Numpy usada: ', np.__version__)
print('Versión de Matplotlib usada: ', matplotlib.__version__)
Versión de Python usada:  3.4.1 (v3.4.1:c0e311e010fc, May 18 2014, 10:38:22) [MSC v.1600 32 bit (Intel)]
Versión de Numpy usada:  1.8.1
Versión de Matplotlib usada:  1.3.1

A continuación creamos nuestra muestra de datos totalmente inventada:
In [3]:
## Creamos un conjunto de datos
datos = np.arange(10,90,10)
## Los datos los queremos en tanto por ciento
datos = datos * 100. / datos.sum()
## Direcciones en radianes empezando por el N
## A las direcciones les restamos 22.5º para que las barras
## estén centradas exactamente en 0, 45, 90,...
direcciones = (np.arange(0, 360, 45) - 22.5) * math.pi / 180.
sectores = ['N','NE','E','SE','S','SW','W','NW']
En el bloque anterior de código, lo único que hemos hecho es crear un conjunto de datos sin sentido y los hemos separado en 8 intervalos que pretenden ser las 8 direcciones de donde provienen las nubes empezando por el Norte y en el sentido de las agujas del reloj. Finalmente los datos los expresamos como frecuencia en tanto por ciento en cada una de las 8 direcciones.
Matplotlib nos permite hacer gráficos polares pero estos gráficos están pensados para gráficos en sentido contrario a las agujas del reloj y empezando a las tres en punto (o al este). Por ello debemos modificar como se verán los datos en el gráfico polar. Para ello definimos el tipo de gráfico, colocamos el nombre de la dirección en cada sector definido (en este caso hemos usado 8 sectores), ponemos un título a nuestro gráfico y hemos acabado.
In [4]:
fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(111, polar=True)
## La siguiente línea de código hace que los datos vayan en el 
## sentido de las agujas del reloj
ax.set_theta_direction(-1)
## La siguiente línea de código coloca el 'origen' de la rotación
## donde le indiquemos, en este caso em Norte.
ax.set_theta_zero_location('N')
## Título
ax.set_title('Procedencia de las nubes en agosto (%)')
## Dibujamos los datos
ax.bar(direcciones, datos)
## Colocamos las etiquetas del eje x
ax.set_thetagrids(np.arange(0, 360, 45), sectores, frac = 1.1, fontsize = 10)
Out[4]:
(<a list of 16 Line2D ticklines objects>,
 <a list of 8 Text major ticklabel objects>)
Y listo.
Saludos.

¿Cómo borrar por encima de una línea en matplotlib?

Inauguramos sección nueva en el 2014 con las preguntas que nos llegan de nuestros lectores por las redes sociales o el correo electrónico :) Nos llegan unas cuantas, ¡así que tenemos material para al menos una pregunta semanal! Estas serán entradas breves que publicaremos cada martes y que tratarán de responder vuestras dudas sin rodeos. ¡Si queréis mandar las vuestras no dudéis en contactar con nosotros!

Empezamos con Alberto, que me comenta:

¿Cómo puedo «borrar» lo que tengo por encima de una línea en matplotlib? He intentado con fill_between entre la línea de estabilidad funcional (línea roja) pero solo rellena con color, no sobreescribe que es lo que pretendo. ¿Se te ocurre alguna forma?

Mapa compresor - Primera versión

Alberto está escribiendo un programa para dibujar mapas de actuaciones de turbomáquinas en Python, similares a los que producen programas privativos como GSP (ejemplos) o GasTurb (ejemplos). En esos mapas aparece la línea de estabilidad funcional (surge line o stall line) por encima de la cual la turbomáquina no puede funcionar. Es preciso, por tanto, borrar todo lo que quede por encima de ella para suprimir información innecesaria del gráfico. El código es un poco complicado, así que voy a comentar solo los conceptos fundamentales.

Lo primero que hice (después de admitir que no tenía ni idea) fue intentar trabajar sobre lo que ya había intentado. Efectivamente, si usas la función fill_between el relleno se queda «por debajo» de las líneas que ya había, en lugar de taparlas. Consultando la documentación de fill_between vi que admitía un parámetro zorder, que controla la visibilidad de los elementos de la gráfica: por defecto vale 0, y cuanto mayor es más arriba aparece el elemento. Usando un valor lo suficientemente alto se llega a este resultado:

Mapa compresor - Segunda versión

Que es más o menos lo que se pretendía... pero en mi ordenador se vio el detalle fatal: el color de fondo y la rejilla quedan tapados. Esta solución no es suficiente.

Continue reading

Repaso a PyData 2013

Unos días después de la PyConUS 2013 se celebró la primera PyData del año (creo que serán semestrales de forma regular aunque el tiempo dirá). Entre las charlas había algunas introductorias, otras más avanzadas y otras enseñando aplicaciones prácticas.

Entre las charlas introductorias destacaremos:

Introducción a Numpy por Bryan Van De Ven: si no conoces absolutamente nada de Numpy esta es tu charla. Da un repaso por las cosas más frecuentes del uso de Numpy sin meterse en cosas muy esotéricas. Puedes sacar la libreta e ir apuntando las cosas que creas que te puedan resultar útiles para tus análisis.

Pandas por Wes McKinney: Es una charla introductoria. El problema que veo es que Pandas no es algo tan centrado como Numpy con su ndarray, las posibilidades de uso son múltiples y, quizá, hacer algo introductorio en vídeo sobre Pandas no resulte tan sencillo como  hacerlo con Numpy. En general, la documentación de Pandas es aceptable (aunque incompleta en algunos momentos) y la veo como un buen punto de partida antes de empezar a ver vídeos sobre Pandas. Creo que lo mejor para empezar con Pandas es echarle un ojo al tour de 10 minutos en vídeo o en texto) y luego empezar a trastear con la librería y con la documentación para empezar a entenderlo. Por nuestra parte, estamos preparando nuestro tutorial cuyos primeros capítulos estaran disponibles en breve, stay tuned!!!! En esta conferencia ha habido más vídeos sobre Pandas pero son más avanzados (primero para marujear con datos de forma productiva, segundo (con numpy y statsmodels) para análisis de series temporales) .

Aprendiendo Python por Peter Norvig: Otro tutorial más para empezar con Python!!

Hacer bonitos gráficos con MatPlotLib por Mike Müller: Otro más avanzado muestra como hacer MatPlotLib más interactivo gracias al gran Jake Vanderplas. Os dejamos aquí nuestro tutorial de matplotlib por si alguno no lo conoce aún (#autobombo).

Visualización de datos con NodeBox por Lynn Cherny: Librería para hacer gráficos más 'artísticos'. Yo tengo sentimientos encontrados con algunos enfoques de este tipo de gráficos (NodeBox, D3,...) por lo que te recomiendo mejor verlo y, si alguien quiere, lo discutimos en los comentarios.

Scikit-image por Davin Potts: Creo que esta librería es una de las grandes desconocidas y ofrece unas posibilidades muy interesantes. Si no la conoces deberías echarle un ojo al vídeo.

Entre las que hablan sobre cosas más prácticas y no específicamente de librerías destacaría (alguna no porque me haya gustado especialmente):

Análisis de redes sociales por Katherine Chuang: Estas están muy de moda (teoría de grafos) y están empezando a ser aburridas si no muestran algo excepcional o no sacan conclusiones **medibles** de todo el análisis chachiguay que hacen. Usa NetworkX, también muy de moda.

Plataforma de datos espacio temporales para el océano por André Karpistsenko: Esta me ha parecido interesante ya que muestra todo el pifostio de tecnologías y trabajo que hay detrás de muchas webs a las que voy a descargarme datos para mis análisis.

Hay más charlas avanzadas que hablan de HDF5 ([1]), Machine Learning ([1], [2], [3]), Blaze (el futuro de Numpy), IPython y más cosas del Big Data y herramientas Python para lidiar con ello.

Si le echáis un ojo a algún vídeo, por favor, dejad algún comentario más abajo para saber lo que os ha parecido.

Saludos y espero veros pronto entre esa gran cantidad de datos :-P

Revisión del tutorial de matplotlib.pyplot

El tutorial de matplotlib.pyplot publicado en este blog durante el 2012 ha sido revisado, corregido :-( y publicado con formato notebook de ipython.

Se ha subido el material al repositorio de pybonacci en github por lo que lo podéis descargar, usar, modificar, mejorar,...

Si lo queréis ver online podéis usar el nbviewer de la web de ipython.

P.D.: Nos estamos poniendo al día con lo último en boga de la comunidad científica. Y estad atentos puesto que el notebook de IPython va a seguir pegando fuerte.

Creando una animación con matplotlib y ffmpeg

En esta nueva entrada vamos a ver una revisión rápida al módulo animation en matplotlib, disponible desde la versión 1.1 de matplotlib.

[Para esta entrada se ha usado matplotlib 1.1.1, numpy 1.6.1, ipython 0.13 sobre python 2.7.3 y ffmpeg como librería externa que usará matplotlib para crear el video de la animación (aunque también puede usar mencoder)] todo ello corriendo en linux. Puede que los usuarios de windows tengan problemas al guardar el video si ffmpeg no está instalado y/o correctamente configurado para que matplotlib pueda trabajar con ffmpeg.

Hay varias formas de hacer una animación usando FuncAnimation, ArtistAnimation y/o TimedAnimation. Las dos primeras formas son clases que heredan de la tercera mientras que la tercera hereda de la clase base Animation.

Para este ejemplo de como hacer una animación con matplotlib y ffmpeg vamos a usar FuncAnimation y vamos a representar la evolución de un atractor de Lorenz en 3D.

Continue reading

Visualizando líneas de corriente en Python con matplotlib

Introducción

Hoy vamos a ver cómo representar diagramas de corriente en Python usando matplotlib. Este tipo de diagramas aparecen en Mecánica de Fluidos para visualizar el movimiento del fluido que estamos estudiando.

Hace unos días nos hicimos eco en Pybonacci de que se había liberado matplotlib 1.2.0, que introducía entre otras cosas soporte para Python 3 y la nueva función streamplot:

Así que vamos a estrenar las entradas con Python 3.3 y matplotlib 1.2 con un bonito ejemplo de Aerodinámica básica :) El ejemplo y las gráficas están basados en la página de la Wikipedia sobre flujo potencial alrededor de un cilindro circular.

En esta entrada se han usado python 3.3.0, numpy 1.7.0b2 y matplotlib 1.2.0.

Continue reading

Repaso a la EuroScipy 2012

Como todos sabéis, hace un par de semanas se celebró la Euroscipy 2012 con mucho material interesante que repasar. Voy a hablar de los que tienen algo de material para poder juzgar sobre algo.

Tutoriales básicos para científicos (o no):

Tutoriales avanzados (estos sí que son más bien para científicos):

Charlas (solo alguna puesto que otras no tocan mi campo de acción y no he perdido mucho tiempo con ellas y no podría opinar con rigor):

Espero que le echéis un vistazo a todo ese gran material, que nos contéis si lo usáis y como, que nos aviséis si veis los vídeos o material complementario y que disfrutéis tanto como yo :-)

Hasta la próxima.