Recording¶
The recording layer captures a per-step history of where every vehicle is, for later animation. It is deliberately matplotlib-free (it is imported by the core), so recording a run adds no plotting dependency; rendering the history to a video lives separately under Visualizations.
Enable it with Network.compile(record_history=True); the result is a
SimulationHistory on Simulation.history (JSON-serialisable via save/load).
See Movement animations.
History container¶
SimulationHistory
dataclass
¶
SimulationHistory(time_step: float, node_positions: dict = dict(), link_endpoints: dict = dict(), connector_nodes: dict = dict(), frames: list[Frame] = list())
A recorded run: static geometry plus one :class:Frame per step.
Produced by a simulation compiled with record_history=True (exposed as
Simulation.history) and consumed by
:mod:mesoltm.visualizations.animation to render frames/video. It is
self-contained — geometry is captured alongside the frames — so
:meth:save/:meth:load let the video be generated later, without the live
simulation.
Attributes:
| Name | Type | Description |
|---|---|---|
time_step |
float
|
Simulation step |
node_positions |
dict
|
|
link_endpoints |
dict
|
real |
connector_nodes |
dict
|
connector |
frames |
list[Frame]
|
One :class: |
from_state
classmethod
¶
from_state(state: NetworkState) -> SimulationHistory
Create an empty history, capturing the geometry from state.
from_dict
classmethod
¶
from_dict(data: dict) -> SimulationHistory
Rebuild a history from :meth:to_dict output (ids become strings).
Frame and snapshots¶
Frame
dataclass
¶
Frame(step: int, time: float, agents: list[AgentSnapshot], waiting: list[WaitingSnapshot], link_occupancy: dict[int | str, int])
A full snapshot of the network at one simulation step.
Attributes:
| Name | Type | Description |
|---|---|---|
step |
int
|
The simulation step index this frame captures. |
time |
float
|
The simulated time in seconds ( |
agents |
list[AgentSnapshot]
|
Agents on real links (see :class: |
waiting |
list[WaitingSnapshot]
|
Agents waiting to enter, by node (see :class: |
link_occupancy |
dict[int | str, int]
|
|
AgentSnapshot
dataclass
¶
AgentSnapshot(vehicle_id: int, link_id: int | str, queue_index: int, queue_len: int, route: Sequence[int | str], next_link_id: int | str | None, next_node: NodeId | None, category: str = DEFAULT_CATEGORY, props: dict = dict())
One agent travelling on a real link at a given step.
The whole remaining route is logged verbatim from vehicle.route (never
recomputed), so the plan recorded here is exactly the one the simulation used
— including any exogenous mid-run rerouting — and the next hop is simply read
back from it.
Attributes:
| Name | Type | Description |
|---|---|---|
vehicle_id |
int
|
The vehicle's id (drawn as its label). |
link_id |
int | str
|
The real link the agent occupies. |
queue_index |
int
|
FIFO position on the link; |
queue_len |
int
|
Number of vehicles on the link this step. |
route |
Sequence[int | str]
|
The agent's remaining real-link route from the current link
onward ( |
next_link_id |
int | str | None
|
The link the agent will enter next ( |
next_node |
NodeId | None
|
The node the agent heads toward next (downstream node of
|
category |
str
|
Colour/legend category (see :data: |
props |
dict
|
A snapshot copy of the vehicle's |
WaitingSnapshot
dataclass
¶
WaitingSnapshot(vehicle_id: int, node_id: NodeId, route: Sequence[int | str], next_link_id: int | str | None, next_node: NodeId | None, category: str = DEFAULT_CATEGORY, props: dict = dict())
One agent waiting to enter the network at a node.
Waiting means either queued in an origin's vertical entry queue or sitting on
an access connector — in both cases the agent is drawn beside node_id,
the node it is waiting to enter.
Attributes:
| Name | Type | Description |
|---|---|---|
vehicle_id |
int
|
The vehicle's id. |
node_id |
NodeId
|
The node the agent is waiting at / wants to enter. |
route |
Sequence[int | str]
|
The agent's planned real-link route (from |
next_link_id |
int | str | None
|
The (real) link it intends to enter next ( |
next_node |
NodeId | None
|
The node it heads toward next, or |
category |
str
|
Colour/legend category (see :data: |
props |
dict
|
A snapshot copy of the vehicle's metadata (see
:class: |
Capture helpers¶
capture_frame
¶
capture_frame(state: NetworkState, classify: ClassifyFn | None = None, step: int | None = None) -> Frame
Build a :class:Frame from the live network state.
No route is ever computed here. Each agent's remaining plan is read verbatim
from its vehicle.route (via :meth:NetworkState.remaining_real_route, the
same helper the rerouting interface uses), so the logged route always matches
what the simulation actually ran — including any exogenous mid-run rerouting —
and the drawn next hop is simply read back from it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
NetworkState
|
The live :class: |
required |
classify
|
ClassifyFn | None
|
Optional |
None
|
step
|
int | None
|
Step index to stamp on the frame; defaults to |
None
|
Returns:
| Type | Description |
|---|---|
Frame
|
The captured frame (scalars only; safe to keep as the sim advances). |
record_run
¶
record_run(sim: Simulation, classify: ClassifyFn | None = None) -> SimulationHistory
Run a simulation to completion, recording a frame per step.
A convenience for the batch case (no custom stepping/injection): it enables
history logging, runs sim and returns the populated
:class:SimulationHistory. For a custom step loop (e.g. a controller that
injects vehicles), compile with record_history=True instead and read
sim.history after the loop.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sim
|
Simulation
|
A compiled simulation (its |
required |
classify
|
ClassifyFn | None
|
Optional per-agent category classifier. |
None
|
Returns:
| Type | Description |
|---|---|
SimulationHistory
|
The recorded history. |