Skip to content

Figures

Peter Corke edited this page May 25, 2026 · 3 revisions

Figures and Graphics

This page summarizes bdsim graphics behavior for both users and developers.

User-facing capabilities

bdsim graphics blocks (for example SCOPE, SCOPEXY, and VEHICLEPLOT) can:

  • render live figures during simulation
  • animate during run(...) when animation=True
  • keep windows open at run end when hold=True
  • save movie output for blocks configured with movie=... (requires ffmpeg)

Runtime options that affect graphics

  • graphics: enables/disables graphics handling for graphics blocks
  • animation: enables periodic frame refresh during simulation
  • hold: blocks at run end for interactive GUI backends

In notebooks, figures are updated inline instead of relying on GUI event loops.

Backends and display policy

Graphics output is coordinated by display managers in src/bdsim/display.py.

Display manager classes

  • DisplayManager: base interface + factory (DisplayManager.create(...))
  • MatplotlibDisplayManager: GUI matplotlib behavior
  • NotebookDisplayManager: inline notebook behavior (IPython.display)

The simulator creates one manager per run and calls three lifecycle methods:

  1. show_initial() before frame callbacks start
  2. refresh() during animation frame callbacks
  3. finalize() at end-of-run

Notebook-specific behavior

Notebook rendering has two important differences from desktop GUI backends:

  • updates are done via display_id + update_display
  • at finalize, bdsim performs one final refresh to include the terminal sample, then closes figures to avoid duplicate auto-rendered outputs at cell end

This ordering is intentional and avoids two common notebook issues:

  • missing final point in animated plots
  • duplicate final figure appended after simulation output

Internal flow

High-level control points are:

  • BDSim.run(...) in src/bdsim/run_sim.py
  • Runner.done(...) in src/bdsim/components.py
  • GraphicsBlock.step()/done() in src/bdsim/block.py

During animated runs, the scheduler posts frame callbacks that call display_manager.refresh().

At end-of-run:

  • GUI backend: final behavior is controlled by hold
  • notebook backend: display_manager.finalize() handles the last refresh and duplicate-suppression policy

Notes for contributors

  • Prefer backend-specific behavior in display manager subclasses, not spread across run-loop branches.
  • Keep notebook and GUI lifecycle differences localized to display.py.
  • If you change finalize ordering, regression-test for both:
    • final point visibility
    • duplicate notebook figure outputs

Clone this wiki locally