Vicsek Lab: Animation Loop
Module 2: Synchronization and Collective Behaviour
This page continues Animation. You already have run_simulation(), make_figure() and init_particles_plot(). Now you write the function that advances the model at every frame and assemble the full script (Hunter 2007).
Write the Animation Update Function
This is the core loop:
- advance the Vicsek dynamics by one step (
vicsek_equations). - update
xy_tail. - update the particle artists.
Use this checklist:
Complete update_animation(), following the comments for each step.
def update_animation(frame: int):
nonlocal xy, xy_tail, theta, noise_eta, v0, radius_interaction, box_size
# TODO: advance the Vicsek equations
# TODO: update the tail tensor
# TODO: update the particle artists with set_data
return (plt_particles, plt_current)Tip: blitting requires you to return artists If you set blit=True, your update function must return an iterable of the artists that changed, as shown above. If you forget to return them, the animation will run but the plot will not update (it will look frozen).
Move the function update_animation inside run_simulation so it can access the state variables with nonlocal.
Use the tail trick. Store the last TAIL_LEN positions:
- shift the tensor with
np.roll(...), - write the newest positions into the last slice.
This avoids creating new arrays each frame.
def update_animation(frame: int):
nonlocal \
xy, \
xy_tail, \
theta, \
noise_eta, \
v0, \
radius_interaction, \
box_size
xy, theta = vicsek_equations(
xy,
theta,
v0=v0,
dt=dt,
radius_interaction=radius_interaction,
box_size=box_size,
noise=noise_eta,
)
# Update tails
xy_tail = np.roll(xy_tail, shift=-1, axis=2)
xy_tail[:, :, -1] = xy
plt_particles.set_data(xy_tail[0].flatten(), xy_tail[1].flatten())
plt_current.set_data(xy[0], xy[1])
return (plt_particles, plt_current)Create the Animation Object
Matplotlib uses FuncAnimation. Inside run_simulation, after defining update_animation, create the animation object:
ani = animation.FuncAnimation(fig, update_animation, interval=0, blit=True)interval=0makes it as fast as your computer can handle.- You can set a larger interval (e.g. 20 ms) to reduce CPU usage.
Full Script
At this point you have built every piece.
Assemble run_simulation(): parameters, initial state, figure, particle artists, the update function and the animation object. Run the script and check that the particles move and align.
This version has no order plot, noise plot or sliders yet. It focuses on the particle animation.
def run_simulation(dt: float = 1.0) -> None:
# Parameters
num_boids = 100
noise_eta = 0.5
box_size = 10.0
radius_interaction = 1.0
v0 = 0.03
# Initialize state
xy, theta = initialize_particles(num_boids, box_size)
# Order parameter history and noise diagnostic
# will be initialized here
# Create figure and axes
fig, ax_plane = make_figure()
# Initialize plots
xy_tail, plt_particles, plt_current = init_particles_plot(ax_plane, xy, box_size, tail_len=20)
# The order plot and noise plot will go here
# Sliders will be added here
# Define the animation update function
def update_animation(frame: int):
nonlocal xy, xy_tail, theta
xy, theta = vicsek_equations(
xy,
theta,
v0=v0,
dt=dt,
radius_interaction=radius_interaction,
box_size=box_size,
noise=noise_eta,
)
xy_tail = np.roll(xy_tail, shift=-1, axis=2)
xy_tail[:, :, -1] = xy
plt_particles.set_data(xy_tail[0].flatten(), xy_tail[1].flatten())
plt_current.set_data(xy[0], xy[1])
return (plt_particles, plt_current)
# Create the animation object
ani = animation.FuncAnimation(fig, update_animation, interval=0, blit=True)
# The slider callbacks will come here
plt.show()Important: For your script to work, remember to call the run_simulation() function at the end of your script:
if __name__ == "__main__":
run_simulation()Checklist (Debugging)
If your animation is blank:
- Did you return the artists in
update_animation? - Did you set axis limits (
set_xlim,set_ylim)? - Are
xyandthetaupdated each frame? - Are you calling
plt.show()at the end ofrun_simulation()? - Are you calling
run_simulation()at the end of your script?
Extension
- Add the order parameter plot and noise diagnostic plot.
- Add sliders for
noise_etaandv0. - Add a slider for
radius_interactionand see how it affects the dynamics.
Interactive Animation shows how to add the order parameter plot and the noise diagnostic plot.