AulaML Python · C++
Python intermedio · 40 min · Python para ciencia de datos

Matplotlib y Seaborn

Figura, ejes y el gráfico que responde la pregunta en lugar de decorarla

Un gráfico es un argumento visual: si no sabes qué pregunta responde, cualquier dibujo parece correcto. Aprenderás el modelo de figura y ejes, los gráficos esenciales de Matplotlib y Seaborn, cómo etiquetarlos y combinarlos en subplots, y qué errores de lectura evitar.

Lección 4 de 5 del módulo
Al terminar esta lección podrás
  • Explicar la relación entre figura, ejes y artistas en Matplotlib
  • Dibujar líneas, barras, dispersiones, histogramas, cajas y mapas de calor
  • Etiquetar ejes, títulos y leyendas, y guardar la figura en un archivo
  • Componer varios gráficos con subplots y compartir escalas
  • Elegir el gráfico adecuado para cada tipo de pregunta y detectar ejes engañosos

Antes necesitas: Pandas: Series y DataFrames · Estadística y análisis exploratorio

En esta lección
  1. ¿Qué es Matplotlib?
  2. ¿Para qué sirve?
  3. ¿Cómo funciona por dentro? Figura y ejes
  4. Sintaxis: la receta mínima
  5. Ejemplo básico: evolución mensual
  6. Ejemplo intermedio: dispersión y distribución
  7. Caso práctico: cuatro vistas del mismo mes
  8. Visualización: un mapa de calor
  9. Errores comunes
  10. Buenas prácticas
  11. Ejercicios
  12. Soluciones explicadas
  13. Resumen
  14. Evaluación

Puedes calcular la media de ventas por mes y presentarla en una tabla de doce números. Nadie la recordará. El mismo dato en una línea con los meses en el eje horizontal muestra en dos segundos si el negocio crece, se estanca o cae en diciembre. Esa traducción de números a forma es el trabajo de la visualización.

Pero un gráfico también puede mentir sin escribir una sola palabra falsa: recortar el eje vertical, elegir barras para una serie temporal o dibujar un promedio que esconde dos grupos opuestos. Aprender las herramientas y los criterios va junto; por eso esta lección dedica tanto espacio a decidir como a dibujar.

¿Qué es Matplotlib?

Matplotlib es la biblioteca de gráficos de referencia en Python. Casi todo lo que ves en un cuaderno, un informe o un artículo científico pasa por ella, directa o indirectamente. Su módulo pyplot ofrece una interfaz rápida, y la API orientada a objetos permite controlar cada detalle.

Seaborn se construye sobre Matplotlib y añade dos cosas: funciones estadísticas listas para usar (histogramas con densidad, diagramas de caja, mapas de calor) y un estilo por defecto más cuidado. No compiten: Seaborn dibuja sobre los mismos ejes de Matplotlib, así que puedes mezclar ambos en una figura.

¿Para qué sirve?

  • Explorar: ver la forma de una distribución antes de elegir una prueba estadística o un modelo.
  • Detectar errores: un histograma revela montos negativos o edades imposibles que una tabla de resumen esconde.
  • Comparar grupos: barras por sede, cajas por segmento, líneas por canal a lo largo del tiempo.
  • Comunicar: un informe con una figura clara necesita menos texto y se recuerda más.
  • Depurar un modelo: curvas de aprendizaje y residuos se leen mejor como imagen que como lista de números.

¿Cómo funciona por dentro? Figura y ejes

Matplotlib organiza el dibujo en tres niveles. La Figure es el lienzo completo, con su tamaño en pulgadas y su resolución. Dentro hay uno o varios Axes, cada uno con su propio sistema de coordenadas, sus ejes y sus datos. Y dentro de cada Axes están los artistas: líneas, puntos, barras, textos, que son lo que finalmente se pinta.

Esa jerarquía explica el patrón que usarás siempre: fig, ax = plt.subplots() crea un lienzo y un eje, y luego llamas a métodos de ax. Cuando necesitas cuatro gráficos, plt.subplots(2, 2) devuelve un arreglo de ejes que recorres con índices. Si usas la interfaz rápida plt.plot(...), Matplotlib dibuja sobre el eje activo, y ahí nacen los gráficos superpuestos que no sabes de dónde salen.

