Skip to content

SBGN

momapy.sbgn

SBGN (Systems Biology Graphical Notation) subpackage.

Abstract bases live here; concrete classes for each sublanguage are in the pd (Process Description) and af (Activity Flow) subpackages.

Modules:

Name Description
af

SBGN Activity Flow (AF) subpackage facade.

elements

Abstract base classes and mixins for SBGN model and layout elements.

io

Input/output module for SBGN maps.

layout

Abstract base class for SBGN layouts.

map

Abstract base class for SBGN maps.

model

Abstract base class for SBGN models.

pd

SBGN Process Description (PD) subpackage facade.

styling

Styling module for SBGN maps.

utils

Utility functions for SBGN map manipulation.

Classes:

Name Description
SBGNAuxiliaryUnit

Abstract base class for SBGN auxiliary units.

SBGNDoubleHeadedArc

Abstract base class for SBGN double-headed arcs.

SBGNLayout

Base class for SBGN layouts.

SBGNMap

Abstract base class for SBGN maps.

SBGNModel

Abstract base class for SBGN models.

SBGNModelElement

Abstract base class for SBGN model elements.

SBGNNode

Abstract base class for SBGN nodes.

SBGNRole

Abstract base class for SBGN roles.

SBGNSingleHeadedArc

Abstract base class for SBGN single-headed arcs.

SBGNAuxiliaryUnit dataclass

SBGNAuxiliaryUnit(*, id_: str = make_uuid4_as_str())

Bases: SBGNModelElement

Abstract base class for SBGN auxiliary units.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'ca1586d0-8475-44af-b510-1317ae5c311b'

Methods:

Name Description
descendants

Return every ModelElement reachable from self, excluding self.

descendants

descendants() -> list[ModelElement]

Return every ModelElement reachable from self, excluding self.

This reflectively walks the dataclass field-graph (i.e. reference reachability) across scalar ModelElement fields and frozenset/tuple containers, deduplicating by object identity. A model element referenced by several parents therefore appears once.

Note the deliberate contrast with LayoutElement.descendants, which instead walks the explicit children() tree (visual containment): there a layout element contained under two parents is reached through each, with no identity dedup.

Returns:

Type Description
list[ModelElement]

The list of reachable ModelElement instances in visit

list[ModelElement]

order, without self.

Source code in src/momapy/core/elements.py
def descendants(self) -> list["ModelElement"]:
    """Return every `ModelElement` reachable from `self`, excluding `self`.

    This reflectively walks the dataclass field-graph (i.e. *reference
    reachability*) across scalar `ModelElement` fields and
    `frozenset`/`tuple` containers, deduplicating by object identity. A
    model element referenced by several parents therefore appears once.

    Note the deliberate contrast with
    [`LayoutElement.descendants`][momapy.core.elements.LayoutElement.descendants],
    which instead walks the explicit `children()` tree (visual
    *containment*): there a layout element contained under two parents is
    reached through each, with no identity dedup.

    Returns:
        The list of reachable `ModelElement` instances in visit
        order, without `self`.
    """
    seen: set[int] = {id(self)}
    result: list[ModelElement] = []
    if dataclasses.is_dataclass(self):
        for field in dataclasses.fields(type(self)):
            _walk_model_graph(getattr(self, field.name), seen, result)
    return result

SBGNDoubleHeadedArc dataclass

SBGNDoubleHeadedArc(*, id_: str = make_uuid4_as_str(), layout_elements: tuple[LayoutElement, ...] = tuple(), group_fill: NoneValueType | Color | None = None, group_fill_rule: FillRule | None = None, group_filter: NoneValueType | Filter | None = None, group_font_family: str | None = None, group_font_size: float | None = None, group_font_style: FontStyle | None = None, group_font_weight: FontWeight | float | None = None, group_stroke: NoneValueType | Color | None = None, group_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, group_stroke_dashoffset: NoneValueType | float | None = None, group_stroke_width: NoneValueType | float | None = None, group_text_anchor: TextAnchor | None = None, group_transform: NoneValueType | tuple[Transformation, ...] | None = None, end_shorten: float = 0.0, fill: NoneValueType | Color | None = None, filter_: NoneValueType | Filter | None = None, path_fill: NoneValueType | Color | None = NoneValue, path_filter: NoneValueType | Filter | None = None, path_stroke: NoneValueType | Color | None = black, path_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, path_stroke_dashoffset: NoneValueType | float | None = None, path_stroke_width: float | None = 1.25, path_transform: NoneValueType | tuple[Transformation, ...] | None = None, stroke: NoneValueType | Color | None = None, stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, stroke_dashoffset: NoneValueType | float | None = None, stroke_width: NoneValueType | float | None = None, segments: tuple[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc, ...] = tuple(), source: LayoutElement | None = None, start_shorten: float = 0.0, target: LayoutElement | None = None, transform: NoneValueType | tuple[Transformation, ...] | None = None, end_arrowhead_fill: NoneValueType | Color | None = white, end_arrowhead_filter: NoneValueType | Filter | None = None, end_arrowhead_stroke: NoneValueType | Color | None = black, end_arrowhead_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, end_arrowhead_stroke_dashoffset: NoneValueType | float | None = None, end_arrowhead_stroke_width: float | None = 1.25, end_arrowhead_transform: NoneValueType | tuple[Transformation, ...] | None = None, start_arrowhead_fill: NoneValueType | Color | None = white, start_arrowhead_filter: NoneValueType | Filter | None = None, start_arrowhead_stroke: NoneValueType | Color | None = black, start_arrowhead_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, start_arrowhead_stroke_dashoffset: NoneValueType | float | None = None, start_arrowhead_stroke_width: float | None = 1.25, start_arrowhead_transform: NoneValueType | tuple[Transformation, ...] | None = None)

Bases: DoubleHeadedArc

Abstract base class for SBGN double-headed arcs.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'9f61ffce-9ea1-4ca2-8f92-f3e12ff5fdd8'
layout_elements tuple[LayoutElement, ...]

The sub-layout elements of the group layout. These are part of the children of the group layout

<dynamic>
group_fill NoneValueType | Color | None

The fill color of the group layout

None
group_fill_rule FillRule | None

The fill rule of the group layout

None
group_filter NoneValueType | Filter | None

The filter of the group layout

None
group_font_family str | None

The font family of the group layout

None
group_font_size float | None

The font size of the group layout

None
group_font_style FontStyle | None

The font style of the group layout

None
group_font_weight FontWeight | float | None

The font weight of the group layout

None
group_stroke NoneValueType | Color | None

The stroke color of the group layout

None
group_stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the group layout

None
group_stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the group layout

None
group_stroke_width NoneValueType | float | None

The stroke width of the group layout

None
group_text_anchor TextAnchor | None

The text anchor of the group layout

None
group_transform NoneValueType | tuple[Transformation, ...] | None

The transform of the group layout

None
end_shorten float

The length the end of the arc will be shorten by

0.0
fill NoneValueType | Color | None

The fill color of the arc

None
filter_ NoneValueType | Filter | None

The filter of the arc

None
path_fill NoneValueType | Color | None

The path fill color of the arc

<momapy.drawing.NoneValueType object at 0x7fb1b7eb96a0>
path_filter NoneValueType | Filter | None

The path filter of the arc

None
path_stroke NoneValueType | Color | None

The path stroke color of the arc

Color(red=0, green=0, blue=0, alpha=1.0)
path_stroke_dasharray NoneValueType | tuple[float, ...] | None

The path stroke dasharray of the arc

None
path_stroke_dashoffset NoneValueType | float | None

The path stroke dashoffset of the arc

None
path_stroke_width float | None

The path stroke width of the arc

1.25
path_transform NoneValueType | tuple[Transformation, ...] | None

The path transform of the arc

None
stroke NoneValueType | Color | None

The stroke color of the arc

None
stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the arc

None
stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the arc

None
stroke_width NoneValueType | float | None

The stroke width of the arc

None
segments tuple[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc, ...]

The path segments of the arc

<dynamic>
source LayoutElement | None

The source of the arc

None
start_shorten float

The length the start of the arc will be shorten by

0.0
target LayoutElement | None

The target of the arc

None
transform NoneValueType | tuple[Transformation, ...] | None

The transform of the arc

None
end_arrowhead_fill NoneValueType | Color | None

The end arrowhead fill color of the arc

Color(red=255, green=255, blue=255, alpha=1.0)
end_arrowhead_filter NoneValueType | Filter | None

The end arrowhead filter of the arc

None
end_arrowhead_stroke NoneValueType | Color | None

The end arrowhead stroke color of the arc

Color(red=0, green=0, blue=0, alpha=1.0)
end_arrowhead_stroke_dasharray NoneValueType | tuple[float, ...] | None

The end arrowhead stroke dasharray of the arc

None
end_arrowhead_stroke_dashoffset NoneValueType | float | None

The end arrowhead stroke dashoffset of the arc

None
end_arrowhead_stroke_width float | None

The end arrowhead stroke width of the arc

1.25
end_arrowhead_transform NoneValueType | tuple[Transformation, ...] | None

The end arrowhead transform of the arc

None
start_arrowhead_fill NoneValueType | Color | None

The start arrowhead fill color of the arc

Color(red=255, green=255, blue=255, alpha=1.0)
start_arrowhead_filter NoneValueType | Filter | None

The start arrowhead filter of the arc

None
start_arrowhead_stroke NoneValueType | Color | None

The start arrowhead stroke color of the arc

Color(red=0, green=0, blue=0, alpha=1.0)
start_arrowhead_stroke_dasharray NoneValueType | tuple[float, ...] | None

The start arrowhead stroke dasharray of the arc

None
start_arrowhead_stroke_dashoffset NoneValueType | float | None

The start arrowhead stroke dashoffset of the arc

None
start_arrowhead_stroke_width float | None

The start arrowhead stroke width of the arc

1.25
start_arrowhead_transform NoneValueType | tuple[Transformation, ...] | None

The start arrowhead transform of the arc

None

Methods:

Name Description
anchor_point

Return an anchor point of the layout element.

bbox

Compute and return the bounding box of the group layout element.

childless

Return a copy of the arc with no children.

children

Return the children of the group layout.

contains

Return True if another layout element is a descendant of the layout element, False otherwise.

descendants

Return the descendants of the layout element.

drawing_elements

Return the drawing elements of the group layout.

end_arrowhead_base

Return the base anchor point of the double-headed arc end arrowhead.

end_arrowhead_bbox

Return the bounding box of the double-headed arc end arrowhead.

end_arrowhead_border

Return the point at the intersection of the drawing elements of the double-headed arc end arrowhead and the line going through the center of these drawing elements and the given point.

end_arrowhead_drawing_elements

Return the drawing elements of the double-headed arc end arrowhead.

end_arrowhead_length

Return the length of the double-headed arc end arrowhead.

end_arrowhead_tip

Return the tip anchor point of the double-headed arc end arrowhead.

end_point

Return the ending point of the arc.

equals

Return True if the layout element is equal to another layout element, False otherwise.

flattened

Return a list containing copy of the layout element with no children and all its descendants with no children.

fraction

Return the position and angle on the arc at a given fraction (of the total arc length).

length

Return the total length of the arc path.

own_bbox

Compute and return the bounding box of the self drawing element of the group layout.

own_children

Return the self children of the arc.

own_drawing_elements

Return the self drawing elements of the double-headed arc. These include the drawing elements of the arc path, the start arrowhead, and the end arrowhead.

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

path_drawing_elements

Return the drawing elements of the double-headed arc path.

points

Return the points of the arc path.

start_arrowhead_base

Return the base anchor point of the double-headed arc start arrowhead.

start_arrowhead_bbox

Return the bounding box of the double-headed arc start arrowhead.

start_arrowhead_border

Return the point at the intersection of the drawing elements of the double-headed arc start arrowhead and the line going through the center of these drawing elements and the given point.

start_arrowhead_drawing_elements

Return the drawing elements of the double-headed arc start arrowhead.

start_arrowhead_length

Return the length of the double-headed arc start arrowhead.

start_arrowhead_tip

Return the tip anchor point of the double-headed arc start arrowhead.

start_point

Return the starting point of the arc.

to_geometry

Return a list of geometry primitives from the drawing elements.

anchor_point

anchor_point(anchor_name: str) -> Point

Return an anchor point of the layout element.

Source code in src/momapy/core/elements.py
def anchor_point(self, anchor_name: str) -> Point:
    """Return an anchor point of the layout element."""
    return getattr(self, anchor_name)()

bbox

bbox() -> Bbox

Compute and return the bounding box of the group layout element.

