Primero: Para ver todo el código en un notebook de jupyter solo da clic aquí

Graficar es una de las cosas más útiles que podemos aprender en nuestro camino a ser data scientists. Nos permite visualizar de forma sencilla y rápida data, hacer predicciones y a ver todo de forma más clara.

Así que vamos a intentar aprender los básico para graficar con la librería matplotlib.

Vamos a empezar con algo super sencillo y es el gráfico de líneas

  1. Importamos las librerias necesarias 
import numpy as np
import matplotlib.pyplot as plt

Ahora supongamos que necesitamos un gráfico que muestre el tiempo usado por día para hacer ejercicio por una semana, los datos van a estar por minutos.

2. Creamos una lista con los tiempos 

tiempo = [50, 100, 30, 65, 30, 0, 6]

3. Ahora con matplotlib podemos dibujar un gráfico a partir de esta lista

plt.plot(tiempo)

Super easy peasy ¿No creen?

Este gráfico tiene dos ejes, el horizontal (X) con 7 números de 0 a 6 y el vertical con los tiempos (Y) que empieza con el mínimo 0 hasta el máximo 100. Estos números corresponden a los índices de los valores en la lista y matplotlib genera una escala a partir de ellos.

Así pues podemos crear gráficos a partir de listas pero también podemos hacerlo con arrays de numpy, ahí está gracia de todo. 

Por ejemplo podemos generar un array aleatorio de tiempo usado para hacer ejercicio en el último mes (30 días)

tiempo = np.random.randint(100, size=[30])
plt.plot(tiempo)

Como puedes ver con numpy tenemos una forma perfecta de generar valores aleatorios para nuestros gráficos. 

Ahora, que ya tenemos claro como gráficas, vamos a trabajar con los ejes

Aquí vamos a:

  •  Mapear texto en los ejes numéricos.
  • A trabajar con el eje X y el eje Y.
  • A crear gráficos con los ejes invertidos.

¡Suena divertido! 

Primero mapeamos: 

Por defecto en los gráficos no podemos mostrar texto en los ejes porque estos se basan en valores numéricos.

Lo que podemos hacer es mapear los textos a mostrar en una lista del mismo tamaño que el número de valores del eje (x para el horizontal e y para el vertical), utilizando los métodos xticks() o yticks()

Algo como esto: 

tiempo = np.random.randint(100, size=[7])
días = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado','Domingo']
mapeado = range(len(días))
plt.plot(tiempo)           # Añadimos el gráfico
plt.xticks(mapeado, días) # Mapeamos los valores horizontales
plt.show() # Ahora lo mostramos

Y ya vemos mucho más claro nuestro gráfico

Ahora eje x y eje y 

Por si no te acuerdas muy bien cual es cual, te dejo la siguiente imagen

Hasta ahora los gráficos que hemos visualizado los hemos creado a partir de vectores de una dimensión (¿No sabes que es un vector? Te dejo nuestro post de vectores aquí) 

Al utilizar un único vector en el método .plot() éste lo toma como los valores del eje Y y genera el eje X automáticamente a partir de la longitud del vector.

Ahora bien, nosotros podemos decidir los valores del eje X si los pasamos en otro vector como primer parámetro:

x = np.arange(6) 
y = np.random.randint(20, size=[6])
plt.plot(x, y)
plt.show()

Por si no recuerdas la función arange, aquí te dejo un ejemplo

np.arange(3)
array([0, 1, 2])

Ahora…

Gráficos invertidos

Algo interesante es que cambiando el orden de los ejes podemos generar un gráfico invertido. Pero ¿Cómo lo hacemos? Es muy fácil 

plt.plot(y, x) 
plt.show()

Ahora vamos a hablar de límites: 

En algunas ocasiones necesitaremos manipular los límites inferiores y superiores de los ejes. Eso podemos hacerlo gracias a los métodos

  • plt.xlim(min, max)
  • plt.ylim(min, max)

Volvamos al código que ya habíamos hecho

tiempo = np.random.randint(100, size=[7])
días = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado','Domingo']
mapeado = range(len(días))
plt.plot(tiempo)           # Añadimos el gráfico
plt.xticks(mapeado, días) # Mapeamos los valores horizontales
plt.show() # Ahora lo mostramos

Y el gráfico que esto nos había generado 

En este gráfico estamos manejando un array de datos aleatorios de 0 a 100. Sin embargo el gráfico establecerá los límites en los meses con más y menos horas de ejercicio

Podemos establecer que utilice 0 y 100 como escala para el eje Y con las horas de ejercicio aunque no tengamos ningún valor explícito con ellos:

