Interactive Plots and Events
Matplotlib figures are event-driven: the canvas emits signals (mouse press, motion, key, resize) and your code can react by redrawing. That is how you build click-to-inspect charts, hover readouts, and dashboard controls in plain matplotlib without a web framework. In Jupyter, the widget backend gives you pan/zoom/inspect for free - the event API is for the custom interactions it does not cover.
Connecting to Events
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 300)
fig, ax = plt.subplots()
line, = ax.plot(x, np.sin(x))
readout = ax.text(0.02, 0.95, "", transform=ax.transAxes,
va="top", fontsize=10, family="monospace")
def on_click(event):
if event.inaxes is not ax:
return
i = int(np.argmin(np.abs(x - event.xdata)))
readout.set_text(f"x={x[i]:.3f} y={np.sin(x[i]):.3f}")
ax.plot([x[i]], [np.sin(x[i])], "ro", markersize=8, zorder=5)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("button_press_event", on_click)
plt.show()
mpl_connect registers a callback for a named event; the callback receives an event object with xdata/ydata (in data coordinates when the click is inside the axes), key, button, and inaxes. Call fig.canvas.draw_idle() (or draw()) to render the change. mpl_disconnect(cid) removes the handler when the figure goes away.
The Useful Events
| Event | Payload | Typical use |
|---|---|---|
button_press_event | xdata, ydata, button | select a point, annotate on click |
motion_notify_event | xdata, ydata | hover crosshair and readout |
key_press_event | key | shortcut keys: "r" reset, "s" save |
resize_event | width, height | re-layout text on window change |
axes_leave_event | - | clear the hover readout |
For hover effects, guard motion_notify_event with a throttle (it fires on every pixel of movement) and with event.inaxes is ax so the cursor only reports inside the chart.
A Key-Driven Save
def on_key(event):
if event.key == "s":
fig.savefig("chart.png", dpi=150, bbox_inches="tight")
elif event.key == "r":
ax.cla()
line, = ax.plot(x, np.sin(x))
fig.canvas.draw_idle()
fig.canvas.mpl_connect("key_press_event", on_key)
Two lines of keyboard handling turn a static plot into a small tool: "s" exports the current view, "r" resets it. The same pattern scales to slider-style controls via matplotlib.widgets (Slider, ButtonCheckRadio, CheckButtons) for in-figure parameter tuning.
The Jupyter Shortcut
In a notebook, %matplotlib widget (ipywidgets backend) adds native pan, zoom, and point inspection to every plot with zero event code. Reach for the event API when the interaction is specific to your data - snapping to the nearest sample, filtering by region, exporting the selection - or when the plot runs in a desktop app where the widget backend is unavailable.
Summary
Build interactions by connecting callbacks to canvas events: button_press_event for selection, motion_notify_event (throttled) for hover readouts, key_press_event for shortcuts, then redraw with draw_idle. In Jupyter, %matplotlib widget covers the common cases for free - the event API is for the interactions that are actually yours.