Source code in src/momapy/core/layout.py
def bbox(self) -> Bbox:
    """Compute and return the bounding box of the group layout element."""
    own_bbox = self.own_bbox()
    bboxes = [child.bbox() for child in self.children()]
    min_x = own_bbox.north_west().x
    min_y = own_bbox.north_west().y
    max_x = own_bbox.south_east().x
    max_y = own_bbox.south_east().y
    for bbox in bboxes:
        if bbox.north_west().x < min_x:
            min_x = bbox.north_west().x
        if bbox.north_west().y < min_y:
            min_y = bbox.north_west().y
        if bbox.south_east().x > max_x:
            max_x = bbox.south_east().x
        if bbox.south_east().y > max_y:
            max_y = bbox.south_east().y
    bbox = Bbox(
        Point(min_x / 2 + max_x / 2, min_y / 2 + max_y / 2),
        max_x - min_x,
        max_y - min_y,
    )
    return bbox

childless

childless() -> Self

Return a copy of the arc with no children.

Source code in src/momapy/core/layout.py
def childless(self) -> typing_extensions.Self:
    """Return a copy of the arc with no children."""
    return dataclasses.replace(self, layout_elements=tuple([]))

children

children() -> list[LayoutElement]

Return the children of the group layout.

These are the self children of the group layout (returned by the own_children method) and the other children of the group layout (given by the layout_elements attribute).

Source code in src/momapy/core/layout.py
def children(self) -> list[LayoutElement]:
    """Return the children of the group layout.

    These are the self children of the group layout (returned by the `own_children` method) and the other children of the group layout (given by the `layout_elements` attribute).
    """
    return self.own_children() + list(self.layout_elements)

contains

contains(other: LayoutElement) -> bool

Return True if another layout element is a descendant of the layout element, False otherwise.

Source code in src/momapy/core/elements.py
def contains(self, other: "LayoutElement") -> bool:
    """Return `True` if another layout element is a descendant of the layout element, `False` otherwise."""
    return other in self.descendants()

descendants

descendants() -> list[LayoutElement]

Return the descendants of the layout element.

This walks the explicit children() tree (i.e. visual containment) depth-first, returning every layout element in the contained subtree (without self).

Note the deliberate contrast with ModelElement.descendants and Model.descendants, which reflectively walk the dataclass field-graph (i.e. reference reachability) and deduplicate by object identity. A model element referenced by several parents therefore appears once across the model graph, whereas layout descendants are strictly the contained subtree and a layout element contained under two parents is reached through each.

Returns:

Type Description
list[LayoutElement]

The list of descendant layout elements in visit order.

Source code in src/momapy/core/elements.py
def descendants(self) -> list["LayoutElement"]:
    """Return the descendants of the layout element.

    This walks the explicit `children()` tree (i.e. visual
    *containment*) depth-first, returning every layout element in the
    contained subtree (without `self`).

    Note the deliberate contrast with
    [`ModelElement.descendants`][momapy.core.elements.ModelElement.descendants]
    and [`Model.descendants`][momapy.core.model.Model.descendants],
    which reflectively walk the dataclass field-graph (i.e. *reference
    reachability*) and deduplicate by object identity. A model element
    referenced by several parents therefore appears once across the
    model graph, whereas layout descendants are strictly the contained
    subtree and a layout element contained under two parents is reached
    through each.

    Returns:
        The list of descendant layout elements in visit order.
    """
    descendants = []
    for child in self.children():
        descendants.append(child)
        descendants += child.descendants()
    return descendants

drawing_elements

drawing_elements() -> list[DrawingElement]

Return the drawing elements of the group layout.

The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.

Source code in src/momapy/core/layout.py
def drawing_elements(self) -> list[DrawingElement]:
    """Return the drawing elements of the group layout.

    The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.
    """
    drawing_elements = self.own_drawing_elements()
    for child in self.children():
        if child is not None:
            drawing_elements += child.drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}",
        elements=tuple(drawing_elements),
        id_=f"{self.id_}",
        fill=self.group_fill,
        fill_rule=self.group_fill_rule,
        filter_=self.group_filter,
        font_family=self.group_font_family,
        font_size=self.group_font_size,
        font_style=self.group_font_style,
        font_weight=self.group_font_weight,
        stroke=self.group_stroke,
        stroke_dasharray=self.group_stroke_dasharray,
        stroke_dashoffset=self.group_stroke_dashoffset,
        stroke_width=self.group_stroke_width,
        text_anchor=self.group_text_anchor,
        transform=self.group_transform,
    )
    return [group]

end_arrowhead_base

end_arrowhead_base() -> Point

Return the base anchor point of the double-headed arc end arrowhead.

Source code in src/momapy/core/layout.py
def end_arrowhead_base(self) -> Point:
    """Return the base anchor point of the double-headed arc end arrowhead."""
    arrowhead_length = self.end_arrowhead_length()
    if arrowhead_length == 0:
        return self.end_point()
    segment = self.segments[-1]
    segment_length = segment.length()
    if segment_length == 0:
        return self.end_arrowhead_tip() - (arrowhead_length, 0)
    fraction = 1 - (arrowhead_length + self.end_shorten) / segment_length
    return segment.get_position_at_fraction(fraction)

end_arrowhead_bbox

end_arrowhead_bbox() -> Bbox

Return the bounding box of the double-headed arc end arrowhead.

Source code in src/momapy/core/layout.py
def end_arrowhead_bbox(self) -> Bbox:
    """Return the bounding box of the double-headed arc end arrowhead."""
    return get_drawing_elements_bbox(self.end_arrowhead_drawing_elements())

end_arrowhead_border

end_arrowhead_border(point: Point) -> Point

Return the point at the intersection of the drawing elements of the double-headed arc end arrowhead and the line going through the center of these drawing elements and the given point.

When there are multiple intersection points, the one closest to the given point is returned.

Source code in src/momapy/core/layout.py
def end_arrowhead_border(self, point: Point) -> Point:
    """Return the point at the intersection of the drawing elements of the double-headed arc end arrowhead and the line going through the center of these drawing elements and the given point.

    When there are multiple intersection points, the one closest to the given point is returned.
    """
    point = get_drawing_elements_border(
        self.end_arrowhead_drawing_elements(), point
    )
    if point is None:
        return self.end_arrowhead_tip()
    return point

end_arrowhead_drawing_elements

end_arrowhead_drawing_elements() -> list[DrawingElement]

Return the drawing elements of the double-headed arc end arrowhead.

Source code in src/momapy/core/layout.py
def end_arrowhead_drawing_elements(
    self,
) -> list[DrawingElement]:
    """Return the drawing elements of the double-headed arc end arrowhead."""
    drawing_elements = self._end_arrowhead_border_drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}_end_arrowhead",
        elements=tuple(drawing_elements),
        fill=self.end_arrowhead_fill,
        filter_=self.end_arrowhead_filter,
        id_=f"{self.id_}_end_arrowhead",
        stroke=self.end_arrowhead_stroke,
        stroke_width=self.end_arrowhead_stroke_width,
        stroke_dasharray=self.end_arrowhead_stroke_dasharray,
        stroke_dashoffset=self.end_arrowhead_stroke_dashoffset,
        transform=self.end_arrowhead_transform,
    )
    transformation = self._get_end_arrowhead_transformation()
    group = group.transformed(transformation)
    return [group]

end_arrowhead_length

end_arrowhead_length() -> float

Return the length of the double-headed arc end arrowhead.

Source code in src/momapy/core/layout.py
def end_arrowhead_length(self) -> float:
    """Return the length of the double-headed arc end arrowhead."""
    bbox = get_drawing_elements_bbox(self._end_arrowhead_border_drawing_elements())
    if math.isnan(bbox.width):
        return 0.0
    return bbox.east().x

end_arrowhead_tip

end_arrowhead_tip() -> Point

Return the tip anchor point of the double-headed arc end arrowhead.

Source code in src/momapy/core/layout.py
def end_arrowhead_tip(self) -> Point:
    """Return the tip anchor point of the double-headed arc end arrowhead."""
    segment = self.segments[-1]
    segment_length = segment.length()
    if segment_length == 0:
        return segment.p2
    fraction = 1 - self.end_shorten / segment_length
    return segment.get_position_at_fraction(fraction)

end_point

end_point() -> Point

Return the ending point of the arc.

Raises:

Type Description
ValueError

If the arc has no segments.

Source code in src/momapy/core/layout.py
def end_point(self) -> Point:
    """Return the ending point of the arc.

    Raises:
        ValueError: If the arc has no segments.
    """
    if not self.segments:
        raise ValueError("arc has no segments")
    return self.points()[-1]

equals

equals(other: LayoutElement, flattened: bool = False, unordered: bool = False) -> bool

Return True if the layout element is equal to another layout element, False otherwise.

Source code in src/momapy/core/elements.py
def equals(
    self, other: "LayoutElement", flattened: bool = False, unordered: bool = False
) -> bool:
    """Return `True` if the layout element is equal to another layout element, `False` otherwise."""
    if type(self) is type(other):
        if not flattened:
            return self == other
        else:
            if not unordered:
                return self.flattened() == other.flattened()
            else:
                return set(self.flattened()) == set(other.flattened())
    return False

flattened

flattened() -> list[LayoutElement]

Return a list containing copy of the layout element with no children and all its descendants with no children.

Source code in src/momapy/core/elements.py
def flattened(self) -> list["LayoutElement"]:
    """Return a list containing copy of the layout element with no children and all its descendants with no children."""
    flattened = [self.childless()]
    for child in self.children():
        flattened += child.flattened()
    return flattened

fraction

fraction(fraction: float) -> tuple[Point, float]

Return the position and angle on the arc at a given fraction (of the total arc length).

Raises:

Type Description
ValueError

If the arc has no segments.

Source code in src/momapy/core/layout.py
def fraction(self, fraction: float) -> tuple[Point, float]:
    """Return the position and angle on the arc at a given fraction (of the total arc length).

    Raises:
        ValueError: If the arc has no segments.
    """
    if not self.segments:
        raise ValueError("arc has no segments")
    current_length = 0
    length_to_reach = fraction * self.length()
    for segment in self.segments:
        current_length += segment.length()
        if current_length >= length_to_reach:
            break
    segment_start_length = current_length - segment.length()
    segment_fraction = (length_to_reach - segment_start_length) / segment.length()
    position, angle = segment.get_position_and_angle_at_fraction(segment_fraction)
    return position, angle

length

length() -> float

Return the total length of the arc path.

Source code in src/momapy/core/layout.py
def length(self) -> float:
    """Return the total length of the arc path."""
    return sum([segment.length() for segment in self.segments])

own_bbox

own_bbox() -> Bbox

Compute and return the bounding box of the self drawing element of the group layout.

Source code in src/momapy/core/layout.py
def own_bbox(self) -> Bbox:
    """Compute and return the bounding box of the self drawing element of the group layout."""
    primitives = self.own_to_geometry()
    if not primitives:
        return Bbox(Point(0.0, 0.0), 0, 0)
    bboxes = [p.bbox() for p in primitives]
    return Bbox.union(bboxes)

own_children

own_children() -> list[LayoutElement]

Return the self children of the arc.

Source code in src/momapy/core/layout.py
def own_children(self) -> list[LayoutElement]:
    """Return the self children of the arc."""
    return []

own_drawing_elements

own_drawing_elements() -> list[DrawingElement]

Return the self drawing elements of the double-headed arc. These include the drawing elements of the arc path, the start arrowhead, and the end arrowhead.

Source code in src/momapy/core/layout.py
def own_drawing_elements(self) -> list[DrawingElement]:
    """Return the self drawing elements of the double-headed arc. These include the drawing elements of the arc path, the start arrowhead, and the end arrowhead."""
    drawing_elements = (
        self.path_drawing_elements()
        + self.start_arrowhead_drawing_elements()
        + self.end_arrowhead_drawing_elements()
    )

    group = Group(
        class_=f"{type(self).__name__}_own",
        elements=tuple(drawing_elements),
        id_=f"{self.id_}_own",
        fill=self.fill,
        filter_=self.filter_,
        stroke=self.stroke,
        stroke_dasharray=self.stroke_dasharray,
        stroke_dashoffset=self.stroke_dashoffset,
        stroke_width=self.stroke_width,
        transform=self.transform,
    )
    return [group]

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

Source code in src/momapy/core/layout.py
def own_to_geometry(
    self,
) -> list[
    Segment | QuadraticBezierCurve | CubicBezierCurve | GeometryEllipticalArc
]:
    """Return a list of geometry primitives from the self drawing elements."""
    return drawing_elements_to_geometry(self.own_drawing_elements())

path_drawing_elements

path_drawing_elements() -> list[Path]

Return the drawing elements of the double-headed arc path.