# Límites verticales
plt.plot(tiempo) # Añadimos el gráfico
plt.xticks(mapeado, días) # Mapeamos los valores horizontales
plt.ylim(0, 100) # Configuramos el límite vertical
plt.show() # Finalmente lo mostramos

Utilizando los límites podemos centrarnos en una parte específica del gráfico.

Por ejemplo si quisiéramos mostrar únicamente los días de Miércoles, Jueves y Viernes, podemos limitar el eje X a los valores numéricos de los meses 2, 3 y 4 con un range de 2 a 4:

# Límites horizontales
plt.plot(tiempo) # Añadimos el gráfico
plt.xticks(mapeado, días) # Mapeamos los valores horizontales
plt.xlim(2, 4) # Configuramos el límite horizontal
plt.ylim(0, 100) # Configuramos el límite vertical
plt.show() # Finalmente lo mostramos

Es casi como hacer un zoom a la gráfica

Ahora vamos a poner un poco más entendibles nuestros gráficos. Vamos a personalizarlos añadiéndoles títulos, etiquetas y leyendas.

Para ello utilizaremos los métodos:

  • plt.title(“Título”)
  • plt.xlabel(“Etiqueta horizontal”)
  • plt.ylabel(“Etiqueta vertical”)
tiempo = np.random.randint(100, size=[6])
días = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo']
mapeado = range(len(días))
plt.plot(tiempo)                                
plt.xticks(mapeado, días)
plt.xlim(0, 2)
plt.title("Horas de ejercicio al empezar semana")
plt.xlabel("Días")
plt.ylabel("Cantidad de tiempo en horas")
plt.show()

 Aquí te explico mejor el código

Y ahora veamos la gráfica

¿Mucho más clara, cierto? Podemos ver los nombres de los ejes y todo.

El otro elemento informativo que podemos añadir son las leyendas utilizando:

  • plt.legend(LOCALIZACIÓN)

Podemos elegir optativamente una localización a partir de las distintas opciones que nos indican en la documentación de matplotlib y que os dejaré recopiladas abajo en los apuntes:

  • ‘best’ => 0
  • ‘upper right’ => 1
  • ‘upper left’ => 2
  • ‘lower left’ => 3
  • ‘lower right’ => 4
  • ‘right’ => 5
  • ‘center left’ => 6
  • ‘center right’ => 7
  • ‘lower center’ => 8
  • ‘upper center’ => 9
  • ‘center’ => 10

Aquí te muestro un ejemplo simple

En este escenario donde dibujamos un único vector de datos una leyenda no tiene mucho sentido, pero si en lugar de uno tuviéramos por ejemplo tres vectores representando el tiempo de tres personas la cosa cambiaría

días = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo']
mapeado = range(len(días))
plt.plot(np.random.randint(100, size=[6]), label="Natalia")
plt.plot(np.random.randint(100, size=[6]), label="Yeison")
plt.plot(np.random.randint(100, size=[6]), label="Juan")
plt.xticks(mapeado, días)
plt.xlim(2, 4)
plt.title("Tiempo invertido en hacer ejercicio")
plt.xlabel("días")
plt.ylabel("Cantidad de tiempo en horas")
plt.legend()
plt.show()

Para seguir personalizando nuestros gráficos también podemos utilizar estilos de línea y marcadores

Líneas: Vamos a empezar con las líneas usando nuestro ejemplo de horas invertidas haciendo ejercicio y lo haremos justo en el momento de añadir el gráfico de cada persona.

Tenemos las siguientes propiedades básicas:

  • linewidth (lw): Ancho de la línea
  • linestyle (ls): Estilo de la línea *
  • color: Color de la línea (número y decimal)
  • alpha: Opacidad de la línea (de 0 a 1)
días =  ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo']
mapeado = range(len(días))
plt.plot(np.random.randint(100, size=[6]),
label="Natalia", color="red", ls="-", lw="3")
plt.plot(np.random.randint(100, size=[6]),
label="Yeison", color="#0000ff", ls="--", lw="4")
plt.plot(np.random.randint(100, size=[6]),
label="Juan", color="green", ls="-.", lw="4")
plt.xticks(mapeado, días)
plt.legend()
plt.show()

Marcadores

En los gráficos lineales los marcadores hacen referencia a los puntos o vértices donde se dibujan los valores.

Vamos a ver los siguientes métodos:

  • marker: Tipo de marcador *
  • markersize: Tamaño del marcador
  • markerfacecolor: Color del marcador (número y decimal)
  • markeredgecolor: Color del borde (número y decimal)
  • markeredgewidth: Tamaño del borde
