Diagrams
Structural diagram contracts, themes, DOT export and Graphviz rendering.
Import diagram types and rendering helpers from snnlab.viz. Create network diagrams with lang.diagram, or construct a Diagram yourself to include ordinary PyTorch layers and other external elements.
from snnlab import lang, viz
diagram = lang.diagram(bundle, view="expanded")
viz.render_diagram(diagram, "network.png", scale=2, height_to_width_ratio=None)Diagram data
Diagram
class Diagram:
name: str
nodes: tuple[DiagramNode, ...]
edges: tuple[DiagramEdge, ...]
groups: tuple[DiagramGroup, ...] = ()
title: str | None = None
metadata: dict[str, object] = field(default_factory=dict)DiagramNode
class DiagramNode:
id: str
title: str
detail: str
badge: str
kind: str = "neutral"
accent_role: str = "ink"
classes: tuple[str, ...] = ()
pen_width: float = 1.0
margin: tuple[float, float] = (0.18, 0.14)DiagramEdge
class DiagramEdge:
source: str
target: str
role: str = "signal"
label: str = ""
connection: str = "feedforward"
id: str | None = None
classes: tuple[str, ...] = ()
constraint: bool = True
pen_width: float = 1.1
frozen: bool = FalseDiagramGroup
class DiagramGroup:
id: str
label: str
members: tuple[str, ...]
same_rank: bool = False
same_row: bool = FalseDiagram validates unique node IDs, existing edge endpoints and group members. metadata carries renderer-neutral context. A node supplies its text, category and accent role; an edge supplies direction, semantic role, optional label and routing hints. frozen=True marks a frozen connection visually. Groups enclose existing nodes; same_rank and same_row cannot both be enabled.
Colour roles resolve against DiagramTheme. Use roles such as signal, inhibitory, modulatory, output_line or training_line, rather than arbitrary colour values in an edge’s role. Node classes and edge classes become rendering metadata.
diagram_to_dot
def diagram_to_dot(
diagram: Diagram,
*,
theme: DiagramTheme = DiagramTheme(),
height_to_width_ratio: float | None = None,
canvas_size: tuple[int, int] | None = None,
) -> str: ...Returns Graphviz DOT text without invoking Graphviz or writing a file. height_to_width_ratio must be finite and positive, or None for unconstrained natural layout. The default uses natural layout without a fixed ratio. canvas_size=(1920, 900) requests a centred canvas at a constant node and type scale; dimensions are positive integers in pixels at the base 144 DPI.
render_diagram
def render_diagram(
diagram: Diagram,
path: str | Path,
*,
scale: int = 1,
theme: DiagramTheme = DiagramTheme(),
height_to_width_ratio: float | None = None,
canvas_size: tuple[int, int] | None = None,
) -> Path: ...Returns the output Path and creates its parent directories. The suffix selects .svg, .png, .pdf or .dot. DOT writes source directly; other formats invoke the external Graphviz dot executable. PNG rendering uses 144 DPI multiplied by scale; scale must be a positive integer. When canvas_size is supplied, SVG intrinsic dimensions match PNG dimensions; PNG scale multiplies the canvas dimensions. A canvas smaller than the natural layout raises ValueError before export, preventing clipping. A failed Graphviz command raises RuntimeError; a missing executable fails at process launch.
DiagramTheme
class DiagramTheme:
background: str = "#FFFFFF"
ink: str = "#28323C"
muted: str = "#6B7680"
line: str = "#D8DEE3"
neutral: str = "#FAFBFC"
output: str = "#F4F7FA"
modulatory: str = "#92764B"
training: str = "#F4F8F7"
inhibitory: str = "#AA5B63"
signal: str = "#7A8690"
output_line: str = "#58768F"
training_line: str = "#56857D"
title_size: int = 18
label_size: int = 14
secondary_size: int = 11
wrap_columns: int = 26
font_name: str = "Helvetica"This immutable theme defines colours, font sizes, the font family and wrapping. The default uses bold node names and quieter regular detail, with muted red for inhibition, slate blue for outputs and teal for trainable parameters. Frozen training links are grey and dashed. The main forward path receives alignment priority, feedback routes beneath it, and training annotations sit below the last component they describe. It is separate from the Matplotlib Theme. Passing a custom diagram theme changes rendering without changing network or diagram semantics.