Manual de introducción a matplotlib.pyplot (VIII): Texto y anotaciones

Esto pretende ser un tutorial del módulo pyplot de la librería matplotlib. El tutorial lo dividiremos de la siguiente forma (que podrá ir cambiando a medida que vayamos avanzando).

  1. Primeros pasos
  2. Creando ventanas, manejando ventanas y configurando la sesión
  3. Configuración del gráfico
  4. Tipos de gráfico I
  5. Tipos de gráfico II
  6. Tipos de gráfico III
  7. Tipos de gráfico IV
  8. Texto y anotaciones (arrow, annotate, table, text...)
  9. Herramientas estadísticas (acorr, cohere, csd, psd, specgram, spy, xcorr, ...)
  10. Eventos e interactividad (connect, disconnect, ginput, waitforbuttonpress...)
  11. Miscelánea

[Para este tutorial se ha usado python 2.7.1, ipython 0.11, numpy 1.6.1 y matplotlib 1.1.0 ]

[DISCLAIMER: Muchos de los gráficos que vamos a representar no tienen ningún sentido físico y los resultados solo pretenden mostrar el uso de la librería].

En todo momento supondremos que se ha iniciado la sesión y se ha hecho

import matplotlib.pyplot as plt
import numpy as np
plt.ion()

Hasta ahora hemos visto como configurar las ventanas, manejo de las mismas, definir áreas de gráfico, algunos tipos de gráficos... En esta ocasión nos interesa ver como podemos meter anotaciones, tablas,..., en nuestros gráficos.

A lo largo de las anteriores entregas del tutorial hemos podido ver algunas formas de tener anotaciones típicas para el título, los ejes, leyenda,... (title, suptitle, xlabel, ylabel, figtext, legend,...). En este caso vamos a revisar las posibilidades de escribir texto personalizado mediante el uso de plt.text, plt.arrow, plt.annotate y plt.table.

Como caso sencillo para anotar texto en nuestro gráfico podemos usar plt.text. En el siguiente ejemplo vamos a resaltar donde está el valor máximo y el valor mínimo de una serie de datos:

a = np.random.rand(10)  # Creamos una serie de 10 valores pseudo-aleatorios entre 0 y 1
plt.plot(a)  # Los dibujamos
plt.ylim(-0.2, 1.2)  # Definimos el rango de valores para el eje y
plt.text(np.argmin(a), np.min(a) - 0.1, u'Mínimo', fontsize = 10, horizontalalignment='center', verticalalignment='center')  # Colocamos texto cerca del valor donde se encuentra el mínimo
plt.text(np.argmax(a), np.max(a) + 0.1, u'Máximo', fontsize = 10, horizontalalignment='center', verticalalignment='center')  # Colocamos texto cerca del valor donde se encuentra el máximo

El resultado es el siguiente:

Lo que hemos hecho en plt. text es definir la posición del texto con un valor para la x y un valor para la y (en el sistema de referencia de los datos), la cadena de texto a mostrar, como queremos que sea la fuente, donde queremos que vaya colocado, si la queremos rotar, si la queremos en negrita,...

Al anterior ejemplo le podemos incluir una flecha que una el texto con la representación del valor máximo y del valor mínimo. Para ello podemos usar plt.arrow modificando ligeramente el anterior código:

plt.plot(a)
plt.ylim(-0.5, 1.5)  # Extendemos un poco el rango del eje y
plt.text(np.argmax(a), np.max(a) + 0.4, u'Máximo', fontsize = 10, horizontalalignment='center', verticalalignment='center')  # Recolocamos el texto del máximo
plt.text(np.argmin(a), np.min(a) - 0.4, u'Mínimo', fontsize = 10, horizontalalignment='center', verticalalignment='center')  # Recolocamos el texto del mínimo
plt.arrow(np.argmax(a), np.max(a) + 0.3, 0, -0.3, length_includes_head = "True", shape = "full", width=0.07, head_width=0.1)  # Unimos el texto al valor representado
plt.arrow(np.argmin(a), np.min(a) - 0.3, 0, 0.3, length_includes_head = "True", shape = "full", width=0.07, head_width=0.1)  # Unimos el texto al valor representado

El resultado obtenido es el siguiente:

En plt.arrow hemos de definir el origen de la flecha, la distancia desde ese origen hasta el otro extremo de la flecha, si queremos que tenga cabecera, si queremos que la cabecera esté en el origen, el color de la flecha,...

Lo que hemos hecho con plt.text y con plt.arrow lo podemos hacer de forma más compacta y elegante con plt.annotate. Como anteriormente, hacemos uso de un ejemplo y vamos viendo las partes a modificar de plt.annotate:

plt.plot(a)
plt.ylim(-0.5, 1.5)  # Extendemos un poco el rango del eje y
plt.annotate(u'Máximo', xy = (np.argmax(a), np.max(a)), xycoords = 'data', xytext = (np.argmax(a) - 1.5, np.max(a) + 0.4), textcoords = 'data', arrowprops = dict(arrowstyle = "->"))
plt.annotate(u'Mínimo', xy = (np.argmin(a), np.min(a)), xycoords = 'data', xytext = (np.argmin(a) + 1, np.min(a) + 1.2), textcoords = 'data', arrowprops = dict(arrowstyle = "->"))

Siendo el resultado el siguiente:

En plt.annotate introducimos la cadena de caracteres a mostrar, indicamos hacia donde apuntará esa cadena de caracteres (xy, en este caso estamos usando el sistema de referencia de los datos, 'data', pero podemos usar píxeles, puntos,...), la posición del texto (xytext), y como se representará la flecha. Con plt.annotate podemos tener anotaciones elegantes de forma sencilla como puedes ver en estos enlaces [1], [2].

Por último, vamos a ver como podemos dibujar una tabla de forma sencilla. Con plt.table podemos meter rápidamente una tabla pero por defecto la mete debajo del eje x. Vamos a ver un ejemplo que he encontrado en SO donde metemos la tabla dentro de los ejes.

valores = [[np.argmax(a), np.argmin(a)], [np.max(a), np.min(a)]]
etiquetas_fil = ('x', 'y')
etiquetas_col = (u'Máximo', u'Mínimo')
plt.plot(a)
plt.table(cellText=valores, rowLabels=etiquetas_fil, colLabels = etiquetas_col, colWidths = [0.3]*len(a), loc='upper center')

Cuyo resultado es el siguiente:

Donde hemos definido los valores de las celdas internas (cellText), Las etiquetas de filas y columnas (rowLabels y colLabels), el ancho de las celdas y la localización de la tabla.

Y, después de este breve entrada, hemos acabado por hoy haciendo un montón de anotaciones. Si quieres ver las anteriores entregas del tutorial pulsa aquí. Y si quieres ver la nueva entrega tendrás que esperar un poquito (pero muy poquito esta vez, espero).

Kiko Correoso

Licenciado y PhD en Ciencias Físicas, especializado en temas de física, meteorología, climatología, energías renovables, estadística, aprendizaje automático, análisis y visualización de datos. Apasionado de Python y su comunidad. Fundador de pybonacci y editor del sitio en el que se divulga Python, Ciencia y el conocimiento libre en español.

More Posts

Follow Me:
TwitterLinkedIn

2 thoughts on “Manual de introducción a matplotlib.pyplot (VIII): Texto y anotaciones

Leave a Reply