días =  ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo']
mapeado = range(len(días))
plt.plot(np.random.randint(100, size=[6]), label="Natalia",
marker="o", markersize="8", markeredgewidth="2",
markerfacecolor="green", markeredgecolor="white")
plt.plot(np.random.randint(100, size=[6]), label="Yeison",
marker="*", markersize="10", markeredgewidth="2",
markerfacecolor="red", markeredgecolor="white")
plt.plot(np.random.randint(100, size=[6]), label="Juan",
marker="D", markersize="5", markeredgewidth="2",
markerfacecolor="orange", markeredgecolor="white")
plt.xticks(mapeado, días)
plt.legend()
plt.show()

Ahora hablemos de un un concepto que puede ser nuevo para muchos. Los subgraficos

Ya hemos visto cómo crear gráficos. ¿Pero y si queremos dibujar más de un gráfico en el mismo espacio? ¿Por ejemplo para hacer una comparativa de los tiempos de ejercicio de cada personas cada sin sobreponer las líneas en la misma figura? Para esos casos podemos utilizar subgráficos.

La regla de oro para añadir subgráficos es imaginar que estamos dibujando una tabla y cada subgráfico se dibujará en una celda dentro de esa tabla.

Por tanto lo que debemos indicarle a matplotlib es en qué celda debe dibujar cada subgráfico:

plt.subplot(1, 3, 1)  # Tabla 1x3 y dibujaremos en la celda 1
plt.plot(np.random.randint(100, size=[6]), label="Natalia", color="green")
plt.ylim(0, 100)
plt.legend()
plt.subplot(1, 3, 2)  # Tabla 1x3 y dibujaremos en la celda 2
plt.plot(np.random.randint(100, size=[6]), label="Yeison", color="red")
plt.ylim(0, 100)
plt.legend()
plt.subplot(1, 3, 3)  # Tabla 1x3 y dibujaremos en la celda 3
plt.plot(np.random.randint(100, size=[6]), label="Juan", color="cyan")
plt.ylim(0, 100)
plt.legend()
plt.show()  # Dibujamos el conjunto

¿Bastante útil, no crees? 

Hasta ahora todo lo que hemos hecho con matplotlib ha sido dibujar gráficos en celdas, pero en la vida real necesitaremos manejar estos gráficos para poder exportarlos y utilizarlos en nuestros programas y aplicaciones web.

Para manejarlos se utilizan las figuras, la versión orientada a objetos de todo lo que hemos estado haciendo usando instancias y métodos. Cambia un poco la sintaxis así que revisa muy bien

# La figura crea un espacio donde dibujar el gráfico
fig = plt.figure()
# Necesitamos definir una relación de tamaños para el rectángulo del dibujo (l,b,w,h)
# Nota: En jupyter l(eft) y b(ottom) para el primer gráfico no se tienen en cuenta
rect = (0, 0, 1, 1)
# Añadimos los límites para crear un objeto de ejes sobre el que dibujar el gráfico
axes = fig.add_axes(rect)
# A partir de este objeto podremos crear nuestro gráfico como si fuera el clásico plt
axes.plot(np.random.randint(100, size=[6]), label="Natalia", color="green")
axes.plot(np.random.randint(100, size=[6]), label="Yeison", color="red")
axes.plot(np.random.randint(100, size=[6]), label="Juan", color="cyan")
# La mayor diferencia ahora es a la hora de personalizar el gráfico, teniéndonos
# que referir a los métodos con la palabra set precediendo del nombre clásico
axes.set_ylim(0, 100)
axes.set_xlabel("días")
axes.set_ylabel("Cantidad en €")
axes.set_title("Ahorros del primer semestre")
# La parte de mapear los nombres cambia un poco y requiere usar dos métodos
días = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo']
mapeado = range(len(días))
axes.set_xticks(mapeado)
axes.set_xticklabels(días)
# Finalmente mostramos la figura
fig.show()

¿Cuál es el objetivo de esto? Pues que al ser un objeto independiente podemos modificar su tamaño estableciendo una relación de pulgadas en ancho/alto y una densidad de píxeles por pulgada (dpi):

fig = plt.figure(figsize=(1, 1), dpi=100) 
fig = plt.figure(figsize=(4, 2), dpi=100)
fig = plt.figure(figsize=(3, 4), dpi=100)

1 comment on “Graficando con Numpy y matplotlib.pyplot (Todas las bases)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *