Graphical¶
Time-signal plots: a trajectory’s signals, one row per component, on a chosen backend.
- class minilink.graphical.signals.time_signals.SignalTrace(signal, component, label, unit, values, color, alpha=1.0, linewidth=1.5)[source]¶
One scalar time trace selected from a vector signal.
- Parameters:
signal (str)
component (int)
label (str)
unit (str)
values (ndarray)
color (str)
alpha (float)
linewidth (float)
- class minilink.graphical.signals.time_signals.SignalPlotSpec(title, t, traces, abscissa_label='Time [s]')[source]¶
Backend-neutral signal plot request.
- Parameters:
title (str)
t (ndarray)
traces (tuple[SignalTrace, ...])
abscissa_label (str)
- class minilink.graphical.signals.time_signals.LivePlotHandle[source]¶
Base class for live signal plot handles.
- minilink.graphical.signals.time_signals.resolve_plot_signals(sys)[source]¶
Return default time-signal names for
sys(leaf or diagram).Leaf systems plot the state
x, and the inputuwhen they have one. Diagrams plot flattened states plus controller control outputs ({id}:ufor static or dynamic controllers) and source outputs ({id}:y) without requiring explicitsys_id:portnames from the user.- Return type:
tuple[str, …]
- minilink.graphical.signals.time_signals.build_signal_plot_spec(sys, traj, *, signals=('x', 'u'), title=None, abscissa_label='Time [s]')[source]¶
Build a one-component-per-row plot specification.
- Parameters:
signals (tuple[str, ...])
title (str | None)
abscissa_label (str)
- Return type:
- minilink.graphical.signals.time_signals.plot_time_signals(sys, traj, *, signals=('x', 'u'), abscissa_label='Time [s]', backend='matplotlib', show=True, **kwargs)[source]¶
Plot sampled time signals with the selected backend.
- Parameters:
signals (tuple[str, ...])
abscissa_label (str)
show (bool)
- Return type:
PlotResult
- minilink.graphical.signals.time_signals.open_time_signal_plot(sys, traj, *, signals=('x', 'u'), abscissa_label='Time [s]', backend='matplotlib', show=True, **kwargs)[source]¶
Open a live time-signal plot with an update handle.
- Parameters:
signals (tuple[str, ...])
abscissa_label (str)
show (bool)
- Return type:
Phase plane: a system’s vector field over two state coordinates, with an optional trajectory.
- minilink.graphical.phase_plane.phase_plane.plot_phase_plane(sys, traj=None, *, x_axis=0, y_axis=None, u=None, x_ref=None, t=0.0, bounds=None, grid_shape=(21, 21), params=None, title=None, backend='matplotlib', streamplot=False, show=True, **kwargs)[source]¶
Plot a phase-plane vector field with an optional trajectory overlay.
- Parameters:
sys (DynamicSystem) – Continuous-time model whose
fdefines the vector field (leaf subclass or wired diagram with stackedf).x_axis (int)
y_axis (int | None)
t (float)
grid_shape (tuple[int, int])
title (str | None)
backend (str)
streamplot (bool)
show (bool)
- Return type:
PlotResult
- minilink.graphical.phase_plane.phase_plane.build_phase_plane_spec(sys, traj=None, *, x_axis=0, y_axis=None, u=None, x_ref=None, t=0.0, bounds=None, grid_shape=(21, 21), params=None, title=None)[source]¶
Build a phase-plane vector-field specification.
The selected state coordinates vary over the plot grid. All other state components are held at
x_refand the input is held atu.- Parameters:
x_axis (int)
y_axis (int | None)
t (float)
grid_shape (tuple[int, int])
title (str | None)
- Return type:
- class minilink.graphical.phase_plane.phase_plane.PhasePlaneSpec(title, X, Y, V, W, x_axis, y_axis, x_label, y_label, x_unit, y_unit, x_bounds, y_bounds, trajectory=None)[source]¶
Backend-neutral phase-plane plot request.
- Parameters:
title (str)
X (ndarray)
Y (ndarray)
V (ndarray)
W (ndarray)
x_axis (int)
y_axis (int)
x_label (str)
y_label (str)
x_unit (str)
y_unit (str)
x_bounds (tuple[float, float])
y_bounds (tuple[float, float])
trajectory (PhasePlaneTrajectoryOverlay | None)
- class minilink.graphical.phase_plane.phase_plane.PhasePlaneTrajectoryOverlay(x, y)[source]¶
Trajectory data projected onto two phase-plane axes.
- Parameters:
x (ndarray)
y (ndarray)
- minilink.graphical.phase_plane.phase_plane.render_phase_plane_matplotlib(spec, *, streamplot=False, show=True, ax=None, figsize=None, dpi=None, vector_color='C0', trajectory_color='C1', vector_kwargs=None, trajectory_kwargs=None, start_kwargs=None, end_kwargs=None, block=None, pause=0.0)[source]¶
Render a phase-plane specification with matplotlib.
- Parameters:
spec (PhasePlaneSpec)
streamplot (bool)
show (bool)
vector_color (str)
trajectory_color (str)
block (bool | None)
pause (float)
- Return type:
PlotResult
- minilink.graphical.phase_plane.phase_plane.render_phase_plane_plotly(spec, *, streamplot=False, show=True)[source]¶
Render a phase-plane specification with Plotly (quiver or streamlines).
- Parameters:
spec (PhasePlaneSpec)
streamplot (bool)
show (bool)
- Return type:
PlotResult
Diagram topology: the backend-neutral nodes, ports, edges and clusters a diagram is drawn from.
- minilink.graphical.diagrams.topology.build_diagram_topology(sys_or_diagram, *, abstract_boundary=False, expand=False)[source]¶
Build a display/export topology snapshot from a system or diagram.
abstract_boundary=Trueremoves external Inputs/Outputs routing nodes and recordsboundary_inputs/boundary_outputsanchors on wired ports.expand=Truereplaces every nested diagram by its own blocks, at every depth, and records oneTopologyClusterper nested diagram.- Return type:
- minilink.graphical.diagrams.topology.expand_nested_diagrams(topology, diagram)[source]¶
Replace every nested diagram block by its own blocks, grouped in a cluster.
The blocks of a nested diagram keep their ids behind the diagram’s id (
controller__pi). An edge that reached a boundary port of a nested diagram goes straight to the block ports wired to that port inside: one edge per inner reader of a boundary input, none when nothing is wired behind the port. A boundary port left unconnected outside draws nothing.- Parameters:
topology (DiagramTopology)
- Return type:
- minilink.graphical.diagrams.topology.abstract_boundary_ports(topology)[source]¶
Remove external input/output routing nodes and record boundary port anchors.
Diagram boundary ports that wire straight through
input/outputnodes are mapped to the connected subsystem port. Internal edges between subsystems are unchanged. Unconnected boundary ports are omitted from the snapshot.- Parameters:
topology (DiagramTopology)
- Return type:
- class minilink.graphical.diagrams.topology.DiagramTopology(name, nodes, edges, boundary_inputs=(), boundary_outputs=(), clusters=())[source]¶
Read-only topology snapshot for display/export.
nodesandedgesare always a complete flat diagram.clustersonly groups the nodes that came out of an expanded nested diagram.- Parameters:
name (str)
nodes (tuple[TopologyNode, ...])
edges (tuple[TopologyEdge, ...])
boundary_inputs (tuple[BoundaryPortRef, ...])
boundary_outputs (tuple[BoundaryPortRef, ...])
clusters (tuple[TopologyCluster, ...])
- class minilink.graphical.diagrams.topology.TopologyNode(id, name, display_id, kind, inputs, outputs)[source]¶
One display node in a system or diagram topology.
- Parameters:
id (str)
name (str)
display_id (str)
kind (str)
inputs (tuple[TopologyPort, ...])
outputs (tuple[TopologyPort, ...])
- class minilink.graphical.diagrams.topology.TopologyPort(id, dim, label=None)[source]¶
One input or output port on a topology node;
labelis the text drawn, the id by default.- Parameters:
id (str)
dim (int)
label (str | None)
- property text: str¶
its label, else its id.
- Type:
The text drawn beside the port
- class minilink.graphical.diagrams.topology.TopologyEdge(source_node, source_port, target_node, target_port)[source]¶
Directed port-to-port connection.
- Parameters:
source_node (str)
source_port (str)
target_node (str)
target_port (str)
- class minilink.graphical.diagrams.topology.BoundaryPortRef(diagram_port, node_id, port_id)[source]¶
One diagram boundary port routed to an internal block port.
- Parameters:
diagram_port (str)
node_id (str)
port_id (str)
- class minilink.graphical.diagrams.topology.TopologyCluster(id, name, display_id, node_ids, clusters=())[source]¶
One nested diagram, drawn as a labelled box around its own blocks.
- Parameters:
id (str)
name (str)
display_id (str)
node_ids (tuple[str, ...])
clusters (tuple[TopologyCluster, ...])
Diagram export: a system’s block topology in Graphviz or Mermaid form.
- class minilink.graphical.diagrams.export.TopologyExporter[source]¶
Small topology exporter contract.
- minilink.graphical.diagrams.export.export_diagram_topology(sys_or_diagram, *, backend='graphviz', expand=True, **kwargs)[source]¶
Export a system or diagram topology with the selected backend.
expand=Trueexports the blocks of every nested diagram, grouped in a labelled box;expand=Falseexports a nested diagram as one block.
Trajectory animation: frame-keyed drawable hooks to a flat draw list, then a renderer.
- class minilink.graphical.animation.animator.Animator(sys)[source]¶
Playback coordinator: frame-keyed hooks → flat draw list → renderer.
Owns the simulated system and delegates drawing to an
AnimationRenderer, one of the backends underminilink.graphical.animation.renderers, picked by name throughmake_renderer(). Each frame resolves the system’s named frame poses (tf()), the cached kinematic geometry (get_kinematic_geometry()) and the per-frame dynamic geometry (get_dynamic_geometry()) into the flat(primitive, world 4x4)draw list the renderers consume, and the camera from the system’s hints. Matplotlib figure size and resolution live inminilink.graphical.common.matplotlib_style.Live sessions (interactive
game()mode) are orchestrated byRealtimeSimulator, which drivesopen_live_scene()andupdate_live_frame()per frame; the animator itself stays playback and frame resolution only.- animate_simulation(traj, time_factor_video=1.0, is_3d=False, save=False, file_name='Animation', show=True, html=None, renderer='matplotlib', native=True, scene_title=None, camera=None, overlays=None)[source]¶
Plays back a full simulation trajectory.
The four orthogonal kwargs are:
renderer: graphics tech ("matplotlib","meshcat","plotly","pygame").is_3d: 2-D or 3-D axes for the flat renderers (matplotlib, plotly, pygame). Meshcat is always a 3-D viewer and ignores it.html: output channel.Noneauto-resolves viaminilink.graphical.common.environment.prefers_inline_animation():Truein Colab and in local Jupyter when the active matplotlib backend is non-interactive (inline/agg),Falsefor bare script, IPython REPL, and Jupyter with an interactive backend (qt/widget/macosx/tk/nbagg). ExplicitTrue/Falseis honored.native: playback engine.True(default) drives the backend’s own animation engine:matplotlib.animation.FuncAnimationfor matplotlib,meshcat.animation.Animation+set_animationfor meshcat, and browser-side Plotly frames for plotly.Falsefalls back to the per-frame Python loop (handy for debugging or when the native path’s limitations matter).
cameraaccepts the optional override: a constant 4x4 or acamera(frames, x, u, t)callable.Notes
Meshcat native animation keyframes rigid poses (position+quaternion), and plays geometry that changes (
Arrowlength/direction,TorqueArrowsweep,CustomLinetrails / horizons) as a flipbook of pages, each shown over its own frames. In 3-D, Meshcat draws line primitives as thin ribbons so matplotlib dash styles and widths remain visible.Plotly does not support the per-frame Python loop (
native=Falsewithhtml=False): usenative=Trueorhtml=Truefor inline/browser playback.save=Truewrites a file before playback: matplotlib a GIF, meshcat a standalone HTML page of the native keyframed animation.- Parameters:
html (bool | None)
native (bool)
scene_title (str | None)
- show(x, u, t=0.0, is_3d=False, renderer='matplotlib', camera=None, overlays=None)[source]¶
Render a single static frame at state x, u, t.
- class minilink.graphical.animation.animator.AnimationRenderer(animator)[source]¶
One backend (matplotlib, meshcat, pygame, …) for static views and trajectory playback. Subclasses own all library-specific setup and I/O.
- abstract open_scene(*, is_3d, show, camera, title=None)[source]¶
Initialize backend resources for one render session.
camerais a 4x4camera_matrix()used to set up initial framing. Renderers consume the slots they understand (target, projection-axis columns, view scale, view-out direction) and ignore the rest; seeDESIGN.md§4.7.- Parameters:
is_3d (bool)
show (bool)
title (str | None)
- Return type:
None
- abstract draw_frame(primitives, transforms, t, camera)[source]¶
Draw one frame from precomputed transforms and camera.
- Parameters:
t (float)
- Return type:
None
- abstract present(*, block, interval_s=None)[source]¶
Present the currently drawn frame and optionally block/sleep.
- Parameters:
block (bool)
interval_s (float | None)
- Return type:
None
- poll_events()[source]¶
Return backend events/state for interactive loops.
Live external input and output live in
minilink.simulation.realtime(RealtimeInput/RealtimeOutput); renderers stay draw/present-only and report only view events such as{"quit": True}.
- abstract close_scene()[source]¶
Release/close backend resources for the current session.
- Return type:
None
- render_inline_animation(primitives, frames, schedule, *, is_3d)[source]¶
Optional notebook inline output (default: unsupported).
framesentries each carry"transforms"and"camera"(seeminilink.graphical.animation.Animator._prepare_transforms()).- Parameters:
is_3d (bool)
- export_animation(primitives, frames, schedule, file_name, *, is_3d=False)[source]¶
Optional animation export (default: unsupported).
- Parameters:
file_name (str)
is_3d (bool)
- Return type:
None
- play_native(primitives, frames, schedule, *, is_3d, scene_title=None)[source]¶
Optional native playback using the backend’s own animation engine.
Subclasses that support a native animation API (matplotlib
FuncAnimation, meshcatAnimation+set_animation, …) override this hook. Default raisesNotImplementedErrorso callers can fall back to the generic per-frame loop.- Parameters:
is_3d (bool)
scene_title (str | None)
- class minilink.graphical.animation.animator.MatplotlibRenderer(animator)[source]¶
Static matplotlib figure and GIF / notebook HTML animation.
- open_scene(*, is_3d, show, camera, title=None)[source]¶
Initialize backend resources for one render session.
camerais a 4x4camera_matrix()used to set up initial framing. Renderers consume the slots they understand (target, projection-axis columns, view scale, view-out direction) and ignore the rest; seeDESIGN.md§4.7.- Parameters:
is_3d (bool)
show (bool)
title (str | None)
- Return type:
None
- draw_frame(primitives, transforms, t, camera)[source]¶
Draw one frame from precomputed transforms and camera.
- Parameters:
t (float)
- Return type:
None
- present(*, block, interval_s=None)[source]¶
Present the currently drawn frame and optionally block/sleep.
- Parameters:
block (bool)
interval_s (float | None)
- Return type:
None
- poll_events()[source]¶
Return backend events/state for interactive loops.
Live external input and output live in
minilink.simulation.realtime(RealtimeInput/RealtimeOutput); renderers stay draw/present-only and report only view events such as{"quit": True}.- Return type:
dict[str, bool]
- render_inline_animation(primitives, frames, schedule, *, is_3d)[source]¶
Optional notebook inline output (default: unsupported).
framesentries each carry"transforms"and"camera"(seeminilink.graphical.animation.Animator._prepare_transforms()).- Parameters:
is_3d (bool)
- export_animation(primitives, frames, schedule, file_name, *, is_3d=False)[source]¶
Optional animation export (default: unsupported).
- Parameters:
file_name (str)
is_3d (bool)
- Return type:
None
- play_native(primitives, frames, schedule, *, is_3d, scene_title=None)[source]¶
Drive playback through
matplotlib.animation.FuncAnimationinstead of a Python frame loop.Only the window path lands here: Colab and Jupyter-with-non-interactive backend are routed to
render_inline_animationupstream viaminilink.graphical.common.environment.prefers_inline_animation().Bare script (
is_blocking_needed() is True): block until the user closes the window, then clean up.IPython terminal REPL or Jupyter with an interactive backend (
qt/widget/macosx/tk/nbagg): show the window non-blocking and intentionally retain strong references to the figure andFuncAnimationonselfso the backend event loop can drive playback withoutFuncAnimationbeing garbage collected.
- Parameters:
is_3d (bool)
scene_title (str | None)
- class minilink.graphical.animation.animator.MeshcatRenderer(animator)[source]¶
Browser-based playback and static-HTML snapshots.
The viewer is always 3-D, so the
is_3dargument of the renderer interface is accepted and ignored: lines are always drawn as ribbons with a visible width and dash pattern.- open_scene(*, is_3d, show, camera, title=None)[source]¶
Initialize backend resources for one render session.
camerais a 4x4camera_matrix()used to set up initial framing. Renderers consume the slots they understand (target, projection-axis columns, view scale, view-out direction) and ignore the rest; seeDESIGN.md§4.7.- Parameters:
is_3d (bool)
show (bool)
title (str | None)
- Return type:
None
- draw_frame(primitives, transforms, t, camera)[source]¶
Draw one frame from precomputed transforms and camera.
- Parameters:
t (float)
- Return type:
None
- present(*, block, interval_s=None)[source]¶
Present the currently drawn frame and optionally block/sleep.
- Parameters:
block (bool)
interval_s (float | None)
- Return type:
None
- export_animation(primitives, frames, schedule, file_name, *, is_3d=False)[source]¶
Write a standalone HTML page of the native Meshcat animation.
- Parameters:
file_name (str)
is_3d (bool)
- Return type:
None
- play_native(primitives, frames, schedule, *, is_3d, scene_title=None)[source]¶
Drive playback through
meshcat.animation.Animation+Visualizer.set_animationinstead of a Python frame loop. The browser plays keyframes natively; notime.sleepin Python.- Parameters:
is_3d (bool)
scene_title (str | None)
- render_inline_animation(primitives, frames, schedule, *, is_3d)[source]¶
Return an
IPython.display.HTMLiframe snapshot of the meshcat scene with the animation embedded. UsesVisualizer.render_staticunder the hood, which wrapsstatic_html()in a self-containedsrcdoc=. Ideal for Colab: no zmq client, no port forwarding.- Parameters:
is_3d (bool)
- class minilink.graphical.animation.animator.PlotlyRenderer(animator)[source]¶
Notebook-friendly Plotly renderer.
This backend is intended for static figures and precomputed trajectory playback. It deliberately does not implement a high-frequency live update loop for
game()or trajectory-optimization iteration callbacks.- open_scene(*, is_3d, show, camera, title=None)[source]¶
Initialize backend resources for one render session.
camerais a 4x4camera_matrix()used to set up initial framing. Renderers consume the slots they understand (target, projection-axis columns, view scale, view-out direction) and ignore the rest; seeDESIGN.md§4.7.- Parameters:
is_3d (bool)
show (bool)
title (str | None)
- Return type:
None
- draw_frame(primitives, transforms, t, camera)[source]¶
Draw one frame from precomputed transforms and camera.
- Parameters:
t (float)
- Return type:
None
- present(*, block, interval_s=None)[source]¶
Present the currently drawn frame and optionally block/sleep.
- Parameters:
block (bool)
interval_s (float | None)
- poll_events()[source]¶
Return backend events/state for interactive loops.
Live external input and output live in
minilink.simulation.realtime(RealtimeInput/RealtimeOutput); renderers stay draw/present-only and report only view events such as{"quit": True}.
- render_inline_animation(primitives, frames, schedule, *, is_3d)[source]¶
Optional notebook inline output (default: unsupported).
framesentries each carry"transforms"and"camera"(seeminilink.graphical.animation.Animator._prepare_transforms()).- Parameters:
is_3d (bool)
- play_native(primitives, frames, schedule, *, is_3d, scene_title=None)[source]¶
Optional native playback using the backend’s own animation engine.
Subclasses that support a native animation API (matplotlib
FuncAnimation, meshcatAnimation+set_animation, …) override this hook. Default raisesNotImplementedErrorso callers can fall back to the generic per-frame loop.- Parameters:
is_3d (bool)
scene_title (str | None)
- class minilink.graphical.animation.animator.PygameRenderer(animator)[source]¶
800×600 window; ESC or close to quit.
- open_scene(*, is_3d, show, camera, title=None)[source]¶
Initialize backend resources for one render session.
camerais a 4x4camera_matrix()used to set up initial framing. Renderers consume the slots they understand (target, projection-axis columns, view scale, view-out direction) and ignore the rest; seeDESIGN.md§4.7.- Parameters:
is_3d (bool)
show (bool)
title (str | None)
- Return type:
None
- draw_frame(primitives, transforms, t, camera)[source]¶
Draw one frame from precomputed transforms and camera.
- Parameters:
t (float)
- Return type:
None
- present(*, block, interval_s=None)[source]¶
Present the currently drawn frame and optionally block/sleep.
- Parameters:
block (bool)
interval_s (float | None)
- Return type:
None
- minilink.graphical.animation.animator.make_renderer(name, animator)[source]¶
Return a backend instance for name.
To add a backend, implement
AnimationRendererand extend this function.- Parameters:
name (str)
animator (Animator)
- Return type:
Graphical primitives: shapes in their own local frame, and the 4x4 camera transforms.
- class minilink.graphical.animation.primitives.GraphicPrimitive(color='blue', linewidth=1, style='-', local_transform=None)[source]¶
Base class for all geometric objects rendered by the animator engine.
A system’s visualization is a dict of named frames to primitives (shapes defined in their own local frame) plus, at every instant, one 4x4 homogeneous transform per frame placing it in the world (see
minilink.core.system.System.get_kinematic_geometry(),get_dynamic_geometry(), andtf()). Renderers draw the primitives; they never know about states or inputs.Primitives are honest: they bake their full point geometry at real world size in their own local frame.
local_transformis a fixed 4x4 graphical offset baked into the primitive (a constant pose within its frame), so the animator poses a primitive atframes[key] @ local_transform; it defaults to identity. Placement helpers for spans and coils live inminilink.graphical.catalog.shapes; rigid pose math lives inminilink.core.kinematics.
- class minilink.graphical.animation.primitives.CustomLine(pts, color='blue', linewidth=1, style='-', opacity=1.0)[source]¶
A generic sequence of connected line segments.
- class minilink.graphical.animation.primitives.Point(pt=(0, 0, 0), color='red', marker='o', size=5)[source]¶
An individual point marker.
- class minilink.graphical.animation.primitives.Circle(radius=1.0, center=(0, 0, 0), color='blue', fill=False)[source]¶
A basic circle primitive. Lives in the XY plane by default.
- class minilink.graphical.animation.primitives.Sphere(radius=1.0, center=(0, 0, 0), color='blue', opacity=1.0)[source]¶
A 3D sphere primitive centered at
centerin local frame.
- class minilink.graphical.animation.primitives.Rod(length=1.0, radius=0.05, color='blue', opacity=1.0, linewidth=2, style='-')[source]¶
A slender rigid rod primitive aligned with local -Y axis.
- class minilink.graphical.animation.primitives.Plane(normal=(0, 1, 0), offset=0.0, size=10.0, thickness=0.02, color='lightgray', opacity=0.65)[source]¶
A finite square patch representing a plane: n·x = offset.
The patch is centered at
offset * normaland spanssize x size.
- class minilink.graphical.animation.primitives.Box(length_x=1.0, length_y=1.0, length_z=1.0, center=(0.0, 0.0, 0.0), color='gray', opacity=1.0)[source]¶
Axis-aligned rectangular solid in local frame (centered at
center).Dimensions are full lengths along local X, Y, Z. Used for simple vehicle bodies and blocks in 3D renderers (MeshCat box geometry).
- Parameters:
length_x (float)
length_y (float)
length_z (float)
opacity (float)
- class minilink.graphical.animation.primitives.ExtrudedPolygon(pts_xy, height=1.0, center=(0.0, 0.0, 0.0), color='gray', opacity=1.0)[source]¶
Convex polygon in local XY, extruded symmetrically along local Z.
This is useful for light-weight 3D body shells such as vehicle noses, cabins, side pods, and tapered covers without introducing a full mesh asset pipeline.
- Parameters:
height (float)
opacity (float)
- class minilink.graphical.animation.primitives.Arrow(base=(0.0, 0.0), vector=(1.0, 0.0), scale=1.0, head_ratio=0.15, color='red', linewidth=2, style='-')[source]¶
A straight arrow at honest world size — shaft from base along vector.
Accepts planar (length-2) or spatial (length-3) base / vector. Geometry is baked at true length
scale * |vector|; the renderer simply drawsself.ptsposed by the frame. Pass body-framevectorand key the primitive to that body frame so its orientation comes fromtf(no manualcos/sinrotation). For world-aligned task forces, key to a translation-only frame and pass the force components directly as vector.
- class minilink.graphical.animation.primitives.TorqueArrow(sweep, radius=1.0, head_ratio=0.4, n_arc_pts=40, color='red', linewidth=2, style='-')[source]¶
A curved torque arc at honest geometry — sweep baked into the points.
The arc for the given sweep and radius is built at construction, centered at the local origin; the placing frame supplies world position and the start orientation. Rebuild it each frame in
get_dynamic_geometrywith the instantaneous torque.- Parameters:
sweep (float) – Arc sweep angle in radians (positive = CCW, negative = CW).
radius (float) – Radius of the arc in world units.
head_ratio (float) – Chevron barb length as a fraction of the radius.
n_arc_pts (int) – Number of sample points used for a full-circle arc (subsampled proportionally for smaller sweeps).
- class minilink.graphical.animation.primitives.HorizonPolyline(plans, *, color='tab:orange', linewidth=2, style='--')[source]¶
World-frame polyline of the active receding-horizon plan at time t.
plansis a sequence of(t_solve, trajectory)pairs with world-frametrajectory.xandtrajectory.t. At playback time t, the primitive draws the latest plan witht_solve <= tover samples withtrajectory.t >= t.Geometry is rebuilt each frame through
points_at()(an overlay’sget_dynamic_geometry(t)bakes the world polyline into aCustomLine).
- class minilink.graphical.animation.primitives.TrajectoryPolyline(trajectory, *, window='prefix', color='tab:blue', linewidth=2, style='-')[source]¶
World-frame XY polyline sampled from a
Trajectory.At playback time t:
window="prefix"Samples with
trajectory.t <= t— a growing executed trail.window="suffix"Samples with
trajectory.t >= t.window="all"Full trajectory polyline (time-independent geometry).
Geometry is rebuilt each frame through
compute_pts(), likeHorizonPolyline.
- minilink.graphical.animation.primitives.arrow_pts(base, vector, scale=1.0, head_ratio=0.15)[source]¶
Polyline (Nx3) of a straight arrow from base along vector.
Accepts matching length-2 or length-3 base / vector. Planar arrows stay in local XY (
z = 0); spatial arrows build the chevron in a plane spanned by the shaft and a deterministic perpendicular. Drawn length isscale * |vector|. A near-zero vector collapses to a single point.- Parameters:
base (array-like, length 2 or 3) – Tail of the arrow in the local frame.
vector (array-like, length 2 or 3) – Direction (and, with scale, length) of the shaft.
scale (float) – Multiplies vector to set the drawn length (e.g. a force gain).
head_ratio (float) – Chevron barb length as a fraction of the shaft length.
- minilink.graphical.animation.primitives.torque_arc_pts(sweep, radius=1.0, head_ratio=0.4, n_arc_pts=40)[source]¶
Polyline (Nx3) of a circular torque arc + chevron, centered at the origin.
The arc is baked at the given sweep (radians, + = CCW) and radius, so the sweep rides in the geometry rather than a transform side-channel.
- minilink.graphical.animation.primitives.camera_matrix(target=(0.0, 0.0, 0.0), plot_axes=(0, 1), scale=10.0)[source]¶
Standard 4x4 camera transform.
The matrix doubles as the camera’s pose in the world frame and the renderer projection knob. The
T[3, 3]slot carries the view scale (orthographic half-extent for matplotlib / pygame; camera distance for meshcat).Slot meaning¶
T[:3, 3]— look-at target in world (point at the center of the view).T[:3, 0]— world direction shown as plot horizontal axis.T[:3, 1]— world direction shown as plot vertical axis.T[:3, 2]— camera view-out direction (projected away in 2D / ortho; eye-out in 3D perspective).T[3, 3]— view scale (orthographic half-extent in world units for matplotlib / pygame; perspective camera distance for meshcat).
- param target:
Look-at point in world coordinates.
- type target:
array-like of length 3, optional
- param plot_axes:
World axis indices used as plot-X (
i) and plot-Y (j).Ris built so its columns are(e_i, e_j, e_i x e_j). Default(0, 1)is the canonical top-down view.- type plot_axes:
tuple of two ints in {0, 1, 2}, optional
- param scale:
View half-extent (orthographic) or camera distance (perspective).
- type scale:
float, optional
- returns:
4x4 camera transform.
- rtype:
np.ndarray
- minilink.graphical.animation.primitives.world_to_camera(camera)[source]¶
Return the world-to-camera (view) 4x4 matrix.
Inverts the rigid part of camera (target translation +
R); the amplitude channelT[3, 3]is reset to 1 so the result is a regular rigid transform suitable for pre-multiplying body transforms before orthographic 2D rendering.
- minilink.graphical.animation.primitives.ground_line(length=20.0, y=0.0, color='black', style='--')[source]¶
Horizontal reference line of span length at height y (e.g. ground).
- minilink.graphical.animation.primitives.spring_line(coils=6, amplitude=0.12, color='black', linewidth=1)[source]¶
Unit-length zig-zag spring along local +X (lead-in, coils coils, lead-out).
Drawn from x=0 to x=1; pair with a transform that spans the two endpoints.
- minilink.graphical.animation.primitives.wheel_box(length=0.45, width=0.16)[source]¶
Small flat box used as a wheel/contact patch in vehicle diagrams.
- minilink.graphical.animation.primitives.vehicle_body(length=1.0, width=0.5, color='blue', opacity=0.85)[source]¶
Planar car/robot shell (arrow-shaped outline pointing along +X).
- minilink.graphical.animation.primitives.bounding_points(primitive)[source]¶
Local points that bound the primitive, plus a radial pad, or
Nonewhen excluded.Returns
(pts, pad): an(N, 3)array of local-frame points and a scalar margin to add around them (a rod’s radius, a sphere’s radius). The auto-fit camera transforms the points into the world and pads the box. Backdrops and force glyphs (primitive.camera_fitisFalse) returnNone; unknown primitives count as their origin only.
- minilink.graphical.animation.primitives.bounding_radius(primitive)[source]¶
Radius of a ball about the local origin containing the primitive (
Nonewhen excluded).
Abstract animation backend.
- class minilink.graphical.animation.renderers.renderer.AnimationRenderer(animator)[source]¶
One backend (matplotlib, meshcat, pygame, …) for static views and trajectory playback. Subclasses own all library-specific setup and I/O.
- abstract open_scene(*, is_3d, show, camera, title=None)[source]¶
Initialize backend resources for one render session.
camerais a 4x4camera_matrix()used to set up initial framing. Renderers consume the slots they understand (target, projection-axis columns, view scale, view-out direction) and ignore the rest; seeDESIGN.md§4.7.- Parameters:
is_3d (bool)
show (bool)
title (str | None)
- Return type:
None
- abstract draw_frame(primitives, transforms, t, camera)[source]¶
Draw one frame from precomputed transforms and camera.
- Parameters:
t (float)
- Return type:
None
- abstract present(*, block, interval_s=None)[source]¶
Present the currently drawn frame and optionally block/sleep.
- Parameters:
block (bool)
interval_s (float | None)
- Return type:
None
- poll_events()[source]¶
Return backend events/state for interactive loops.
Live external input and output live in
minilink.simulation.realtime(RealtimeInput/RealtimeOutput); renderers stay draw/present-only and report only view events such as{"quit": True}.
- abstract close_scene()[source]¶
Release/close backend resources for the current session.
- Return type:
None
- render_inline_animation(primitives, frames, schedule, *, is_3d)[source]¶
Optional notebook inline output (default: unsupported).
framesentries each carry"transforms"and"camera"(seeminilink.graphical.animation.Animator._prepare_transforms()).- Parameters:
is_3d (bool)
- export_animation(primitives, frames, schedule, file_name, *, is_3d=False)[source]¶
Optional animation export (default: unsupported).
- Parameters:
file_name (str)
is_3d (bool)
- Return type:
None
- play_native(primitives, frames, schedule, *, is_3d, scene_title=None)[source]¶
Optional native playback using the backend’s own animation engine.
Subclasses that support a native animation API (matplotlib
FuncAnimation, meshcatAnimation+set_animation, …) override this hook. Default raisesNotImplementedErrorso callers can fall back to the generic per-frame loop.- Parameters:
is_3d (bool)
scene_title (str | None)
Port maps: a block’s output over swept input components, and a controller’s control law.
- minilink.graphical.port_map.plot_input_output_map(block, *, in_port=None, out_port=None, x_axis=0, y_axis=None, out_axis=0, bounds=None, grid_shape=(101, 101), show_3d=False, params=None, t=0.0, title=None, cmap='bwr', vmin=None, vmax=None, ax=None, show=True)[source]¶
Plot one output component of
blockover swept input components.Sweeps one component of an input port (a line) or two (a heatmap, or a 3-D surface with
show_3d=True) through the output port’s ordinarycompute: no special block API is required.- Parameters:
block (System) – Any block with input and output ports; evaluated through the output port’s
computeat the block’s nominal state and pinned inputs.in_port (str, optional) – Port ids; default first input port and first output port.
out_port (str, optional) – Port ids; default first input port and first output port.
x_axis (int, optional) – Input-port components to sweep.
y_axis=Nonedraws a 1-D line.y_axis (int, optional) – Input-port components to sweep.
y_axis=Nonedraws a 1-D line.out_axis (int, optional) – Output component to plot (vector outputs).
bounds (optional) – Sweep ranges:
(lo, hi)for a line,((xlo, xhi), (ylo, yhi))for a surface. Defaults to the port bounds when finite, else ±10.show_3d (bool, optional) –
Truedraws a 3-D surface instead of a heatmap.params (dict, optional) – Alternative parameter set passed through to the port compute.
ax (matplotlib axes, optional) – Draw into an existing subplot (side-by-side comparisons).
- Return type:
PlotResult
- minilink.graphical.port_map.plot_control_law(block, *, x_axis=None, y_axis=None, u_axis=0, r=None, space=None, bounds=None, grid_shape=(101, 101), show_3d=False, params=None, t=0.0, title=None, cmap='bwr', vmin=None, vmax=None, ax=None, show=True)[source]¶
Plot the textbook slice of a controller block’s control law.
The block’s port names say what it reads (
minilink.core.feedback.block_roles()): the measurementyorx, or the error entry of a compensator. The zero-argument call picks the sweep space (minilink.core.feedback.plot_space_of(): error space for error-driven laws, absolute measurement/state otherwise), sweeps the first relevant coordinates, and pins the reference and every other coordinate at its nominal value. Blocks with internal state are evaluated atx0(the instantaneous law). Likeplot_input_output_map(), it evaluates the block through its output port’scompute.- Parameters:
block (System) – A block that reads a measurement (
y,xor an error entry) and commandsu.x_axis (int, optional) – Workspace components to sweep, in
z = [measurement-space; x_ctrl]. Components0 .. p-1are the measurement-space coordinates;p ..index the block’s internal state (dynamic controllers), for slices such as the error against the integral state.y_axis=Noneon a scalar measurement draws a line.y_axis (int, optional) – Workspace components to sweep, in
z = [measurement-space; x_ctrl]. Components0 .. p-1are the measurement-space coordinates;p ..index the block’s internal state (dynamic controllers), for slices such as the error against the integral state.y_axis=Noneon a scalar measurement draws a line.u_axis (int, optional) – Control component to draw (MIMO commands).
r (array, optional) – Pin the reference at this value; default the ref-port nominal.
space (str, optional) – Override the sweep space:
"error","error_qdq","measurement", or"state"; default from the ports or the block’splot_space.bounds (optional) – Sweep ranges, as in
plot_input_output_map().show_3d (bool, optional) –
Truedraws a 3-D surface instead of a heatmap.params (dict, optional) – Alternative parameter set (gain sweeps, trained vs. untrained).
- Return type:
PlotResult
- class minilink.graphical.port_map.SweepAxis(target, index, label, unit, bounds, base=0.0, sign=1.0)[source]¶
One swept coordinate mapped affinely into the block evaluation inputs.
The swept value
venters the flat input bundle (target="u") or the block state (target="x") atindexasbase + sign * v. Absolute coordinates usesign=+1; error coordinates usesign=-1with the reference component asbase(y = r - e).- Parameters:
target (str)
index (int)
label (str)
unit (str)
bounds (tuple[float, float])
base (float)
sign (float)
- class minilink.graphical.port_map.PortMapSpec(title, x_values, y_values, U, x_label, x_unit, y_label, y_unit, out_label, out_unit, vmin, vmax)[source]¶
Backend-neutral input-output map plot request.
- Parameters:
title (str)
x_values (ndarray)
y_values (ndarray | None)
U (ndarray)
x_label (str)
x_unit (str)
y_label (str | None)
y_unit (str | None)
out_label (str)
out_unit (str)
vmin (float | None)
vmax (float | None)
- minilink.graphical.port_map.render_port_map_matplotlib(spec, *, show_3d=False, cmap='bwr', ax=None, show=True, figsize=None, dpi=None, block=None, pause=0.0)[source]¶
Render a port-map specification with matplotlib.
- Parameters:
spec (PortMapSpec)
show_3d (bool)
cmap (str)
show (bool)
block (bool | None)
pause (float)
- Return type:
PlotResult
Control-analysis figures: one spec, rendered with matplotlib or plotly.
- class minilink.graphical.control.ControlFigure(title, panels, subtitle='', share_x=False, extra=<factory>)[source]¶
A titled stack of panels;
subtitlenames the channel (From / To).One or two panels of line traces, markers, dashed reference lines and text notes: enough for Bode, pole-zero, root locus, Nyquist and step-response plots.
matplotlib_backendandplotly_backendrender the same spec.- Parameters:
title (str)
panels (tuple[Panel, ...])
subtitle (str)
share_x (bool)
extra (dict)
- class minilink.graphical.control.Note(text, x=0.02, y=0.05)[source]¶
A text box anchored at a fraction of the panel (
0..1).- Parameters:
text (str)
x (float)
y (float)
- class minilink.graphical.control.Panel(traces, x_label, y_label, lines=(), notes=(), x_log=False, zero_lines=False, x_lim=None, y_lim=None, y_ticks=None)[source]¶
One axes: traces, references, notes, and how the axes are drawn.
- class minilink.graphical.control.RefLine(axis, value, color='#7f7f7f', dash='dash')[source]¶
A dashed reference line across the panel:
axisis"x"or"y".- Parameters:
axis (str)
value (float)
color (str)
dash (str)
- class minilink.graphical.control.Trace(x, y, color, mode='lines', marker='x', size=8.0, width=1.5, dash='solid', label='', hover=(), arrows=False)[source]¶
A line or a marker set;
hoverholds one text per point for plotly.- Parameters:
x (ndarray)
y (ndarray)
color (str)
mode (str)
marker (str)
size (float)
width (float)
dash (str)
label (str)
hover (tuple[str, ...])
arrows (bool)
- minilink.graphical.control.render_control_figure(spec, *, backend='matplotlib', show=True)[source]¶
Render
specwith the selected backend and return aPlotResult.- Parameters:
spec (ControlFigure)
Graphical catalog¶
Shape primitives and the placement helpers that pose them in a frame.
- class minilink.graphical.catalog.shapes.Arrow(base=(0.0, 0.0), vector=(1.0, 0.0), scale=1.0, head_ratio=0.15, color='red', linewidth=2, style='-')[source]¶
A straight arrow at honest world size — shaft from base along vector.
Accepts planar (length-2) or spatial (length-3) base / vector. Geometry is baked at true length
scale * |vector|; the renderer simply drawsself.ptsposed by the frame. Pass body-framevectorand key the primitive to that body frame so its orientation comes fromtf(no manualcos/sinrotation). For world-aligned task forces, key to a translation-only frame and pass the force components directly as vector.
- class minilink.graphical.catalog.shapes.Box(length_x=1.0, length_y=1.0, length_z=1.0, center=(0.0, 0.0, 0.0), color='gray', opacity=1.0)[source]¶
Axis-aligned rectangular solid in local frame (centered at
center).Dimensions are full lengths along local X, Y, Z. Used for simple vehicle bodies and blocks in 3D renderers (MeshCat box geometry).
- Parameters:
length_x (float)
length_y (float)
length_z (float)
opacity (float)
- class minilink.graphical.catalog.shapes.Circle(radius=1.0, center=(0, 0, 0), color='blue', fill=False)[source]¶
A basic circle primitive. Lives in the XY plane by default.
- class minilink.graphical.catalog.shapes.ExtrudedPolygon(pts_xy, height=1.0, center=(0.0, 0.0, 0.0), color='gray', opacity=1.0)[source]¶
Convex polygon in local XY, extruded symmetrically along local Z.
This is useful for light-weight 3D body shells such as vehicle noses, cabins, side pods, and tapered covers without introducing a full mesh asset pipeline.
- Parameters:
height (float)
opacity (float)
- class minilink.graphical.catalog.shapes.HorizonPolyline(plans, *, color='tab:orange', linewidth=2, style='--')[source]¶
World-frame polyline of the active receding-horizon plan at time t.
plansis a sequence of(t_solve, trajectory)pairs with world-frametrajectory.xandtrajectory.t. At playback time t, the primitive draws the latest plan witht_solve <= tover samples withtrajectory.t >= t.Geometry is rebuilt each frame through
points_at()(an overlay’sget_dynamic_geometry(t)bakes the world polyline into aCustomLine).
- minilink.graphical.catalog.shapes.Line¶
alias of
CustomLine
- class minilink.graphical.catalog.shapes.Plane(normal=(0, 1, 0), offset=0.0, size=10.0, thickness=0.02, color='lightgray', opacity=0.65)[source]¶
A finite square patch representing a plane: n·x = offset.
The patch is centered at
offset * normaland spanssize x size.
- class minilink.graphical.catalog.shapes.Point(pt=(0, 0, 0), color='red', marker='o', size=5)[source]¶
An individual point marker.
- class minilink.graphical.catalog.shapes.Rod(length=1.0, radius=0.05, color='blue', opacity=1.0, linewidth=2, style='-')[source]¶
A slender rigid rod primitive aligned with local -Y axis.
- class minilink.graphical.catalog.shapes.Sphere(radius=1.0, center=(0, 0, 0), color='blue', opacity=1.0)[source]¶
A 3D sphere primitive centered at
centerin local frame.
- class minilink.graphical.catalog.shapes.TorqueArrow(sweep, radius=1.0, head_ratio=0.4, n_arc_pts=40, color='red', linewidth=2, style='-')[source]¶
A curved torque arc at honest geometry — sweep baked into the points.
The arc for the given sweep and radius is built at construction, centered at the local origin; the placing frame supplies world position and the start orientation. Rebuild it each frame in
get_dynamic_geometrywith the instantaneous torque.- Parameters:
sweep (float) – Arc sweep angle in radians (positive = CCW, negative = CW).
radius (float) – Radius of the arc in world units.
head_ratio (float) – Chevron barb length as a fraction of the radius.
n_arc_pts (int) – Number of sample points used for a full-circle arc (subsampled proportionally for smaller sweeps).
- class minilink.graphical.catalog.shapes.TrajectoryPolyline(trajectory, *, window='prefix', color='tab:blue', linewidth=2, style='-')[source]¶
World-frame XY polyline sampled from a
Trajectory.At playback time t:
window="prefix"Samples with
trajectory.t <= t— a growing executed trail.window="suffix"Samples with
trajectory.t >= t.window="all"Full trajectory polyline (time-independent geometry).
Geometry is rebuilt each frame through
compute_pts(), likeHorizonPolyline.
- minilink.graphical.catalog.shapes.ground_line(length=20.0, y=0.0, color='black', style='--')[source]¶
Horizontal reference line of span length at height y (e.g. ground).
- minilink.graphical.catalog.shapes.spring_line(coils=6, amplitude=0.12, color='black', linewidth=1)[source]¶
Unit-length zig-zag spring along local +X (lead-in, coils coils, lead-out).
Drawn from x=0 to x=1; pair with a transform that spans the two endpoints.
- minilink.graphical.catalog.shapes.spring_between(p0, p1, *, coils=6, amplitude=0.12, color='black', linewidth=1)[source]¶
World-space spring coil from p0 to p1 (dynamic-tier geometry).
Coil count and lateral amplitude stay fixed in world units; only span along the axis changes with compression/extension.
- minilink.graphical.catalog.shapes.line_segment(p0, p1, **style)[source]¶
Honest world-space line segment (dynamic-tier geometry).
- minilink.graphical.catalog.shapes.segment_pose_2d(p0, p1)[source]¶
Pose a unit 2-D segment primitive to span p0 → p1 (static
tftier).Used for fixed-length chord lines where endpoints are known each frame. Native-array: NumPy or JAX depending on the input backend.
- minilink.graphical.catalog.shapes.link_pose_3d(p0, p1)[source]¶
Rigid pose for a unit
Rod(length on primitive) from p0 toward p1.Native-array: NumPy or JAX depending on the input backend. Near-zero span collapses to a pure translation at p0.
- minilink.graphical.catalog.shapes.point_pose(p)[source]¶
Pure translation placing a primitive at p.
Native-array: NumPy or JAX depending on the input backend. Length-2 points are lifted to the
z = 0plane.
- minilink.graphical.catalog.shapes.plane_airframe_3d(length=2.0, width=0.2, l_cg=None, span=2.0, chord_w=0.35, chord_t=0.2, span_t=0.7, fin_height=0.35, l_w=0.0, l_t=None, color='#2f6fed', wing_color='#4c8cff', tail_color='#3a7af0')[source]¶
Body-frame solid airframe for meshcat (c.g. at the origin).
Axes match a standard aircraft body frame:
+xforward,+yright,+zdown. The fuselage is anExtrudedPolygonside silhouette (local XY = bodyx–up, extruded along bodyy); wing / horizontal tail / vertical fin are thinBoxsolids.
- minilink.graphical.catalog.shapes.vehicle_body(length=1.0, width=0.5, color='blue', opacity=0.85)[source]¶
Planar car/robot shell (arrow-shaped outline pointing along +X).
- minilink.graphical.catalog.shapes.wheel_box(length=0.45, width=0.16)[source]¶
Small flat box used as a wheel/contact patch in vehicle diagrams.
Skins: a plant’s swappable look, as primitives keyed to the frames of its tf.
- minilink.graphical.catalog.skins.car_skin_2d(plant, color='#1a1a1a')[source]¶
2-D centerline car look: chassis line + two axle wheels.
A skin is a plant’s swappable look,
(plant) -> dict[frame, list[primitive]]: point geometry keyed to the frames of the plant’stf, with no state math (tfplaces every frame). A plant opts in withskin = car_skin_2dand swaps its look with one assignment (car.skin = car_skin_3d), keeping the samefand the sametf. Skins are plain functions, so a custom skin is just another(plant) -> dict.Frame keys:
body(chassis along the wheelbase plus the rear wheel outline; the rear axle offset is baked into the wheellocal_transform), andaxle_front(steered front wheel). The placingtfsupplies world pose and the front steer angle.
- minilink.graphical.catalog.skins.car_skin_3d(plant, color='#151922')[source]¶
3-D four-wheel car look: ground plane, body box, four wheel rods.
Frame keys:
world(ground),body(chassis box plus the two rear wheel rods; fixed hub offsets are baked into each rodlocal_transform), andwheel_fl/wheel_fr(steered front rods placed bytf).
- minilink.graphical.catalog.skins.plane_skin_3d(plant, color='#2f6fed')[source]¶
3-D aircraft look: ground plane plus solid fuselage / wing / tails.
Frame keys:
world(ground) andbody(airframe solids with the c.g. at the body-frame origin). Reads length / span / lever arms from plant graphic attrs andparamswhen present.
- minilink.graphical.catalog.skins.ur5_skin(plant)[source]¶
Schematic UR5 look made from link and joint cylinders.
Frame keys are
base,link0…link5,joint0…joint6, andtool. The plant’stfplaces every moving part.
- minilink.graphical.catalog.skins.merge_skins(*skins)[source]¶
Compose skin factories into one
(plant) -> dictthat merges their output.Primitive lists are concatenated per frame key, so several looks stack on a single plant (e.g. a base body plus a decal layer).
- minilink.graphical.catalog.skins.debug_state_skin(plant)[source]¶
Opt-in schematic dashboard: one marker per state and input, in a column.
A quick look for non-spatial plants (chemical reactors, filters, …) that have no natural geometry. Markers are keyed to
worldand offset vertically vialocal_transform(blue dots for states, red crosses for inputs).
Animation cameras: the 4x4 view from a drawable’s hints, and ready-made factories.
- minilink.graphical.animation.camera.resolve_camera_from_hints(source, frames, x=None, u=None, t=0.0, *, override=None)[source]¶
Resolve the 4x4 camera for one frame from a drawable’s hints.
The camera is a view hint, not a kinematic frame, so it lives in the graphical band (out of
tf/core/kinematics.py) and keeps its view scale in theT[3, 3]slot ofcamera_matrix(). Of the four design layers, two meet here:Layer 2, the default resolver: a drawable’s plain
camera_*attributes plus the resolvedtfframes give the 4x4 of each frame (following a frame whencamera_follow_frameis set).Layer 3, the override: an explicit
animate(camera=…), a constant 4x4ndarrayor a callablecamera(frames, x, u, t) -> 4x4;follow_frame_camera()andfixed_camera()build such callables.
Layer 1 (the
camera_*attributes onSystem) and Layer 4 (multi-source selection) live elsewhere.- Parameters:
source (object) – The drawable supplying
camera_*attributes (Layer 1).frames (dict[str, 4x4]) – Resolved
tffor this instant (used when following a frame).x (optional) – Playback state/input/time, forwarded to a callable override.
u (optional) – Playback state/input/time, forwarded to a callable override.
t (optional) – Playback state/input/time, forwarded to a callable override.
override (ndarray or callable, optional) – Layer-3
animate(camera=…)override. A constant 4x4 is returned as-is; a callable is invoked asoverride(frames, x, u, t).
- Returns:
4x4 camera transform (rigid pose +
T[3, 3]view scale).- Return type:
np.ndarray
- minilink.graphical.animation.camera.fit_camera_to_frames(frames, *, plot_axes=(0, 1), margin=1.15, min_scale=0.5)[source]¶
Camera that frames every primitive of frames: the auto-fit for hint-less drawables.
frames are the animator’s per-frame dicts (
primitivesplus worldtransforms). Backdrops (planes) are ignored. The view is centred on the bounding box of everything drawn, with a square half-width margin times the larger box half-extent along plot_axes.
- minilink.graphical.animation.camera.follow_frame_camera(frame_key, *, scale=10.0, plot_axes=(0, 1), target_offset=(0.0, 0.0, 0.0))[source]¶
Return a callable camera that re-centers on
frames[frame_key]each frame.The callable is the whole Layer-3 contract — pass it to
animate(camera=…). target_offset shifts the look-at relative to the followed frame’s origin.
- minilink.graphical.animation.camera.fixed_camera(target, *, scale=10.0, plot_axes=(0, 1))[source]¶
Return a callable camera fixed at target (a constant look-at).
Like
follow_frame_camera()but frame-independent; pass it toanimate(camera=…).
Time-only overlay drawables for composition at animate(overlays=[...]).
- class minilink.graphical.animation.drawables.Overlay[source]¶
Base overlay: time-only drawable hooks with empty defaults.
Overlays reuse the same three drawable hooks as
Systembut are driven by playback time t only (nox/u). The animator resolves each overlay withtf(t), cachedget_kinematic_geometry(), andget_dynamic_geometry(t), then concatenates the flat draw lists after the primary plant.
- class minilink.graphical.animation.drawables.Replay(drawable, trajectory)[source]¶
Full-skin ghost: forward another drawable’s hooks at
trajectorysamples.
- class minilink.graphical.animation.drawables.SceneHistory(**layers)[source]¶
Time-indexed plan/trail/reference polylines (graphics-only, not collision).
Static layers (e.g. a fixed reference
CustomLine) live in kinematic geometry. Layers withpoints_at()/points_at()are rebuilt each frame inget_dynamic_geometry(t).
- class minilink.graphical.animation.drawables.SceneVisualizer(scene, *, color='#c44e52', opacity=0.45)[source]¶
Static obstacle skin exported from a collision-first
Scene.
- minilink.graphical.animation.drawables.scene_as_visualizer(scene, **kwargs)[source]¶
Build a
SceneVisualizeroverlay for scene.