Skip to content

geomotif.bases.segments

Base for motifs that are straight lines between a set of points.

Nodes and edges, nothing more. That covers the complete graphs, chord diagrams, modular-arithmetic circles (connect i to k*i mod n, the times-table cardioid) and every form of string art -- all of which are the same motif with a different edge rule.

Classes:

Name Description
SegmentMotif

Base for a motif built from straight segments between indexed points.

SegmentMotif dataclass

SegmentMotif(*, merge: bool = False, show_nodes: bool = False)

Bases: Motif, ABC

Base for a motif built from straight segments between indexed points.

Implement :meth:nodes and :meth:edges; :meth:build turns them into strokes. A ten-line class gets you the whole times-table family::

@register("modular.multiplication", family="graph", example={"modulus": 200})
@dataclass(frozen=True, slots=True)
class ModularMultiplication(SegmentMotif):
    modulus: int = 200
    factor: int = 2

    def nodes(self) -> Sequence[Point]:
        step = math.tau / self.modulus
        return [(math.cos(i * step), math.sin(i * step)) for i in range(self.modulus)]

    def edges(self) -> Iterable[tuple[int, int]]:
        return ((i, self.factor * i % self.modulus) for i in range(self.modulus))
Notes

Edges are undirected: (i, j) and (j, i) are the same segment and the duplicate is dropped, as is any self-loop (i, i). Both are routine outputs of an arithmetic edge rule rather than mistakes, so neither is an error -- but drawing them would waste plotter time on nothing.

Methods:

Name Description
nodes

Return the points the edges are drawn between.

edges

Return index pairs into :meth:nodes, one per segment.

nodes abstractmethod

nodes() -> Sequence[Point]

Return the points the edges are drawn between.

Source code in src/geomotif/bases/segments.py
@abstractmethod
def nodes(self) -> Sequence[Point]:
    """Return the points the edges are drawn between."""

edges abstractmethod

edges() -> Iterable[tuple[int, int]]

Return index pairs into :meth:nodes, one per segment.

Source code in src/geomotif/bases/segments.py
@abstractmethod
def edges(self) -> Iterable[tuple[int, int]]:
    """Return index pairs into :meth:`nodes`, one per segment."""