14. Tipos de gráfico en matplotlib#

Hasta ahora sólo hemos utilizado la función plot para crear gráficos de línea.

A continuación revisaremos como crear gráficas otras usuales como las nubes de puntos y los mapas de contornos con matplotlib

Utilizaremos los mismos datos de la lección pasada

%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

data_covid = pd.read_csv("data/covid19_extract.csv").drop(["Lat", "Long", "Province/State"], axis=1)
data_covid.set_index("Country/Region", inplace=True)
data_chile = data_covid.loc["Chile"].values
data_argentina = data_covid.loc["Argentina"].values
data_bolivia = data_covid.loc["Bolivia"].values

14.1. Nubes de puntos#

Los gráficos de nube de puntos son útiles para explorar si existe correlación entre dos conjuntos de datos

En matplotlib se crean con la función scatter

A continuación se muestran algunos de los argumentos principales de esta función

fig, ax = plt.subplots(figsize=(7, 3), tight_layout=True)

ax.scatter(x=data_argentina, # Posición horizontal de los puntos
           y=data_chile, # Posición vertical de los puntos
           marker='o', # forma de los puntos
           s=20, # Tamaño de los puntos
           c='r', # Color de los puntos
           alpha=1.) # Opacidad de los puntos

ax.set_xlabel('Cantidad de casos en Argentina')
ax.set_ylabel('Cantidad de casos en Chile');
../../_images/66f03d23f5a9523d90825809146358b3498b21c8c066c6243da70e865b8ba273.png

También es posible especificar el tamaño y el color por punto en lugar de globalmente. Esto nos permite agregar más información al gráfico

En el siguiente ejemplo se utiliza el tamaño del punto para representar la cantidad total de casos y el color la fecha

fig, ax = plt.subplots(figsize=(7, 3), tight_layout=True)

ax.scatter(x=data_argentina,
           y=data_chile,  
           s=(data_argentina + data_chile)/50, # Cantidad total de casos (normalizado)
           c=range(len(data_argentina)), # Días
           alpha=0.8)

ax.set_xlabel('Cantidad de casos en Argentina')
ax.set_ylabel('Cantidad de casos en Chile');
../../_images/662c1e94094f292c960078ece50d9b36e79948137d17f064cd22e681858793af.png

Una nube de puntos también es útil si tenemos datos que no están muestreados regularmente o que tienen “espacios” que no sería correcto conectar

El siguiente ejemplo corresponde al brillo de una estrella en función del tiempo, detectado por el telescopio Vista. Esta serie de tiempo se conoce como curva de luz

En este ejemplo no se sabe como varía el brillo entre cada fecha por lo que no es correcto “conectar los puntos” con una linea

tiempo, brillo, error = pd.read_csv("data/rrl.dat", header=None, delim_whitespace=True).values[:, :3].T

fig, ax = plt.subplots(2, figsize=(7, 4), tight_layout=True, sharex=True)

ax[0].plot(tiempo, brillo)
ax[0].set_title('Incorrecto, induce a confusión')
ax[1].scatter(tiempo, brillo, s=5)
ax[1].set_title('Correcto');
# Se puede obtener un resultado idéntico con:
#ax[1].plot(tiempo, brillo, 'o') 
../../_images/b505cfbf7f568fb8f9d6b63a34d023ad5d51274db07ffa76b377afe193ff5fad.png

Importante

Conocer la naturaleza de los datos es fundamental para poder graficarlos de la mejor forma

14.2. Lineas con barras de error#

El gráfico de linea con barras de error es útil si queremos mostrar la incerteza asociada a nuestras variables.

Podemos hacer un gráfico con barras de error con la función errorbar

  • Se pueden agregar barras de error tanto para la variable dependiente (vertical) como la independiente (horizontal)

  • La incerteza puede ser un número o un vector del mismo tamaño de la variable correspondiente

Para la curva de luz anterior teníamos información sobre el error en el brillo (variable dependiente). Podemos agregarlo al gráfico con el argumento yerr como sigue