Source code in src/momapy/core/layout.py
def path_drawing_elements(self) -> list[Path]:
    """Return the drawing elements of the double-headed arc path."""
    start_arrowhead_length = self.start_arrowhead_length()
    end_arrowhead_length = self.end_arrowhead_length()
    if len(self.segments) == 1:
        segment = (
            self.segments[0]
            .shortened(self.start_shorten + start_arrowhead_length, "start")
            .shortened(self.end_shorten + end_arrowhead_length, "end")
        )
        actions = [
            MoveTo(segment.p1),
            self._make_path_action_from_segment(segment),
        ]
    else:
        first_segment = self.segments[0].shortened(
            self.start_shorten + start_arrowhead_length, "start"
        )
        last_segment = self.segments[-1].shortened(
            self.end_shorten + end_arrowhead_length, "end"
        )
        actions = [
            MoveTo(first_segment.p1),
            self._make_path_action_from_segment(first_segment),
        ]
        for segment in self.segments[1:-1]:
            action = self._make_path_action_from_segment(segment)
            actions.append(action)
        actions.append(self._make_path_action_from_segment(last_segment))
    path = Path(
        actions=tuple(actions),
        class_=f"{type(self).__name__}_path",
        fill=self.path_fill,
        filter_=self.path_filter,
        id_=f"{self.id_}_path",
        stroke=self.path_stroke,
        stroke_dasharray=self.path_stroke_dasharray,
        stroke_dashoffset=self.path_stroke_dashoffset,
        stroke_width=self.path_stroke_width,
        transform=self.path_transform,
    )
    return [path]

points

points() -> list[Point]

Return the points of the arc path.

An arc with no segments has no points and returns an empty list.

Source code in src/momapy/core/layout.py
def points(self) -> list[Point]:
    """Return the points of the arc path.

    An arc with no segments has no points and returns an empty list.
    """
    if not self.segments:
        return []
    points = []
    for segment in self.segments:
        points.append(segment.p1)
    points.append(segment.p2)
    return points

start_arrowhead_base

start_arrowhead_base() -> Point

Return the base anchor point of the double-headed arc start arrowhead.

Source code in src/momapy/core/layout.py
def start_arrowhead_base(self) -> Point:
    """Return the base anchor point of the double-headed arc start arrowhead."""
    arrowhead_length = self.start_arrowhead_length()
    if arrowhead_length == 0:
        return self.start_point()
    segment = self.segments[0]
    segment = Segment(segment.p2, segment.p1)
    segment_length = segment.length()
    if segment_length == 0:
        return self.start_arrowhead_tip() + (arrowhead_length, 0)
    fraction = 1 - (arrowhead_length + self.start_shorten) / segment_length
    return segment.get_position_at_fraction(fraction)

start_arrowhead_bbox

start_arrowhead_bbox() -> Bbox

Return the bounding box of the double-headed arc start arrowhead.

Source code in src/momapy/core/layout.py
def start_arrowhead_bbox(self) -> Bbox:
    """Return the bounding box of the double-headed arc start arrowhead."""
    return get_drawing_elements_bbox(self.start_arrowhead_drawing_elements())

start_arrowhead_border

start_arrowhead_border(point: Point) -> Point

Return the point at the intersection of the drawing elements of the double-headed arc start arrowhead and the line going through the center of these drawing elements and the given point.

When there are multiple intersection points, the one closest to the given point is returned.

Source code in src/momapy/core/layout.py
def start_arrowhead_border(self, point: Point) -> Point:
    """Return the point at the intersection of the drawing elements of the double-headed arc start arrowhead and the line going through the center of these drawing elements and the given point.

    When there are multiple intersection points, the one closest to the given point is returned.
    """
    point = get_drawing_elements_border(
        self.start_arrowhead_drawing_elements(), point
    )
    if point is None:
        return self.start_arrowhead_tip()
    return point

start_arrowhead_drawing_elements

start_arrowhead_drawing_elements() -> list[DrawingElement]

Return the drawing elements of the double-headed arc start arrowhead.

Source code in src/momapy/core/layout.py
def start_arrowhead_drawing_elements(
    self,
) -> list[DrawingElement]:
    """Return the drawing elements of the double-headed arc start arrowhead."""
    drawing_elements = self._start_arrowhead_border_drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}_start_arrowhead",
        elements=tuple(drawing_elements),
        id_=f"{self.id_}_start_arrowhead",
        fill=self.start_arrowhead_fill,
        filter_=self.start_arrowhead_filter,
        stroke=self.start_arrowhead_stroke,
        stroke_dasharray=self.start_arrowhead_stroke_dasharray,
        stroke_dashoffset=self.start_arrowhead_stroke_dashoffset,
        stroke_width=self.start_arrowhead_stroke_width,
        transform=self.start_arrowhead_transform,
    )
    transformation = self._get_start_arrowhead_transformation()
    group = group.transformed(transformation)
    return [group]

start_arrowhead_length

start_arrowhead_length() -> float

Return the length of the double-headed arc start arrowhead.

Source code in src/momapy/core/layout.py
def start_arrowhead_length(self) -> float:
    """Return the length of the double-headed arc start arrowhead."""
    bbox = get_drawing_elements_bbox(
        self._start_arrowhead_border_drawing_elements()
    )
    if math.isnan(bbox.width):
        return 0.0
    return abs(bbox.west().x)

start_arrowhead_tip

start_arrowhead_tip() -> Point

Return the tip anchor point of the double-headed arc start arrowhead.

Source code in src/momapy/core/layout.py
def start_arrowhead_tip(self) -> Point:
    """Return the tip anchor point of the double-headed arc start arrowhead."""
    segment = self.segments[0]
    segment = Segment(segment.p2, segment.p1)
    segment_length = segment.length()
    if segment_length == 0:
        return segment.p2
    fraction = 1 - self.start_shorten / segment_length
    return segment.get_position_at_fraction(fraction)

start_point

start_point() -> Point

Return the starting point of the arc.

Raises:

Type Description
ValueError

If the arc has no segments.

Source code in src/momapy/core/layout.py
def start_point(self) -> Point:
    """Return the starting point of the arc.

    Raises:
        ValueError: If the arc has no segments.
    """
    if not self.segments:
        raise ValueError("arc has no segments")
    return self.points()[0]

to_geometry

Return a list of geometry primitives from the drawing elements.

Source code in src/momapy/core/elements.py
def to_geometry(
    self,
) -> list[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc]:
    """Return a list of geometry primitives from the drawing elements."""
    return drawing_elements_to_geometry(self.drawing_elements())

SBGNLayout dataclass

SBGNLayout(*, id_: str = make_uuid4_as_str(), layout_elements: tuple[LayoutElement, ...] = tuple(), group_fill: NoneValueType | Color | None = None, group_fill_rule: FillRule | None = None, group_filter: NoneValueType | Filter | None = None, group_font_family: str | None = None, group_font_size: float | None = None, group_font_style: FontStyle | None = None, group_font_weight: FontWeight | float | None = None, group_stroke: NoneValueType | Color | None = None, group_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, group_stroke_dashoffset: NoneValueType | float | None = None, group_stroke_width: NoneValueType | float | None = None, group_text_anchor: TextAnchor | None = None, group_transform: NoneValueType | tuple[Transformation, ...] | None = None, fill: NoneValueType | Color | None = white, filter_: NoneValueType | Filter | None = None, height: float, label: TextLayout | None = None, position: Point, stroke: NoneValueType | Color | None = None, stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, stroke_dashoffset: NoneValueType | float | None = None, stroke_width: NoneValueType | float | None = None, transform: NoneValueType | tuple[Transformation, ...] | None = None, width: float)

Bases: Layout

Base class for SBGN layouts.

SBGN layouts define the visual representation of SBGN models, including the positions and styles of glyphs.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'8ccd4512-a554-429e-b2a2-8ea3c066be05'
layout_elements tuple[LayoutElement, ...]

The sub-layout elements of the group layout. These are part of the children of the group layout

<dynamic>
group_fill NoneValueType | Color | None

The fill color of the group layout

None
group_fill_rule FillRule | None

The fill rule of the group layout

None
group_filter NoneValueType | Filter | None

The filter of the group layout

None
group_font_family str | None

The font family of the group layout

None
group_font_size float | None

The font size of the group layout

None
group_font_style FontStyle | None

The font style of the group layout

None
group_font_weight FontWeight | float | None

The font weight of the group layout

None
group_stroke NoneValueType | Color | None

The stroke color of the group layout

None
group_stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the group layout

None
group_stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the group layout

None
group_stroke_width NoneValueType | float | None

The stroke width of the group layout

None
group_text_anchor TextAnchor | None

The text anchor of the group layout

None
group_transform NoneValueType | tuple[Transformation, ...] | None

The transform of the group layout

None
fill NoneValueType | Color | None

The fill color of the node

Color(red=255, green=255, blue=255, alpha=1.0)
filter_ NoneValueType | Filter | None

The filter of the node

None
height float

The height of the node

required
label TextLayout | None

The label of the node

None
position Point

The position of the node

required
stroke NoneValueType | Color | None

The stroke color of the node

None
stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the node

None
stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the node

None
stroke_width NoneValueType | float | None

The stroke width of the node

None
transform NoneValueType | tuple[Transformation, ...] | None

The transform of the node

None
width float

The width of the node

required

Methods:

Name Description
anchor_point

Return an anchor point of the layout element.

angle

Return the point on the border of the node that intersects the drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

bbox

Compute and return the bounding box of the group layout element.

border

Return the point on the border of the node that intersects the drawing elements of the node with the line formed of the center anchor point of the node and the given point.

center

Return the center anchor of the node.

childless

Return a copy of the node with no children.

children

Return the children of the group layout.

contains

Return True if another layout element is a descendant of the layout element, False otherwise.

descendants

Return the descendants of the layout element.

drawing_elements

Return the drawing elements of the group layout.

east

Return the east anchor of the node.

east_north_east

Return the east north east anchor of the node.

east_south_east

Return the east south east anchor of the node.

equals

Return True if the layout element is equal to another layout element, False otherwise.

flattened

Return a list containing copy of the layout element with no children and all its descendants with no children.

is_sublayout

Return True if the layout is a sublayout of another given layout, False otherwise.

label_center

Return the label center anchor of the node.

north

Return the north anchor of the node.

north_east

Return the north east anchor of the node.

north_north_east

Return the north north east anchor of the node.

north_north_west

Return the north north west anchor of the node.

north_west

Return the north west anchor of the node.

own_angle

Return the point on the border of the node that intersects the self drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

own_bbox

Compute and return the bounding box of the self drawing element of the group layout.

own_border

Return the point on the border of the node that intersects the self drawing elements of the node with the line formed of the center anchor point of the node and the given point.

own_children

Return the self children of the node. A node has unique child that is its label.

own_drawing_elements

Return the node's own drawing elements.

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

size

Return the size of the node.

south

Return the south anchor of the node.

south_east

Return the south east anchor of the node.

south_south_east

Return the south south east anchor of the node.

south_south_west

Return the south south west anchor of the node.

south_west

Return the south west anchor of the node.

to_geometry

Return a list of geometry primitives from the drawing elements.

west

Return the west anchor of the node.

west_north_west

Return the west north west anchor of the node.

west_south_west

Return the west south west anchor of the node.

Attributes:

Name Type Description
x float

Return the x coordinate of the node.

y float

Return the y coordinate of the node.

anchor_point

anchor_point(anchor_name: str) -> Point

Return an anchor point of the layout element.

Source code in src/momapy/core/elements.py
def anchor_point(self, anchor_name: str) -> Point:
    """Return an anchor point of the layout element."""
    return getattr(self, anchor_name)()

angle

angle(angle: float, unit: Literal['degrees', 'radians'] = 'degrees') -> Point | None

Return the point on the border of the node that intersects the drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

Source code in src/momapy/core/layout.py
def angle(
    self,
    angle: float,
    unit: typing.Literal["degrees", "radians"] = "degrees",
) -> Point | None:
    """Return the point on the border of the node that intersects the drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal."""
    return get_drawing_elements_angle(
        drawing_elements=self.drawing_elements(),
        angle=angle,
        unit=unit,
        center=self.center(),
    )

bbox

bbox() -> Bbox

Compute and return the bounding box of the group layout element.

Source code in src/momapy/core/layout.py
def bbox(self) -> Bbox:
    """Compute and return the bounding box of the group layout element."""
    own_bbox = self.own_bbox()
    bboxes = [child.bbox() for child in self.children()]
    min_x = own_bbox.north_west().x
    min_y = own_bbox.north_west().y
    max_x = own_bbox.south_east().x
    max_y = own_bbox.south_east().y
    for bbox in bboxes:
        if bbox.north_west().x < min_x:
            min_x = bbox.north_west().x
        if bbox.north_west().y < min_y:
            min_y = bbox.north_west().y
        if bbox.south_east().x > max_x:
            max_x = bbox.south_east().x
        if bbox.south_east().y > max_y:
            max_y = bbox.south_east().y
    bbox = Bbox(
        Point(min_x / 2 + max_x / 2, min_y / 2 + max_y / 2),
        max_x - min_x,
        max_y - min_y,
    )
    return bbox

border

border(point: Point) -> Point | None

Return the point on the border of the node that intersects the drawing elements of the node with the line formed of the center anchor point of the node and the given point.

When there are multiple intersection points, the one closest to the given point is returned.

