Diagram Module (stx.diagram)

Paper-optimized diagram generation with Mermaid and Graphviz backends.

Quick Reference

from scitex.diagram import Diagram

# Create from Python
d = Diagram(type="workflow", title="Analysis Pipeline")
d.add_node("load", "Load Data", shape="stadium")
d.add_node("proc", "Process", shape="rounded", emphasis="primary")
d.add_node("save", "Save Results", shape="stadium", emphasis="success")
d.add_edge("load", "proc")
d.add_edge("proc", "save")

# Export
d.to_mermaid("pipeline.mmd")
d.to_graphviz("pipeline.dot")

# Or from YAML specification
d = Diagram.from_yaml("pipeline.diagram.yaml")

YAML Specification

type: workflow
title: SciTeX Analysis Pipeline

paper:
  column: single          # single or double
  mode: publication       # draft or publication
  reading_direction: left_to_right

layout:
  groups:
    Input: [load, preprocess]
    Analysis: [analyze, test]

nodes:
  - id: load
    label: Load Data
    shape: stadium
  - id: analyze
    label: Statistical Test
    shape: rounded
    emphasis: primary

edges:
  - from: load
    to: analyze

Node Shapes

box, rounded, stadium, diamond, circle, codeblock

Node Emphasis

  • normal – Default (dark)

  • primary – Key nodes (blue)

  • success – Positive outcomes (green)

  • warning – Issues (red)

  • muted – Secondary (gray)

Diagram Types

  • workflow – Left-to-right sequential processes

  • decision – Top-to-bottom decision trees

  • pipeline – Data pipeline stages

  • hierarchy – Tree structures

  • comparison – Side-by-side comparison

Paper Modes

  • draft – Full arrows, medium spacing, all edges visible

  • publication – Tight spacing, return edges invisible, optimized for column width

Backends

  • Mermaid (.mmd) – Web/markdown rendering

  • Graphviz DOT (.dot) – Tighter layouts, render with dot -Tpng

  • YAML (.diagram.yaml) – Semantic spec, human/LLM-readable

API Reference

Public diagram API for figrecipe.

This module is the public face of figrecipe’s diagram subsystem. The implementation lives in the private figrecipe._diagram package; this module re-exports the stable, public diagram API so consumers can write:

import figrecipe.diagram
from figrecipe.diagram import Diagram, compile_to_mermaid

It mirrors how figrecipe.pyplot is exposed as a public submodule on top of the recording internals.

Examples

Box-and-arrow diagram (the primary Diagram builder):

>>> from figrecipe.diagram import Diagram
>>> d = Diagram(title="Pipeline")
>>> d.add_box("Load", x_mm=10, y_mm=10)

Mermaid / Graphviz compilation from a semantic DiagramSpec:

>>> from figrecipe.diagram import (
...     DiagramSpec, DiagramType, NodeSpec, EdgeSpec, compile_to_mermaid
... )
>>> spec = DiagramSpec(
...     type=DiagramType.WORKFLOW,
...     nodes=[NodeSpec(id="a", label="Start"),
...            NodeSpec(id="b", label="End")],
...     edges=[EdgeSpec(source="a", target="b")],
... )
>>> mermaid = compile_to_mermaid(spec)
class scitex.diagram.Diagram(title=None, width_mm=170.0, height_mm=120.0, padding_mm=10.0, gap_mm=None)[source]

Builder for rich box-and-arrow diagrams with mm-based coordinates.

add_box(id, title, subtitle=None, content=None, emphasis='normal', shape='rounded', x_mm=None, y_mm=None, width_mm=None, height_mm=None, fill_color=None, border_color=None, title_color=None, padding_mm=5.0, margin_mm=0.0, node_class=None, state=None, language=None, bullet=None)[source]

Add a rich text box. See BoxSpec for node_class/state/language/bullet.

Return type:

Diagram