fig, ax = plt.subplots(figsize=(7, 3), tight_layout=True)

ax.errorbar(x=tiempo, # Eje x
            y=brillo, # Eje y
            xerr=0.0, # Error en el eje x
            yerr=error, # Error en el eje y
            fmt='.', elinewidth=None, ecolor=None, capsize=None);

ax.set_xlabel('Tiempo')
ax.set_ylabel('Brillo estelar');
../../_images/a29a5947a280804f5e2fa9672977e30f5eb9f4c9bc43b5145c70858d3ed5f219.png

14.3. Rango de datos#

Podemos utilizar la función fill_between para dibujar áreas

Este tipo de gráfico es útil si queremos:

  • presentar la incerteza asociada a la variable dependiente

  • resumir el comportamiento de varios gráficos de linea

data = np.vstack((data_chile, data_argentina, data_bolivia))
media = np.mean(data, axis=0)
devstd = np.std(data, axis=0)
fig, ax = plt.subplots(figsize=(7, 4), tight_layout=True, facecolor='w')
ax.grid()
ax.plot(media, label='Promedio de casos en Chile, Argentina y Bolivia')
ax.fill_between(x=range(len(media)),
                y1=media - devstd, 
                y2=media + devstd, 
                alpha=0.5, label='Desviación estándar')
ax.legend(loc=2);
../../_images/c8738bb8ac253ebeffee57d99ef719c96bc01b87ac11daefc9fbf1d03c2503f4.png

14.4. Lineas sobrepuestas#

Podemos utilziar la función stackplot para dibujar lineas sobrepuestas

Este tipo de gráfico sirve para estudiar la contribución de múltiples variables con respecto a su valor acumulado (suma)

fig, ax = plt.subplots(figsize=(7, 4), tight_layout=True, facecolor='w')
ax.grid()
ax.stackplot(range(len(data_chile)), # Esto corresponde al eje horizontal
             data_chile, # Los siguientes datos se graficaran en el eje vertical
             data_argentina, 
             data_bolivia, 
             alpha=0.5, labels=('Chile', 'Argentina', 'Bolivia'));
plt.legend(loc=2);
../../_images/6b2208ffeff89e146991d08cb317a2b3ae0cc200cc041578f2f919df58d36a8a.png

14.5. Gráficos de Barra#

Podemos utilizar la función bar para crear gráficos de barra

Este tipo de gráfico sirve para comparar una cierta cantidad con respecto a distintos grupos

fig, ax = plt.subplots(figsize=(7, 4), tight_layout=True, facecolor='w')

ax.bar(x=range(3), # Posición de las barras
       height=[data_chile[-1], data_argentina[-1], data_bolivia[-1]], # Tamaño de las barras
       width=0.8, bottom=0, align='center', # Ancho y alineación de las barras
       color=None, edgecolor=None, linewidth=None); # Color y otros aspectos estéticos

ax.set_ylabel('Infectados totales a la fecha')
ax.set_xticks(range(3))
ax.set_xticklabels(['Chile', 'Argentina', 'Bolivia']);
../../_images/02d4228417a50aafc4b60ae208f838b03b7b2f6be7a62a045e8e6e7af3ea9a2f.png

14.6. Histogramas#

Podemos utilizar la función hist para crear y graficar histogramas con matplotlib

Un histograma es una representación de la distribución de una o más variables y su construcción involucra

  • Medir el rango de la variable

  • Dividir el rango en \(N\) cajones

  • Contar cuantas muestras corresponden a cada cajón

La cantidad de cajones y el rango se especifican con los argumentos bins y range, respectivamente

fig, ax = plt.subplots(figsize=(7, 4), tight_layout=True, facecolor='w')

ax.hist(data_chile[1:] - data_chile[:-1], # Datos
        bins=20, # Cantidad de cajones por columna
        density=False, # Normalización 
        histtype='bar', color=None); # Aspectos visuales

