Está en la página 1de 26

VisualizacionMatplotlib

January 21, 2020

1 IEBS
1.1 Generación modular de gráficos con matplotlib en Python
Javier Cózar del Olmo

Índice

• Section ??
• Section ??
• Section ??
• Section ??
– Section ??
– Section ??
– Section ??
– Section ??
– Section ??
– Section ??
– Section ??
– Section ??
– Section ??
• Section ??
• Section ??
• Section ??
• Section ??
• Section ??

1.2 Conceptos básicos


1.2.1 Backend
Aunque no vamos a utilizar la interfaz de backend para la generación de gráficos, es necesario
saber mínimamente qué es y cómo se configura.
El backend es el encargado de transformar la figura de matplotlib en un gráfico que podamos
visualizar. Matplotlib puede ser utilizado para la generación de gráficos en varios contextos: de

1
manera independiente, en aplicaciones tk o qt, en notebooks, en archivos de imagen, etc. Debido
a que el proceso de renderización depende del contexto, es necesario un backend específico para
cada uno de ellos. La siguiente línea muestra los backends disponibles.

In [1]: %matplotlib --list

Available matplotlib backends: ['tk', 'gtk', 'gtk3', 'wx', 'qt4', 'qt5', 'qt', 'osx', 'nbagg', '

En el caso de las libretas Jupyter, se trabaja con dos backends distintos: inline y notebook. El
primero de ellos muestra los gráficos como imágenes estáticas, y es usado frecuentemente cuando
las libretas se utilizan como informe (es el usado en los ejemplos anteriores). El segundo permite
cierto nivel de interactividad, es más flexible, y es más indicado cuando se han de hacer modifica-
ciones sobre un mismo gráfico de manera progresiva.
En Python, la elección del backend se hace mediante la función
matplotlib.use(nombre_backend). En Jupyter, la elección de un backend se puede hacer
mediante un magic.

In [2]: %matplotlib inline


# %matplotlib notebook

1.2.2 Scripting
El módulo principal de esta capa es matplotlib.pyplot. Proporciona una interfaz, parecida a la
de otras herramientas como Matlab, que permite elaborar las gráficas directamente y, sobre todo
(por la dificultad que esto conlleva) gestionar la creación de figuras y el backend (documentación).
La siguiente celda importa este módulo, usualmente renombrado a plt.

In [3]: import matplotlib.pyplot as plt

Vamos a utilizar la interfaz de scripting de matplotlib. Eso significa que al ejecutar ciertas op-
eraciones construirá y enriquecerá el gráfico actual.
Un gráfico se crea ejecutando el comando plt.figure(), y a partir de ahí todos los comandos
hacen referencia a esa figura, hasta que se construya otra figura diferente.
La siguiente celda de código construye una gráfica sencilla y le asigna un título.

In [4]: # Construimos los datos


x_data = [1,2,3,4,5,6,7,8,9,10]
y_data = [x ** 2 for x in x_data]

# Y creamos la figura
fig = plt.figure(figsize=(3,3))
plt.plot(x_data, y_data, scalex=True)
plt.title("Gráfica de ejemplo")

Out[4]: Text(0.5, 1.0, 'Gráfica de ejemplo')

2
La llamada a estas funciones nos devuelven objetos de la figura o dentro de ella. Estos objetos
pueden ser usados a través de la API de Artist, o como argumentos por otras funciones.
Por ejemplo, si usamos el backend notebook, es necesario que cerremos la figura para que
deje de consumir recursos (y “terminar” esa interactividad). Existe una función expuesta en
matplotlib.pyplot para cerrar una figura abierta:

In [5]: plt.close(fig)

1.3 Datos - mtcars


Vamos a trabajar con este conjunto de datos. Está formado por 32 instancias que contienen datos
sobre el consumo de combustible y 10 características de coches publicados en la revista Motor
Trend US magazine en 1974. La variable mpg es la que indica el consumo de combustible (en
millas por galón). Las características de cada coche son medidas en las siguientes variables:

• cyl: Número de cilindros


• disp: Cilindrada en cc
• hp: Potencia en C.V.
• drat: Ratio eje trasero
• wt: Peso en libras
• qsec: Tiempo (segundos) en recorrer 1/4 de milla
• vs: Tipo de motor (0 = V-shaped, 1 = straight)
• am: Transmisión (0 = automático, 1 = manual)
• gear: Número de marchas (sin contar marcha atrás)
• carb: Número de carburadores

In [7]: # Usaremos pandas para cargar los datos


import pandas as pd

# cargamos mtcars

3
mtcars = pd.read_csv("https://vincentarelbundock.github.io/Rdatasets/csv/datasets/mtcars
# renombramos la primera columna a model
mtcars.rename({'Unnamed: 0': 'model'}, axis=1, inplace=True)
# creamos una nueva columna llamada brand (la marca del coche)
mtcars['brand'] = mtcars['model'].str.extract(r'(\w+)')
# y creamos las variables am y vs como categóricas
mtcars['am'] = pd.Categorical(mtcars['am']).rename_categories({0: 'automatic', 1: 'manua
mtcars['vs'] = pd.Categorical(mtcars['vs']).rename_categories({0: 'V-shaped', 1: 'straig
In [8]: mtcars.head()
Out[8]: model mpg cyl disp hp drat wt qsec vs \
0 Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 V-shaped
1 Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 V-shaped
2 Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 straight
3 Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 straight
4 Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 V-shaped

am gear carb brand


0 manual 4 4 Mazda
1 manual 4 4 Mazda
2 manual 4 1 Datsun
3 automatic 3 1 Hornet
4 automatic 3 2 Hornet

1.4 Formato de los datos de entrada


Los datos pueden ser proporcionados en varios formatos:
• Colecciones estándar de Python (tuplas, listas)
• Arrays Numpy
• Series y DataFrames de Pandas
Todos son equivalentes, y no tienen una distinción especial en cuanto a la apariencia. Son
puramente datos. Por ejemplo, si pasamos un DataFrame de Pandas con 100 filas, 3 columnas y un
índice a
plt.plot(df)
es equivalente a:
plt.plot(df.index, df.col1, df.index, df.col2, df.index, df.col3)
Además, pyplot permite trabajar con otros tipos de datos, como por ejemplo datetime. Por
último, el manejo de las colecciones y tipos de datos es relativamente transparante, por lo que no
hay que llevar a cabo ninguna conversión explícita.
In [13]: df_plot = mtcars.set_index("mpg")[["hp", "wt"]]

fig = plt.figure(figsize=(10,5))
plt.plot(df_plot, ".b")
pass

4
In [15]: df_plot = mtcars.set_index("mpg")[["hp", "wt"]]
x = df_plot.index
y1 = df_plot.hp
y2 = df_plot.wt

fig = plt.figure(figsize=(10,5))
plt.plot(x, y1, ".b", x, y2, ".r")
pass

5
1.5 Tipos de gráficos
matplotlib.pyplot incluye una serie de funciones para generar gráficos, accesibles a través de
diferentes funciones. A continuación veremos las más utilizadas, así como los parámetros más
útiles.

1.5.1 plt.plot
Esta función genera un gráfico enfrentando los valores en el eje y contra los valores en el eje x.
Sirve para generar gráficas de líneas y de nubes de puntos.

In [16]: # necesitamos ordenar, ya que maplotlib está centrado en los valores y depende del orde
df = mtcars.sort_values("hp")

fig = plt.figure(figsize=(10,5))
plt.plot(df.hp, df.mpg)
pass

1.6 Format strings


La forma más compacta de especificaf el formato de una serie de datos dentro de una figura es
usando los format strings. Éstos son strings que contienen 3 partes bien diferenciadas (link oficial):

fmt = '[marker][line][color]'

donde marker se refiere al tipo de elemento que se usa para dibujar cada elemento (dato), line
si se dibuja una línea entre elementos, y color el color de los mismos. Todos ellos son opcionales.

1.6.1 Markers

6
character description
. point marker
, pixel marker
o circle marker
v triangle_down marker
ˆ triangle_up marker
< triangle_left marker
> triangle_right marker
1 tri_down marker
2 tri_up marker
3 tri_left marker
4 tri_right marker
s square marker
p pentagon marker
star marker
h hexagon1 marker
H hexagon2 marker
+ plus marker
x x marker
D diamond marker
d thin_diamond marker

_ hline marker

1.6.2 Line Styles

character description
- solid line style
– dashed line style
-. dash-dot line style
: dotted line style

1.6.3 Colors

character color
b blue
g green
r red
c cyan
m magenta
y yellow
k black
w white

7
Además de la ventaja de codificar en un solo parámetro la forma del marcador, el tipo de línea y
el color, las funciones permiten pasar de forma posicional este argumento junto con los datos de
cada serie.
En la siguiente celda vamos a construir una gráfica plt.plot con dos series de datos. La
primera será una línea continua azul, y la segunda una línea discontinua roja en la que los datos
vienen marcados con x.

In [17]: # Construimos los datos


x_data = [1,2,3,4,5,6,7,8,9,10]
y1_data = [x * 5 for x in x_data]
y2_data = [x ** 2 for x in x_data]

# Y creamos la figura
fig = plt.figure(figsize=(3,3))
plt.plot(x_data, y1_data, "-", x_data, y2_data, "x--r")
pass

También podemos, por ejemplo, dibujar los puntos de diferente color en función del valor de
una variable. Esto se consigue imprimiéndolos en diferentes series de valores.

In [18]: fig = plt.figure(figsize=(10,5))


for c in mtcars.am.cat.categories:
df = mtcars.loc[lambda df: df.am == c]
plt.plot(df.hp, df.mpg, 'o')
pass

8
Por el contrario, una de las desventajas es que no nos permite separar la definición de cada
uno de estos elementos por serie de datos, es decir, no permite dibujar una línea negra en la que
los marcadores sean puntos rojos.
En este caso, no queda más remedio que editar los argumentos del tipo de gráfico en concreto:
Line2D

In [21]: # Y creamos la figura


fig = plt.figure(figsize=(10,5))
df = mtcars.sort_values("hp")
plt.plot(df.hp, df.mpg, ".-k", markerfacecolor='#FF0000', markeredgecolor='red', marker
pass

9
1.6.4 stackplot
Los gráficos de pila permiten representar la relacion y suma de varias series. En Matplotlib se
construyen mediante la función pyplot.stackplot(). Si el eje X es una variable discreta, da la
misma información visual que los stacked bars. Si el eje X es una variable continua (por ejemplo,
una variable temporal) los stackplots son la opción adecuada.

In [39]: df = (
mtcars
.assign(n=1)
[['brand', 'am', 'n']]
.pivot_table(
values="n",
index='brand',
columns='am',
aggfunc="sum",
fill_value=0
)
)

fig = plt.figure(figsize=(10,5))

plt.stackplot(df.index, df.manual, df.automatic)


# Veremos mas adelante el significado de esta función
plt.xticks(rotation=45)
pass

10
1.6.5 Bar
Son gráficos que se utilizan para mostrar como alguna cantidad varía entre un conjunto pequeño
de elementos (valores discretos). Se dibujan con la función pyplot.bar(). El primer argumento
debe ser una secuencia de labels (texto) o enteros, y el segundo un número indicando la altura de
cada barra.

In [22]: fig = plt.figure(figsize=(10,5))


plt.bar(mtcars.brand, mtcars.mpg)
plt.xticks(rotation=45)
pass

Podemos editar el aspecto de las barras con los argumentos descritos en la documentación.

In [23]: fig = plt.figure(figsize=(10,5))


plt.bar(mtcars.brand, mtcars.mpg, color="r", width=0.5)
plt.xticks(rotation=45)
pass

11
Si ponemos dos series, se imprimen en sucesión una detrás de otra.

In [29]: fig = plt.figure(figsize=(10,5))


for c in mtcars.am.cat.categories:
df = mtcars.loc[lambda df: df.am == c]
plt.bar(df.model, df.mpg)
plt.xticks(rotation=45)
pass

12
Si lo que queremos es intercalarlas, tenemos que controlar la posición con el primer argumento.
Como debe ser un entero, debemos usar la función xticks (la describiremos más adelante) para
mostrar los textos.

In [34]: import numpy as np

df = (
mtcars
[["brand", "mpg", "am"]]
.pivot_table(values="mpg", index='brand', columns='am',aggfunc="mean", fill_value=0
)

barwidth = 0.4

indices = np.arange(len(df.index))

fig = plt.figure(figsize=(10,5))

plt.bar(indices - 0.2, df.manual, width=barwidth, label="manual")


plt.bar(indices + 0.2, df.automatic, width=barwidth, label="automatic")

plt.xticks(indices, df.index, rotation=45)


# más adelante se explicará la función legened
plt.legend()
pass

13
Finalmente, existe una función idéntica llamada plt.barh que dibuja las columnas en horizon-
tal.

In [37]: df = (
mtcars
[["brand", "mpg", "am"]]
.pivot_table(values="mpg", index='brand', columns='am',aggfunc="mean", fill_value=0
)

barheight = 0.4

indices = np.arange(len(df.index))

fig = plt.figure(figsize=(10,7))

plt.barh(indices - 0.2, df.manual, height=barheight, label="manual")


plt.barh(indices + 0.2, df.automatic, height=barheight, label="automatic")

# más adelante se explicarán las funciones xticks, yticks y legend


plt.yticks(indices, df.index)
plt.legend()
pass

14
1.6.6 hist
La función pyplot.hist() construye un histograma a partir de un conjunto de datos con el
número de bins especificado. Este histograma puede representar en el eje y las frecuencias ab-
solutas, o las relativas. En este caso, con el parámetro density=True se indica que se utilicen las
frecuencias relativas.

In [40]: fig = plt.figure(figsize=(10,5))

plt.hist(
[mtcars.loc[lambda df: df.am == "manual"].mpg, mtcars.loc[lambda df: df.am == "auto
stacked=False, density=False, bins=10
)
pass

1.6.7 Boxplot
Se pueden crear con pyplot.boxplot. Representa la distribución de la. Es posible cambiar el
aspecto de las distintas componentes de las cajas, pero esto requiere acceder directamente a ellas.
Se pueden consultar diferentes parametros en la documentación.

In [42]: fig = plt.figure(figsize=(10,8))

plt.boxplot(
[mtcars.loc[lambda df: df.am == "manual"].mpg, mtcars.loc[lambda df: df.am == "auto
)
pass

15
1.6.8 Pie
Se construyen mediante la función pyplot.pie(). No son muy recomendados (se prefieren los
gráficos de barras) pero han sido ampliamente utilizados para comparar proporciones entre los
valores de una variable.
Se pueden consultar diferentes parámetros en la documentación. Permiten manejar multitud
de aspectos, como los colores (colors), el modo enque se muestra la información (autopct), si se
destaca algún sector y cuanto (explode), etc.

In [44]: df = mtcars.groupby("brand").mean()

fig = plt.figure(figsize=(10,10))
plt.pie(df.mpg, labels=df.index)
pass

16
1.6.9 Text
Se puede añador texto en una gráfica mediante pyplot.text(). Los dos primeros parámetros
constituyen el punto de referencia. Los parámetros horizontalalignment y verticalalignment
determinan cómo debe ser la alineación del texto con respecto a este punto.

In [47]: fig = plt.figure(figsize=(10, 8))

plt.boxplot(
[mtcars.loc[lambda df: df.am == "manual"].mpg, mtcars.loc[lambda df: df.am == "auto
)
posx = 1
posy = mtcars.loc[lambda df: df.am == "manual"].mpg.mean()

17
plt.text(posx, posy, "Valor medio de mpg para manual", horizontalalignment="left")
pass

1.6.10 Annotate
Cuando se utilizan flechas y texto para hacer una anotación, se puede hacer directamente con la
función pyplot.annotate. Ésta toma como parámetros las coordenadas de la punta de la flecha y
el texto. En ambos casos, se puede especificar qué unidades se utilizan (en el ejemplo los datos).
También las propiedades de la flecha.
Se puede consultar la parametrización en la documentación.

In [48]: fig = plt.figure(figsize=(10, 8))

plt.boxplot(
[mtcars.loc[lambda df: df.am == "manual"].mpg, mtcars.loc[lambda df: df.am == "auto
)
posx = 1
posy = mtcars.loc[lambda df: df.am == "manual"].mpg.mean()
plt.annotate(
"Valor medio de mpg para manual",

18
xy=(posx, posy),
xytext=(2, 30),
horizontalalignment="center",
textcoords = 'data',
arrowprops = dict(arrowstyle="->", color='b'), fontsize='small', color='b'
)
pass

1.6.11 hlines y vlines


También se pueden dibujar líneas verticales y horizontales, con las coordenadas en el eje X e Y
respectivamente. Adicionalmente hay que especificar el alto o ancho de la línea indicando el
(ymin, ymax) o el (xmin, xmax).

In [50]: fig = plt.figure(figsize=(10, 8))

plt.boxplot(
[mtcars.loc[lambda df: df.am == "manual"].mpg, mtcars.loc[lambda df: df.am == "auto
)
posx = 1

19
posy = mtcars.loc[lambda df: df.am == "manual"].mpg.mean()
plt.annotate(
"Valor medio de mpg para manual",
xy=(posx, posy),
xytext=(2, 30),
horizontalalignment="center",
textcoords = 'data',
arrowprops = dict(arrowstyle="->", color='b'), fontsize='small', color='b'
)
plt.hlines(posy, 0.5, 1.5, color="blue")
pass

1.7 Títulos y etiquetas


Los títulos principal y secundario se añaden, respectivamente, mediante las funciones
pyplot.title() y pyplot.suptitle(). Las etiquetas de los ejes, mediante las funciones
pyplot.xlabel() e pyplot.ylabel().
Tanto las funciones title como xlabel y ylabel aceptan argumentos de tipo Text.

20
In [211]: # Construimos los datos
x_data = [1,2,3,4,5,6,7,8,9,10]
y_data = [x ** 2 for x in x_data]

# Y creamos la figura
fig = plt.figure(figsize=(3,3))
plt.plot(x_data, y_data, ".-b")

# Añade el título
plt.title("Título de ejemplo", fontsize="large")

# Añade las etiquetas de los ejes


plt.xlabel("Serie", color='blue')
plt.ylabel("Cuadrado", color='blue', rotation=45, labelpad=20);

1.8 Ejes
Es posible establecer el rango de cada eje con las funciones pyplot.xlim() e pyplot.ylim(). Es
posible indicar los rangos de mayor a menor valor, cambiando así el aspecto de la gráfica.
También se pueden determinar los puntos concretos que se muestran en cada eje, su aspecto,
mediante pyplot.xticks() y pyplot.yticks().
Al igual que los títulos y las etiquetas, xticks y yticks aceptan argumentos de tipo Text.

In [60]: # Construimos los datos


x_data = [1,2,3,4,5,6,7,8,9,10]
y_data = [x ** 2 for x in x_data]

# Y creamos la figura

21
fig = plt.figure(figsize=(6, 6))
plt.plot(x_data, y_data, ".-b")

# Cambiamos los limites de los ejes x e y


plt.xlim(-1, 12)
plt.ylim(-10, 120)

# Cambia los ticks de los ejes x e y


plt.xticks([0, 5, 10], ['bajo', 'medio', 'alto'], color = 'blue', rotation=45)
size = 'small',
# cuando los ticks y sus labels coinciden, no es necesario especificar ambos
plt.yticks([0, 40, 80, 120], color = 'grey')
pass

22
1.9 Leyenda
En los gráficos, además, se pueden incluir leyendas. Esto se hace automáticamente añadiendo
una etiqueta a cada serie (argumento label="string"), y luego invocando pyplot.legend() con
los parámetros correspondientes. Uno de ellos, loc, determina dónde se coloca la leyenda. Si se
asigna el valor best la leyenda se coloca automáticamente, y puede cambiar de ubicación al añadir
o borrar elementos.
Información con respecto a leyendas puede encontrarse aquí. Para leyendas más complejas
puede consultarse esta guía.

In [69]: fig = plt.figure(figsize=(10,8))

for c in mtcars.am.cat.categories:
df = mtcars.loc[lambda df: df.am == c]
plt.plot(df.hp, df.mpg, 'o', label=c)

# Establece la leyenda en la gráfica. La localiza automáticamente.


plt.legend(loc='best', fontsize='large', shadow=True);
pass

23
1.10 Estilos
Hasta el momento, todas las gráficas se han hecho con el aspecto por defecto. Sin embargo,
el método style de plt permite cambiar la aparencia de las gráficas, en muchos casos para
adaptarlas al contexto (presentación, artículo, notebook, etc. Existe una gran variedad de esti-
los disponibles, que pueden consultarse en el objeto pyplot.style.available.
Adicionalmente, existe un estilo llamado default que deja el estilo por defecto.

In [70]: plt.style.available

Out[70]: ['seaborn-dark',
'seaborn-darkgrid',
'seaborn-ticks',
'fivethirtyeight',
'seaborn-whitegrid',
'classic',
'_classic_test',
'fast',
'seaborn-talk',
'seaborn-dark-palette',
'seaborn-bright',
'seaborn-pastel',
'grayscale',
'seaborn-notebook',
'ggplot',
'seaborn-colorblind',
'seaborn-muted',
'seaborn',
'Solarize_Light2',
'seaborn-paper',
'bmh',
'tableau-colorblind10',
'seaborn-white',
'dark_background',
'seaborn-poster',
'seaborn-deep']

In [73]: # se pueden combinar estilos


plt.style.use(['grayscale', 'seaborn-poster'])
# Construimos los datos
x_data = [1,2,3,4,5,6,7,8,9,10]
y_data = [x ** 2 for x in x_data]

# Y creamos la figura
fig = plt.figure(figsize=(3,3))
plt.plot(x_data, y_data, ".-")

Out[73]: [<matplotlib.lines.Line2D at 0x11e9f90f0>]

24
In [75]: # asi dejamos el estilo por defecto
plt.style.use('default')

1.11 Múltiples gráficos en una figura


Como mencionamos al principio de la clase, los gráficos se incluyen en un objeto o capa axes. Una
figura contiene uno o varios elementos de tipo axes.
Para crear una figura con múltiples figuras, disponemos de la función plt.subplots(). Ésta
admite varios parámetros para controlar la distribución y aspecto de las figuras. Las más impor-
tantes son: - nrows y ncols: crea una matriz de subplots (axes), distribuidos en ese número de
filas y columnas. - shareX y shareY: controla el aspecto del eje x e y de los subplots. Si es True,
todos los suplots comparten el mismo dominio del eje X e Y respectivamente. Si no, cada uno será
independiente.
Puede encontrarse más información sobre el manejo de esta función aquí.

In [76]: import numpy as np

In [77]: # Construimos los datos


x_data = [1,2,3,4,5,6,7,8,9,10]

y11_data = [x * 5 for x in x_data]


y12_data = [x ** 2 for x in x_data]
y13_data = [np.log(x) for x in x_data]

y21_data = [x * -5 for x in x_data]


y22_data = [x ** -2 for x in x_data]
y23_data = [np.log(1/x) for x in x_data]

25
# Y creamos la figura
fig, axes_grid = plt.subplots(2, 3, figsize=(10,3), sharey=False)

axes_grid[0, 0].plot(x_data, y11_data, "--r")


axes_grid[0, 1].plot(x_data, y12_data, "--r")
axes_grid[0, 2].plot(x_data, y13_data, "--r")

axes_grid[1, 0].plot(x_data, y21_data, "--b")


axes_grid[1, 1].plot(x_data, y22_data, "--b")
axes_grid[1, 2].plot(x_data, y23_data, "--b")

Out[77]: [<matplotlib.lines.Line2D at 0x11e90c978>]

26

También podría gustarte