Visualization
The moro.visualization package provides tools for plotting and
animating serial robot manipulators.
Visualization tools for serial robots.
- class moro.visualization.DHSegmentData(row_index: int, kind: Literal['d', 'a'], start: ndarray, end: ndarray)[source]
Bases:
objectOne numerical DH translation contribution, in base coordinates.
row_index is 1-based. kind is “d” or “a”. The endpoints are independent, finite real arrays with shape (3,) when produced by
evaluate_robot(). These segments describe DH geometry, not the physical shape of a robot link.- end: ndarray
- kind: Literal['d', 'a']
- row_index: int
- start: ndarray
- class moro.visualization.FrameData(T: ndarray)[source]
Bases:
objectNumerical homogeneous transformation of one robot frame.
- T: ndarray
- property position
- property rotation
- property x
- property y
- property z
- class moro.visualization.JointData(index: int, kind: Literal['r', 'p'], origin: ndarray, axis: ndarray)[source]
Bases:
objectKinematic metadata for a single classic-DH joint.
The index is the 1-based DH row/joint index; kind is “r” or “p”. Origin is the previous frame origin p_(i-1), and axis is its positive z direction z_(i-1), both expressed in world/base coordinates. Together they define the motion axis, not physical actuator geometry.
Origin and axis are independent finite float arrays of shape (3,). Any nonzero finite axis is normalized to unit length on construction.
- axis: ndarray
- index: int
- kind: Literal['r', 'p']
- origin: ndarray
- class moro.visualization.MatplotlibBackend[source]
Bases:
objectRender robot kinematic diagrams using Matplotlib 3D.
- static animate(scene_data_list: list[SceneData], interval=100, figsize=(10, 8), style: VisualizationStyle | None = None, layout: VisualizationLayout | None = None, framing: SceneFraming | None = None, **kwargs)[source]
Create a Matplotlib animation.
Notes
Keep a reference to the returned
FuncAnimationuntil it has been displayed or saved; otherwise it may be garbage-collected prematurely.
- static render(scene_data: SceneData, ax=None, figsize=(10, 8), view_init=(30, 30), style: VisualizationStyle | None = None, layout: VisualizationLayout | None = None, framing: SceneFraming | None = None)[source]
Render one robot configuration on a Matplotlib 3D axis.
- class moro.visualization.RobotVisualizer(robot: Robot)[source]
Bases:
objectRender a
moro.core.Robotusing the available backends.
- class moro.visualization.SceneBounds(minimum: tuple[float, float, float], maximum: tuple[float, float, float])[source]
Bases:
objectFinite axis-aligned bounds in the robot’s world-coordinate units.
- property center: tuple[float, float, float]
Center of the box, avoiding overflow from direct endpoint addition.
- maximum: tuple[float, float, float]
- minimum: tuple[float, float, float]
- property size: tuple[float, float, float]
Nonnegative extents along world X, Y and Z.
- class moro.visualization.SceneData(joints: list[~numpy.ndarray], frames: list[~moro.visualization.data.FrameData], dimension: float, dh_segments: list[~moro.visualization.data.DHSegmentData] = <factory>, joint_data: list[~moro.visualization.data.JointData] = <factory>)[source]
Bases:
objectEvaluated numerical data for one robot configuration.
dh_segments lists two contributions per DH row in d, a order. joint_data describes each motion axis in joint index order. Both fields are optional so legacy positional scene construction remains valid. The historic joints positions still denote frame origins.
- property characteristic_length: float | None
Sum of the evaluated absolute DH translation lengths.
Returns None when geometric segments are unavailable (e.g. a legacy manually constructed scene). Returns 0.0 for explicitly evaluated but degenerate DH geometry. No absolute unit-dependent minimum is imposed, and the result follows mutations to segments.
- dh_segments: list[DHSegmentData]
- dimension: float
- joints: list[ndarray]
- class moro.visualization.SceneFraming(bounds: SceneBounds, center: tuple[float, float, float], half_extent: float, fit_radius: float)[source]
Bases:
objectWorld-space framing instructions, independent of projection and viewport.
- bounds: SceneBounds
- center: tuple[float, float, float]
- fit_radius: float
- half_extent: float
- class moro.visualization.ThreeJSBackend[source]
Bases:
objectRender robot kinematic diagrams using Three.js.
- static animate(scene_data_list: list[SceneData], width: int = 800, height: int = 600, style: VisualizationStyle | None = None, layout: VisualizationLayout | None = None, framing: SceneFraming | None = None, interval: float = 100)[source]
Return an interactive Three.js animation as
IPython.display.HTML.
- static render(scene_data: SceneData, width: int = 800, height: int = 600, style: VisualizationStyle | None = None, layout: VisualizationLayout | None = None, framing: SceneFraming | None = None)[source]
Return an interactive Three.js view as
IPython.display.HTML.
- class moro.visualization.VisualizationLayout(reference_length: float, frame_length: float, joint_radius: float, base_radius: float, link_radius: float)[source]
Bases:
objectResolved world-space sizes shared by rendering backends.
All five lengths use the robot’s input linear units. The nominal link radius is not yet modified by VisualizationStyle.link_linewidth.
- base_radius: float
- frame_length: float
- joint_radius: float
- link_radius: float
- reference_length: float
- class moro.visualization.VisualizationStyle(show_frames: bool = True, show_links: bool = True, show_joints: bool = True, show_base: bool = True, show_grid: bool = True, link_color: str = '#778877', joint_color: str = '#ff1493', base_color: str = '#ff00ff', frame_scale: float | None = None, joint_size: float | None = None, base_size: float | None = None, link_linewidth: float = 3, show_trajectory: bool = False, trajectory_color: str = '#1565c0', trajectory_linewidth: float = 2, trajectory_mode: str = 'full', joint_representation: Literal['auto', 'simple', 'kinematic'] = 'auto', joint_scale: float = 1.0, joint_appearance: Literal['schematic', 'solid'] = 'solid', revolute_color: str = '#0072B2', prismatic_color: str = '#D55E00')[source]
Bases:
objectStyle configuration for robot visualization.
- Parameters:
- show_framesbool
Draw coordinate frames at each joint.
- show_linksbool
Draw links connecting consecutive joints.
- show_jointsbool
Draw joint markers.
- show_basebool
Highlight the base joint when joints are visible.
- show_gridbool
Draw the reference grid.
- joint_representationstr
‘auto’ (default) selects backend-appropriate joint markers: R/P solids in Three.js if joint metadata exists, otherwise spheres; Matplotlib uses spheres. ‘simple’ forces spheres; ‘kinematic’ requests R/P geometry explicitly.
- joint_scalefloat
Finite positive dimensionless factor for kinematic joint symbols.
- joint_appearancestr
‘solid’ (default within kinematic mode, Three.js) or ‘schematic’ (also available in Matplotlib). In ‘auto’ mode, Three.js uses ‘solid’ when full joint metadata is available.
- revolute_colorstr
Color of kinematic revolute joint symbols or solid cylinders.
- prismatic_colorstr
Color of kinematic prismatic joint symbols or solid prisms.
- link_colorstr
Color used for links.
- joint_colorstr
Color used for joints.
- base_colorstr
Color used for the base joint.
- frame_scalefloat or None
Length of frame axes in robot units. If None, use the shared layout.
- joint_sizefloat or None
Explicit size: Matplotlib marker area factor (s=size*100 in pt²), or Three.js world-space radius. If None, use the backend adapter.
- base_sizefloat or None
Base marker size with the same backend-specific semantics as joint_size. If None, use the backend adapter.
- link_linewidthfloat
Link thickness in Matplotlib points; Three.js uses it as a multiplicative factor relative to its nominal link radius (value/3).
- show_trajectorybool
Draw end-effector Cartesian trajectory in animations.
- trajectory_colorstr
Color used for the trajectory line.
- trajectory_linewidthfloat
Trajectory line thickness.
- trajectory_modestr
Trajectory display mode:
"full"or"trace".
- base_color: str
- base_size: float | None
- frame_scale: float | None
- joint_appearance: Literal['schematic', 'solid']
- joint_color: str
- joint_representation: Literal['auto', 'simple', 'kinematic']
- joint_scale: float
- joint_size: float | None
- link_color: str
- link_linewidth: float
- prismatic_color: str
- revolute_color: str
- show_base: bool
- show_frames: bool
- show_grid: bool
- show_joints: bool
- show_links: bool
- show_trajectory: bool
- trajectory_color: str
- trajectory_linewidth: float
- trajectory_mode: str
- moro.visualization.compute_scene_bounds(scene: SceneData, *, layout: VisualizationLayout | None = None, style: VisualizationStyle | None = None) SceneBounds[source]
Bound visible robot primitives in one evaluated configuration.
Includes DH translation segments, or legacy joint-to-joint links when no DH data is present; visible joints and their nominal radii; visible local frame origins and axis tips; and the EE position if a trajectory is shown.
Link radii are conservative world-space estimates using the Three.js linewidth ratio. Explicit Matplotlib marker sizes are in points-squared, so they cannot be interpreted as physical radii here. Global axes and grids do not contribute. A fully hidden or empty scene has a zero-size box at the world origin, expanded visually by resolve_framing.
- moro.visualization.evaluate_robot(robot: Robot, num_vals: dict) SceneData[source]
Evaluate a robot at a numerical configuration.
- Parameters:
- robotRobot
Serial-link robot instance.
- num_valsdict
Mapping from symbolic variables to numerical values.
- Returns:
- SceneData
Numerical frame origins, frame transformations, ordered DH translation segments and kinematic joint axes in the base frame.
- moro.visualization.plot_workspace(workspace, *, projection='auto', ax=None, figsize=(8, 6), marker_size=8, alpha=0.5)[source]
Plot a sampled workspace as a Matplotlib point cloud.
- moro.visualization.resolve_framing(scenes: Sequence[SceneData], *, layout: VisualizationLayout | None = None, style: VisualizationStyle | None = None, margin: float = 0.1, min_extent_factor: float = 0.1) SceneFraming[source]
Resolve one stable view volume around all sampled scenes.
Bounds cover only the supplied configurations, not continuous robot motion between sampled frames. Both half_extent (cube) and fit_radius (enclosing sphere) include a relative margin and a visual-only minimum proportional to the reference length, with no absolute physical floor.
- moro.visualization.resolve_layout(scenes: Sequence[SceneData], *, reference_length: float | None = None) VisualizationLayout[source]
Resolve one stable geometric layout for a scene or animation.
Scale precedence: 1. Explicit finite positive reference_length. 2. Maximum positive DH characteristic length across scenes. 3. Maximum finite positive legacy SceneData.dimension. 4. Visual-only fallback length of 1.0.
SceneData.characteristic_length remains unchanged, including when zero or unavailable. No camera, plot bounds, or backend-specific sizes are calculated here. Resolve once per precomputed animation, not per frame.
- moro.visualization.resolve_reference_length(scenes: Iterable[SceneData]) float | None[source]
Return the largest available characteristic length across scenes.
Only evaluated DH geometry contributes. Legacy scenes without segments are ignored. None means no evaluated geometry was available; 0.0 means that all evaluated geometry is degenerate. The caller must handle the visual fallback separately when the result is zero or unavailable.
The result is suitable for keeping graphical dimensions constant through a precomputed animation sequence.
- moro.visualization.union_bounds(bounds: Sequence[SceneBounds]) SceneBounds[source]
Compute the AABB union of a nonempty sequence of boxes.