stormvogel.to_dot

Attributes

Functions

_invert_lightness(→ str)

Return the lightness-inverted counterpart of hex_color for dark mode.

_dark_mode_parts(→ tuple[str, str, str] | None)

Collect colors and build dark-mode CSS for an SVG.

_dark_mode_svg(→ bytes)

Return SVG bytes with the dark-mode <style> injected inside the <svg>.

_dark_mode_html(→ str)

Return an HTML string with the dark-mode <style> placed outside the SVG.

_auto_action_positions(→ dict)

Compute positions for action nodes whose state source has a known position.

suggest_positions(→ dict)

Run the graphviz dot layout engine on model and return the computed state positions.

_observation_color_map(→ dict)

Return a mapping from each Observation to a muted pastel hex color.

plot_model_pydot(→ None)

Render a stormvogel model to SVG/PDF using pydot.

Module Contents

stormvogel.to_dot._NAMED_COLORS
stormvogel.to_dot._invert_lightness(hex_color: str) str

Return the lightness-inverted counterpart of hex_color for dark mode.

stormvogel.to_dot._dark_mode_parts(svg_bytes: bytes) tuple[str, str, str] | None

Collect colors and build dark-mode CSS for an SVG.

Returns (svg_id, style_block, svg_with_id) or None if no colors were found. The <style> block is not yet inserted into the SVG so callers can decide whether to inject it inside or outside the <svg>.

stormvogel.to_dot._dark_mode_svg(svg_bytes: bytes) bytes

Return SVG bytes with the dark-mode <style> injected inside the <svg>.

Used for .svg file output, where the style must travel with the file.

stormvogel.to_dot._dark_mode_html(svg_bytes: bytes) str

Return an HTML string with the dark-mode <style> placed outside the SVG.

MyST/Sphinx strips <style> elements from SVG cell outputs but passes HTML outputs through unchanged, so placing the style adjacent to the SVG keeps it intact.

stormvogel.to_dot._auto_action_positions(model: stormvogel.model.Model, positions: dict, self_loop_radius: float = 0.7, action_radius: float = 0.5, collision_threshold: float = 0.2, perp_offset: float = 0.3) dict

Compute positions for action nodes whose state source has a known position.

For regular (non-self-loop) actions the action node is placed at action_radius inches from the source state in the direction of the probability-weighted average of target positions. Using a fixed radius (rather than the midpoint) keeps the dot close to its source state, which makes ownership visually unambiguous and avoids the dot landing near or inside a distant target state’s circle.

For self-loop actions the action node is placed at self_loop_radius inches from the state, cycling through compass angles (below, lower-left, lower-right, …) so that multiple self-loops on the same state do not overlap.

After initial placement, action nodes that land within collision_threshold inches of each other are spread symmetrically perpendicular to their common direction (same-source) or to the line connecting their source states (different-source), separated by perp_offset inches.

stormvogel.to_dot.suggest_positions(model: stormvogel.model.Model, rankdir: str = 'LR', width: float = 0.8, size: str | None = None, ranksep: float | None = None, nodesep: float | None = None) dict

Run the graphviz dot layout engine on model and return the computed state positions.

The returned dict maps each State to an (x, y) tuple (inches) that can be passed directly as the positions argument of plot_model_pydot(). Useful when two models share the same state space and you want both rendered with an identical layout.

Parameters:
  • model – The model to lay out.

  • rankdir – Layout direction (“LR”, “TB”, etc.).

  • width – Diameter of state circles in inches (affects spacing).

  • size – Optional Graphviz size attribute, e.g. "5,3" to cap the layout at 5 × 3 inches. Dot scales the positions down to fit.

  • ranksep – Graphviz ranksep — minimum distance between ranks (columns in LR layout). Larger values spread the graph horizontally.

  • nodesep – Graphviz nodesep — minimum distance between nodes in the same rank (rows in LR layout). Larger values spread vertically.

stormvogel.to_dot._observation_color_map(model: stormvogel.model.Model, saturation: float = 0.4, lightness: float = 0.82) dict

Return a mapping from each Observation to a muted pastel hex color.

stormvogel.to_dot.plot_model_pydot(model: stormvogel.model.Model, output_file: str | None = None, positions: dict | None = None, rankdir: str = 'LR', width: float = 0.8, policy: dict | None = None, state_colors: dict[str, str] | None = None, default_fill: str = '#a6cee3', show_state_rewards: bool = True, show_transition_rewards: bool = True, auto_action_positions: bool = True, highlight_state: stormvogel.model.State | None = None, self_loop_position: str | dict[stormvogel.model.State, str] | None = None, color_by_observation: bool = True) None

Render a stormvogel model to SVG/PDF using pydot.

State nodes are circles; action nodes are small filled squares (unlabeled). The edge from a state to an action node carries the action label; edges from an action node to successors carry the probability. DTMCs use direct state-to-state edges instead. The initial state gets an incoming arrow.

Parameters:
  • model – The model to render.

  • output_file – Path ending in .svg or .pdf. None returns an HTML object containing the SVG for display in Jupyter / MyST notebooks.

  • positions – Optional dict mapping State to (x, y). States without an entry are auto-placed by neato. Action nodes are never required in this dict: when the source state has a known position the action node is placed automatically (midpoint toward target states for regular actions; offset below the state for self-loops). Explicit (State, Action) entries override the automatic placement.

  • rankdir – Layout direction (“LR”, “TB”, etc.); ignored when positions are given (neato is used instead of dot).

  • width – Diameter of state circles in inches (all states uniform).

  • policy – Optional dict[State, Action]. The chosen action node and the edge leading to it are highlighted in orange; non-chosen action edges are drawn in a lighter gray.

  • state_colors – Optional mapping from state label to fill color. The first matching label (in dict-insertion order) determines the fill. States with no matching label use default_fill.

  • default_fill – Fill color applied to states that have no entry in state_colors.

  • show_state_rewards – When True, append state reward values to each state node label. Has no effect if the model has no state rewards.

  • show_transition_rewards – When True, append transition reward values to the edge label between an action node and its successor. Has no effect if the model has no transition rewards.

  • auto_action_positions – When True (default), action node positions are computed automatically from state positions. Set to False to let the layout engine place all action nodes freely.

  • highlight_state – Optional single state to highlight with a thick orange border. The fill color is still determined by state_colors / default_fill.

  • self_loop_position – Compass direction(s) controlling where self-loop edges are drawn. A single string (e.g. "s", "ne") applies to all self-loops; a dict[State, str] gives per-state control. Both headport and tailport are set to the chosen direction. None (default) lets Graphviz decide.

  • color_by_observation – When True, states are filled with automatically chosen muted pastel colors, one distinct color per observation. state_colors (label-based) still takes priority. Has no effect on models that do not support observations.