Visualization¶
PyStator can generate diagrams of your state machines from their definitions — no separate diagram tool or manual drawing required. Diagrams stay in sync with the YAML automatically.
Available formats¶
| Function | Output format | Best for |
|---|---|---|
to_mermaid |
Mermaid stateDiagram-v2 |
Markdown docs, GitHub READMEs, MkDocs |
to_mermaid_flowchart |
Mermaid flowchart |
Alternative visual style |
to_dot |
Graphviz DOT | High-quality rendered images (png, svg, pdf) |
to_scxml |
SCXML XML | Interoperability with other FSM tools |
get_statistics |
Python dict | Programmatic analysis (CI checks, docs metadata) |
Mermaid state diagram¶
from pystator import StateMachine
from pystator.visualization import to_mermaid
machine = StateMachine.from_yaml("order_fsm.yaml")
diagram = to_mermaid(
machine,
title="Order Lifecycle",
show_guards=True, # default: True
show_actions=False, # default: False — keeps diagrams readable
show_timeouts=True, # default: True
direction="LR", # "TB" (top-bottom), "LR" (left-right), "BT", "RL"
)
print(diagram)
Example output:
---
title: Order Lifecycle
---
stateDiagram-v2
direction LR
[*] --> pending
pending --> confirmed : confirm
confirmed --> shipped : ship [stock_available]
shipped --> delivered : deliver
delivered --> [*]
pending --> cancelled : cancel
confirmed --> cancelled : cancel
Paste directly into any Markdown file or MkDocs page and it renders automatically (MkDocs Material has built-in Mermaid support).
Embedding in MkDocs¶
Embedding in a GitHub README¶
GitHub renders Mermaid code blocks natively since 2022:
Mermaid flowchart¶
Produces a flowchart diagram instead of stateDiagram-v2 — useful when you prefer a different visual layout:
from pystator.visualization import to_mermaid_flowchart
diagram = to_mermaid_flowchart(machine, title="Order Flow", direction="TB")
print(diagram)
State shapes:
- Initial states → stadium shape ([name])
- Terminal states → double-hexagon {{name}}
- Normal states → rectangle [name]
Graphviz DOT¶
For high-quality rendered images (PNG, SVG, PDF) suitable for architecture docs:
from pystator.visualization import to_dot
dot_source = to_dot(
machine,
title="Order Lifecycle",
show_guards=True,
show_actions=True,
)
print(dot_source)
Render with the graphviz command-line tool:
# Save to file
python -c "
from pystator import StateMachine
from pystator.visualization import to_dot
m = StateMachine.from_yaml('order_fsm.yaml')
print(to_dot(m, title='Order FSM'))
" > order.dot
# Render to PNG
dot -Tpng order.dot -o order.png
# Render to SVG
dot -Tsvg order.dot -o order.svg
Or render programmatically with the graphviz Python package:
import graphviz
dot_source = to_dot(machine, title="Order FSM")
graph = graphviz.Source(dot_source)
graph.render("docs/diagrams/order_fsm", format="png", cleanup=True)
SCXML export¶
SCXML is a W3C standard format for state machine definitions. Use it for interoperability with other FSM tools or formal verification:
from pystator.visualization import to_scxml
scxml_doc = to_scxml(machine)
with open("order_fsm.scxml", "w") as f:
f.write(scxml_doc)
Machine statistics¶
get_statistics returns a dict of counts useful for documentation, monitoring, or CI gates:
from pystator.visualization import get_statistics
stats = get_statistics(machine)
print(stats)
# {
# "state_count": 5,
# "transition_count": 7,
# "terminal_state_count": 2,
# "initial_state": "pending",
# "terminal_states": ["delivered", "cancelled"],
# "trigger_count": 6,
# "guard_count": 3,
# "action_count": 4,
# "has_timeouts": False,
# "has_parallel_states": False,
# "has_hierarchical_states": False,
# }
Using statistics in CI¶
Fail a CI step if the FSM grows unexpectedly complex:
from pystator import StateMachine
from pystator.visualization import get_statistics
machine = StateMachine.from_yaml("order_fsm.yaml")
stats = get_statistics(machine)
assert stats["state_count"] <= 20, f"Too many states: {stats['state_count']}"
assert stats["terminal_state_count"] >= 1, "No terminal states defined"
Generating diagrams for all machines¶
from pathlib import Path
from pystator import StateMachine
from pystator.visualization import to_mermaid
machines_dir = Path("machines")
docs_dir = Path("docs/diagrams")
docs_dir.mkdir(parents=True, exist_ok=True)
for yaml_file in machines_dir.glob("*.yaml"):
machine = StateMachine.from_yaml(str(yaml_file))
diagram = to_mermaid(machine, title=machine.name)
out = docs_dir / f"{yaml_file.stem}.md"
out.write_text(f"# {machine.name}\n\n```mermaid\n{diagram}\n```\n")
print(f"Generated {out}")
See also¶
- FSM Config Reference — full YAML spec
- Linting — static analysis of state machine definitions
- API Reference — Visualization