Connections & Paths¶
Connections link entities and surfaces together. The Pathable protocol lets you position anything along any curve.
See also
For connection patterns and anchor techniques, see Connections and Anchors. For parametric positioning, see Paths and Parametric Positioning.
Connection ¶
Connection(start: Connectable, end: Connectable, start_anchor: AnchorSpec = 'center', end_anchor: AnchorSpec = 'center', *, path: Path | None = None, curvature: float | None = None, visible: bool = True, width: float = 1, color: PaintLike = 'black', z_index: int = 0, cap: CapName = 'round', start_cap: CapName | None = None, end_cap: CapName | None = None, opacity: float = 1.0, color_brightness: float | None = None, style: PathStyle | None = None, segments: int = 32)
A connection between two connectable objects (entities or surfaces).
Connections link any connectable objects together with a visible line
by default. Use visible=False for invisible relationships.
Attributes:
| Name | Type | Description |
|---|---|---|
start |
Connectable
|
The starting connectable object |
end |
Connectable
|
The ending connectable object |
start_anchor |
AnchorSpec
|
Name of anchor on start object |
end_anchor |
AnchorSpec
|
Name of anchor on end object |
data |
dict[str, Any]
|
Custom data dictionary |
Example
dot1 = Dot(100, 100)
dot2 = Dot(200, 200)
# Visible straight line (default)
conn = dot1.connect(dot2)
# Styled line
conn = dot1.connect(dot2, width=2, color="red")
# Arc
conn = dot1.connect(dot2, curvature=0.3)
# Custom path
conn = dot1.connect(dot2, path=Path.Wave())
# Cell-to-cell connection
conn = cell_a.connect(cell_b, color="red")
# Entity-to-cell connection
conn = dot.connect(cell, end_anchor="left")
Create a connection between two connectable objects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
Connectable
|
The starting entity or surface. |
required |
end
|
Connectable
|
The ending entity or surface. |
required |
start_anchor
|
AnchorSpec
|
Anchor name on start object. |
'center'
|
end_anchor
|
AnchorSpec
|
Anchor name on end object. |
'center'
|
path
|
Path | None
|
Custom path geometry (e.g. Path.Wave()). For simple arcs
use |
None
|
curvature
|
float | None
|
Arc curvature (-1 to 1). Positive bows left,
negative bows right. Cannot be used with |
None
|
visible
|
bool
|
Whether the connection renders. Default True. |
True
|
width
|
float
|
Line width in pixels. |
1
|
color
|
PaintLike
|
Line color. |
'black'
|
z_index
|
int
|
Layer order (higher = on top). |
0
|
cap
|
CapName
|
Cap style for both ends ("round", "butt", "square"). |
'round'
|
start_cap
|
CapName | None
|
Override cap for start end (e.g. "arrow"). |
None
|
end_cap
|
CapName | None
|
Override cap for end end (e.g. "arrow"). |
None
|
opacity
|
float
|
Opacity (0.0 transparent to 1.0 opaque). |
1.0
|
color_brightness
|
float | None
|
Brightness multiplier 0.0 (black) to 1.0 (unchanged). |
None
|
style
|
PathStyle | None
|
PathStyle object (overrides individual params). |
None
|
segments
|
int
|
Number of Bézier segments for path rendering. |
32
|
point_at ¶
point_at(t: float) -> Coord
Get a point along the connection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
t
|
float
|
Parameter from 0 (start) to 1 (end). |
required |
Returns:
| Type | Description |
|---|---|
Coord
|
Coord at that position along the connection. |
angle_at ¶
Get the tangent angle in degrees at parameter t.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
t
|
float
|
Parameter from 0 (start) to 1 (end). |
required |
Returns:
| Type | Description |
|---|---|
float
|
Angle in degrees. |
Or via the entity/surface shorthand:
Geometry Options¶
| Mode | SVG Output | Notes |
|---|---|---|
| (default) | <line> element |
Straight connection |
curvature=0.3 |
Single cubic Bezier <path> |
Arc; curvature controls bow direction and amount |
path=Path(pathable) |
Fitted Bezier <path> |
Any Pathable -- wave, spiral, custom shape |
visible=False |
Nothing (to_svg() returns "") |
Pure relationship -- point_at(t) still works |
Coordinates are auto-mapped
For curvature=, the arc is built in normalized unit-chord space. For path=, the path geometry is pre-computed. Both are automatically stretched and rotated (affine transform) to connect the actual anchor positions at render time.
The Pathable Protocol¶
The Pathable protocol defines a single required method:
Where t ranges from 0.0 (start) to 1.0 (end). This enables the along/t parametric positioning system used in all builder methods.
Built-in Pathables¶
| Entity | Description |
|---|---|
Line |
Linear interpolation from start to end |
Curve |
Smooth curve with adjustable bow |
Ellipse |
Parametric ellipse (t=0 right, t=0.25 top, t=0.5 left, t=0.75 bottom) |
Path |
Evaluates stored cubic Bezier segments |
Connection |
Dynamic path between entities |
Optional Pathable Methods¶
| Method / Property | Used By | Description |
|---|---|---|
arc_length() |
add_text(along=) |
Total path length for text sizing |
angle_at(t) |
get_angle_at() |
Tangent angle for alignment |
to_svg_path_d() |
add_text(along=) |
SVG path for <textPath> warping |
closed |
to_svg_path_d() |
Whether start and end coincide (closed loop) |
Built-in Path Shapes¶
Ready-to-use pathable classes, accessible as nested classes on Path. All implement point_at(t), angle_at(t), arc_length(), to_svg_path_d(), and the closed property.
Wave ¶
Wave(start: CoordLike = (0, 0), end: CoordLike = (1, 0), amplitude: float = 0.15, frequency: float = 2)
Bases: PathShape
Sinusoidal wave between two points.
Generates a sine oscillation along the Y-axis relative to the
baseline from start to end.
When start and end are omitted, defaults to normalized
(0, 0) -> (1, 0) space — ideal for connection shapes.
Example
Standalone path::
wave = Wave(start=(50, 100), end=(550, 100), amplitude=40, frequency=4)
scene.add_path(wave, width=2, color="blue")
Connection path::
wave = Wave(amplitude=0.15, frequency=3)
conn = dot_a.connect(dot_b, path=Path(wave), style=style)
In a cell::
wave = Wave(start=cell.top_left, end=cell.bottom_right, amplitude=5)
cell.add_path(wave, width=1, color="red")
Spiral ¶
Spiral(center: CoordLike = (0, 0), start_radius: float = 0, end_radius: float = 50, turns: float = 3)
Bases: PathShape
Archimedean spiral expanding outward from center.
The spiral makes turns revolutions while the radius grows
linearly from start_radius to end_radius.
Example
Standalone path::
spiral = Spiral(center=(200, 200), end_radius=80, turns=4)
scene.add_path(spiral, width=1.5, color="coral")
In a cell::
spiral = Spiral(center=cell.center, end_radius=40, turns=3)
cell.add_dot(along=spiral, t=cell.brightness, color="coral")
Closed path with fill::
spiral = Spiral(center=(200, 200), end_radius=60, turns=5)
scene.add_path(spiral, closed=True, fill="lightblue", color="navy")
Lissajous ¶
Lissajous(center: CoordLike = (0, 0), a: int = 3, b: int = 2, delta: float = pi / 2, size: float = 50)
Bases: PathShape
Lissajous curve: x = size * sin(a*t + delta), y = size * sin(b*t).
A closed curve (closed = True) when a/b is rational.
Common ratios:
a=3, b=2— figure-eight varianta=1, b=2— parabola-likea=5, b=4— complex knot
Because this is a closed loop, using it directly as a connection shape
will raise ValueError. Use start_t/end_t to take an arc::
arc = Path(Lissajous(), start_t=0, end_t=0.5)
dot_a.connect(dot_b, path=arc)
Example
Standalone closed path::
liss = Lissajous(center=(200, 200), a=3, b=2, size=80)
scene.add_path(liss, closed=True, fill="lightblue", color="navy")
Connection via arc::
liss = Lissajous(a=3, b=2, size=50)
conn = dot_a.connect(dot_b, path=Path(liss, start_t=0, end_t=0.5))
Position dots along curve::
liss = Lissajous(center=cell.center, size=60)
cell.add_dot(along=liss, t=cell.brightness, color="coral")
Zigzag ¶
Bases: PathShape
Triangle wave (zigzag) between two points.
Generates a zigzag pattern along the Y-axis relative to the
baseline from start to end.
When start and end are omitted, defaults to normalized
(0, 0) -> (1, 0) space — ideal for connection shapes.
Example
Standalone path::
zz = Zigzag(start=(50, 100), end=(550, 100), teeth=8, amplitude=20)
scene.add_path(zz, width=2, color="orange")
Connection path::
zz = Zigzag(teeth=6, amplitude=0.12)
conn = dot_a.connect(dot_b, path=Path(zz), style=style)
# As a standalone path
spiral = Path.Spiral(center=cell.center, end_radius=40, turns=3)
cell.add_path(spiral, width=1.5, color="coral")
# As a connection path (open shapes work directly)
wave = Path.Wave(amplitude=0.15, frequency=3)
conn = dot_a.connect(dot_b, path=Path(wave), style=style)
# Closed shapes need start_t/end_t to create an arc for connections
liss_arc = Path(Path.Lissajous(size=50), start_t=0, end_t=0.5)
conn = dot_a.connect(dot_b, path=liss_arc)
Custom Pathables¶
Any object with point_at(t: float) -> Coord works as a path. See the Pathable Protocol for a full walkthrough of creating custom paths.