HOWTO · Matplotlib
How to Plot Data in Real Time Using Matplotlib
Plot changing data in a Matplotlib window with FuncAnimation(), manual canvas redraws, or an updating scatter artist.
On this page
To plot changing data in a Matplotlib window, update the data held by the plotted artists and let a GUI-capable backend refresh the display. Choose FuncAnimation() when updates arrive as frames, canvas.draw() and canvas.flush_events() when a loop needs direct control, or a scatter artist when each update adds a point. These examples generate values locally; replace the update logic with values from your own source when adapting them. They do not connect to a sensor or network feed.
Animate a plot with FuncAnimation()
matplotlib.animation.FuncAnimation calls an update function for each frame and schedules redraws. The callback receives the current frame value, updates the existing line, and returns the artists that changed. frames=10 supplies values from 0 through 9, while interval=50 requests a 50 millisecond delay between frames; actual timing depends on the GUI event loop.
Keep a reference to the animation object for as long as the window is open. The example displays the animation interactively. To save it, call ani.save("animation.gif", writer="pillow", fps=10) before plt.show() and install a compatible animation writer such as Pillow. Saving is a separate rendering step and does not create a live data feed.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
figure, ax = plt.subplots()
line, = ax.plot([], [])
ax.set(xlim=(0, 2 * np.pi), ylim=(-1, 1), xlabel="x", ylabel="sin(x)")
def update(frame):
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x - frame / 5)
line.set_data(x, y)
return (line,)
ani = FuncAnimation(figure, update, frames=40, interval=50, blit=True)
plt.show()
Use init_func if the animation needs a separate initial state, and use fargs to pass additional fixed inputs to the callback. If the window opens without updating, check that the selected Matplotlib backend supports a GUI event loop and keep ani alive while the window is displayed.
Update a line with canvas.draw() and canvas.flush_events()
For a loop that controls each update, create a line once and change its data with set_ydata(). Then canvas.draw() renders the updated figure and canvas.flush_events() lets the GUI process pending events. These are Matplotlib canvas methods; they do not clear the figure. plt.ion() enables interactive mode, and a short pause gives the GUI time to respond.
import time
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 200)
figure, ax = plt.subplots()
line, = ax.plot(x, np.sin(x))
ax.set(xlim=(0, 2 * np.pi), ylim=(-1, 1), xlabel="x", ylabel="sin(x)")
plt.ion()
for frame in range(40):
line.set_ydata(np.sin(x - frame / 5))
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.05)
plt.ioff()
plt.show()
This approach is useful when the loop also needs to coordinate other work. Keep each update short so the event loop can process input and redraw requests. On a non-interactive backend, the calls can render a figure but cannot provide a responsive window; select a GUI backend for interactive updates.
Create a real-time scatter plot
For a stream of points, create one scatter artist and replace its offsets as new coordinates arrive. Updating the same artist avoids accumulating a new plotted object on every iteration. plt.pause() updates the GUI event loop between frames, and the axis limits below keep all generated points visible.
import numpy as np
import matplotlib.pyplot as plt
figure, ax = plt.subplots()
points = ax.scatter([], [])
ax.set(xlim=(0, 4), ylim=(-1.1, 1.1), xlabel="x", ylabel="sin(x)")
x_values = []
y_values = []
for frame in range(100):
x = frame * 0.04
x_values.append(x)
y_values.append(np.sin(x))
points.set_offsets(np.column_stack((x_values, y_values)))
plt.pause(0.05)
plt.show()
If only the newest point matters, keep a single coordinate pair instead of retaining the full history. If all past points should remain visible, extend the axis limits as the stream grows. For high-rate data, update less often than data arrives or keep only a recent window so drawing does not become the bottleneck.