add_container(id, title=None, children=None, emphasis='muted', x_mm=None, y_mm=None, width_mm=None, height_mm=None, fill_color=None, border_color=None, title_loc='upper center', direction='row', container_gap_mm=8.0, container_padding_mm=8.0, equalize_heights=True, equalize_widths=True)[source]

Add a container. equalize_heights/widths: match children in row/column.

Return type:

Diagram

add_arrow(source, target, source_anchor='auto', target_anchor='auto', source_dx=0.0, source_dy=0.0, target_dx=0.0, target_dy=0.0, label=None, style='solid', color=None, curve=0.0, linewidth_mm=0.5, label_offset_mm=None, margin_mm=None)[source]

Add an arrow connecting two boxes.

Return type:

Diagram

add_icon(id, source, x_mm, y_mm, width_mm=8.0, height_mm=8.0, color=None, opacity=1.0)[source]

Add an icon (SVG/PNG or built-in: warning/check/cross/info/lock).

Return type:

Diagram

validate_containers()[source]

Check every container fully encloses its declared children.

Return type:

None

validate_no_overlap()[source]

Check that no two boxes overlap each other.

Return type:

None

auto_layout(layout='lr', margin_mm=15.0, box_size_mm=None, gap_mm=10.0, avoid_overlap=True, justify='space-between', align_items='center')[source]

Automatically position boxes. See _layout for details.

Return type:

Diagram

render(ax=None, auto_fix=False, auto_curve=True)[source]

Render. auto_fix=True resolves violations; auto_curve=False skips R7.

Return type:

Tuple[Figure, Axes]

save(path, dpi=200, save_recipe=True, save_hitmap=False, save_debug=True, watermark=False)[source]

Render, crop, and save. watermark=True adds ‘Plotted by scitex.ai’.

Return type:

Path

render_to_file(path, dpi=200, save_recipe=True, save_hitmap=False, save_debug=True, watermark=False)

Render, crop, and save. watermark=True adds ‘Plotted by scitex.ai’.

Return type:

Path

to_dict()[source]

Convert diagram to dictionary for serialization.

Return type:

Dict[str, Any]

classmethod from_dict(data)[source]

Create Diagram from dictionary (recipe reproduction).

Return type:

Diagram

scitex.diagram.GraphDiagram

alias of Diagram

class scitex.diagram.DiagramSpec(type=DiagramType.WORKFLOW, title='', paper=<factory>, layout=<factory>, nodes=<factory>, edges=<factory>, theme=<factory>)[source]

Complete diagram specification - the semantic layer.

type: DiagramType = 'workflow'
title: str = ''
paper: PaperConstraints
layout: LayoutHints
nodes: List[NodeSpec]
edges: List[EdgeSpec]
theme: Dict[str, str]
classmethod from_dict(data)[source]

Create DiagramSpec from dictionary (parsed YAML).

Return type:

DiagramSpec

class scitex.diagram.DiagramType(value)[source]

Semantic type of diagram - affects layout strategy.

WORKFLOW = 'workflow'
DECISION = 'decision'
PIPELINE = 'pipeline'
HIERARCHY = 'hierarchy'
COMPARISON = 'comparison'
class scitex.diagram.NodeSpec(id, label, shape='box', emphasis='normal')[source]

Specification for a single node.

id: str
label: str
shape: Literal['box', 'rounded', 'diamond', 'circle', 'stadium', 'codeblock'] = 'box'
emphasis: Literal['normal', 'primary', 'success', 'warning', 'muted'] = 'normal'
short_label(max_chars=20)[source]

Return truncated label for compact layouts.

Return type:

str

class scitex.diagram.EdgeSpec(source, target, label=None, style='solid', arrow='normal')[source]

Specification for an edge between nodes.

