Skip to content

Matplotlib Subplots: Crear Figuras Multipanel con plt.subplots()

Updated on

Las figuras de un solo panel rara vez son suficientes para análisis reales. Necesita comparar distribuciones lado a lado, mostrar un gráfico de dispersión junto a sus residuos, o presentar cuatro métricas en un diseño de dashboard. Sin subplots, crearía figuras separadas que pierden su relación visual cuando se presentan juntas.

La función plt.subplots() de Matplotlib crea figuras multipanel con ejes compartidos, tamaño consistente y layouts flexibles. Esta guía cubre todo, desde cuadrículas básicas hasta layouts asimétricos avanzados.

📚

Subplots Básicos

Fila Única

import matplotlib.pyplot as plt
import numpy as np
 
x = np.linspace(0, 10, 100)
 
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
 
axes[0].plot(x, np.sin(x))
axes[0].set_title('Seno')
 
axes[1].plot(x, np.cos(x), color='orange')
axes[1].set_title('Coseno')
 
axes[2].plot(x, np.tan(x), color='green')
axes[2].set_ylim(-5, 5)
axes[2].set_title('Tangente')
 
plt.tight_layout()
plt.show()

Diseño en Cuadrícula

import matplotlib.pyplot as plt
import numpy as np
 
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
 
x = np.linspace(0, 10, 100)
 
axes[0, 0].plot(x, x, 'b-')
axes[0, 0].set_title('Lineal')
 
axes[0, 1].plot(x, x**2, 'r-')
axes[0, 1].set_title('Cuadrático')
 
axes[1, 0].plot(x, np.sqrt(x), 'g-')
axes[1, 0].set_title('Raíz Cuadrada')
 
axes[1, 1].plot(x, np.log(x + 1), 'm-')
axes[1, 1].set_title('Logarítmico')
 
plt.tight_layout()
plt.show()

Ejes Compartidos

Compartir ejes asegura escalas consistentes para comparación:

import matplotlib.pyplot as plt
import numpy as np
 
np.random.seed(42)
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 1.5, 1000)
 
# Compartir eje X
fig, axes = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
axes[0].hist(data1, bins=30, color='steelblue', alpha=0.7)
axes[0].set_ylabel('Conteo')
axes[0].set_title('Distribución A')
 
axes[1].hist(data2, bins=30, color='coral', alpha=0.7)
axes[1].set_ylabel('Conteo')
axes[1].set_xlabel('Valor')
axes[1].set_title('Distribución B')
 
plt.tight_layout()
plt.show()
import matplotlib.pyplot as plt
import numpy as np
 
# Compartir ambos ejes X e Y
fig, axes = plt.subplots(2, 3, figsize=(12, 8), sharex=True, sharey=True)
 
for i, ax in enumerate(axes.flat):
    data = np.random.randn(100)
    ax.hist(data, bins=20, color=f'C{i}', alpha=0.7)
    ax.set_title(f'Muestra {i+1}')
 
plt.tight_layout()
plt.show()

Control de Espaciado y Layout

tight_layout()

Ajusta automáticamente el espaciado para evitar superposición:

import matplotlib.pyplot as plt
 
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# ... agregar gráficos ...
plt.tight_layout()  # Auto-corregir espaciado
plt.show()

subplots_adjust()

Control manual del espaciado:

import matplotlib.pyplot as plt
 
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
plt.subplots_adjust(
    left=0.1,    # Margen izquierdo
    right=0.95,  # Margen derecho
    top=0.92,    # Margen superior
    bottom=0.08, # Margen inferior
    wspace=0.3,  # Espacio horizontal entre subplots
    hspace=0.4,  # Espacio vertical entre subplots
)
plt.show()

Agregar un Supertítulo

import matplotlib.pyplot as plt
import numpy as np
 
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
fig.suptitle('Funciones Trigonométricas', fontsize=16, fontweight='bold')
 
x = np.linspace(0, 2 * np.pi, 100)
for ax, func, name in zip(axes, [np.sin, np.cos, np.tan], ['sin', 'cos', 'tan']):
    ax.plot(x, func(x))
    ax.set_title(name)
 
plt.tight_layout()
plt.show()

GridSpec para Layouts Asimétricos

Cuando necesita paneles de diferentes tamaños, use GridSpec:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
 
fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(2, 3, figure=fig)
 
# Panel grande izquierdo (abarca 2 filas)
ax1 = fig.add_subplot(gs[:, 0])
ax1.plot(np.random.randn(100).cumsum())
ax1.set_title('Serie Temporal (2 filas)')
 
# Paneles superiores derechos
ax2 = fig.add_subplot(gs[0, 1])
ax2.bar(['A', 'B', 'C'], [3, 7, 5])
ax2.set_title('Gráfico de Barras')
 