ax.set_xlabel('Cantidad de casos nuevos por día en Chile');
../../_images/7dd8b3c5f7f9638604ac68122cfb9d17d032c6a20261dfff1d24a736e52debd0.png

Nota

Si los datos que recibe hist tienen forma de matriz entonces se genera un histograma por cada columna de la matriz

En el siguiente ejemplo se muestra la curva de luz anterior y un histograma de los valores de brillo

fig, ax = plt.subplots(1, 2, figsize=(8, 3), 
                       tight_layout=True, facecolor='w')

ax[0].errorbar(tiempo, brillo, error, fmt='.')
ax[0].set_xlabel('Dias')
ax[0].set_ylabel('Brillo aparente')

ax[1].hist(brillo, bins=10, alpha=0.75, density=True, orientation="horizontal");
ax[1].set_title('Histograma')
ax[1].set_xlabel('Densidad');
../../_images/3c98e46ed34b76ea9e28f200412d986ff6162f9219068a2143cdfc122015144b.png

14.7. Diagrama de caja y bigote#

Podemos utilizar la función boxplot para hacer un diagrama de cajas

Este tipo de gráfico se usa para visualizar y/o comparar la distribución de varios conjuntos de datos

  • La linea naranja corresponde a la media de los datos

  • La parte superior e inferior de la caja corresponden al menor y mayor cuartil, respectivamente

  • Los bigotes son el rango calculado a partir de los cuartiles

  • Las pelotas son puntos fuera del rango anterior (outliers)

A continuación se muestra un ejemplo con las opciones por defecto

fig, ax = plt.subplots(figsize=(7, 4), tight_layout=True)

ax.boxplot(data_covid.values.T, 
           notch=False, 
           sym='o', 
           showmeans=None, 
           showcaps=None, 
           showbox=None);

ax.set_xticklabels(list(data_covid.index));
../../_images/c4576c48d448a9330cee5b43dd386c27082fe0f870d0d8fa19bb555adbc5cced.png

14.8. Mapas de colores#

Para visualizar funciones que varían en dos variables independientes (por ejemplo una superficie) podemos usar Mapas de colores

Revisaremos las siguientes opciones

  • contour y contourf

  • pcolor

  • matshow y imshow

En los mapas de colores la variable dependiente (áltura) se codifica como una escala o paleta de color

Matplotlib ofrece varias paletas de color que se agrupan en tres tipos

  • gradiente: Para representar variables continuas

  • divergentes: Para representar variables continuas con un valor cero

  • categóricas: Para representar clases

scale = np.tile(np.linspace(0, 1, num=256), (20, 1))
fig, ax = plt.subplots(3, figsize=(7, 3), tight_layout=True)
for ax_, cmap_ in zip(ax, [plt.cm.Reds, # Esta es una escala tipo gradiente
                           plt.cm.RdBu, # Esta es de tipo divergente
                           plt.cm.Accent] # Esta es de tipo categórica
                     ):
    ax_.imshow(scale, cmap=cmap_)
    ax_.axis('off')
../../_images/f3d191b7ea63d98049121a3060add77839b45d47125476a785add0d046d10aad.png

Gráficas de contornos

Creemos datos sintéticos tridimensionales para probar los mapas de colores

x = np.linspace(-3, 3, num=10)
X, Y = np.meshgrid(x, x)
Z = np.exp(-0.5*(X-1)**2 - 0.5*(Y+1)**2) + np.exp(-0.5*(X+1)**2 -0.5*(Y-1)**2)

La función contourf crea un gráfico de contornos con el “relleno” coloreado

fig, ax = plt.subplots(figsize=(7, 4))
cplot = ax.contourf(X, Y, Z, # Los tres deben ser matrices
                    levels=6, # Permite ajustar la cantidad de escalones o niveles
                    cmap=plt.cm.Greens) # Paleta de colores

# Colorbar es útil para mostrar como varía la variable Z
fig.colorbar(mappable=cplot, ax=ax, orientation='vertical', pad=0.05); 
../../_images/c0dd6dc6501bf5e7cdbe78e9338edd01c3e496c36267278524c4c976ca83f183.png

