</>waridocu

Python

Matplotlib: graficar con pyplot

Cómo dibujar líneas, barras, dispersión e histogramas con pyplot, cómo poner títulos y leyendas, y en qué se diferencia la interfaz plt de trabajar con figure y axes.

pythonmatplotlibpyplotgraficosvisualizacionlibrerias

El problema: una lista de 500 números no dice nada

Con NumPy ya puedes calcular promedios y máximos de miles de valores. Pero imprimirlos no ayuda a entenderlos: nadie mira 500 números en la consola y ve una tendencia. Un gráfico sí la muestra de un vistazo.

Matplotlib es la librería estándar de Python para eso, y pyplot es su interfaz simple: un conjunto de funciones que van armando el gráfico paso a paso.

bashbash
pip install matplotlib
pythonpython
import matplotlib.pyplot as plt

as plt es, igual que np para NumPy, la convención universal.

El gráfico mínimo

Ejemplo: tres líneas y ya hay un gráficopython
import matplotlib.pyplot as plt

meses = [1, 2, 3, 4, 5]
ventas = [120, 145, 130, 180, 210]

plt.plot(meses, ventas)
plt.show()

plot(x, y) dibuja una línea uniendo los puntos, y show() abre la ventana con el resultado.

Importante

plt.show() va al final, una sola vez, después de todo lo que quieras dibujar. Es un error muy común llamarlo después de cada plot y terminar con varias ventanas de un elemento cada una en vez de un gráfico completo. En un notebook de Jupyter se puede omitir, porque el gráfico se muestra solo.

Un gráfico que se entiende solo

Una línea sin etiquetas no comunica nada. Estas cuatro funciones convierten un dibujo en un gráfico:

Ejemplo: el mismo gráfico, ahora legiblepython
import matplotlib.pyplot as plt

meses = [1, 2, 3, 4, 5]
ventas = [120, 145, 130, 180, 210]

plt.plot(meses, ventas, label="Sucursal centro")

plt.title("Ventas del primer semestre")
plt.xlabel("Mes")
plt.ylabel("Unidades vendidas")
plt.legend()
plt.grid(True)

plt.show()
FunciónQué agrega
plt.title("...")El título arriba del gráfico
plt.xlabel(...) / plt.ylabel(...)El nombre de cada eje
plt.legend()El recuadro que explica cada serie
plt.grid(True)La cuadrícula de fondo
Advertencia

plt.legend() solo muestra las series que tengan label=. Si llamas a legend() y no aparece nada (con una advertencia sobre “No artists with labels found”), es que te faltó el label en el plot.

Varias series en un mismo gráfico

Llamar a plot varias veces antes del show superpone las líneas:

Ejemplo: comparar dos sucursalespython
meses = [1, 2, 3, 4, 5]
centro = [120, 145, 130, 180, 210]
norte = [90, 100, 160, 150, 170]

plt.plot(meses, centro, label="Centro")
plt.plot(meses, norte, label="Norte")

plt.title("Ventas por sucursal")
plt.xlabel("Mes")
plt.ylabel("Unidades")
plt.legend()
plt.show()

Matplotlib les asigna colores distintos automáticamente. Si quieres controlarlos, plot acepta parámetros de estilo:

pythonpython
plt.plot(meses, centro, color="crimson", linestyle="--", marker="o", linewidth=2)
ParámetroPara quéValores típicos
colorColor de la línea"red", "crimson", "#2ecc71"
linestyleTipo de trazo"-" sólida, "--" guiones, ":" puntos
markerMarca en cada punto"o" círculo, "s" cuadrado, "^" triángulo
linewidthGrosorUn número
alphaTransparenciaDe 0 a 1
labelNombre en la leyendaUn texto

Los cuatro tipos de gráfico que más vas a usar

Cambia la función y cambia el gráfico; el resto (títulos, etiquetas, show) es idéntico.

Línea: cómo evoluciona algo en el tiempo

pythonpython
plt.plot(meses, ventas)

Es el gráfico por defecto y el correcto cuando el eje X tiene un orden natural — meses, días, distancias. Unir los puntos con una línea afirma que hay continuidad entre ellos.

Barras: comparar categorías

Ejemplo: comparar valores que no tienen orden entre sípython
productos = ["Café", "", "Mate", "Jugo"]
vendidos = [340, 180, 420, 90]

