spacr.flowview.layout

Deterministic layered layout for FlowView directed acyclic graphs.

Classes

GraphLayout

A mapping of node identifiers plus deterministic canvas dimensions.

NodeLayout

Top-left card position and its stable layer/order assignment.

Functions

layout_graph(→ GraphLayout)

Lay out graph left-to-right using longest paths and median sweeps.

Module Contents

class spacr.flowview.layout.GraphLayout[source]

Bases: collections.abc.Mapping[str, NodeLayout]

A mapping of node identifiers plus deterministic canvas dimensions.

Parameters:
  • nodes – node identifiers mapped to their computed card geometries.

  • width – full canvas width, including both outer margins.

  • height – full canvas height, including both outer margins.

__getitem__(node_id: str) → NodeLayout[source]

Return the computed geometry for one node identifier.

Parameters:

node_id – identifier to look up in nodes.

Returns:

stored NodeLayout for node_id.

Raises:

KeyError – if node_id is absent from this layout.

__iter__() → collections.abc.Iterator[str][source]

Iterate over node identifiers in their stored mapping order.

__len__() → int[source]

Return the number of nodes with computed geometry.

class spacr.flowview.layout.NodeLayout[source]

Top-left card position and its stable layer/order assignment.

Parameters:
  • x – horizontal coordinate of the card’s left edge on the canvas.

  • y – vertical coordinate of the card’s top edge on the canvas.

  • width – rendered card width used for edge routing and canvas bounds.

  • height – rendered card height including metrics and any thumbnail.

  • layer – deterministic longest-path column assigned to the node.

  • order – stable top-to-bottom position within that layer.

property centre_y: float[source]

Vertical centre used when routing edges.

spacr.flowview.layout.layout_graph(graph: spacr.flowview.model.RunGraph, *, card_width: float = CARD_WIDTH, column_gap: float = COLUMN_GAP, row_gap: float = ROW_GAP, margin: float = CANVAS_MARGIN, sweeps: int = 4, node_heights: collections.abc.Mapping[str, float] | None = None) → GraphLayout[source]

Lay out graph left-to-right using longest paths and median sweeps.

Inputs are always assigned to layer zero and outputs to the common final layer. All ties are resolved by node identifier, making the result independent of dictionary insertion order and edge-list order.

Parameters:

graph – run snapshot to lay out; every edge must join two of its nodes and the edges must form no directed cycle, otherwise ValueError is raised. An empty graph yields an empty layout of 2 * margin on each side.

Nested helpers

_reorder.key(node_id: str, current_layer: int = layer, current_positions: Mapping[str, int] = old_positions) → tuple[int, float, int, str]

Rank one node for the current median-sweep layer.

Parameters:
  • node_id – node to rank within the layer being reordered.

  • current_layer – loop layer captured when this key is built.

  • current_positions – that layer’s pre-sort positions, captured to preserve deterministic ordering for ties and isolated nodes.

Returns:

connected nodes first by the median position of their cross-layer neighbours, then prior position and identifier; unconnected nodes follow in their prior deterministic order.

spacr/flowview/layout.py:209