Source code in src/momapy/core/layout.py
def border(self, point: Point) -> Point | None:
    """Return the point on the border of the node that intersects the drawing elements of the node with the line formed of the center anchor point of the node and the given point.

    When there are multiple intersection points, the one closest to the given point is returned.
    """
    return get_drawing_elements_border(
        drawing_elements=self.drawing_elements(),
        point=point,
        center=self.center(),
    )

center

center() -> Point

Return the center anchor of the node.

Source code in src/momapy/core/layout.py
def center(self) -> Point:
    """Return the center anchor of the node."""
    return self.position

childless

childless() -> Self

Return a copy of the node with no children.

Source code in src/momapy/core/layout.py
def childless(self) -> typing_extensions.Self:
    """Return a copy of the node with no children."""
    return dataclasses.replace(self, label=None, layout_elements=tuple([]))

children

children() -> list[LayoutElement]

Return the children of the group layout.

These are the self children of the group layout (returned by the own_children method) and the other children of the group layout (given by the layout_elements attribute).

Source code in src/momapy/core/layout.py
def children(self) -> list[LayoutElement]:
    """Return the children of the group layout.

    These are the self children of the group layout (returned by the `own_children` method) and the other children of the group layout (given by the `layout_elements` attribute).
    """
    return self.own_children() + list(self.layout_elements)

contains

contains(other: LayoutElement) -> bool

Return True if another layout element is a descendant of the layout element, False otherwise.

Source code in src/momapy/core/elements.py
def contains(self, other: "LayoutElement") -> bool:
    """Return `True` if another layout element is a descendant of the layout element, `False` otherwise."""
    return other in self.descendants()

descendants

descendants() -> list[LayoutElement]

Return the descendants of the layout element.

This walks the explicit children() tree (i.e. visual containment) depth-first, returning every layout element in the contained subtree (without self).

Note the deliberate contrast with ModelElement.descendants and Model.descendants, which reflectively walk the dataclass field-graph (i.e. reference reachability) and deduplicate by object identity. A model element referenced by several parents therefore appears once across the model graph, whereas layout descendants are strictly the contained subtree and a layout element contained under two parents is reached through each.

Returns:

Type Description
list[LayoutElement]

The list of descendant layout elements in visit order.

Source code in src/momapy/core/elements.py
def descendants(self) -> list["LayoutElement"]:
    """Return the descendants of the layout element.

    This walks the explicit `children()` tree (i.e. visual
    *containment*) depth-first, returning every layout element in the
    contained subtree (without `self`).

    Note the deliberate contrast with
    [`ModelElement.descendants`][momapy.core.elements.ModelElement.descendants]
    and [`Model.descendants`][momapy.core.model.Model.descendants],
    which reflectively walk the dataclass field-graph (i.e. *reference
    reachability*) and deduplicate by object identity. A model element
    referenced by several parents therefore appears once across the
    model graph, whereas layout descendants are strictly the contained
    subtree and a layout element contained under two parents is reached
    through each.

    Returns:
        The list of descendant layout elements in visit order.
    """
    descendants = []
    for child in self.children():
        descendants.append(child)
        descendants += child.descendants()
    return descendants

drawing_elements

drawing_elements() -> list[DrawingElement]

Return the drawing elements of the group layout.

The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.

Source code in src/momapy/core/layout.py
def drawing_elements(self) -> list[DrawingElement]:
    """Return the drawing elements of the group layout.

    The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.
    """
    drawing_elements = self.own_drawing_elements()
    for child in self.children():
        if child is not None:
            drawing_elements += child.drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}",
        elements=tuple(drawing_elements),
        id_=f"{self.id_}",
        fill=self.group_fill,
        fill_rule=self.group_fill_rule,
        filter_=self.group_filter,
        font_family=self.group_font_family,
        font_size=self.group_font_size,
        font_style=self.group_font_style,
        font_weight=self.group_font_weight,
        stroke=self.group_stroke,
        stroke_dasharray=self.group_stroke_dasharray,
        stroke_dashoffset=self.group_stroke_dashoffset,
        stroke_width=self.group_stroke_width,
        text_anchor=self.group_text_anchor,
        transform=self.group_transform,
    )
    return [group]

east

east() -> Point

Return the east anchor of the node.

Source code in src/momapy/core/layout.py
def east(self) -> Point:
    """Return the east anchor of the node."""
    return self.own_angle(0)

east_north_east

east_north_east() -> Point

Return the east north east anchor of the node.

Source code in src/momapy/core/layout.py
def east_north_east(self) -> Point:
    """Return the east north east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, -self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

east_south_east

east_south_east() -> Point

Return the east south east anchor of the node.

Source code in src/momapy/core/layout.py
def east_south_east(self) -> Point:
    """Return the east south east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

equals

equals(other: LayoutElement, flattened: bool = False, unordered: bool = False) -> bool

Return True if the layout element is equal to another layout element, False otherwise.

Source code in src/momapy/core/elements.py
def equals(
    self, other: "LayoutElement", flattened: bool = False, unordered: bool = False
) -> bool:
    """Return `True` if the layout element is equal to another layout element, `False` otherwise."""
    if type(self) is type(other):
        if not flattened:
            return self == other
        else:
            if not unordered:
                return self.flattened() == other.flattened()
            else:
                return set(self.flattened()) == set(other.flattened())
    return False

flattened

flattened() -> list[LayoutElement]

Return a list containing copy of the layout element with no children and all its descendants with no children.

Source code in src/momapy/core/elements.py
def flattened(self) -> list["LayoutElement"]:
    """Return a list containing copy of the layout element with no children and all its descendants with no children."""
    flattened = [self.childless()]
    for child in self.children():
        flattened += child.flattened()
    return flattened

is_sublayout

is_sublayout(other: Layout, flattened: bool = False, unordered: bool = False) -> bool

Return True if the layout is a sublayout of another given layout, False otherwise.

Source code in src/momapy/core/layout.py
def is_sublayout(
    self, other: "Layout", flattened: bool = False, unordered: bool = False
) -> bool:
    """Return `True` if the layout is a sublayout of another given layout, `False` otherwise."""

    def _is_sublist(
        list1: list[LayoutElement],
        list2: list[LayoutElement],
        unordered: bool = False,
    ) -> bool:
        if not unordered:
            i = 0
            for elem1 in list1:
                elem2 = list2[i]
                while elem2 != elem1 and i < len(list2) - 1:
                    i += 1
                    elem2 = list2[i]
                if not elem2 == elem1:
                    return False
                i += 1
        else:
            dlist1 = collections.defaultdict(int)
            dlist2 = collections.defaultdict(int)
            for elem1 in list1:
                dlist1[elem1] += 1
            for elem2 in list2:
                dlist2[elem2] += 1
            for elem in dlist1:
                if dlist1[elem] > dlist2[elem]:
                    return False
        return True

    if self.childless() != other.childless():
        return False
    if flattened:
        return _is_sublist(
            self.flattened()[1:],
            other.flattened()[1:],
            unordered=unordered,
        )
    return _is_sublist(self.children(), other.children(), unordered=unordered)

label_center

label_center() -> Point

Return the label center anchor of the node.

Source code in src/momapy/core/layout.py
def label_center(self) -> Point:
    """Return the label center anchor of the node."""
    return self.position

north

north() -> Point

Return the north anchor of the node.

Source code in src/momapy/core/layout.py
def north(self) -> Point:
    """Return the north anchor of the node."""
    return self.own_angle(90)

north_east

north_east() -> Point

Return the north east anchor of the node.

Source code in src/momapy/core/layout.py
def north_east(self) -> Point:
    """Return the north east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, -self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

north_north_east

north_north_east() -> Point

Return the north north east anchor of the node.

Source code in src/momapy/core/layout.py
def north_north_east(self) -> Point:
    """Return the north north east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 4, -self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

north_north_west

north_north_west() -> Point

Return the north north west anchor of the node.

