snnlab
API referencesnnlab.viz

snnlab.viz.diagrams

Complete declared API of the diagrams module, with signatures, data fields, validation and source.

Back to viz reference

Renderer-neutral structural diagrams. Node ids are unique and all edge/group references must resolve. Graphviz renders the generated DOT; SVG and PNG are supported by render_diagram. Diagram styles and labels do not alter the source graph.

The signatures, defaults, fields, docstrings and implementation excerpts below are generated from the Python source. Annotations are shown as declared; unannotated means the source supplies no type annotation. These pages document callable surfaces, including legacy support utilities, without promising backend support for every declaration.

DiagramTheme

View source

Source docstring:

Shared colours and article-scale typography for structural diagrams.

Class decorators: dataclass(frozen=True).

Dataclass constructor parameters. Factory defaults are shown as field declarations; omit these arguments to create fresh values per instance:

DiagramTheme(background: str = '#FFFFFF', ink: str = '#1A1A1A', muted: str = '#5F5F5F', line: str = '#E7E5DF', neutral: str = '#FFFFFF', output: str = '#FFFFFF', modulatory: str = '#E89400', training: str = '#FFFFFF', inhibitory: str = '#C8102E', signal: str = '#5F5F5F', output_line: str = '#E89400', training_line: str = '#00B4D8', title_size: float = 26, label_size: float = 16, secondary_size: float = 13, wrap_columns: int = 14)

Declared fields, including fields inherited from local data classes:

FieldAnnotationDefaultMeaning
backgroundstr'#FFFFFF'Stored member of this data contract; see the class docstring and serialization methods.
inkstr'#1A1A1A'Stored member of this data contract; see the class docstring and serialization methods.
mutedstr'#5F5F5F'Stored member of this data contract; see the class docstring and serialization methods.
linestr'#E7E5DF'Stored member of this data contract; see the class docstring and serialization methods.
neutralstr'#FFFFFF'Stored member of this data contract; see the class docstring and serialization methods.
outputstr'#FFFFFF'Stored member of this data contract; see the class docstring and serialization methods.
modulatorystr'#E89400'Stored member of this data contract; see the class docstring and serialization methods.
trainingstr'#FFFFFF'Authored training declaration or serialized training recipe.
inhibitorystr'#C8102E'Stored member of this data contract; see the class docstring and serialization methods.
signalstr'#5F5F5F'Stored member of this data contract; see the class docstring and serialization methods.
output_linestr'#E89400'Stored member of this data contract; see the class docstring and serialization methods.
training_linestr'#00B4D8'Stored member of this data contract; see the class docstring and serialization methods.
title_sizefloat26Stored member of this data contract; see the class docstring and serialization methods.
label_sizefloat16Stored member of this data contract; see the class docstring and serialization methods.
secondary_sizefloat13Stored member of this data contract; see the class docstring and serialization methods.
wrap_columnsint14Stored member of this data contract; see the class docstring and serialization methods.
Complete class implementation
class DiagramTheme:
    """Shared colours and article-scale typography for structural diagrams."""

    background: str = "#FFFFFF"
    ink: str = "#1A1A1A"
    muted: str = "#5F5F5F"
    line: str = "#E7E5DF"
    neutral: str = "#FFFFFF"
    output: str = "#FFFFFF"
    modulatory: str = "#E89400"
    training: str = "#FFFFFF"
    inhibitory: str = "#C8102E"
    signal: str = "#5F5F5F"
    output_line: str = "#E89400"
    training_line: str = "#00B4D8"

    title_size: float = 26
    label_size: float = 16
    secondary_size: float = 13
    wrap_columns: int = 14

DiagramNode

View source

Source docstring:

One semantic node, independent of the source graph schema.

Class decorators: dataclass(frozen=True).

Dataclass constructor parameters. Factory defaults are shown as field declarations; omit these arguments to create fresh values per instance:

DiagramNode(id: str, title: str, detail: str, badge: str, kind: str = 'neutral', accent_role: str = 'ink', classes: tuple[str, ...] = (), pen_width: float = 1.4, margin: tuple[float, float] = (0.18, 0.14))

Declared fields, including fields inherited from local data classes:

FieldAnnotationDefaultMeaning
idstrrequiredStable identifier in the relevant graph or data contract.
titlestrrequiredStored member of this data contract; see the class docstring and serialization methods.
detailstrrequiredStored member of this data contract; see the class docstring and serialization methods.
badgestrrequiredStored member of this data contract; see the class docstring and serialization methods.
kindstr'neutral'Stored member of this data contract; see the class docstring and serialization methods.
accent_rolestr'ink'Stored member of this data contract; see the class docstring and serialization methods.
classestuple[str, ...]()Number of output/readout classes.
pen_widthfloat1.4Stored member of this data contract; see the class docstring and serialization methods.
margintuple[float, float](0.18, 0.14)Stored member of this data contract; see the class docstring and serialization methods.
Complete class implementation
class DiagramNode:
    """One semantic node, independent of the source graph schema."""

    id: str
    title: str
    detail: str
    badge: str
    kind: str = "neutral"
    accent_role: str = "ink"
    classes: tuple[str, ...] = ()
    pen_width: float = 1.4
    margin: tuple[float, float] = (0.18, 0.14)