En cambio contour crea un mapa de contorno sin relleno

Se puede usar clabel para anotar el valor de los niveles de Z

fig, ax = plt.subplots(figsize=(7, 4))
cplot = ax.contour(X, Y, Z, levels=6, # Igual que en contourf
                   linewidths=2, linestyles='solid', # Aspectos visuales
                   cmap=plt.cm.Greens) # Paleta

ax.clabel(cplot, # Recibe el mapa de contornos
          colors='k', fontsize=10); # Aspectos tipográficos
../../_images/cacac60e1b3509dac07df47fe669d33498e72343c57efcefaae3273834887d81.png

Visualizando matrices e imágenes

Las funciónes matshow e imshow pueden usarse para visualizar arreglos. La primera es para matrices, es decir arreglos bidimensionales. La segunda es para imágenes, es decir arreglos tridimensionales donde la tercera dimensión es el canal de color (RGB)

Veamos primero matshow

fig, ax = plt.subplots(figsize=(5, 4), tight_layout=True)
cplot = ax.matshow(Z, # Matriz
                   cmap=plt.cm.Greens, # Paleta
                   interpolation='none') 
fig.colorbar(cplot);
../../_images/34b2940b69ec4b8dae7c26c1af80ffc34d0c43a5c7feb623f864e936a9f373ab.png

El argumento interpolación controla la suavidad entre los “píxeles”, las opciones son:

interpolation = {'none', 'bilinear', 'bicubic', 'gaussian', 'lanczos'}

Por ejemplo

fig, ax = plt.subplots(figsize=(5, 4), tight_layout=True)
cplot = ax.matshow(Z, cmap=plt.cm.Greens, interpolation='bicubic') 
fig.colorbar(cplot);
../../_images/783b6961019732fd5ef15e254e65d17e488185f38cef98d38b442ca9e7ebec9c.png

Para graficar imagenes es más conveniente usar imshow

Matplotlib también tiene la función imread para importar una imagen como ndarray

img = plt.imread('data/valdivia.png')
fig, ax = plt.subplots(figsize=(7, 5), tight_layout=True)
ax.imshow(img);
../../_images/3084ce2e694cf9b1c149e67b1740fd00f60db812e1ef76d511ecd4b81c2807e0.png

14.9. Gráficas en 3D#

Otra opción para visualizar la interacción entre tres variables es usar gráficos 3D

  • Es necesario importar el módulo Axes3D

  • Luego podemos usar las funciones

    • plot_surface

    • contour, contourf

    • plot_wireframe

Por ejemplo:

from mpl_toolkits.mplot3d.axes3d import Axes3D

# Debemos indicar los ejes que son 3D
fig, ax = plt.subplots(figsize=(8, 5), 
                       subplot_kw={'projection': '3d'}) 

cplot = ax.plot_surface(X, Y, Z, cmap=plt.cm.Greens)
fig.colorbar(cplot)

# Podemos especificar el "ángulo de la cámara" con 
ax.view_init(45, # Elevación
             45 # Azimut 
            );
../../_images/04127b7c5192cf944fe00c28b3f50a927e2a806a28c395ecc7287bffedde0137.png

El módulo Axes3D puede usarse también para hacer líneas y nubes de puntos en 3D a partir de arreglos unidimensionales (vértices)

El siguiente ejemplo muestra una espiral en 3D creada usando coordenadas polares

fig, ax = plt.subplots(1, 2, figsize=(8, 5), 
                       subplot_kw={'projection': '3d'})

N = 100
rho = np.linspace(0, 2, num=N)
phi = np.linspace(0, 20, num=N)
x = rho*np.cos(phi)
y = rho*np.sin(phi)
z = np.linspace(0, 2, num=N)

ax[0].plot(x, y, z)
ax[1].scatter(x, y, z);
../../_images/b772ef6f3b56e94995f601a6bc32e68584cb0313caf37182a06aa6e2128d7df4.png