La otra noción importante es la escala. Un eje lineal no siempre es la mejor elección: para datos que crecen multiplicándose, la escala logarítmica hace visible lo que el eje lineal aplasta. Y recortar el eje vertical cambia por completo la impresión que produce la misma serie de datos, aunque los números no cambien.

PreguntaGráficoQué evitar
¿Cómo evoluciona en el tiempo?LíneaBarras para series continuas
¿Cómo se compara entre categorías?BarrasOrdenar por valor o el mensaje se pierde
¿Hay relación entre dos variables?DispersiónTrazar una recta sin mirar los puntos
¿Cómo se distribuye una variable?Histograma o cajaUn solo número de resumen
¿Cómo se cruzan dos categorías?Mapa de calorColores sin escala ni valores

Sintaxis: la receta mínima

Todo gráfico legible tiene título, ejes con nombre y, si hay varias series, leyenda. Matplotlib no los añade por ti porque no sabe qué significan tus datos. Estas cinco llamadas cubren el ochenta por ciento de los casos.

PYTHON esqueleto.py
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(6, 3.5))
ax.plot([1, 2, 3], [10, 12, 9], label="Lima")
ax.set_title("Ventas por mes")
ax.set_xlabel("Mes")
ax.set_ylabel("Miles de soles")
ax.legend()
ax.grid(alpha=0.3)
fig.savefig("ventas.png", dpi=150, bbox_inches="tight")
  • figsize se mide en pulgadas; dpi multiplica los píxeles al guardar.
  • ax.set_title, ax.set_xlabel y ax.set_ylabel son la forma orientada a objetos.
  • label dentro del dibujo más ax.legend() producen la leyenda.
  • bbox_inches="tight" recorta el espacio sobrante al exportar.
  • Para varios ejes: fig, ejes = plt.subplots(1, 2, sharey=True) y luego ejes[0], ejes[1].

Ejemplo básico: evolución mensual

Cuatro meses bastan para ver el patrón. La línea conecta valores consecutivos, así que sugiere continuidad: es la elección natural cuando el eje horizontal es tiempo.

PYTHON linea.py
import matplotlib.pyplot as plt

meses = ["Ene", "Feb", "Mar", "Abr"]
ventas = [120, 95, 140, 165]

fig, ax = plt.subplots(figsize=(6, 3))
ax.plot(meses, ventas, marker="o", color="#4c6ef5")
ax.set_title("Ventas mensuales")
ax.set_ylabel("Miles de soles")
ax.grid(alpha=0.3)
fig.savefig("ventas.png", dpi=150, bbox_inches="tight")

plot recibe la lista de etiquetas y la de valores; marker="o" añade un punto en cada dato para que se vea dónde hay medición real y dónde solo interpolación. La caída de febrero y la recuperación posterior son evidentes, pero el eje empieza en cero, así que la amplitud no está exagerada.

Si en lugar de una serie temporal tuvieras cuatro categorías sin orden, ax.bar(meses, ventas) sería más honesto: las barras no insinúan que existe un camino entre una categoría y la siguiente.

Ejemplo intermedio: dispersión y distribución

Supón que tienes horas de estudio y notas de diez estudiantes. La pregunta tiene dos partes: ¿hay relación entre ambas variables? ¿Y cómo se distribuyen las notas? Ninguna figura responde a las dos, así que dibuja dos ejes en la misma figura.

PYTHON dos_vistas.py
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

notas = pd.DataFrame({
    "horas": [2, 3, 4, 4, 5, 6, 7, 8, 9, 10],
    "nota": [10, 11, 12, 14, 13, 15, 15, 17, 16, 18],
})

fig, ejes = plt.subplots(1, 2, figsize=(9, 3.5))
sns.scatterplot(data=notas, x="horas", y="nota", ax=ejes[0])
sns.histplot(data=notas, x="nota", bins=5, ax=ejes[1])
ejes[0].set_title("Horas y nota")
ejes[1].set_title("Distribución de notas")
fig.tight_layout()

La dispersión asciende de izquierda a derecha: quien estudia más tiende a sacar más nota, aunque con dispersión. La nota media es 14.1 y el histograma muestra que la mayoría se concentra entre 12 y 17. Las dos vistas se complementan, y ax= es la clave: indica a Seaborn sobre qué eje dibujar en lugar de crear una figura nueva.