ax3 = fig.add_subplot(gs[0, 2])
ax3.scatter(np.random.randn(50), np.random.randn(50))
ax3.set_title('Dispersión')
 
# Panel inferior ancho (abarca 2 columnas)
ax4 = fig.add_subplot(gs[1, 1:])
ax4.hist(np.random.randn(500), bins=30, color='coral')
ax4.set_title('Histograma (2 columnas)')
 
plt.tight_layout()
plt.show()

subplot2grid para Layout Basado en Posición

import matplotlib.pyplot as plt
import numpy as np
 
fig = plt.figure(figsize=(12, 8))
 
# (filas, cols), (fila_inicio, col_inicio), rowspan, colspan
ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=2)
ax2 = plt.subplot2grid((3, 3), (0, 2), rowspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0))
ax4 = plt.subplot2grid((3, 3), (1, 1))
ax5 = plt.subplot2grid((3, 3), (2, 0), colspan=3)
 
ax1.set_title('Superior Ancho')
ax2.set_title('Derecho Alto')
ax3.set_title('Centro Izquierda')
ax4.set_title('Centro Medio')
ax5.set_title('Inferior Ancho Completo')
 
plt.tight_layout()
plt.show()

Iterar Sobre Subplots

import matplotlib.pyplot as plt
import numpy as np
 
# Aplanar array de axes para iteración fácil
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
 
datasets = [np.random.randn(100) for _ in range(6)]
colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c']
 
for ax, data, color, i in zip(axes.flat, datasets, colors, range(6)):
    ax.hist(data, bins=20, color=color, alpha=0.7)
    ax.set_title(f'Conjunto de Datos {i+1}')
    ax.set_xlabel('Valor')
    ax.set_ylabel('Conteo')
 
plt.tight_layout()
plt.show()

Eliminar Subplots Vacíos

Cuando tiene menos gráficos que posiciones en la cuadrícula:

import matplotlib.pyplot as plt
import numpy as np
 
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
data_count = 5  # Solo 5 conjuntos de datos para 6 espacios
 
for i, ax in enumerate(axes.flat):
    if i < data_count:
        ax.plot(np.random.randn(50).cumsum())
        ax.set_title(f'Gráfico {i+1}')
    else:
        ax.set_visible(False)  # Ocultar subplot vacío
 
plt.tight_layout()
plt.show()

Exploración Interactiva Multipanel

Para exploración visual rápida donde quiere comparar diferentes vistas del mismo conjunto de datos interactivamente, PyGWalker (opens in a new tab) le permite crear dashboards arrastrando y soltando columnas en Jupyter -- sin necesidad de código de subplots:

import pandas as pd
import pygwalker as pyg
 
df = pd.read_csv('your_data.csv')
walker = pyg.walk(df)

FAQ

¿Cómo creo subplots en Matplotlib?

Use fig, axes = plt.subplots(filas, columnas) para crear una figura con una cuadrícula de subplots. Acceda a ejes individuales con axes[fila, columna] para cuadrículas o axes[i] para filas/columnas únicas. Siempre llame a plt.tight_layout() al final para evitar etiquetas superpuestas.

¿Cómo comparto ejes entre subplots?

Pase sharex=True o sharey=True a plt.subplots(). Por ejemplo, fig, axes = plt.subplots(2, 1, sharex=True) hace que ambos subplots compartan la misma escala del eje x. Esto es útil para comparar distribuciones o series temporales.

¿Cómo creo subplots de diferentes tamaños?

Use matplotlib.gridspec.GridSpec para layouts asimétricos. Cree una cuadrícula y use notación de slice para abarcar múltiples celdas: ax = fig.add_subplot(gs[0, :2]) crea un subplot que abarca las dos primeras columnas de la primera fila.

¿Cómo ajusto el espaciado entre subplots?

Llame a plt.tight_layout() para espaciado automático. Para control manual, use plt.subplots_adjust(wspace=0.3, hspace=0.4) donde wspace es el espaciado horizontal y hspace es el espaciado vertical.

¿Cómo agrego un título sobre todos los subplots?

Use fig.suptitle('Mi Título', fontsize=16) para agregar un supertítulo sobre todos los subplots. Puede necesitar ajustar el margen superior con plt.subplots_adjust(top=0.92) o llamar a plt.tight_layout() para evitar superposición.

Conclusión

El plt.subplots() de Matplotlib es la base para figuras multipanel. Úselo con (filas, columnas) para cuadrículas regulares, sharex/sharey para escalas consistentes, tight_layout() para espaciado automático, y GridSpec para layouts asimétricos. Para iteración rápida, aplane el array de axes con axes.flat y recorra. Estos patrones cubren la gran mayoría de las necesidades de visualización multipanel.

📚