Matplotlib permite crear experiencias interactivas tanto en terminales como en notebooks. Aprovecharemos el modo interactivo, selectores y widgets para responder a eventos del usuario sin abandonar la API orientada a objetos.
12.1 plt.ion() y gráficos interactivos
El modo interactivo actualiza la figura mientras el script sigue ejecutándose. Necesitás un backend interactivo: QtAgg (basado en Qt, ofrece ventanas modernas con soporte completo de widgets) o TkAgg (usa Tkinter, liviano y disponible por defecto en muchas instalaciones). Ambos permiten que la ventana de la figura procese eventos de zoom/pan sin bloquear tu código.
import numpy as np
import matplotlib.pyplot as plt
import time
plt.ion()
fig, ax = plt.subplots(layout="constrained")
x = np.linspace(0, 2 * np.pi, 300)
(line,) = ax.plot(x, np.sin(x), label="sin(x)")
ax.set_ylim(-1.5, 1.5)
ax.legend()
fig.canvas.draw_idle()
for f in np.linspace(1, 3, 30):
y = np.sin(f * x)
line.set_ydata(y)
ax.set_title(f"Frecuencia: {f:.2f} Hz")
fig.canvas.draw_idle()
fig.canvas.flush_events()
time.sleep(0.05)
plt.ioff()
plt.show()
💡 Si no ves actualizaciones, verificá el backend con matplotlib.get_backend() o probá en un entorno notebook con %matplotlib widget.
12.2 Zoom, pan y selección
La barra de herramientas de cualquier figura incluye zoom y pan. Para selecciones más avanzadas Matplotlib dispone de SpanSelector, RectangleSelector, LassoSelector, etc.
Selección horizontal con SpanSelector
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
x = np.linspace(0, 10, 500)
y = np.sin(2 * np.pi * x) * np.exp(-0.2 * x)
fig, (ax, ax_zoom) = plt.subplots(2, 1, figsize=(8, 6), layout="constrained")
ax.plot(x, y)
ax.set_title("Arrastrá para seleccionar un rango (horizontal)")
ax_zoom.set_title("Zoom del rango seleccionado")
def onselect(xmin, xmax):
mask = (x >= xmin) & (x <= xmax)
ax_zoom.clear()
ax_zoom.plot(x[mask], y[mask])
ax_zoom.set_title(f"Rango seleccionado: {xmin:.2f} a {xmax:.2f}")
fig.canvas.draw_idle()
span = SpanSelector(
ax,
onselect,
direction="horizontal",
useblit=True,
props=dict(alpha=0.3),
interactive=True
)
plt.show()
Selección rectangular con RectangleSelector
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import RectangleSelector
rng = np.random.default_rng(0)
x = rng.normal(0, 1, 800)
y = rng.normal(0, 1, 800)
fig, ax = plt.subplots(layout="constrained")
pts = ax.scatter(x, y, s=12, alpha=0.7)
ax.set_title("Arrastrá un rectángulo para seleccionar puntos")
def onselect(eclick, erelease):
xmin, xmax = sorted([eclick.xdata, erelease.xdata])
ymin, ymax = sorted([eclick.ydata, erelease.ydata])
sel = (x >= xmin) & (x <= xmax) & (y >= ymin) & (y <= ymax)
pts.set_alpha(np.where(sel, 1.0, 0.3))
fig.canvas.draw_idle()
rect = RectangleSelector(
ax,
onselect,
useblit=True,
button=[1],
props=dict(facecolor="tab:blue", alpha=0.15, edgecolor="k")
)
plt.show()