plt.bar(productos, vendidos, color="teal")
plt.title("Unidades vendidas por producto")
plt.ylabel("Unidades")
plt.show()

bar es lo correcto cuando el eje X son categorías sin orden. Usar una línea aquí sería un error de lectura: sugeriría que hay una progresión del café al té que no existe. Para barras horizontales, plt.barh(...).

Dispersión: la relación entre dos variables

Ejemplo: ¿estudiar más se relaciona con mejor nota?python
import numpy as np

horas = np.array([1, 2, 2, 3, 4, 4, 5, 6, 7, 8])
notas = np.array([3, 4, 5, 5, 6, 7, 7, 8, 9, 9])

plt.scatter(horas, notas, color="darkorange", alpha=0.7)
plt.title("Horas de estudio vs. nota")
plt.xlabel("Horas")
plt.ylabel("Nota")
plt.show()

scatter dibuja puntos sueltos, sin unirlos. Es lo indicado cuando cada punto es una observación independiente y lo que buscas es ver si hay una tendencia entre las dos variables.

Histograma: cómo se reparten los valores

Ejemplo: la distribución de 1000 valores aleatoriospython
import numpy as np

datos = np.random.normal(170, 10, 1000)

plt.hist(datos, bins=30, color="mediumpurple", edgecolor="white")
plt.title("Distribución de estaturas")
plt.xlabel("cm")
plt.ylabel("Frecuencia")
plt.show()

hist recibe una sola lista de valores, los agrupa en intervalos (bins) y dibuja cuántos cayeron en cada uno. No confundir con bar: en bar tú das la altura de cada barra; en hist la altura la cuenta Matplotlib.

Nota

bins cambia mucho la lectura del histograma: pocos intervalos esconden detalle, demasiados lo llenan de ruido. Entre 20 y 50 suele ser un buen punto de partida para unos cuantos cientos de datos.

Varios gráficos en una figura: subplots

Para poner gráficos lado a lado, subplot(filas, columnas, posición):

Ejemplo: dos gráficos en la misma ventanapython
plt.subplot(1, 2, 1)
plt.plot(meses, centro)
plt.title("Centro")

plt.subplot(1, 2, 2)
plt.bar(productos, vendidos)
plt.title("Productos")

plt.tight_layout()
plt.show()

subplot(1, 2, 1) significa “una fila, dos columnas, estoy trabajando en la primera”. Todo lo que dibujes después va ahí, hasta que llames al siguiente subplot. tight_layout() reacomoda los márgenes para que los títulos no se pisen.

Importante

La posición se cuenta desde 1, no desde 0 — es de los pocos lugares de Python donde eso pasa, y confunde a todo el mundo la primera vez.

plt.* y el enfoque orientado a objetos

En documentación y respuestas de internet vas a ver dos estilos distintos, y conviene reconocerlos:

Ejemplo: el estilo plt (implícito)python
plt.plot(x, y)
plt.title("Título")
plt.show()
Ejemplo: el estilo orientado a objetos (explícito)python
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title("Título")
plt.show()

Los dos producen el mismo gráfico. La diferencia es dónde va el resultado:

  • plt.algo(...) actúa sobre “el gráfico actual”, un estado global que Matplotlib mantiene por detrás. Cómodo para algo rápido.
  • fig, ax = plt.subplots() te devuelve los objetos: fig es la ventana entera y ax los ejes de un gráfico concreto. Cada llamada dice explícitamente sobre cuál actúa.

Fíjate en el detalle que más marea al pasar de uno a otro: los nombres cambian. plt.title(...) se convierte en ax.set_title(...), plt.xlabel(...) en ax.set_xlabel(...). La regla es que casi todo gana el prefijo set_.

Nota

Para un gráfico suelto, el estilo plt alcanza y es más corto. Cuando hay varios subplots o el gráfico se arma dentro de una función, el estilo con ax evita el error clásico de dibujar sobre el gráfico equivocado porque el “actual” no era el que creías.

Guardar en vez de mostrar

pythonpython
plt.savefig("ventas.png", dpi=150, bbox_inches="tight")

savefig guarda el gráfico en un archivo — la extensión decide el formato (.png, .pdf, .svg). dpi controla la resolución y bbox_inches="tight" recorta el margen blanco sobrante.

Advertencia

savefig tiene que ir antes de show(). show() vacía la figura al cerrarse, así que si guardas después obtienes un PNG en blanco. Es uno de los errores más frustrantes de Matplotlib justamente porque no da ningún mensaje de error.