DiagramEdge

View source

Source docstring:

A directed semantic relationship between two diagram nodes.

Class decorators: dataclass(frozen=True).

Dataclass constructor parameters. Factory defaults are shown as field declarations; omit these arguments to create fresh values per instance:

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.7, frozen: bool = False)

Declared fields, including fields inherited from local data classes:

FieldAnnotationDefaultMeaning
sourcestrrequiredStored member of this data contract; see the class docstring and serialization methods.
targetstrrequiredStored member of this data contract; see the class docstring and serialization methods.
rolestr'signal'Stored member of this data contract; see the class docstring and serialization methods.
labelstr''Stored member of this data contract; see the class docstring and serialization methods.
connectionstr'feedforward'Declared connection kind, for example feedforward, recurrent or feedback.
idstr | NoneNoneStable identifier in the relevant graph or data contract.
classestuple[str, ...]()Number of output/readout classes.
constraintboolTrueParameter constraint or Graphviz layout constraint, as annotated.
pen_widthfloat1.7Stored member of this data contract; see the class docstring and serialization methods.
frozenboolFalseWhether this parameter scope is excluded from optimizer updates.
Complete class implementation
class DiagramEdge:
    """A directed semantic relationship between two diagram nodes."""

    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.7
    frozen: bool = False

DiagramGroup

View source

Source docstring:

A labelled visual boundary around existing nodes.

Class decorators: dataclass(frozen=True).

Dataclass constructor parameters. Factory defaults are shown as field declarations; omit these arguments to create fresh values per instance:

DiagramGroup(id: str, label: str, members: tuple[str, ...], same_rank: bool = False, same_row: bool = False)

Declared fields, including fields inherited from local data classes:

FieldAnnotationDefaultMeaning
idstrrequiredStable identifier in the relevant graph or data contract.
labelstrrequiredStored member of this data contract; see the class docstring and serialization methods.
memberstuple[str, ...]requiredStored member of this data contract; see the class docstring and serialization methods.
same_rankboolFalseStored member of this data contract; see the class docstring and serialization methods.
same_rowboolFalseStored member of this data contract; see the class docstring and serialization methods.
Complete class implementation
class DiagramGroup:
    """A labelled visual boundary around existing nodes."""

    id: str
    label: str
    members: tuple[str, ...]
    same_rank: bool = False
    same_row: bool = False

Diagram

View source

Source docstring:

Renderer-neutral structural diagram ready for composition.

Class decorators: dataclass(frozen=True).

Dataclass constructor parameters. Factory defaults are shown as field declarations; omit these arguments to create fresh values per instance:

Diagram(name: str, nodes: tuple[DiagramNode, ...], edges: tuple[DiagramEdge, ...], groups: tuple[DiagramGroup, ...] = (), title: str | None = None, metadata: dict[str, object] = field(default_factory=dict))

Declared fields, including fields inherited from local data classes:

FieldAnnotationDefaultMeaning
namestrrequiredName used to identify the authored or rendered object.
nodestuple[DiagramNode, ...]requiredStored member of this data contract; see the class docstring and serialization methods.
edgestuple[DiagramEdge, ...]requiredStored member of this data contract; see the class docstring and serialization methods.
groupstuple[DiagramGroup, ...]()Stored member of this data contract; see the class docstring and serialization methods.
titlestr | NoneNoneStored member of this data contract; see the class docstring and serialization methods.
metadatadict[str, object]field(default_factory=dict)Stored member of this data contract; see the class docstring and serialization methods.

Constructor/initialization exception expressions:

Explicit exception expression
ValueError('diagram node ids must be unique')
ValueError(f'diagram edge references unknown node: {edge.source} -> {edge.target}')
ValueError('diagram groups cannot request both same_rank and same_row')
ValueError(f'diagram group {group.id} references unknown nodes: ' + ', '.join(sorted(unknown)))
Complete class implementation
class Diagram:
    """Renderer-neutral structural diagram ready for composition."""

    name: str
    nodes: tuple[DiagramNode, ...]
    edges: tuple[DiagramEdge, ...]
    groups: tuple[DiagramGroup, ...] = ()
    title: str | None = None
    metadata: dict[str, object] = field(default_factory=dict)

    def __post_init__(self) -> None:
        ids = [node.id for node in self.nodes]
        if len(ids) != len(set(ids)):
            raise ValueError("diagram node ids must be unique")
        known = set(ids)
        for edge in self.edges:
            if edge.source not in known or edge.target not in known:
                raise ValueError(
                    f"diagram edge references unknown node: {edge.source} -> {edge.target}"
                )
        for group in self.groups:
            if group.same_rank and group.same_row:
                raise ValueError("diagram groups cannot request both same_rank and same_row")
            unknown = set(group.members) - known
            if unknown:
                raise ValueError(
                    f"diagram group {group.id} references unknown nodes: "
                    + ", ".join(sorted(unknown))
                )

