Vicsek Lab: Animation
Module 2: Synchronization and Collective Behaviour
This page guides you through a basic animation of the Vicsek model with Matplotlib (Vicsek et al. 1995; Hunter 2007). The optional Interactive Animation builds on it.
You already have the Vicsek functions implemented (e.g. initialize_particles, vicsek_equations, vicsek_order_parameter).
Your job here is to assemble them into a 2D particle animation (with a short tail) that shows the recent trajectory of each particle.
Imports and Model Functions
Create a new script named vicsek_animation.py. At the end of this page you will have a complete version.
Start with these imports:
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from matplotlib.axes import Axes
# make sure Python can find your package/module
sys.path.append(".")
# import Vicsek utilities from your project
from amlab.collective_motion.vicsek import initialize_particles, vicsek_equations, vicsek_order_parameter- If you get
ModuleNotFoundError, you likely needsys.path.append(".")(or adjust it to your repo root). - Prefer importing from your package (e.g.
amlab...) rather than relative imports.
The Main Function
Put everything inside a function so you can run it with different dt.
Create a function skeleton and choose parameter defaults. Take the values from Initialization and Update Rule.
def run_simulation(dt: float = 1.0) -> None:
"""Run an interactive Vicsek animation (Matplotlib)."""
# TODO: choose defaults
num_boids =
noise_eta =
box_size =
radius_interaction =
v0 =
# Tail length for trajectory visualization
TAIL_LEN = 20
# TODO: initialize the state (xy, theta)
# We stop here for nowStart with the small system of the earlier pages. The speed and radius follow Vicsek et al. (1995).
def run_simulation(dt: float = 1.0) -> None:
"""Run an interactive Vicsek animation (Matplotlib)."""
num_boids = 100
noise_eta = 0.5
box_size = 10.0
radius_interaction = 1.0
v0 = 0.03
# Tail length for trajectory visualization
TAIL_LEN = 20
xy, theta = initialize_particles(num_boids, box_size)Create the Figure Layout
For now you only need one axis for the particles. Interactive Animation turns this into a grid with space for sliders and diagnostics.
Create the figure and name the axis.
def make_figure():
# A single square axis for the particles
fig, ax_plane = plt.subplots(figsize=(8, 8))
return fig, ax_planeDraw Particles
To show the movement of the particles, draw them to look like “tadpoles”: a big head with a smaller tail. In practice, you plot their current position as the “head”, using a bigger marker, and their recent trajectory as the “tail”, using many small points. This will show the direction of movement and give a better sense of the dynamics. You use two artists:
- one for the tail (many tiny points),
- one for the current positions (bigger markers).
Translating this to code, you will - create xy_tail with shape (2, N, TAIL_LEN), and - create the two Line2D artists with ax_plane.plot(...).
def init_particles_plot(ax_plane: Axes, xy: np.ndarray, box_size: float, tail_len: int):
# build a tail tensor by repeating xy across a third axis
xy_tail = np.repeat(xy[:, :, np.newaxis], tail_len, axis=2)
# tail (small grey points)
(plt_particles,) = ax_plane.plot(
xy_tail[0].flatten(), xy_tail[1].flatten(),
linestyle="", marker=".", markersize=2, color="grey"
)
# current positions (bigger black circles)
(plt_current,) = ax_plane.plot(
xy[0], xy[1],
linestyle="", marker="o", markersize=3, color="black"
)
# set plot limits
ax_plane.set_xlim(0, box_size)
ax_plane.set_ylim(0, box_size)
ax_plane.set_aspect("equal")
return xy_tail, plt_particles, plt_current