source: str
target: str
label: str | None = None
style: Literal['solid', 'dashed', 'dotted'] = 'solid'
arrow: Literal['normal', 'none', 'open'] = 'normal'
class scitex.diagram.PaperConstraints(column=ColumnLayout.SINGLE, max_width_mm=170, reading_direction='left_to_right', mode=PaperMode.DRAFT, emphasize=<factory>, main_flow=<factory>, secondary_flow=<factory>, return_edges=<factory>)[source]

Paper-specific constraints that affect layout.

column: ColumnLayout = 'single'
max_width_mm: int = 170
reading_direction: Literal['left_to_right', 'top_to_bottom'] = 'left_to_right'
mode: PaperMode = 'draft'
emphasize: List[str]
main_flow: List[str]
secondary_flow: List[str]
return_edges: List[tuple]
class scitex.diagram.LayoutHints(layers=<factory>, alignment=<factory>, layer_gap=SpacingLevel.MEDIUM, node_gap=SpacingLevel.MEDIUM, groups=<factory>)[source]

Abstract layout hints - compiled to backend directives.

layers: List[List[str]]
alignment: Dict[str, str]
layer_gap: SpacingLevel = 'medium'
node_gap: SpacingLevel = 'medium'
groups: Dict[str, List[str]]
class scitex.diagram.ColumnLayout(value)[source]

Paper column layout.

SINGLE = 'single'
DOUBLE = 'double'
class scitex.diagram.SpacingLevel(value)[source]

Abstract spacing levels - mapped to backend-specific values.

TIGHT = 'tight'
COMPACT = 'compact'
MEDIUM = 'medium'
LARGE = 'large'
class scitex.diagram.PaperMode(value)[source]

Paper mode affects layout density and edge visibility.

DRAFT = 'draft'
PUBLICATION = 'publication'
scitex.diagram.compile_to_mermaid(spec, preset=None)[source]

Compile DiagramSpec to Mermaid format with paper-optimized settings.

Parameters:
  • spec (DiagramSpec) – The semantic diagram specification.

  • preset (DiagramPreset, optional) – Override preset (default: inferred from spec.type).

Returns:

Mermaid diagram source code.

Return type:

str

scitex.diagram.compile_to_graphviz(spec, preset=None)[source]

Compile DiagramSpec to Graphviz DOT format.

Parameters:
Returns:

Graphviz DOT source code.

Return type:

str

class scitex.diagram.DiagramPreset(mermaid_direction, mermaid_theme, graphviz_rankdir, graphviz_ranksep, graphviz_nodesep, spacing_map, mermaid_shapes, graphviz_shapes, emphasis_styles)[source]

Rules for compiling a diagram type.

mermaid_direction: str
mermaid_theme: Dict[str, str]
graphviz_rankdir: str
graphviz_ranksep: float
graphviz_nodesep: float
spacing_map: Dict[str, Dict[str, float]]
mermaid_shapes: Dict[str, str]
graphviz_shapes: Dict[str, str]
emphasis_styles: Dict[str, Dict[str, str]]
scitex.diagram.get_preset(diagram_type)[source]

Get preset for diagram type.

Return type:

DiagramPreset

scitex.diagram.list_presets()[source]

List all available presets with descriptions.

Return type:

dict

class scitex.diagram.SplitConfig(enabled=False, max_nodes=12, strategy=SplitStrategy.BY_GROUPS, keep_hubs=True, ghost_style='muted')[source]

Configuration for auto-splitting.

enabled: bool = False
max_nodes: int = 12
strategy: SplitStrategy = 'by_groups'
keep_hubs: bool = True
ghost_style: str = 'muted'
class scitex.diagram.SplitResult(figures, labels, cut_nodes)[source]

Result of splitting a diagram.

figures: List[DiagramSpec]
labels: List[str]
cut_nodes: Set[str]
class scitex.diagram.SplitStrategy(value)[source]
BY_GROUPS = 'by_groups'
BY_ARTICULATION = 'by_articulation'
scitex.diagram.get_available_backends()[source]

Get available rendering backends and their status.

Return type:

dict