diagram_to_dot

View source

def diagram_to_dot(diagram: Diagram, *, theme: DiagramTheme=DiagramTheme(), height_to_width_ratio: float | None=0.58) -> str

Source docstring:

Compile a structured diagram into deterministic Graphviz DOT.
ParameterAnnotationDefaultMeaning
diagramDiagramrequiredDefined by the source contract and implementation below.
themeDiagramThemeDiagramTheme()Defined by the source contract and implementation below.
height_to_width_ratiofloat | None0.58Defined by the source contract and implementation below.

Return annotation: str.

Return expressions (branch-dependent; names refer to the linked implementation):

'\n'.join(lines) + '\n'

Explicit exceptions in this implementation; called helpers may raise additional errors:

Explicit exception expression
ValueError('diagram height-to-width ratio must be finite and positive')
ValueError(f'unknown diagram node kind: {node.kind}')
ValueError(f'unknown diagram edge role: {edge.role}')
Implementation
def diagram_to_dot(
    diagram: Diagram,
    *,
    theme: DiagramTheme = DiagramTheme(),
    height_to_width_ratio: float | None = 0.58,
) -> str:
    """Compile a structured diagram into deterministic Graphviz DOT."""

    if height_to_width_ratio is not None and (
        not math.isfinite(height_to_width_ratio) or height_to_width_ratio <= 0
    ):
        raise ValueError("diagram height-to-width ratio must be finite and positive")
    title = (diagram.title or diagram.name.replace("_", " ")).upper()
    ratio = (
        ""
        if height_to_width_ratio is None
        else f', ratio="{height_to_width_ratio:g}"'
    )
    lines = [
        f"digraph {_q(diagram.name)} {{",
        f'graph [rankdir=LR{ratio}, bgcolor="{theme.background}", pad="0.4", nodesep="0.40", ranksep="0.40",',
        f'  splines=spline, outputorder=edgesfirst, fontname="Menlo", fontcolor="{theme.ink}",',
        f"  label=<<B>{html.escape(title)}</B>>, labelloc=t, labeljust=l, fontsize={theme.title_size:g}, compound=true, newrank=true];",
        f'node [shape=plain, fontname="Menlo", fontcolor="{theme.ink}"];',
        f'edge [fontname="Menlo", fontsize={theme.secondary_size:g}, fontcolor="{theme.ink}", color="{theme.ink}", penwidth=2.0, arrowsize=0.8];',
    ]
    known_kinds = {
        "component",
        "population",
        "output",
        "objective",
        "training",
        "input",
        "operation",
        "neutral",
    }
    for node in diagram.nodes:
        if node.kind not in known_kinds:
            raise ValueError(f"unknown diagram node kind: {node.kind}")
        border = _colour(theme, node.accent_role)
        classes = " ".join(("node", *node.classes))
        margin = f"{node.margin[0]:g},{node.margin[1]:g}"
        lines.append(
            f"{_q(node.id)} [id={_q(_svg_id(node.id))}, class={_q(classes)}, "
            f'label={_card(node, theme)}, shape=box, style="filled", '
            f'fillcolor="{theme.background}", color="{border}", penwidth={node.pen_width:g}, margin="{margin}"];'
        )
    # External sources share the entry column; downstream inputs retain their rank.
    targets = {edge.target for edge in diagram.edges}
    grouped = {member for group in diagram.groups for member in group.members}
    sources = [
        node.id for node in diagram.nodes
        if node.kind == "input" and node.id not in targets and node.id not in grouped
    ]
    if len(sources) > 1:
        lines.append("{ rank=same; " + " ".join(f"{_q(node)};" for node in sources) + " }")
    row_membership = {}
    for group in diagram.groups:
        lines.append(
            f"subgraph {_q('cluster_' + _svg_id(group.id))} {{ label=<<B>{html.escape(group.label.upper())}</B>>; "
            f'color="{theme.line}"; fontcolor="{theme.ink}"; fontname="Menlo"; '
            f'fontsize={theme.label_size:g}; penwidth=1.2; style="solid"; margin=16; labeljust="l";'
        )
        if group.same_rank:
            lines.append("rank=same;")
        lines.extend(f"{_q(member)};" for member in group.members)
        if group.same_row:
            # Invisible ordering edges arrange the row without adding scientific links.
            row_membership.update((member, group.id) for member in group.members)
            for source, target in zip(group.members, group.members[1:]):
                lines.append(
                    f"{_q(source)} -> {_q(target)} "
                    '[style=invis, weight=100, constraint=true];'
                )
        lines.append("}")
    for edge in diagram.edges:
        colour = theme.ink
        arrow = "normal"
        style = "solid"
        if edge.role == "inhibitory":
            colour, arrow = theme.inhibitory, "tee"
        elif edge.role == "modulatory":
            arrow, style = "diamond", "dashed"
        elif edge.role == "signal":
            colour, arrow = theme.signal, "vee"
        elif edge.role == "output":
            colour = theme.output_line
        elif edge.role == "training":
            colour, arrow, style = (
                theme.training_line,
                "none" if edge.frozen else "vee",
                "dotted",
            )
        elif edge.role != "excitatory":
            raise ValueError(f"unknown diagram edge role: {edge.role}")
        if edge.connection == "feedback":
            style = "dashed"
        attributes = []
        if edge.id is not None:
            attributes.append(f"id={_q('e_' + _svg_id(edge.id))}")
        classes = " ".join(("edge", *edge.classes))
        if edge.classes:
            attributes.append(f"class={_q(classes)}")
        internal_row = (
            edge.source in row_membership
            and row_membership.get(edge.target) == row_membership[edge.source]
        )
        attributes.extend(
            [
                f'color="{colour}"',
                f"arrowhead={arrow}",
                f"style={style}",
                (f'label=<<B>{_label(edge.label, theme.wrap_columns)}</B>>' if edge.label else 'label=""'),
                f"constraint={'true' if edge.constraint and not internal_row else 'false'}",
                f"penwidth={edge.pen_width:g}",
            ]
        )
        lines.append(
            f"{_q(edge.source)} -> {_q(edge.target)} [{', '.join(attributes)}];"
        )
    lines.append("}")
    return "\n".join(lines) + "\n"

