Matplotlib es la biblioteca de referencia del ecosistema científico de Python para crear gráficos estáticos, animados e interactivos. Está escrita en Python puro con extensiones en C, depende de NumPy para datos numéricos y se integra nativamente con Pandas, SciPy, scikit-learn y Jupyter Lab. La versión 3.9 introdujo mejoras importantes en tipado con TypedDict, 3D acelerado y nuevos estilos por defecto compatibles con Python 3.12.
¿Qué es Matplotlib?
Matplotlib proporciona dos interfaces complementarias: pyplot, una máquina de estados inspirada en MATLAB que lleva el estado global de la figura activa, y una API orientada a objetos que manipula directamente Figure, Axes y Artist. La segunda es la recomendada para contenido reutilizable y para cualquier aplicación que genere figuras en paralelo.
Jerarquía Figure, Axes y Artist
Todo gráfico en Matplotlib se descompone en tres niveles. Este diagrama resume cómo encajan los contenedores principales y qué artistas vive en cada uno.
graph TD
Figure["Figure (contenedor raíz)"]
Figure --> SupTitle["suptitle"]
Figure --> Axes1["Axes 1 (plot cartesiano)"]
Figure --> Axes2["Axes 2 (proyección 3D)"]
Figure --> Axes3["Axes 3 (proyección polar)"]
Figure --> Colorbar["Colorbar (Axes secundario)"]
Axes1 --> XAxis["XAxis"]
Axes1 --> YAxis["YAxis"]
Axes1 --> Line2D["Line2D"]
Axes1 --> PathCollection["PathCollection (scatter)"]
Axes1 --> Text["Text (título, etiquetas, anotaciones)"]
Axes1 --> Legend["Legend"]
XAxis --> Tick["Tick, Locator, Formatter"]
YAxis --> Tick
- Figure es el lienzo completo y gestiona el canvas del backend.
- Axes es la región donde se dibujan los datos. Una figura puede tener muchos
Axescon proyecciones distintas (cartesiana, polar, 3D). - Artist es todo elemento dibujable:
Line2D,PathCollection,Text,Patch,Image, etc.
Instalación de Matplotlib
Para instalar Matplotlib se utiliza pip o conda:
pip install matplotlib
conda install -c conda-forge matplotlib
Matplotlib 3.9 o superior requiere Python 3.10 como mínimo y NumPy 1.23 o superior. En entornos científicos conviene instalar también ipympl para el backend interactivo en Jupyter Lab y pillow para exportación de imágenes.
pyplot frente a API orientada a objetos
Las dos interfaces no son excluyentes, pero responden a patrones distintos. Este diagrama ilustra el flujo de datos y estado en cada una.
flowchart LR
subgraph Pyplot["pyplot (state-machine)"]
P1["plt.plot(x, y)"]
P2["plt.xlabel(...)"]
P3["plt.title(...)"]
P4["plt.show()"]
P1 --> P2 --> P3 --> P4
P1 -.-> CurrentAxes["gca() (Axes activo)"]
P2 -.-> CurrentAxes
P3 -.-> CurrentAxes
end
subgraph OO["API orientada a objetos"]
O1["fig, ax = plt.subplots()"]
O2["ax.plot(x, y)"]
O3["ax.set_xlabel(...)"]
O4["ax.set_title(...)"]
O5["fig.savefig(...)"]
O1 --> O2 --> O3 --> O4 --> O5
end
La API orientada a objetos gana en claridad cuando hay varios Axes, cuando la figura se devuelve como resultado de una función o cuando el código se ejecuta fuera de un notebook (tests, pipelines, servicios web).
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot([1, 2, 3, 4, 5], [10, 15, 13, 17, 20],
color="steelblue", linewidth=2, marker="o", label="serie A")
ax.set_xlabel("Tiempo")
ax.set_ylabel("Valor")
ax.set_title("Gráfico de líneas con API OO")
ax.legend()
fig.savefig("grafico.png", dpi=200, bbox_inches="tight")
Backends y entornos
El backend decide cómo se renderiza la figura: ventana nativa, archivo de imagen, SVG, PDF o figura embebida en el navegador. Este diagrama resume los backends más habituales y cuándo conviene cada uno.
graph LR
Matplotlib[Matplotlib core]
Matplotlib --> NoGUI{"¿Necesita ventana interactiva?"}
NoGUI -- "No, solo exportar" --> NonInteractive["Backends no interactivos"]
NoGUI -- "Sí, escritorio" --> InteractiveDesktop["Backends GUI"]
NoGUI -- "Sí, navegador" --> InteractiveWeb["Backends web"]
NonInteractive --> Agg["Agg (PNG)"]
NonInteractive --> PDF["PDF (vectorial)"]
NonInteractive --> SVG["SVG (vectorial)"]
NonInteractive --> PS["PostScript / EPS"]
InteractiveDesktop --> TkAgg["TkAgg (por defecto Windows)"]
InteractiveDesktop --> QtAgg["QtAgg (Qt5 / Qt6)"]
InteractiveDesktop --> MacOSX["macosx"]
InteractiveWeb --> InlineJupyter["inline (Jupyter Classic)"]
InteractiveWeb --> Ipympl["ipympl (Jupyter Lab)"]
InteractiveWeb --> WebAgg["WebAgg (servidor local)"]
En pipelines de producción y servidores sin pantalla se fija matplotlib.use("Agg") antes de importar pyplot. En Jupyter Lab se activa la interacción con %matplotlib widget usando ipympl.
Gráficos básicos
Gráfico de líneas
Un gráfico de líneas muestra tendencias a lo largo de un eje continuo, habitualmente el tiempo.
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4, 5], [10, 15, 13, 17, 20],
color="steelblue", linewidth=2, marker="o")
ax.set_xlabel("Tiempo")
ax.set_ylabel("Valor")
ax.set_title("Gráfico de líneas")
Gráfico de dispersión
Visualiza la relación entre dos variables numéricas y permite mapear una tercera a color o tamaño.
import numpy as np
rng = np.random.default_rng(42)
x = rng.standard_normal(200)
y = x + rng.standard_normal(200) * 0.5
fig, ax = plt.subplots()
sc = ax.scatter(x, y, c=y, cmap="viridis", alpha=0.7, edgecolors="white")
fig.colorbar(sc, ax=ax, label="Valor Y")
ax.set_xlabel("Variable X")
ax.set_ylabel("Variable Y")
Gráfico de barras
Compara cantidades entre categorías discretas.
categorias = ["A", "B", "C", "D"]
valores = [4, 7, 1, 8]
fig, ax = plt.subplots()
ax.bar(categorias, valores,
color=["#3498db", "#e74c3c", "#2ecc71", "#f39c12"])
ax.set_ylabel("Valores")
Personalización
ax.set_title("Título del gráfico", fontsize=16, fontweight="bold")
ax.set_xlabel("Etiqueta del eje X", fontsize=12)
ax.set_ylabel("Etiqueta del eje Y", fontsize=12)
ax.legend(loc="upper right", frameon=True)
Hojas de estilo
Matplotlib ofrece hojas de estilo listas para usar y es posible crear archivos .mplstyle propios.
plt.style.use("seaborn-v0_8")
plt.style.use(["dark_background", "./corporate.mplstyle"])
Anotaciones
Las anotaciones dirigen la atención del lector hacia puntos concretos.
ax.annotate("Punto importante", xy=(2, 15), xytext=(3, 20),
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=0.2"),
fontsize=12)
Colormaps perceptualmente uniformes
Matplotlib incluye familias de colormaps separadas por uso: secuenciales (viridis, cividis, inferno, magma, plasma), divergentes (RdBu_r, coolwarm, seismic), cualitativos (tab10, Set2) y cíclicos (twilight). La familia recomendada para datos científicos es viridis (y cividis en contextos accesibles para daltonismo) porque preserva la luminosidad al imprimir en escala de grises.
Subplots y layouts
fig, axs = plt.subplots(2, 2, figsize=(10, 8), layout="constrained")
axs[0, 0].plot(x, y)
axs[0, 0].set_title("Líneas")
axs[0, 1].bar(categorias, valores)
axs[0, 1].set_title("Barras")
axs[1, 0].scatter(x, y)
axs[1, 0].set_title("Dispersión")
axs[1, 1].hist(rng.standard_normal(1000), bins=30)
axs[1, 1].set_title("Histograma")
Gráficos 3D
from mpl_toolkits.mplot3d import Axes3D # habilita projection="3d"
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection="3d")
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X ** 2 + Y ** 2))
ax.plot_surface(X, Y, Z, cmap="viridis")
ax.view_init(elev=30, azim=45)
Guardar figuras en varios formatos
Para publicaciones científicas o informes conviene exportar en vectorial (SVG o PDF) y en PNG a 300 dpi para previsualización.
fig.savefig("grafico.png", dpi=300, bbox_inches="tight")
fig.savefig("grafico.pdf", bbox_inches="tight")
fig.savefig("grafico.svg", bbox_inches="tight")
Animaciones con FuncAnimation
El módulo matplotlib.animation permite generar animaciones programáticas y exportarlas a GIF, MP4 o HTML5. Este diagrama resume el ciclo de FuncAnimation.
sequenceDiagram
participant Dev as Código
participant Fig as Figure
participant Anim as FuncAnimation
participant Writer as FFmpeg / Pillow
Dev->>Fig: fig, ax = plt.subplots()
Dev->>Fig: artista = ax.plot([], [])
Dev->>Anim: FuncAnimation(fig, update, frames, init_func, interval, blit)
loop Cada frame i
Anim->>Dev: update(i)
Dev-->>Anim: devuelve artistas modificados
Anim->>Fig: redibuja (blit si aplica)
end
Dev->>Anim: anim.save("salida.mp4", writer="ffmpeg")
Anim->>Writer: serializa frames
Writer-->>Dev: archivo de vídeo
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
line, = ax.plot([], [])
def init():
ax.set_xlim(0, 2 * np.pi)
ax.set_ylim(-1.1, 1.1)
return line,
def update(frame):
x = np.linspace(0, 2 * np.pi, 200)
line.set_data(x, np.sin(x + frame / 10))
return line,
anim = FuncAnimation(fig, update, frames=100, init_func=init,
interval=50, blit=True)
Integración con Pandas, Seaborn y Jupyter Lab
Matplotlib es la base sobre la que se apoyan Pandas (con el método DataFrame.plot), Seaborn (con gráficos estadísticos de alto nivel) y Jupyter Lab (con backend inline e ipympl). Este diagrama muestra las dependencias y los puntos de extensión.
graph TD
NumPy[NumPy] --> MatplotlibCore[Matplotlib core]
MatplotlibCore --> Pyplot[pyplot]
MatplotlibCore --> Animation[animation]
MatplotlibCore --> Toolkits[mpl_toolkits (3D, axes_grid1)]
MatplotlibCore --> Pandas[Pandas DataFrame.plot]
MatplotlibCore --> Seaborn[Seaborn]
MatplotlibCore --> Mplfinance[mplfinance (finanzas)]
MatplotlibCore --> Plotly[Plotly (interop parcial)]
MatplotlibCore --> Streamlit[Streamlit st.pyplot]
MatplotlibCore --> JupyterLab[Jupyter Lab + ipympl]
Seaborn --> PandasData[DataFrames limpios]
Pandas --> PandasData
import pandas as pd
df = pd.DataFrame({
"Año": [2020, 2021, 2022, 2023, 2024],
"Ventas": [250, 300, 400, 350, 420],
})
ax = df.plot(x="Año", y="Ventas", kind="bar", figsize=(8, 5), legend=False)
ax.set_ylabel("Ventas")
Buenas prácticas
- Preferir la API orientada a objetos en cualquier contenido que sobreviva a una sesión interactiva.
- Usar
layout="constrained"al crear la figura para evitar solapes, alternativa moderna atight_layout. - Elegir colormaps perceptualmente uniformes (
viridis,cividis) y evitarjet. - Exportar en formato vectorial (SVG o PDF) para publicaciones y en PNG a 300 dpi para informes.
- Fijar
matplotlib.rcParamsal inicio del notebook o del módulo para unificar estilo en todo el proyecto.
Recursos adicionales
- Documentación oficial: matplotlib.org
- Galería de ejemplos: matplotlib.org/stable/gallery
- mplfinance (gráficos financieros): github.com/matplotlib/mplfinance