Seaborn distingue funciones de ejes, como histplot, scatterplot, boxplot y heatmap, que aceptan ax=, y funciones de figura, como relplot o displot, que devuelven un objeto propio y gestionan varios paneles. Si mezclas las dos familias sin cuidado, acabas con figuras vacías o con dos lienzos abiertos.

Caso práctico: cuatro vistas del mismo mes

Un informe de ventas suele necesitar cuatro respuestas: cuánto se vendió, quién compró, cómo se distribuyen los montos y qué producto pesa más. Cuatro paneles en una sola figura permiten compararlas sin cambiar de página.

PYTHON panel.py
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

pedidos = pd.read_csv("pedidos.csv")
fig, ejes = plt.subplots(2, 2, figsize=(10, 6))

sns.lineplot(data=pedidos, x="dia", y="ingreso", ax=ejes[0, 0])
sns.barplot(data=pedidos, x="sede", y="ingreso", estimator="sum", ax=ejes[0, 1])
sns.histplot(data=pedidos, x="ingreso", bins=20, ax=ejes[1, 0])
sns.boxplot(data=pedidos, x="producto", y="ingreso", ax=ejes[1, 1])

for eje in ejes.flat:
    eje.label_outer()
fig.tight_layout()
fig.savefig("panel_ventas.png", dpi=150)

ejes es un arreglo de dos por dos; se indexa con ejes[fila, columna]. ejes.flat lo recorre como si fuera una lista, y label_outer evita repetir las etiquetas internas, que es lo que hace ilegible un panel. barplot con estimator="sum" dibuja el total por sede y añade intervalos de confianza por defecto: si no los quieres, pasa errorbar=None.

Visualización: un mapa de calor

La matriz siguiente son las visitas a una tienda por día y franja horaria. Un mapa de calor es exactamente esto: una tabla donde el color codifica el valor. Antes de dibujarla, lee las celdas; después, comprueba si el color resalta lo mismo que los números.

Mapa de datos ·Visitas por día y franja horaria
5 × 4 rango [12, 72] Veinte celdas: cinco días por cuatro franjas. La media es 36.8 visitas.
9 h
12 h
15 h
18 h
lun
12
34
28
45
mar
15
42
31
50
mié
18
46
35
55
jue
14
40
30
48
vie
22
55
44
72

Recorre los pasos para ver cómo cambian las celdas.

El color ayuda a ver el patrón de un vistazo, pero puede engañar si la escala no está indicada o si dos mapas distintos usan rangos diferentes. Con annot=True y fmt="d" los valores quedan escritos, y cmap="viridis" mantiene el orden perceptual incluso para quien no distingue bien los colores.

Ejecución visual ·De una lista a una barra con referencia
1 / 7
1 import matplotlib.pyplot as plt
2
3 ventas = [120, 95, 140, 165]
4 promedio = sum(ventas) / len(ventas)
5 etiquetas = ["Ene", "Feb", "Mar", "Abr"]
6 fig, ax = plt.subplots(figsize=(6, 3))
7 ax.bar(etiquetas, ventas)
8 ax.axhline(promedio, color="gray", linestyle="--")
9 print(f"Promedio: {promedio}")
Se carga pyplot, el módulo de dibujo.
Variables
plt = módulo pyplot
Salida
—

Avanza paso a paso: observa la línea resaltada, las variables y la salida.

Errores comunes

SíntomaCausaSolución
No aparece ninguna ventanaEn un script falta plt.show()Añádelo al final o usa fig.savefig
Los gráficos se superponenSe dibujó sobre el eje activoCrea fig, ax y usa métodos de ax
TypeError: 'Figure' object is not subscriptableAsignaste solo la figurafig, ax = plt.subplots()
TypeError al pasar texto a sns.heatmapEl mapa de calor necesita una tabla 2D numéricaHaz pivot o selecciona solo columnas numéricas
Las etiquetas del eje x se pisanDemasiadas categorías o texto largoRota con rotation=45, ha="right"

El error de interpretación más frecuente no está en el código. Recortar el eje vertical para que las barras se vean «mejor» convierte una diferencia del 2 % en una montaña rusa. Si necesitas el detalle, usa un gráfico de puntos o una escala adecuada, pero dilo en el título.

