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.
- 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
- ¿Qué es Matplotlib?
- ¿Para qué sirve?
- ¿Cómo funciona por dentro? Figura y ejes
- Sintaxis: la receta mínima
- Ejemplo básico: evolución mensual
- Ejemplo intermedio: dispersión y distribución
- Caso práctico: cuatro vistas del mismo mes
- Visualización: un mapa de calor
- Errores comunes
- Buenas prácticas
- Ejercicios
- Soluciones explicadas
- Resumen
- 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.
| Pregunta | Gráfico | Qué evitar |
|---|---|---|
| ¿Cómo evoluciona en el tiempo? | Línea | Barras para series continuas |
| ¿Cómo se compara entre categorías? | Barras | Ordenar por valor o el mensaje se pierde |
| ¿Hay relación entre dos variables? | Dispersión | Trazar una recta sin mirar los puntos |
| ¿Cómo se distribuye una variable? | Histograma o caja | Un solo número de resumen |
| ¿Cómo se cruzan dos categorías? | Mapa de calor | Colores 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.
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")figsizese mide en pulgadas;dpimultiplica los píxeles al guardar.ax.set_title,ax.set_xlabelyax.set_ylabelson la forma orientada a objetos.labeldentro del dibujo másax.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 luegoejes[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.
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.
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.
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.
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.
import matplotlib.pyplot as pltventas = [120, 95, 140, 165]promedio = sum(ventas) / len(ventas)etiquetas = ["Ene", "Feb", "Mar", "Abr"]fig, ax = plt.subplots(figsize=(6, 3))ax.bar(etiquetas, ventas)ax.axhline(promedio, color="gray", linestyle="--")print(f"Promedio: {promedio}")pyplot, el módulo de dibujo.—
Avanza paso a paso: observa la línea resaltada, las variables y la salida.
Errores comunes
| Síntoma | Causa | Solución |
|---|---|---|
| No aparece ninguna ventana | En un script falta plt.show() | Añádelo al final o usa fig.savefig |
| Los gráficos se superponen | Se dibujó sobre el eje activo | Crea fig, ax y usa métodos de ax |
TypeError: 'Figure' object is not subscriptable | Asignaste solo la figura | fig, ax = plt.subplots() |
TypeError al pasar texto a sns.heatmap | El mapa de calor necesita una tabla 2D numérica | Haz pivot o selecciona solo columnas numéricas |
| Las etiquetas del eje x se pisan | Demasiadas categorías o texto largo | Rota 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.
plt.plot(meses, ventas)
plt.title("Ventas")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,cividisoBlues. - Guarda con
dpi=150o más ybbox_inches="tight"para que el texto no se recorte.
Ejercicios
Barras con referencia
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.
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.
Detectar una distribución sesgada
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
¿Qué devuelve plt.subplots(2, 2)?
Tienes ventas de cuatro productos sin relación temporal. ¿Qué gráfico responde mejor a «cuál vende más»?
Un gráfico de barras empieza el eje vertical en 95 en lugar de 0. ¿Qué efecto tiene?
¿Ya lo entendiste?
Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.