Source code in src/momapy/core/layout.py
def north_north_west(self) -> Point:
    """Return the north north west anchor of the node."""
    line = Line(self.center(), self.center() - (self.width / 4, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

north_west

north_west() -> Point

Return the north west anchor of the node.

Source code in src/momapy/core/layout.py
def north_west(self) -> Point:
    """Return the north west anchor of the node."""
    line = Line(self.center(), self.center() - (self.width / 2, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

own_angle

own_angle(angle: float, unit: Literal['degrees', 'radians'] = 'degrees') -> Point | None

Return the point on the border of the node that intersects the self drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

Source code in src/momapy/core/layout.py
def own_angle(
    self,
    angle: float,
    unit: typing.Literal["degrees", "radians"] = "degrees",
) -> Point | None:
    """Return the point on the border of the node that intersects the self drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal."""
    return get_drawing_elements_angle(
        drawing_elements=self.own_drawing_elements(),
        angle=angle,
        unit=unit,
        center=self.center(),
    )

own_bbox

own_bbox() -> Bbox

Compute and return the bounding box of the self drawing element of the group layout.

Source code in src/momapy/core/layout.py
def own_bbox(self) -> Bbox:
    """Compute and return the bounding box of the self drawing element of the group layout."""
    primitives = self.own_to_geometry()
    if not primitives:
        return Bbox(Point(0.0, 0.0), 0, 0)
    bboxes = [p.bbox() for p in primitives]
    return Bbox.union(bboxes)

own_border

own_border(point: Point) -> Point | None

Return the point on the border of the node that intersects the self drawing elements of the node with the line formed of the center anchor point of the node and the given point.

When there are multiple intersection points, the one closest to the given point is returned.

Source code in src/momapy/core/layout.py
def own_border(self, point: Point) -> Point | None:
    """Return the point on the border of the node that intersects the self drawing elements of the node with the line formed of the center anchor point of the node and the given point.

    When there are multiple intersection points, the one closest to the given point is returned.
    """
    return get_drawing_elements_border(
        drawing_elements=self.own_drawing_elements(),
        point=point,
        center=self.center(),
    )

own_children

own_children() -> list[LayoutElement]

Return the self children of the node. A node has unique child that is its label.

Source code in src/momapy/core/layout.py
def own_children(self) -> list[LayoutElement]:
    """Return the self children of the node. A node has unique child that is its label."""
    if self.label is not None:
        return [self.label]
    return []

own_drawing_elements

own_drawing_elements() -> list[DrawingElement]

Return the node's own drawing elements.

Source code in src/momapy/core/layout.py
def own_drawing_elements(self) -> list[DrawingElement]:
    """Return the node's own drawing elements."""
    drawing_elements = self._border_drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}_own",
        elements=tuple(drawing_elements),
        fill=self.fill,
        filter_=self.filter_,
        id_=f"{self.id_}_own",
        stroke=self.stroke,
        stroke_dasharray=self.stroke_dasharray,
        stroke_dashoffset=self.stroke_dashoffset,
        stroke_width=self.stroke_width,
        transform=self.transform,
    )
    return [group]

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

Source code in src/momapy/core/layout.py
def own_to_geometry(
    self,
) -> list[
    Segment | QuadraticBezierCurve | CubicBezierCurve | GeometryEllipticalArc
]:
    """Return a list of geometry primitives from the self drawing elements."""
    return drawing_elements_to_geometry(self.own_drawing_elements())

size

size() -> tuple[float, float]

Return the size of the node.

Source code in src/momapy/core/layout.py
def size(self) -> tuple[float, float]:
    """Return the size of the node."""
    return (self.width, self.height)

south

south() -> Point

Return the south anchor of the node.

Source code in src/momapy/core/layout.py
def south(self) -> Point:
    """Return the south anchor of the node."""
    return self.own_angle(270)

south_east

south_east() -> Point

Return the south east anchor of the node.

Source code in src/momapy/core/layout.py
def south_east(self) -> Point:
    """Return the south east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

south_south_east

south_south_east() -> Point

Return the south south east anchor of the node.

Source code in src/momapy/core/layout.py
def south_south_east(self) -> Point:
    """Return the south south east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 4, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

south_south_west

south_south_west() -> Point

Return the south south west anchor of the node.

Source code in src/momapy/core/layout.py
def south_south_west(self) -> Point:
    """Return the south south west anchor of the node."""
    line = Line(self.center(), self.center() + (-self.width / 4, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

south_west

south_west() -> Point

Return the south west anchor of the node.

Source code in src/momapy/core/layout.py
def south_west(self) -> Point:
    """Return the south west anchor of the node."""
    line = Line(self.center(), self.center() + (-self.width / 2, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

to_geometry

Return a list of geometry primitives from the drawing elements.

Source code in src/momapy/core/elements.py
def to_geometry(
    self,
) -> list[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc]:
    """Return a list of geometry primitives from the drawing elements."""
    return drawing_elements_to_geometry(self.drawing_elements())

west

west() -> Point

Return the west anchor of the node.

Source code in src/momapy/core/layout.py
def west(self) -> Point:
    """Return the west anchor of the node."""
    return self.own_angle(180)

west_north_west

west_north_west() -> Point

Return the west north west anchor of the node.

Source code in src/momapy/core/layout.py
def west_north_west(self) -> Point:
    """Return the west north west anchor of the node."""
    line = Line(self.center(), self.center() - (self.width / 2, self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

west_south_west

west_south_west() -> Point

Return the west south west anchor of the node.

Source code in src/momapy/core/layout.py
def west_south_west(self) -> Point:
    """Return the west south west anchor of the node."""
    line = Line(self.center(), self.center() + (-self.width / 2, self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

x property

x: float

Return the x coordinate of the node.

y property

y: float

Return the y coordinate of the node.

SBGNMap dataclass

SBGNMap(*, id_: str = make_uuid4_as_str(), model: SBGNModel | None = None, layout: SBGNLayout | None = None, layout_model_mapping: LayoutModelMapping | None = None)

Bases: Map

Abstract base class for SBGN maps.

SBGN maps combine a model and its visual layout into a complete diagram representation.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'5b61ad97-5448-4e41-8ab2-76556fb65eba'
model SBGNModel | None

The model of the map

None
layout SBGNLayout | None

The layout of the map

None
layout_model_mapping LayoutModelMapping | None

The layout model mapping of the map

None

Methods:

Name Description
get_mapping

Return the model element or layout elements mapped to map_element.

is_submap

Return True if the Map is a submap of another given map, False otherwise.

get_mapping

get_mapping(map_element: MapElement) -> ModelElement | list[LayoutElement | frozenset[LayoutElement]] | None

Return the model element or layout elements mapped to map_element.

The lookup is bidirectional: a layout key (a singleton or frozenset) resolves to its model element, and a model element resolves to the list of layout keys mapped to it. Forwards to layout_model_mapping.get_mapping.

Returns None when the map has no layout_model_mapping (for example a layout-less map such as one read from SBML).

Source code in src/momapy/core/map.py
def get_mapping(
    self,
    map_element: "MapElement",
) -> "ModelElement | list[LayoutElement | frozenset[LayoutElement]] | None":
    """Return the model element or layout elements mapped to `map_element`.

    The lookup is bidirectional: a layout key (a singleton or frozenset)
    resolves to its model element, and a model element resolves to the
    list of layout keys mapped to it. Forwards to
    `layout_model_mapping.get_mapping`.

    Returns `None` when the map has no `layout_model_mapping` (for
    example a layout-less map such as one read from SBML).
    """
    if self.layout_model_mapping is None:
        return None
    return self.layout_model_mapping.get_mapping(map_element)

is_submap

is_submap(other: Map) -> bool

Return True if the Map is a submap of another given map, False otherwise.

A complete map is never a submap of an incomplete one: if either self or other has a None model, layout, or layout-model mapping, this returns False.

Source code in src/momapy/core/map.py
def is_submap(self, other: "Map") -> bool:
    """Return `True` if the `Map` is a submap of another given map, `False` otherwise.

    A complete map is never a submap of an incomplete one: if either `self`
    or `other` has a `None` model, layout, or layout-model mapping, this
    returns `False`.
    """
    if (
        self.model is None
        or self.layout is None
        or self.layout_model_mapping is None
        or other.model is None
        or other.layout is None
        or other.layout_model_mapping is None
    ):
        return False
    return (
        self.model.is_submodel(other.model)
        and self.layout.is_sublayout(other.layout)
        and self.layout_model_mapping.is_submapping(other.layout_model_mapping)
    )

SBGNModel dataclass

SBGNModel(*, id_: str = make_uuid4_as_str())

Bases: Model

Abstract base class for SBGN models.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'667520f3-11b4-472b-8eda-feed44da5aeb'

Methods:

Name Description
descendants

Return every ModelElement reachable from this Model.

is_submodel

Return whether this model is a submodel of another model.

descendants

descendants() -> list[ModelElement]

Return every ModelElement reachable from this Model.

This reflectively walks the dataclass field-graph (i.e. reference reachability) across scalar ModelElement fields and frozenset/tuple containers of the Model, deduplicating by object identity. The Model itself is not a ModelElement and is not included.

This mirrors ModelElement.descendants and contrasts with LayoutElement.descendants, which walks the explicit children() tree (visual containment) rather than reference reachability.

Returns:

Type Description
list[ModelElement]

The list of reachable ModelElement instances in visit

list[ModelElement]

order.

Source code in src/momapy/core/model.py
def descendants(self) -> list[ModelElement]:
    """Return every `ModelElement` reachable from this `Model`.

    This reflectively walks the dataclass field-graph (i.e. *reference
    reachability*) across scalar `ModelElement` fields and
    `frozenset`/`tuple` containers of the `Model`, deduplicating by
    object identity. The `Model` itself is not a `ModelElement` and is
    not included.

    This mirrors
    [`ModelElement.descendants`][momapy.core.elements.ModelElement.descendants]
    and contrasts with
    [`LayoutElement.descendants`][momapy.core.elements.LayoutElement.descendants],
    which walks the explicit `children()` tree (visual *containment*)
    rather than reference reachability.

    Returns:
        The list of reachable `ModelElement` instances in visit
        order.
    """
    seen: set[int] = set()
    result: list[ModelElement] = []
    for field in dataclasses.fields(type(self)):
        _walk_model_graph(getattr(self, field.name), seen, result)
    return result

is_submodel abstractmethod

is_submodel(other: Model) -> bool

Return whether this model is a submodel of another model.

Parameters:

Name Type Description Default
other Model

The model to test against.

required

Returns:

Type Description
bool

True if this model is a submodel of other.

Source code in src/momapy/core/model.py
@abc.abstractmethod
def is_submodel(self, other: "Model") -> bool:
    """Return whether this model is a submodel of another model.

    Args:
        other: The model to test against.

    Returns:
        `True` if this model is a submodel of `other`.
    """
    pass

SBGNModelElement dataclass

SBGNModelElement(*, id_: str = make_uuid4_as_str())

Bases: ModelElement

Abstract base class for SBGN model elements.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'2ac09973-bd0a-4feb-9c58-c6b8b90e28b6'

Methods:

Name Description
descendants

Return every ModelElement reachable from self, excluding self.

descendants

descendants() -> list[ModelElement]

Return every ModelElement reachable from self, excluding self.

This reflectively walks the dataclass field-graph (i.e. reference reachability) across scalar ModelElement fields and frozenset/tuple containers, deduplicating by object identity. A model element referenced by several parents therefore appears once.

Note the deliberate contrast with LayoutElement.descendants, which instead walks the explicit children() tree (visual containment): there a layout element contained under two parents is reached through each, with no identity dedup.

Returns:

Type Description
list[ModelElement]

The list of reachable ModelElement instances in visit

list[ModelElement]

order, without self.

Source code in src/momapy/core/elements.py
def descendants(self) -> list["ModelElement"]:
    """Return every `ModelElement` reachable from `self`, excluding `self`.

    This reflectively walks the dataclass field-graph (i.e. *reference
    reachability*) across scalar `ModelElement` fields and
    `frozenset`/`tuple` containers, deduplicating by object identity. A
    model element referenced by several parents therefore appears once.

    Note the deliberate contrast with
    [`LayoutElement.descendants`][momapy.core.elements.LayoutElement.descendants],
    which instead walks the explicit `children()` tree (visual
    *containment*): there a layout element contained under two parents is
    reached through each, with no identity dedup.

    Returns:
        The list of reachable `ModelElement` instances in visit
        order, without `self`.
    """
    seen: set[int] = {id(self)}
    result: list[ModelElement] = []
    if dataclasses.is_dataclass(self):
        for field in dataclasses.fields(type(self)):
            _walk_model_graph(getattr(self, field.name), seen, result)
    return result

SBGNNode dataclass

SBGNNode(*, id_: str = make_uuid4_as_str(), layout_elements: tuple[LayoutElement, ...] = tuple(), group_fill: NoneValueType | Color | None = None, group_fill_rule: FillRule | None = None, group_filter: NoneValueType | Filter | None = None, group_font_family: str | None = None, group_font_size: float | None = None, group_font_style: FontStyle | None = None, group_font_weight: FontWeight | float | None = None, group_stroke: NoneValueType | Color | None = None, group_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, group_stroke_dashoffset: NoneValueType | float | None = None, group_stroke_width: NoneValueType | float | None = None, group_text_anchor: TextAnchor | None = None, group_transform: NoneValueType | tuple[Transformation, ...] | None = None, fill: NoneValueType | Color | None = white, filter_: NoneValueType | Filter | None = None, height: float, label: TextLayout | None = None, position: Point, stroke: NoneValueType | Color | None = black, stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, stroke_dashoffset: NoneValueType | float | None = None, stroke_width: float | None = 1.25, transform: NoneValueType | tuple[Transformation, ...] | None = None, width: float)

Bases: Node

Abstract base class for SBGN nodes.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'e7f2edc3-a4b8-425b-9a50-5be6d3910b12'
layout_elements tuple[LayoutElement, ...]

The sub-layout elements of the group layout. These are part of the children of the group layout

<dynamic>
group_fill NoneValueType | Color | None

The fill color of the group layout

None
group_fill_rule FillRule | None

The fill rule of the group layout

None
group_filter NoneValueType | Filter | None

The filter of the group layout

None
group_font_family str | None

The font family of the group layout

None
group_font_size float | None

The font size of the group layout

None
group_font_style FontStyle | None

The font style of the group layout

None
group_font_weight FontWeight | float | None

The font weight of the group layout

None
group_stroke NoneValueType | Color | None

The stroke color of the group layout

None
group_stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the group layout

None
group_stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the group layout

None
group_stroke_width NoneValueType | float | None

The stroke width of the group layout

None
group_text_anchor TextAnchor | None

The text anchor of the group layout

None
group_transform NoneValueType | tuple[Transformation, ...] | None

The transform of the group layout

None
fill NoneValueType | Color | None

The fill color of the node

Color(red=255, green=255, blue=255, alpha=1.0)
filter_ NoneValueType | Filter | None

The filter of the node

None
height float

The height of the node

required
label TextLayout | None

The label of the node

None
position Point

The position of the node

required
stroke NoneValueType | Color | None

The stroke color of the node

Color(red=0, green=0, blue=0, alpha=1.0)
stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the node

None
stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the node

None
stroke_width float | None

The stroke width of the node

1.25
transform NoneValueType | tuple[Transformation, ...] | None

The transform of the node

None
width float

The width of the node

required

Methods:

Name Description
anchor_point

Return an anchor point of the layout element.

angle

Return the point on the border of the node that intersects the drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

bbox

Compute and return the bounding box of the group layout element.

border

Return the point on the border of the node that intersects the drawing elements of the node with the line formed of the center anchor point of the node and the given point.

center

Return the center anchor of the node.

childless

Return a copy of the node with no children.

children

Return the children of the group layout.

contains

Return True if another layout element is a descendant of the layout element, False otherwise.

descendants

Return the descendants of the layout element.

drawing_elements

Return the drawing elements of the group layout.

east

Return the east anchor of the node.

east_north_east

Return the east north east anchor of the node.

east_south_east

Return the east south east anchor of the node.

equals

Return True if the layout element is equal to another layout element, False otherwise.

flattened

Return a list containing copy of the layout element with no children and all its descendants with no children.

label_center

Return the label center anchor of the node.

north

Return the north anchor of the node.

north_east

Return the north east anchor of the node.

north_north_east

Return the north north east anchor of the node.

north_north_west

Return the north north west anchor of the node.

north_west

Return the north west anchor of the node.

own_angle

Return the point on the border of the node that intersects the self drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

own_bbox

Compute and return the bounding box of the self drawing element of the group layout.

own_border

Return the point on the border of the node that intersects the self drawing elements of the node with the line formed of the center anchor point of the node and the given point.

own_children

Return the self children of the node. A node has unique child that is its label.

own_drawing_elements

Return the node's own drawing elements.

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

size

Return the size of the node.

south

Return the south anchor of the node.

south_east

Return the south east anchor of the node.

south_south_east

Return the south south east anchor of the node.

south_south_west

Return the south south west anchor of the node.

south_west

Return the south west anchor of the node.

to_geometry

Return a list of geometry primitives from the drawing elements.

west

Return the west anchor of the node.

west_north_west

Return the west north west anchor of the node.

west_south_west

Return the west south west anchor of the node.

Attributes:

Name Type Description
x float

Return the x coordinate of the node.

y float

Return the y coordinate of the node.

anchor_point

anchor_point(anchor_name: str) -> Point

Return an anchor point of the layout element.

Source code in src/momapy/core/elements.py
def anchor_point(self, anchor_name: str) -> Point:
    """Return an anchor point of the layout element."""
    return getattr(self, anchor_name)()

angle

angle(angle: float, unit: Literal['degrees', 'radians'] = 'degrees') -> Point | None

Return the point on the border of the node that intersects the drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

Source code in src/momapy/core/layout.py
def angle(
    self,
    angle: float,
    unit: typing.Literal["degrees", "radians"] = "degrees",
) -> Point | None:
    """Return the point on the border of the node that intersects the drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal."""
    return get_drawing_elements_angle(
        drawing_elements=self.drawing_elements(),
        angle=angle,
        unit=unit,
        center=self.center(),
    )

bbox

bbox() -> Bbox

Compute and return the bounding box of the group layout element.

Source code in src/momapy/core/layout.py
def bbox(self) -> Bbox:
    """Compute and return the bounding box of the group layout element."""
    own_bbox = self.own_bbox()
    bboxes = [child.bbox() for child in self.children()]
    min_x = own_bbox.north_west().x
    min_y = own_bbox.north_west().y
    max_x = own_bbox.south_east().x
    max_y = own_bbox.south_east().y
    for bbox in bboxes:
        if bbox.north_west().x < min_x:
            min_x = bbox.north_west().x
        if bbox.north_west().y < min_y:
            min_y = bbox.north_west().y
        if bbox.south_east().x > max_x:
            max_x = bbox.south_east().x
        if bbox.south_east().y > max_y:
            max_y = bbox.south_east().y
    bbox = Bbox(
        Point(min_x / 2 + max_x / 2, min_y / 2 + max_y / 2),
        max_x - min_x,
        max_y - min_y,
    )
    return bbox

border

border(point: Point) -> Point | None

Return the point on the border of the node that intersects the drawing elements of the node with the line formed of the center anchor point of the node and the given point.

When there are multiple intersection points, the one closest to the given point is returned.

Source code in src/momapy/core/layout.py
def border(self, point: Point) -> Point | None:
    """Return the point on the border of the node that intersects the drawing elements of the node with the line formed of the center anchor point of the node and the given point.

    When there are multiple intersection points, the one closest to the given point is returned.
    """
    return get_drawing_elements_border(
        drawing_elements=self.drawing_elements(),
        point=point,
        center=self.center(),
    )

center

center() -> Point

Return the center anchor of the node.

Source code in src/momapy/core/layout.py
def center(self) -> Point:
    """Return the center anchor of the node."""
    return self.position

childless

childless() -> Self

Return a copy of the node with no children.

Source code in src/momapy/core/layout.py
def childless(self) -> typing_extensions.Self:
    """Return a copy of the node with no children."""
    return dataclasses.replace(self, label=None, layout_elements=tuple([]))

children

children() -> list[LayoutElement]

Return the children of the group layout.

These are the self children of the group layout (returned by the own_children method) and the other children of the group layout (given by the layout_elements attribute).

Source code in src/momapy/core/layout.py
def children(self) -> list[LayoutElement]:
    """Return the children of the group layout.

    These are the self children of the group layout (returned by the `own_children` method) and the other children of the group layout (given by the `layout_elements` attribute).
    """
    return self.own_children() + list(self.layout_elements)

contains

contains(other: LayoutElement) -> bool

Return True if another layout element is a descendant of the layout element, False otherwise.

Source code in src/momapy/core/elements.py
def contains(self, other: "LayoutElement") -> bool:
    """Return `True` if another layout element is a descendant of the layout element, `False` otherwise."""
    return other in self.descendants()

descendants

descendants() -> list[LayoutElement]

Return the descendants of the layout element.

This walks the explicit children() tree (i.e. visual containment) depth-first, returning every layout element in the contained subtree (without self).

Note the deliberate contrast with ModelElement.descendants and Model.descendants, which reflectively walk the dataclass field-graph (i.e. reference reachability) and deduplicate by object identity. A model element referenced by several parents therefore appears once across the model graph, whereas layout descendants are strictly the contained subtree and a layout element contained under two parents is reached through each.

Returns:

Type Description
list[LayoutElement]

The list of descendant layout elements in visit order.

Source code in src/momapy/core/elements.py
def descendants(self) -> list["LayoutElement"]:
    """Return the descendants of the layout element.

    This walks the explicit `children()` tree (i.e. visual
    *containment*) depth-first, returning every layout element in the
    contained subtree (without `self`).

    Note the deliberate contrast with
    [`ModelElement.descendants`][momapy.core.elements.ModelElement.descendants]
    and [`Model.descendants`][momapy.core.model.Model.descendants],
    which reflectively walk the dataclass field-graph (i.e. *reference
    reachability*) and deduplicate by object identity. A model element
    referenced by several parents therefore appears once across the
    model graph, whereas layout descendants are strictly the contained
    subtree and a layout element contained under two parents is reached
    through each.

    Returns:
        The list of descendant layout elements in visit order.
    """
    descendants = []
    for child in self.children():
        descendants.append(child)
        descendants += child.descendants()
    return descendants

drawing_elements

drawing_elements() -> list[DrawingElement]

Return the drawing elements of the group layout.

The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.

Source code in src/momapy/core/layout.py
def drawing_elements(self) -> list[DrawingElement]:
    """Return the drawing elements of the group layout.

    The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.
    """
    drawing_elements = self.own_drawing_elements()
    for child in self.children():
        if child is not None:
            drawing_elements += child.drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}",
        elements=tuple(drawing_elements),
        id_=f"{self.id_}",
        fill=self.group_fill,
        fill_rule=self.group_fill_rule,
        filter_=self.group_filter,
        font_family=self.group_font_family,
        font_size=self.group_font_size,
        font_style=self.group_font_style,
        font_weight=self.group_font_weight,
        stroke=self.group_stroke,
        stroke_dasharray=self.group_stroke_dasharray,
        stroke_dashoffset=self.group_stroke_dashoffset,
        stroke_width=self.group_stroke_width,
        text_anchor=self.group_text_anchor,
        transform=self.group_transform,
    )
    return [group]

east

east() -> Point

Return the east anchor of the node.

Source code in src/momapy/core/layout.py
def east(self) -> Point:
    """Return the east anchor of the node."""
    return self.own_angle(0)

east_north_east

east_north_east() -> Point

Return the east north east anchor of the node.

Source code in src/momapy/core/layout.py
def east_north_east(self) -> Point:
    """Return the east north east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, -self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

east_south_east

east_south_east() -> Point

Return the east south east anchor of the node.

Source code in src/momapy/core/layout.py
def east_south_east(self) -> Point:
    """Return the east south east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

equals

equals(other: LayoutElement, flattened: bool = False, unordered: bool = False) -> bool

Return True if the layout element is equal to another layout element, False otherwise.

Source code in src/momapy/core/elements.py
def equals(
    self, other: "LayoutElement", flattened: bool = False, unordered: bool = False
) -> bool:
    """Return `True` if the layout element is equal to another layout element, `False` otherwise."""
    if type(self) is type(other):
        if not flattened:
            return self == other
        else:
            if not unordered:
                return self.flattened() == other.flattened()
            else:
                return set(self.flattened()) == set(other.flattened())
    return False

flattened

flattened() -> list[LayoutElement]

Return a list containing copy of the layout element with no children and all its descendants with no children.

Source code in src/momapy/core/elements.py
def flattened(self) -> list["LayoutElement"]:
    """Return a list containing copy of the layout element with no children and all its descendants with no children."""
    flattened = [self.childless()]
    for child in self.children():
        flattened += child.flattened()
    return flattened

label_center

label_center() -> Point

Return the label center anchor of the node.

Source code in src/momapy/core/layout.py
def label_center(self) -> Point:
    """Return the label center anchor of the node."""
    return self.position

north

north() -> Point

Return the north anchor of the node.

Source code in src/momapy/core/layout.py
def north(self) -> Point:
    """Return the north anchor of the node."""
    return self.own_angle(90)

north_east

north_east() -> Point

Return the north east anchor of the node.

Source code in src/momapy/core/layout.py
def north_east(self) -> Point:
    """Return the north east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, -self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

north_north_east

north_north_east() -> Point

Return the north north east anchor of the node.

Source code in src/momapy/core/layout.py
def north_north_east(self) -> Point:
    """Return the north north east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 4, -self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

north_north_west

north_north_west() -> Point

Return the north north west anchor of the node.

Source code in src/momapy/core/layout.py
def north_north_west(self) -> Point:
    """Return the north north west anchor of the node."""
    line = Line(self.center(), self.center() - (self.width / 4, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

north_west

north_west() -> Point

Return the north west anchor of the node.

Source code in src/momapy/core/layout.py
def north_west(self) -> Point:
    """Return the north west anchor of the node."""
    line = Line(self.center(), self.center() - (self.width / 2, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

own_angle

own_angle(angle: float, unit: Literal['degrees', 'radians'] = 'degrees') -> Point | None

Return the point on the border of the node that intersects the self drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal.

Source code in src/momapy/core/layout.py
def own_angle(
    self,
    angle: float,
    unit: typing.Literal["degrees", "radians"] = "degrees",
) -> Point | None:
    """Return the point on the border of the node that intersects the self drawing elements of the node with the line passing through the center anchor point of the node and at a given angle from the horizontal."""
    return get_drawing_elements_angle(
        drawing_elements=self.own_drawing_elements(),
        angle=angle,
        unit=unit,
        center=self.center(),
    )

own_bbox

own_bbox() -> Bbox

Compute and return the bounding box of the self drawing element of the group layout.

Source code in src/momapy/core/layout.py
def own_bbox(self) -> Bbox:
    """Compute and return the bounding box of the self drawing element of the group layout."""
    primitives = self.own_to_geometry()
    if not primitives:
        return Bbox(Point(0.0, 0.0), 0, 0)
    bboxes = [p.bbox() for p in primitives]
    return Bbox.union(bboxes)

own_border

own_border(point: Point) -> Point | None

Return the point on the border of the node that intersects the self drawing elements of the node with the line formed of the center anchor point of the node and the given point.

When there are multiple intersection points, the one closest to the given point is returned.

Source code in src/momapy/core/layout.py
def own_border(self, point: Point) -> Point | None:
    """Return the point on the border of the node that intersects the self drawing elements of the node with the line formed of the center anchor point of the node and the given point.

    When there are multiple intersection points, the one closest to the given point is returned.
    """
    return get_drawing_elements_border(
        drawing_elements=self.own_drawing_elements(),
        point=point,
        center=self.center(),
    )

own_children

own_children() -> list[LayoutElement]

Return the self children of the node. A node has unique child that is its label.

Source code in src/momapy/core/layout.py
def own_children(self) -> list[LayoutElement]:
    """Return the self children of the node. A node has unique child that is its label."""
    if self.label is not None:
        return [self.label]
    return []

own_drawing_elements

own_drawing_elements() -> list[DrawingElement]

Return the node's own drawing elements.

Source code in src/momapy/core/layout.py
def own_drawing_elements(self) -> list[DrawingElement]:
    """Return the node's own drawing elements."""
    drawing_elements = self._border_drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}_own",
        elements=tuple(drawing_elements),
        fill=self.fill,
        filter_=self.filter_,
        id_=f"{self.id_}_own",
        stroke=self.stroke,
        stroke_dasharray=self.stroke_dasharray,
        stroke_dashoffset=self.stroke_dashoffset,
        stroke_width=self.stroke_width,
        transform=self.transform,
    )
    return [group]

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

Source code in src/momapy/core/layout.py
def own_to_geometry(
    self,
) -> list[
    Segment | QuadraticBezierCurve | CubicBezierCurve | GeometryEllipticalArc
]:
    """Return a list of geometry primitives from the self drawing elements."""
    return drawing_elements_to_geometry(self.own_drawing_elements())

size

size() -> tuple[float, float]

Return the size of the node.

Source code in src/momapy/core/layout.py
def size(self) -> tuple[float, float]:
    """Return the size of the node."""
    return (self.width, self.height)

south

south() -> Point

Return the south anchor of the node.

Source code in src/momapy/core/layout.py
def south(self) -> Point:
    """Return the south anchor of the node."""
    return self.own_angle(270)

south_east

south_east() -> Point

Return the south east anchor of the node.

Source code in src/momapy/core/layout.py
def south_east(self) -> Point:
    """Return the south east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 2, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

south_south_east

south_south_east() -> Point

Return the south south east anchor of the node.

Source code in src/momapy/core/layout.py
def south_south_east(self) -> Point:
    """Return the south south east anchor of the node."""
    line = Line(self.center(), self.center() + (self.width / 4, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

south_south_west

south_south_west() -> Point

Return the south south west anchor of the node.

Source code in src/momapy/core/layout.py
def south_south_west(self) -> Point:
    """Return the south south west anchor of the node."""
    line = Line(self.center(), self.center() + (-self.width / 4, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

south_west

south_west() -> Point

Return the south west anchor of the node.

Source code in src/momapy/core/layout.py
def south_west(self) -> Point:
    """Return the south west anchor of the node."""
    line = Line(self.center(), self.center() + (-self.width / 2, self.height / 2))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

to_geometry

Return a list of geometry primitives from the drawing elements.

Source code in src/momapy/core/elements.py
def to_geometry(
    self,
) -> list[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc]:
    """Return a list of geometry primitives from the drawing elements."""
    return drawing_elements_to_geometry(self.drawing_elements())

west

west() -> Point

Return the west anchor of the node.

Source code in src/momapy/core/layout.py
def west(self) -> Point:
    """Return the west anchor of the node."""
    return self.own_angle(180)

west_north_west

west_north_west() -> Point

Return the west north west anchor of the node.

Source code in src/momapy/core/layout.py
def west_north_west(self) -> Point:
    """Return the west north west anchor of the node."""
    line = Line(self.center(), self.center() - (self.width / 2, self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

west_south_west

west_south_west() -> Point

Return the west south west anchor of the node.

Source code in src/momapy/core/layout.py
def west_south_west(self) -> Point:
    """Return the west south west anchor of the node."""
    line = Line(self.center(), self.center() + (-self.width / 2, self.height / 4))
    angle = -line.get_angle_to_horizontal()
    return self.own_angle(angle, unit="radians")

x property

x: float

Return the x coordinate of the node.

y property

y: float

Return the y coordinate of the node.

SBGNRole dataclass

SBGNRole(*, id_: str = make_uuid4_as_str(), referred_element: SBGNModelElement)

Bases: SBGNModelElement

Abstract base class for SBGN roles.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'3058a96a-4f26-4363-b709-c74c38730179'
referred_element SBGNModelElement

The SBGN model element this role refers to.

required

Methods:

Name Description
descendants

Return every ModelElement reachable from self, excluding self.

descendants

descendants() -> list[ModelElement]

Return every ModelElement reachable from self, excluding self.

This reflectively walks the dataclass field-graph (i.e. reference reachability) across scalar ModelElement fields and frozenset/tuple containers, deduplicating by object identity. A model element referenced by several parents therefore appears once.

Note the deliberate contrast with LayoutElement.descendants, which instead walks the explicit children() tree (visual containment): there a layout element contained under two parents is reached through each, with no identity dedup.

Returns:

Type Description
list[ModelElement]

The list of reachable ModelElement instances in visit

list[ModelElement]

order, without self.

Source code in src/momapy/core/elements.py
def descendants(self) -> list["ModelElement"]:
    """Return every `ModelElement` reachable from `self`, excluding `self`.

    This reflectively walks the dataclass field-graph (i.e. *reference
    reachability*) across scalar `ModelElement` fields and
    `frozenset`/`tuple` containers, deduplicating by object identity. A
    model element referenced by several parents therefore appears once.

    Note the deliberate contrast with
    [`LayoutElement.descendants`][momapy.core.elements.LayoutElement.descendants],
    which instead walks the explicit `children()` tree (visual
    *containment*): there a layout element contained under two parents is
    reached through each, with no identity dedup.

    Returns:
        The list of reachable `ModelElement` instances in visit
        order, without `self`.
    """
    seen: set[int] = {id(self)}
    result: list[ModelElement] = []
    if dataclasses.is_dataclass(self):
        for field in dataclasses.fields(type(self)):
            _walk_model_graph(getattr(self, field.name), seen, result)
    return result

SBGNSingleHeadedArc dataclass

SBGNSingleHeadedArc(*, id_: str = make_uuid4_as_str(), layout_elements: tuple[LayoutElement, ...] = tuple(), group_fill: NoneValueType | Color | None = None, group_fill_rule: FillRule | None = None, group_filter: NoneValueType | Filter | None = None, group_font_family: str | None = None, group_font_size: float | None = None, group_font_style: FontStyle | None = None, group_font_weight: FontWeight | float | None = None, group_stroke: NoneValueType | Color | None = None, group_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, group_stroke_dashoffset: NoneValueType | float | None = None, group_stroke_width: NoneValueType | float | None = None, group_text_anchor: TextAnchor | None = None, group_transform: NoneValueType | tuple[Transformation, ...] | None = None, end_shorten: float = 0.0, fill: NoneValueType | Color | None = None, filter_: NoneValueType | Filter | None = None, path_fill: NoneValueType | Color | None = NoneValue, path_filter: NoneValueType | Filter | None = None, path_stroke: NoneValueType | Color | None = black, path_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, path_stroke_dashoffset: NoneValueType | float | None = None, path_stroke_width: float | None = 1.25, path_transform: NoneValueType | tuple[Transformation, ...] | None = None, stroke: NoneValueType | Color | None = None, stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, stroke_dashoffset: NoneValueType | float | None = None, stroke_width: NoneValueType | float | None = None, segments: tuple[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc, ...] = tuple(), source: LayoutElement | None = None, start_shorten: float = 0.0, target: LayoutElement | None = None, transform: NoneValueType | tuple[Transformation, ...] | None = None, arrowhead_fill: NoneValueType | Color | None = white, arrowhead_filter: NoneValueType | Filter | None = None, arrowhead_stroke: NoneValueType | Color | None = black, arrowhead_stroke_dasharray: NoneValueType | tuple[float, ...] | None = None, arrowhead_stroke_dashoffset: NoneValueType | float | None = None, arrowhead_stroke_width: float | None = 1.25, arrowhead_transform: NoneValueType | tuple[Transformation, ...] | None = None)

Bases: SingleHeadedArc

Abstract base class for SBGN single-headed arcs.

Parameters:

Name Type Description Default
id_ str

The id of the map element. This id is purely for the user to keep track of the element, it does not need to be unique and is not part of the identity of the element, i.e., it is not considered when testing for equality between two map elements or when hashing the map element

'1cc0c605-fdad-406e-b486-bbd9bef48a20'
layout_elements tuple[LayoutElement, ...]

The sub-layout elements of the group layout. These are part of the children of the group layout

<dynamic>
group_fill NoneValueType | Color | None

The fill color of the group layout

None
group_fill_rule FillRule | None

The fill rule of the group layout

None
group_filter NoneValueType | Filter | None

The filter of the group layout

None
group_font_family str | None

The font family of the group layout

None
group_font_size float | None

The font size of the group layout

None
group_font_style FontStyle | None

The font style of the group layout

None
group_font_weight FontWeight | float | None

The font weight of the group layout

None
group_stroke NoneValueType | Color | None

The stroke color of the group layout

None
group_stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the group layout

None
group_stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the group layout

None
group_stroke_width NoneValueType | float | None

The stroke width of the group layout

None
group_text_anchor TextAnchor | None

The text anchor of the group layout

None
group_transform NoneValueType | tuple[Transformation, ...] | None

The transform of the group layout

None
end_shorten float

The length the end of the arc will be shorten by

0.0
fill NoneValueType | Color | None

The fill color of the arc

None
filter_ NoneValueType | Filter | None

The filter of the arc

None
path_fill NoneValueType | Color | None

The path fill color of the arc

<momapy.drawing.NoneValueType object at 0x7fb1b7eb96a0>
path_filter NoneValueType | Filter | None

The path filter of the arc

None
path_stroke NoneValueType | Color | None

The path stroke color of the arc

Color(red=0, green=0, blue=0, alpha=1.0)
path_stroke_dasharray NoneValueType | tuple[float, ...] | None

The path stroke dasharray of the arc

None
path_stroke_dashoffset NoneValueType | float | None

The path stroke dashoffset of the arc

None
path_stroke_width float | None

The path stroke width of the arc

1.25
path_transform NoneValueType | tuple[Transformation, ...] | None

The path transform of the arc

None
stroke NoneValueType | Color | None

The stroke color of the arc

None
stroke_dasharray NoneValueType | tuple[float, ...] | None

The stroke dasharray of the arc

None
stroke_dashoffset NoneValueType | float | None

The stroke dashoffset of the arc

None
stroke_width NoneValueType | float | None

The stroke width of the arc

None
segments tuple[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc, ...]

The path segments of the arc

<dynamic>
source LayoutElement | None

The source of the arc

None
start_shorten float

The length the start of the arc will be shorten by

0.0
target LayoutElement | None

The target of the arc

None
transform NoneValueType | tuple[Transformation, ...] | None

The transform of the arc

None
arrowhead_fill NoneValueType | Color | None

The arrowhead fill color of the arc

Color(red=255, green=255, blue=255, alpha=1.0)
arrowhead_filter NoneValueType | Filter | None

The arrowhead filter of the arc

None
arrowhead_stroke NoneValueType | Color | None

The arrowhead stroke color of the arc

Color(red=0, green=0, blue=0, alpha=1.0)
arrowhead_stroke_dasharray NoneValueType | tuple[float, ...] | None

The arrowhead stroke dasharray of the arc

None
arrowhead_stroke_dashoffset NoneValueType | float | None

The arrowhead stroke dashoffset of the arc

None
arrowhead_stroke_width float | None

The arrowhead stroke width of the arc

1.25
arrowhead_transform NoneValueType | tuple[Transformation, ...] | None

The arrowhead transform of the arc

None

Methods:

Name Description
anchor_point

Return an anchor point of the layout element.

arrowhead_base

Return the arrowhead base anchor point of the single-headed arc.

arrowhead_bbox

Return the bounding box of the single-headed arc arrowhead.

arrowhead_border

Return the point at the intersection of the drawing elements of the single-headed arc arrowhead and the line going through the center of these drawing elements and the given point.

arrowhead_drawing_elements

Return the drawing elements of the single-headed arc arrowhead.

arrowhead_length

Return the length of the single-headed arc arrowhead.

arrowhead_tip

Return the arrowhead tip anchor point of the single-headed arc.

bbox

Compute and return the bounding box of the group layout element.

childless

Return a copy of the arc with no children.

children

Return the children of the group layout.

contains

Return True if another layout element is a descendant of the layout element, False otherwise.

descendants

Return the descendants of the layout element.

drawing_elements

Return the drawing elements of the group layout.

end_point

Return the ending point of the arc.

equals

Return True if the layout element is equal to another layout element, False otherwise.

flattened

Return a list containing copy of the layout element with no children and all its descendants with no children.

fraction

Return the position and angle on the arc at a given fraction (of the total arc length).

length

Return the total length of the arc path.

own_bbox

Compute and return the bounding box of the self drawing element of the group layout.

own_children

Return the self children of the arc.

own_drawing_elements

Return the self drawing elements of the single-headed arc.

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

path_drawing_elements

Return the drawing elements of the single-headed arc path.

points

Return the points of the arc path.

start_point

Return the starting point of the arc.

to_geometry

Return a list of geometry primitives from the drawing elements.

anchor_point

anchor_point(anchor_name: str) -> Point

Return an anchor point of the layout element.

Source code in src/momapy/core/elements.py
def anchor_point(self, anchor_name: str) -> Point:
    """Return an anchor point of the layout element."""
    return getattr(self, anchor_name)()

arrowhead_base

arrowhead_base() -> Point

Return the arrowhead base anchor point of the single-headed arc.

Source code in src/momapy/core/layout.py
def arrowhead_base(self) -> Point:
    """Return the arrowhead base anchor point of the single-headed arc."""
    arrowhead_length = self.arrowhead_length()
    segment = self.segments[-1]
    segment_length = segment.length()
    if segment_length == 0:
        return self.arrowhead_tip() - (arrowhead_length, 0)
    fraction = 1 - (arrowhead_length + self.end_shorten) / segment_length
    return segment.get_position_at_fraction(fraction)

arrowhead_bbox

arrowhead_bbox() -> Bbox

Return the bounding box of the single-headed arc arrowhead.

Source code in src/momapy/core/layout.py
def arrowhead_bbox(self) -> Bbox:
    """Return the bounding box of the single-headed arc arrowhead."""
    return get_drawing_elements_bbox(self.arrowhead_drawing_elements())

arrowhead_border

arrowhead_border(point: Point) -> Point

Return the point at the intersection of the drawing elements of the single-headed arc arrowhead and the line going through the center of these drawing elements and the given point.

When there are multiple intersection points, the one closest to the given point is returned.

Source code in src/momapy/core/layout.py
def arrowhead_border(self, point: Point) -> Point:
    """Return the point at the intersection of the drawing elements of the single-headed arc arrowhead and the line going through the center of these drawing elements and the given point.

    When there are multiple intersection points, the one closest to the given point is returned.
    """
    point = get_drawing_elements_border(self.arrowhead_drawing_elements(), point)
    if point is None:
        return self.arrowhead_tip()
    return point

arrowhead_drawing_elements

arrowhead_drawing_elements() -> list[DrawingElement]

Return the drawing elements of the single-headed arc arrowhead.

Source code in src/momapy/core/layout.py
def arrowhead_drawing_elements(
    self,
) -> list[DrawingElement]:
    """Return the drawing elements of the single-headed arc arrowhead."""
    drawing_elements = self._arrowhead_border_drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}_arrowhead",
        elements=tuple(drawing_elements),
        fill=self.arrowhead_fill,
        filter_=self.arrowhead_filter,
        id_=f"{self.id_}_arrowhead",
        stroke=self.arrowhead_stroke,
        stroke_dasharray=self.arrowhead_stroke_dasharray,
        stroke_dashoffset=self.arrowhead_stroke_dashoffset,
        stroke_width=self.arrowhead_stroke_width,
        transform=self.arrowhead_transform,
    )
    transformation = self._get_arrowhead_transformation()
    group = group.transformed(transformation)
    return [group]

arrowhead_length

arrowhead_length() -> float

Return the length of the single-headed arc arrowhead.

Source code in src/momapy/core/layout.py
def arrowhead_length(self) -> float:
    """Return the length of the single-headed arc arrowhead."""
    bbox = get_drawing_elements_bbox(self._arrowhead_border_drawing_elements())
    if math.isnan(bbox.width):
        return 0.0
    return bbox.east().x

arrowhead_tip

arrowhead_tip() -> Point

Return the arrowhead tip anchor point of the single-headed arc.

Source code in src/momapy/core/layout.py
def arrowhead_tip(self) -> Point:
    """Return the arrowhead tip anchor point of the single-headed arc."""
    segment = self.segments[-1]
    segment_length = segment.length()
    if segment_length == 0:
        return segment.p2
    fraction = 1 - self.end_shorten / segment_length
    return segment.get_position_at_fraction(fraction)

bbox

bbox() -> Bbox

Compute and return the bounding box of the group layout element.

Source code in src/momapy/core/layout.py
def bbox(self) -> Bbox:
    """Compute and return the bounding box of the group layout element."""
    own_bbox = self.own_bbox()
    bboxes = [child.bbox() for child in self.children()]
    min_x = own_bbox.north_west().x
    min_y = own_bbox.north_west().y
    max_x = own_bbox.south_east().x
    max_y = own_bbox.south_east().y
    for bbox in bboxes:
        if bbox.north_west().x < min_x:
            min_x = bbox.north_west().x
        if bbox.north_west().y < min_y:
            min_y = bbox.north_west().y
        if bbox.south_east().x > max_x:
            max_x = bbox.south_east().x
        if bbox.south_east().y > max_y:
            max_y = bbox.south_east().y
    bbox = Bbox(
        Point(min_x / 2 + max_x / 2, min_y / 2 + max_y / 2),
        max_x - min_x,
        max_y - min_y,
    )
    return bbox

childless

childless() -> Self

Return a copy of the arc with no children.

Source code in src/momapy/core/layout.py
def childless(self) -> typing_extensions.Self:
    """Return a copy of the arc with no children."""
    return dataclasses.replace(self, layout_elements=tuple([]))

children

children() -> list[LayoutElement]

Return the children of the group layout.

These are the self children of the group layout (returned by the own_children method) and the other children of the group layout (given by the layout_elements attribute).

Source code in src/momapy/core/layout.py
def children(self) -> list[LayoutElement]:
    """Return the children of the group layout.

    These are the self children of the group layout (returned by the `own_children` method) and the other children of the group layout (given by the `layout_elements` attribute).
    """
    return self.own_children() + list(self.layout_elements)

contains

contains(other: LayoutElement) -> bool

Return True if another layout element is a descendant of the layout element, False otherwise.

Source code in src/momapy/core/elements.py
def contains(self, other: "LayoutElement") -> bool:
    """Return `True` if another layout element is a descendant of the layout element, `False` otherwise."""
    return other in self.descendants()

descendants

descendants() -> list[LayoutElement]

Return the descendants of the layout element.

This walks the explicit children() tree (i.e. visual containment) depth-first, returning every layout element in the contained subtree (without self).

Note the deliberate contrast with ModelElement.descendants and Model.descendants, which reflectively walk the dataclass field-graph (i.e. reference reachability) and deduplicate by object identity. A model element referenced by several parents therefore appears once across the model graph, whereas layout descendants are strictly the contained subtree and a layout element contained under two parents is reached through each.

Returns:

Type Description
list[LayoutElement]

The list of descendant layout elements in visit order.

Source code in src/momapy/core/elements.py
def descendants(self) -> list["LayoutElement"]:
    """Return the descendants of the layout element.

    This walks the explicit `children()` tree (i.e. visual
    *containment*) depth-first, returning every layout element in the
    contained subtree (without `self`).

    Note the deliberate contrast with
    [`ModelElement.descendants`][momapy.core.elements.ModelElement.descendants]
    and [`Model.descendants`][momapy.core.model.Model.descendants],
    which reflectively walk the dataclass field-graph (i.e. *reference
    reachability*) and deduplicate by object identity. A model element
    referenced by several parents therefore appears once across the
    model graph, whereas layout descendants are strictly the contained
    subtree and a layout element contained under two parents is reached
    through each.

    Returns:
        The list of descendant layout elements in visit order.
    """
    descendants = []
    for child in self.children():
        descendants.append(child)
        descendants += child.descendants()
    return descendants

drawing_elements

drawing_elements() -> list[DrawingElement]

Return the drawing elements of the group layout.

The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.

Source code in src/momapy/core/layout.py
def drawing_elements(self) -> list[DrawingElement]:
    """Return the drawing elements of the group layout.

    The returned drawing elements are a group drawing element formed of the self drawing elements of the group layout and the drawing elements of its children.
    """
    drawing_elements = self.own_drawing_elements()
    for child in self.children():
        if child is not None:
            drawing_elements += child.drawing_elements()
    group = Group(
        class_=f"{type(self).__name__}",
        elements=tuple(drawing_elements),
        id_=f"{self.id_}",
        fill=self.group_fill,
        fill_rule=self.group_fill_rule,
        filter_=self.group_filter,
        font_family=self.group_font_family,
        font_size=self.group_font_size,
        font_style=self.group_font_style,
        font_weight=self.group_font_weight,
        stroke=self.group_stroke,
        stroke_dasharray=self.group_stroke_dasharray,
        stroke_dashoffset=self.group_stroke_dashoffset,
        stroke_width=self.group_stroke_width,
        text_anchor=self.group_text_anchor,
        transform=self.group_transform,
    )
    return [group]

end_point

end_point() -> Point

Return the ending point of the arc.

Raises:

Type Description
ValueError

If the arc has no segments.

Source code in src/momapy/core/layout.py
def end_point(self) -> Point:
    """Return the ending point of the arc.

    Raises:
        ValueError: If the arc has no segments.
    """
    if not self.segments:
        raise ValueError("arc has no segments")
    return self.points()[-1]

equals

equals(other: LayoutElement, flattened: bool = False, unordered: bool = False) -> bool

Return True if the layout element is equal to another layout element, False otherwise.

Source code in src/momapy/core/elements.py
def equals(
    self, other: "LayoutElement", flattened: bool = False, unordered: bool = False
) -> bool:
    """Return `True` if the layout element is equal to another layout element, `False` otherwise."""
    if type(self) is type(other):
        if not flattened:
            return self == other
        else:
            if not unordered:
                return self.flattened() == other.flattened()
            else:
                return set(self.flattened()) == set(other.flattened())
    return False

flattened

flattened() -> list[LayoutElement]

Return a list containing copy of the layout element with no children and all its descendants with no children.

Source code in src/momapy/core/elements.py
def flattened(self) -> list["LayoutElement"]:
    """Return a list containing copy of the layout element with no children and all its descendants with no children."""
    flattened = [self.childless()]
    for child in self.children():
        flattened += child.flattened()
    return flattened

fraction

fraction(fraction: float) -> tuple[Point, float]

Return the position and angle on the arc at a given fraction (of the total arc length).

Raises:

Type Description
ValueError

If the arc has no segments.

Source code in src/momapy/core/layout.py
def fraction(self, fraction: float) -> tuple[Point, float]:
    """Return the position and angle on the arc at a given fraction (of the total arc length).

    Raises:
        ValueError: If the arc has no segments.
    """
    if not self.segments:
        raise ValueError("arc has no segments")
    current_length = 0
    length_to_reach = fraction * self.length()
    for segment in self.segments:
        current_length += segment.length()
        if current_length >= length_to_reach:
            break
    segment_start_length = current_length - segment.length()
    segment_fraction = (length_to_reach - segment_start_length) / segment.length()
    position, angle = segment.get_position_and_angle_at_fraction(segment_fraction)
    return position, angle

length

length() -> float

Return the total length of the arc path.

Source code in src/momapy/core/layout.py
def length(self) -> float:
    """Return the total length of the arc path."""
    return sum([segment.length() for segment in self.segments])

own_bbox

own_bbox() -> Bbox

Compute and return the bounding box of the self drawing element of the group layout.

Source code in src/momapy/core/layout.py
def own_bbox(self) -> Bbox:
    """Compute and return the bounding box of the self drawing element of the group layout."""
    primitives = self.own_to_geometry()
    if not primitives:
        return Bbox(Point(0.0, 0.0), 0, 0)
    bboxes = [p.bbox() for p in primitives]
    return Bbox.union(bboxes)

own_children

own_children() -> list[LayoutElement]

Return the self children of the arc.

Source code in src/momapy/core/layout.py
def own_children(self) -> list[LayoutElement]:
    """Return the self children of the arc."""
    return []

own_drawing_elements

own_drawing_elements() -> list[DrawingElement]

Return the self drawing elements of the single-headed arc.

Source code in src/momapy/core/layout.py
def own_drawing_elements(self) -> list[DrawingElement]:
    """Return the self drawing elements of the single-headed arc."""
    drawing_elements = (
        self.path_drawing_elements() + self.arrowhead_drawing_elements()
    )
    group = Group(
        class_=f"{type(self).__name__}_own",
        elements=tuple(drawing_elements),
        fill=self.fill,
        filter_=self.filter_,
        id_=f"{self.id_}_own",
        stroke=self.stroke,
        stroke_dasharray=self.stroke_dasharray,
        stroke_dashoffset=self.stroke_dashoffset,
        stroke_width=self.stroke_width,
        transform=self.transform,
    )
    return [group]

own_to_geometry

Return a list of geometry primitives from the self drawing elements.

Source code in src/momapy/core/layout.py
def own_to_geometry(
    self,
) -> list[
    Segment | QuadraticBezierCurve | CubicBezierCurve | GeometryEllipticalArc
]:
    """Return a list of geometry primitives from the self drawing elements."""
    return drawing_elements_to_geometry(self.own_drawing_elements())

path_drawing_elements

path_drawing_elements() -> list[Path]

Return the drawing elements of the single-headed arc path.

Source code in src/momapy/core/layout.py
def path_drawing_elements(self) -> list[Path]:
    """Return the drawing elements of the single-headed arc path."""
    arrowhead_length = self.arrowhead_length()
    if len(self.segments) == 1:
        segment = (
            self.segments[0]
            .shortened(self.start_shorten, "start")
            .shortened(self.end_shorten + arrowhead_length, "end")
        )
        actions = [
            MoveTo(segment.p1),
            self._make_path_action_from_segment(segment),
        ]
    else:
        first_segment = self.segments[0].shortened(self.start_shorten, "start")
        last_segment = self.segments[-1].shortened(
            self.end_shorten + arrowhead_length, "end"
        )
        actions = [
            MoveTo(first_segment.p1),
            self._make_path_action_from_segment(first_segment),
        ]
        for segment in self.segments[1:-1]:
            action = self._make_path_action_from_segment(segment)
            actions.append(action)
        actions.append(self._make_path_action_from_segment(last_segment))
    path = Path(
        actions=tuple(actions),
        class_=f"{type(self).__name__}_path",
        fill=self.path_fill,
        filter_=self.path_filter,
        id_=f"{self.id_}_path",
        stroke=self.path_stroke,
        stroke_dasharray=self.path_stroke_dasharray,
        stroke_dashoffset=self.path_stroke_dashoffset,
        stroke_width=self.path_stroke_width,
        transform=self.path_transform,
    )
    return [path]

points

points() -> list[Point]

Return the points of the arc path.

An arc with no segments has no points and returns an empty list.

Source code in src/momapy/core/layout.py
def points(self) -> list[Point]:
    """Return the points of the arc path.

    An arc with no segments has no points and returns an empty list.
    """
    if not self.segments:
        return []
    points = []
    for segment in self.segments:
        points.append(segment.p1)
    points.append(segment.p2)
    return points

start_point

start_point() -> Point

Return the starting point of the arc.

Raises:

Type Description
ValueError

If the arc has no segments.

Source code in src/momapy/core/layout.py
def start_point(self) -> Point:
    """Return the starting point of the arc.

    Raises:
        ValueError: If the arc has no segments.
    """
    if not self.segments:
        raise ValueError("arc has no segments")
    return self.points()[0]

to_geometry

Return a list of geometry primitives from the drawing elements.

Source code in src/momapy/core/elements.py
def to_geometry(
    self,
) -> list[Segment | QuadraticBezierCurve | CubicBezierCurve | EllipticalArc]:
    """Return a list of geometry primitives from the drawing elements."""
    return drawing_elements_to_geometry(self.drawing_elements())