Dibujar sin saber dónde
Incorrecto
PYTHON Usa el eje activo
plt.plot(meses, ventas)
plt.title("Ventas")
Correcto
PYTHON Controla figura y eje
fig, ax = plt.subplots(figsize=(6, 3))
ax.plot(meses, ventas)
ax.set_title("Ventas")

La interfaz rápida dibuja sobre el eje que Matplotlib considera activo, y en un bucle eso produce figuras que se mezclan. Crear la figura explícitamente te da control del tamaño, de los subplots y de lo que guardas.

Buenas prácticas

  • Escribe la pregunta antes del gráfico; si no cabe en una frase, probablemente necesites dos figuras.
  • Etiqueta siempre los ejes con unidades y pon un título que diga qué se está comparando.
  • Ordena las barras por valor: el ojo compara longitudes mejor que posiciones arbitrarias.
  • Usa una sola escala por eje; los ejes gemelos invitan a conclusiones falsas.
  • Prefiere paletas ordenadas y aptas para daltonismo: viridis, cividis o Blues.
  • Guarda con dpi=150 o más y bbox_inches="tight" para que el texto no se recorte.

Ejercicios

Ejercicio 1

Barras con referencia

Dibuja un gráfico de barras con las unidades vendidas de café, té, jugo y agua: 120, 80, 45 y 95. Añade título, etiqueta del eje vertical con la unidad, una línea horizontal en la media y guarda el archivo como unidades.png. Comprueba que la media es 85.
Pista

ax.bar recibe las etiquetas y los valores. ax.axhline dibuja la referencia; súmale linestyle="--" para distinguirla de las barras.

Completar código Completa el gráfico
fig, ax = plt.(figsize=(6, 3))
ax.(meses, ventas)
ax.set("Ventas mensuales")
fig.savefig("ventas.png", dpi=150)

La función que crea figura y ejes devuelve dos objetos. El método del título se llama como el parámetro que quieres escribir.

Ejercicio 2

Detectar una distribución sesgada

Con los montos 12, 15, 18, 20, 22, 25, 30 y 95, dibuja un histograma y un diagrama de caja en dos subplots. Calcula la media y la mediana, y explica en una línea por qué difieren tanto. Señala si el valor 95 queda fuera de los bigotes de la caja.
Pista

La caja marca el rango intercuartílico y los bigotes llegan hasta el dato más lejano dentro de 1.5 veces ese rango. Compara media y mediana antes de mirar el gráfico.

Soluciones explicadas

En el primer ejercicio, la línea de la media convierte un gráfico descriptivo en uno comparativo: ya no solo ves cuánto vendió cada producto, también cuáles están por encima del promedio. Ese pequeño añadido es el que responde una pregunta; sin él, la figura solo repite la tabla.

En el segundo, el orden de las operaciones importa: calculas media y mediana antes de dibujar, para que el gráfico confirme lo que sospechas y no al revés. Los dos paneles muestran el mismo dato desde ángulos distintos, y esa es la razón de usar subplots en lugar de una sola figura sobrecargada.

Resumen

  • Una figura contiene ejes; cada eje contiene artistas como líneas, barras o puntos.
  • fig, ax = plt.subplots() es el punto de partida de cualquier gráfico controlable.
  • Seaborn dibuja sobre ejes de Matplotlib si le pasas ax=; sus funciones de figura crean paneles propios.
  • Título, etiquetas con unidades y leyenda no son decoración: sin ellos el gráfico no se interpreta.
  • Elige el gráfico según la pregunta: línea para tiempo, barras para categorías, dispersión para relación, caja para distribución.
  • Un eje recortado o un doble eje pueden exagerar diferencias reales; decláralo o evítalo.
  • Guarda con fig.savefig(..., dpi=150, bbox_inches="tight") para conservar lo que ves en pantalla.

Evaluación

Evaluación 1

¿Qué devuelve plt.subplots(2, 2)?

Evaluación 2

Tienes ventas de cuatro productos sin relación temporal. ¿Qué gráfico responde mejor a «cuál vende más»?

Evaluación 3

Un gráfico de barras empieza el eje vertical en 95 en lugar de 0. ¿Qué efecto tiene?

Tus notas

¿Ya lo entendiste?

Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.