render_diagram

View source

def render_diagram(diagram: Diagram, path: str | Path, *, scale: int=1, theme: DiagramTheme=DiagramTheme(), height_to_width_ratio: float | None=0.58) -> Path

Source docstring:

Render a diagram as SVG, PNG, PDF, or its deterministic DOT source.
ParameterAnnotationDefaultMeaning
diagramDiagramrequiredDefined by the source contract and implementation below.
pathstr | PathrequiredFilesystem source or destination path, as described below.
scaleint1Defined by the source contract and implementation below.
themeDiagramThemeDiagramTheme()Defined by the source contract and implementation below.
height_to_width_ratiofloat | None0.58Defined by the source contract and implementation below.

Return annotation: Path.

Return expressions (branch-dependent; names refer to the linked implementation):

output

Explicit exceptions in this implementation; called helpers may raise additional errors:

Explicit exception expression
ValueError('diagram scale must be a positive integer')
ValueError('diagram output must be .svg, .png, .pdf, or .dot')
RuntimeError(f'Graphviz failed: {result.stderr.strip()}')
Implementation
def render_diagram(
    diagram: Diagram,
    path: str | Path,
    *,
    scale: int = 1,
    theme: DiagramTheme = DiagramTheme(),
    height_to_width_ratio: float | None = 0.58,
) -> Path:
    """Render a diagram as SVG, PNG, PDF, or its deterministic DOT source."""

    if not isinstance(scale, int) or scale < 1:
        raise ValueError("diagram scale must be a positive integer")
    output = Path(path)
    output.parent.mkdir(parents=True, exist_ok=True)
    dot = diagram_to_dot(
        diagram,
        theme=theme,
        height_to_width_ratio=height_to_width_ratio,
    )
    suffix = output.suffix.lower()
    if suffix not in {".svg", ".png", ".pdf", ".dot"}:
        raise ValueError("diagram output must be .svg, .png, .pdf, or .dot")
    if suffix == ".dot":
        output.write_text(dot)
        return output
    with tempfile.TemporaryDirectory(prefix="snnviz-diagram-") as temporary:
        dot_path = Path(temporary) / "diagram.dot"
        dot_path.write_text(dot)
        args = ["dot", f"-T{suffix[1:]}", str(dot_path), "-o", str(output)]
        if suffix == ".png":
            args.insert(1, f"-Gdpi={144 * scale}")
        result = subprocess.run(args, capture_output=True, text=True)
        if result.returncode:
            raise RuntimeError(f"Graphviz failed: {result.stderr.strip()}")
    return output

On this page