NumPy y pyplot juntos

Es la combinación para la que las dos librerías fueron pensadas: NumPy genera y transforma los datos, pyplot los dibuja.

Ejemplo: dibujar una función matemáticapython
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)

plt.plot(x, y, label="sen(x)")
plt.plot(x, np.cos(x), label="cos(x)", linestyle="--")

plt.title("Seno y coseno")
plt.xlabel("x (radianes)")
plt.ylabel("valor")
plt.axhline(0, color="gray", linewidth=0.8)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

Aquí se ve por qué linspace era la función correcta para esto: 200 puntos repartidos parejo entre 0 y 2π dan una curva suave. Con arange habrías tenido que calcular a mano el paso para que entraran 200.

Pon a prueba

🎯 ¿Qué gráfico corresponde?

Tienes la cantidad de películas vistas por género: comedia 12, drama 8, terror 15, documental 4. Quieres comparar cuál se ve más. ¿Qué función de pyplot corresponde?

  • Correcto. Los géneros son categorías sin progresión: nada hace que "terror" venga después de "comedia". Las barras comparan alturas sin insinuar continuidad, que es exactamente lo que se quiere.

  • Dibujaría, pero comunicaría algo falso: la línea que une "comedia" con "terror" sugiere una transición entre géneros que no existe. Reserva la línea para ejes con orden natural, como el tiempo.

  • Ese es justo el punto en el que se confunden: hist recibe los valores en bruto y él mismo cuenta cuántos caen en cada intervalo. Aquí los totales ya están calculados, así que corresponde bar, donde tú das la altura.

  • scatter sirve para ver la relación entre dos variables numéricas. Con una categoría y un total, los puntos sueltos son más difíciles de comparar que unas barras.

💡 Encuentra los tres errores

Este código se ejecuta sin fallar, pero produce dos ventanas en vez de una, sin leyenda, y guarda un PNG completamente en blanco. ¿Qué está mal?

pythonpython
import matplotlib.pyplot as plt

meses = [1, 2, 3, 4]
centro = [120, 145, 130, 180]
norte = [90, 100, 160, 150]

plt.plot(meses, centro, label="Centro")
plt.show()

plt.plot(meses, norte)
plt.legend()
plt.show()

plt.savefig("ventas.png")

1. Hay dos plt.show(). El primero cierra la figura, así que la segunda línea empieza un gráfico nuevo en vez de superponerse. show() va una sola vez, al final de todo.

2. Al segundo plot le falta label=. legend() solo lista las series etiquetadas; sin label="Norte" no tiene nada que mostrar de esa línea (y Matplotlib avisa con “No artists with labels found”).

3. savefig está después del último show(). Para entonces la figura ya se vació, así que el archivo sale en blanco. Y como no es un error, no hay ningún mensaje que lo delate.

La versión correcta:

pythonpython
plt.plot(meses, centro, label="Centro")
plt.plot(meses, norte, label="Norte")
plt.legend()
plt.savefig("ventas.png")
plt.show()

El orden que conviene memorizar: dibujar todo → etiquetar → guardar → mostrar.

✏️ Completa el gráfico

Un gráfico de barras con título, nombre del eje vertical y guardado en archivo antes de mostrarse.

import matplotlib.pyplot as 

productos = ["Café", "Té", "Mate"]
vendidos = [340, 180, 420]

plt.(productos, vendidos)
plt.("Unidades vendidas")
plt.ylabel("Unidades")
plt.savefig("ventas.png")
plt.()

🧩 Ordena el código

Ordena las líneas para dibujar la curva del seno con título y leyenda, guardarla y mostrarla.

  1. plt.title("Función seno")
  2. x = np.linspace(0, 2 * np.pi, 200)
  3. import numpy as np
  4. plt.show()
  5. plt.plot(x, np.sin(x), label="sen(x)")
  6. plt.legend()
  7. plt.savefig("seno.png")
  8. import matplotlib.pyplot as plt

Hasta aquí llega esta sección

Con NumPy para calcular y pyplot para visualizar tienes la base del stack científico de Python. El paso siguiente natural es pandas, que agrega tablas con nombres de columna (los DataFrame) sobre los arrays de NumPy y se integra con Matplotlib directamente — es la herramienta habitual para leer un CSV, limpiarlo y graficarlo en pocas líneas.