Skip to content

context

Definitions of Custom Accessor- and Diagram-Classtypes based on Accessor and AbstractDiagram.

CableTreeAccessor 🔗

CableTreeAccessor(dgcls: str, render_params: dict[str, t.Any] | None = None)

Bases: ContextAccessor

Provides access to the cable tree diagrams.

Source code in capellambse_context_diagrams/context.py
52
53
54
55
56
57
def __init__(
    self, dgcls: str, render_params: dict[str, t.Any] | None = None
) -> None:
    super().__init__()
    self._dgcls = dgcls
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: m.T | None, objtype: type | None = None) -> m.Accessor | ContextDiagram

Make a CableTreeView for the given model object.

Source code in capellambse_context_diagrams/context.py
195
196
197
198
199
200
201
202
203
204
205
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a CableTreeView for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, CableTreeViewDiagram)

CableTreeViewDiagram 🔗

CableTreeViewDiagram(class_: str, obj: m.ModelElement, *, render_styles: dict[str, styling.Styler] | None = None, default_render_parameters: dict[str, t.Any])

Bases: ContextDiagram

An automatically generated CableTreeView.

Source code in capellambse_context_diagrams/context.py
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_port_labels": True,
        "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE.name,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.collector = cable_tree.collector

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

ClassTreeAccessor 🔗

ClassTreeAccessor(diagclass: str, render_params: dict[str, t.Any] | None = None)

Bases: ContextAccessor

Provides access to the tree view diagrams.

Source code in capellambse_context_diagrams/context.py
129
130
131
132
133
def __init__(
    self, diagclass: str, render_params: dict[str, t.Any] | None = None
) -> None:
    self._dgcls = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: m.T | None, objtype: type | None = None) -> m.Accessor | ContextDiagram

Make a ClassTreeDiagram for the given model object.

Source code in capellambse_context_diagrams/context.py
135
136
137
138
139
140
141
142
143
144
145
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a ClassTreeDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, ClassTreeDiagram)

ClassTreeDiagram 🔗

ClassTreeDiagram(class_: str, obj: m.ModelElement, *, render_styles: dict[str, styling.Styler] | None = None, default_render_parameters: dict[str, t.Any])

Bases: ContextDiagram

An automatically generated ClassTree Diagram.

This diagram is exclusively for Classes.

Source code in capellambse_context_diagrams/context.py
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_symbols_as_boxes": True,
        "edgeRouting": "POLYLINE",
        "direction": "DOWN",
        "nodeSizeConstraints": "NODE_LABELS",
        "edgeLabelsSide": "SMART_DOWN",
        "partitioning": False,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.collector = tree_view.collector

name property 🔗

name: str

Returns the name of the diagram.

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

ContextAccessor 🔗

ContextAccessor(dgcls: str, render_params: dict[str, t.Any] | None = None)

Bases: Accessor

Provides access to the context diagrams.

Source code in capellambse_context_diagrams/context.py
52
53
54
55
56
57
def __init__(
    self, dgcls: str, render_params: dict[str, t.Any] | None = None
) -> None:
    super().__init__()
    self._dgcls = dgcls
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: None, objtype: type[t.Any]) -> ContextAccessor
__get__(obj: m.T, objtype: type[m.T] | None = None) -> ContextDiagram
__get__(obj: m.T | None, objtype: type | None = None) -> m.Accessor | ContextDiagram

Make a ContextDiagram for the given model object.

Source code in capellambse_context_diagrams/context.py
65
66
67
68
69
70
71
72
73
def __get__(
    self, obj: m.T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram:
    """Make a ContextDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, ContextDiagram)

ContextDiagram 🔗

ContextDiagram(class_: str, obj: m.ModelElement, *, render_styles: dict[str, styling.Styler] | None = None, default_render_parameters: dict[str, t.Any])

Bases: AbstractDiagram

An automatically generated context diagram.

ATTRIBUTE DESCRIPTION
target

The m.ModelElement from which the context is collected from.

styleclass

The diagram class (for e.g. [LAB]).

render_styles

Dictionary with the ElkChildType in str format as keys and styling.Styler functions as values. An example is given by: styling.BLUE_ACTOR_FNCS

serializer

The serializer builds a Diagram via serializers.DiagramSerializer.make_diagram by converting every _elkjs.ELKOutputChild into a Box, Edge or Circle.

filters

A list of filter names that are applied during collection of context. Currently this is only done in collectors.exchange_data_collector.

TYPE: MutableSet[str]

Notes
  • display_symbols_as_boxes — Display objects that are normally displayed as symbol as a simple box instead, with the symbol being the box' icon. This avoids the object of interest to become one giant, oversized symbol in the middle of the diagram, and instead keeps the symbol small and only enlarges the surrounding box.
  • display_parent_relation — Display objects with a parent relationship to the object of interest as the parent box.
  • display_derived_interfaces — Display derived objects collected from additional collectors beside the main collector for building the context.
  • slim_center_box — Minimal width for the center box, containing just the icon and the label. This is False if hierarchy was identified.
  • display_port_labels — Display port labels on the diagram.
  • port_label_position - Position of the port labels. See PORT_LABEL_POSITION.
  • hide_direct_children - Hide direct children of the object of interest.
Source code in capellambse_context_diagrams/context.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    super().__init__(obj._model)
    self.target = obj  # type: ignore[misc]
    self.styleclass = class_

    self.render_styles = render_styles or {}
    self.serializer = serializers.DiagramSerializer(self)

    self._elk_input_data: CollectorOutputData | None = None
    self.__filters: cabc.MutableSet[str] = self.FilterSet(self)
    self._default_render_parameters = {
        "display_symbols_as_boxes": False,
        "display_parent_relation": False,
        "hide_direct_children": False,
        "display_derived_interfaces": False,
        "slim_center_box": True,
        "display_port_labels": False,
        "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE.name,
        "transparent_background": False,
    } | default_render_parameters

    if standard_filter := STANDARD_FILTERS.get(class_):
        self.filters.add(standard_filter)
    if standard_styles := STANDARD_STYLES.get(class_):
        self.render_styles = standard_styles

    self.collector: cabc.Callable[
        [ContextDiagram, dict[str, t.Any]], CollectorOutputData
    ] = get_elkdata

name property 🔗

name: str

Returns the diagram name.

nodes property 🔗

nodes: MixedElementList

Return a list of all nodes visible in this diagram.

type property 🔗

type: DiagramType

Return the type of this diagram.

uuid property 🔗

uuid: str

Returns diagram UUID.

FilterSet 🔗

FilterSet(diagram: m.AbstractDiagram)

Bases: MutableSet

A set that stores filter_names and invalidates diagram cache.

Source code in capellambse_context_diagrams/context.py
361
362
363
364
365
366
def __init__(
    self,
    diagram: m.AbstractDiagram,
) -> None:
    self._set: set[str] = set()
    self._diagram = diagram

elk_input_data 🔗

elk_input_data(params: dict[str, t.Any]) -> CollectorOutputData

Returns the ELK input data.

Source code in capellambse_context_diagrams/context.py
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
def elk_input_data(
    self,
    params: dict[str, t.Any],
) -> CollectorOutputData:
    """Returns the ELK input data."""
    params = self._default_render_parameters | params
    for param_name in self._default_render_parameters:
        setattr(self, f"_{param_name}", params.pop(param_name))

    data: CollectorOutputData
    if data := params.get("elkdata", None):  # type: ignore[assignment]
        self._elk_input_data = data

    if self._elk_input_data is None:
        self._elk_input_data = self.collector(self, params)

    return self._elk_input_data

DataFlowAccessor 🔗

DataFlowAccessor(diagclass: str, render_params: dict[str, t.Any] | None = None)

Bases: ContextAccessor

Source code in capellambse_context_diagrams/context.py
173
174
175
176
177
def __init__(
    self, diagclass: str, render_params: dict[str, t.Any] | None = None
) -> None:
    self._dgcls = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: m.T | None, objtype: type | None = None) -> m.Accessor | ContextDiagram

Make a DataFlowViewDiagram for the given model object.

Source code in capellambse_context_diagrams/context.py
179
180
181
182
183
184
185
186
187
188
189
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a DataFlowViewDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, DataFlowViewDiagram)

DataFlowViewDiagram 🔗

DataFlowViewDiagram(class_: str, obj: m.ModelElement, *, render_styles: dict[str, styling.Styler] | None = None, default_render_parameters: dict[str, t.Any])

Bases: ContextDiagram

An automatically generated DataFlowViewDiagram.

Source code in capellambse_context_diagrams/context.py
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_symbols_as_boxes": True,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.collector = dataflow_view.collector

name property 🔗

name: str

Returns the name of the diagram.

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

FunctionalContextAccessor 🔗

FunctionalContextAccessor(dgcls: str, render_params: dict[str, t.Any] | None = None)

Bases: ContextAccessor

Source code in capellambse_context_diagrams/context.py
52
53
54
55
56
57
def __init__(
    self, dgcls: str, render_params: dict[str, t.Any] | None = None
) -> None:
    super().__init__()
    self._dgcls = dgcls
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: m.T | None, objtype: type | None = None) -> m.Accessor | ContextDiagram

Make a ContextDiagram for the given model object.

Source code in capellambse_context_diagrams/context.py
112
113
114
115
116
117
118
119
120
121
122
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a ContextDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, FunctionalContextDiagram)

FunctionalContextDiagram 🔗

FunctionalContextDiagram(class_: str, obj: m.ModelElement, *, default_render_parameters: dict[str, t.Any])

Bases: ContextDiagram

An automatically generated Context Diagram exclusively for Components.

Source code in capellambse_context_diagrams/context.py
553
554
555
556
557
558
559
560
561
562
563
564
565
566
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    default_render_parameters: dict[str, t.Any],
):
    super().__init__(
        class_, obj, default_render_parameters=default_render_parameters
    )

    self.collector: cabc.Callable[
        [FunctionalContextDiagram, dict[str, t.Any]], _elkjs.ELKInputData
    ] = exchanges.functional_context_collector

InterfaceContextAccessor 🔗

InterfaceContextAccessor(diagclass: dict[type[m.ModelElement], str], render_params: dict[str, t.Any] | None = None)

Bases: ContextAccessor

Provides access to the interface context diagrams.

Source code in capellambse_context_diagrams/context.py
90
91
92
93
94
95
96
def __init__(  # pylint: disable=super-init-not-called
    self,
    diagclass: dict[type[m.ModelElement], str],
    render_params: dict[str, t.Any] | None = None,
) -> None:
    self.__dgclasses = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: m.T | None, objtype: type | None = None) -> m.Accessor | ContextDiagram

Make a ContextDiagram for the given model object.

Source code in capellambse_context_diagrams/context.py
 98
 99
100
101
102
103
104
105
106
107
108
def __get__(  # type: ignore
    self, obj: m.T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram:
    """Make a ContextDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    assert isinstance(obj.parent, m.ModelElement)
    self._dgcls = self.__dgclasses[obj.parent.__class__]
    return self._get(obj, InterfaceContextDiagram)

InterfaceContextDiagram 🔗

InterfaceContextDiagram(class_: str, obj: m.ModelElement, *, render_styles: dict[str, styling.Styler] | None = None, default_render_parameters: dict[str, t.Any])

Bases: ContextDiagram

An automatically generated Context Diagram exclusively for ComponentExchanges.

ATTRIBUTE DESCRIPTION
dangling_functional_exchanges

A list of dangling functional exchanges for which either the source or target function were not allocated to a Component, part of the context.

TYPE: list[AbstractExchange]

Notes

The following render parameters are available:

  • include_interface — Boolean flag to enable inclusion of the context diagram target: The interface ComponentExchange.
  • include_port_allocations — Boolean flag to enable rendering of port allocations.
  • hide_functions — Boolean flag to enable white box view: Only displaying Components or Entities.
  • display_port_labels — Display port labels on the diagram.
  • port_label_position — Position of the port labels. See PORT_LABEL_POSITION.

In addition to all other render parameters of ContextDiagram.

Source code in capellambse_context_diagrams/context.py
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "include_interface": False,
        "include_port_allocations": False,
        "hide_functions": False,
        "display_symbols_as_boxes": True,
        "display_port_labels": False,
        "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE.name,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.collector: cabc.Callable[
        [InterfaceContextDiagram, dict[str, t.Any]], _elkjs.ELKInputData
    ] = exchanges.interface_context_collector

RealizationViewContextAccessor 🔗

RealizationViewContextAccessor(diagclass: str, render_params: dict[str, t.Any] | None = None)

Bases: ContextAccessor

Provides access to the realization view diagrams.

Source code in capellambse_context_diagrams/context.py
152
153
154
155
156
def __init__(
    self, diagclass: str, render_params: dict[str, t.Any] | None = None
) -> None:
    self._dgcls = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: m.T | None, objtype: type | None = None) -> m.Accessor | ContextDiagram

Make a RealizationViewDiagram for the given model object.

Source code in capellambse_context_diagrams/context.py
158
159
160
161
162
163
164
165
166
167
168
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a RealizationViewDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, RealizationViewDiagram)

RealizationViewDiagram 🔗

RealizationViewDiagram(class_: str, obj: m.ModelElement, *, render_styles: dict[str, styling.Styler] | None = None, default_render_parameters: dict[str, t.Any])

Bases: ContextDiagram

An automatically generated RealizationViewDiagram Diagram.

This diagram is exclusively for Activity, Functions, Entity and Components of all layers.

Source code in capellambse_context_diagrams/context.py
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_symbols_as_boxes": True,
        "depth": 1,
        "search_direction": "ALL",
        "show_owners": True,
        "layer_sizing": "WIDTH",
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.collector = realization_view.collector

name property 🔗

name: str

Returns the name of the diagram.

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

add_context 🔗

add_context(data: _elkjs.ELKOutputData, is_legend: bool = False) -> None

Add all connected nodes as context to all elements.

Source code in capellambse_context_diagrams/context.py
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
def add_context(data: _elkjs.ELKOutputData, is_legend: bool = False) -> None:
    """Add all connected nodes as context to all elements."""
    if is_legend:
        for child in data.children:
            if child.type == "node":
                child.context = [child.id]
        return

    ids: set[str] = set()

    def get_ids(
        obj: (
            _elkjs.ELKOutputNode
            | _elkjs.ELKOutputPort
            | _elkjs.ELKOutputJunction
            | _elkjs.ELKOutputEdge
        ),
    ) -> None:
        if obj.id and not obj.id.startswith("g_"):
            ids.add(obj.id)
        for child in getattr(obj, "children", []):
            if child.type in {"node", "port", "junction", "edge"}:
                assert child.type != "label"
                get_ids(child)

    def set_ids(
        obj: _elkjs.ELKOutputChild,
        ids: set[str],
    ) -> None:
        obj.context = list(ids)
        for child in getattr(obj, "children", []):
            set_ids(child, ids)

    for child in data.children:
        if child.type in {"node", "port", "junction", "edge"}:
            assert child.type != "label"
            get_ids(child)

    for child in data.children:
        set_ids(child, ids)

adjust_layer_sizing 🔗

adjust_layer_sizing(data: _elkjs.ELKInputData, layout: _elkjs.ELKOutputData, layer_sizing: t.Literal['UNION', 'WIDTH', 'HEIGHT', 'INDIVIDUAL']) -> None

Set nodeSize.minimum config in the layoutOptions.

Source code in capellambse_context_diagrams/context.py
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
def adjust_layer_sizing(
    data: _elkjs.ELKInputData,
    layout: _elkjs.ELKOutputData,
    layer_sizing: t.Literal["UNION", "WIDTH", "HEIGHT", "INDIVIDUAL"],
) -> None:
    """Set `nodeSize.minimum` config in the layoutOptions."""

    def calculate_min(key: t.Literal["width", "height"] = "width") -> float:
        return max(getattr(child.size, key) for child in layout.children)  # type: ignore[union-attr]

    if layer_sizing not in {"UNION", "WIDTH", "HEIGHT", "INDIVIDUAL"}:
        raise NotImplementedError(
            "For ``layer_sizing`` only UNION, WIDTH, HEIGHT or INDIVIDUAL is supported"
        )

    min_w = calculate_min() + 15.0 if layer_sizing in {"UNION", "WIDTH"} else 0
    min_h = (
        calculate_min("height") if layer_sizing in {"UNION", "HEIGHT"} else 0
    )
    for layer in data.children:
        layer.layoutOptions["nodeSize.minimum"] = f"({min_w},{min_h})"

calculate_label_position 🔗

calculate_label_position(x: float, y: float, width: float, height: float, padding: float = 10.0) -> tuple[float, float, float]

Calculate the position of the label and tspan.

The function calculates the center of the rectangle and uses the rectangle's width and height to adjust its position within it. The text is assumed to be horizontally and vertically centered within the rectangle. The tspan y coordinate is for positioning the label right under the left side of the rectangle.

PARAMETER DESCRIPTION
x

The x coordinate of the label position.

TYPE: float

y

The y coordinate of the label position.

TYPE: float

width

Width of the label.

TYPE: float

height

Height of the label

TYPE: float

padding

The padding for the label.

TYPE: float DEFAULT: 10.0

RETURNS DESCRIPTION
position

A tuple containing the x- and y-coordinate for the text element and the adjusted y-coordinate for the tspan element.

Source code in capellambse_context_diagrams/context.py
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
def calculate_label_position(
    x: float,
    y: float,
    width: float,
    height: float,
    padding: float = 10.0,
) -> tuple[float, float, float]:
    """Calculate the position of the label and tspan.

    The function calculates the center of the rectangle and uses the
    rectangle's width and height to adjust its position within it. The
    text is assumed to be horizontally and vertically centered within
    the rectangle. The tspan y coordinate is for positioning the label
    right under the left side of the rectangle.

    Parameters
    ----------
    x
        The x coordinate of the label position.
    y
        The y coordinate of the label position.
    width
        Width of the label.
    height
        Height of the label
    padding
        The padding for the label.

    Returns
    -------
    position
        A tuple containing the x- and y-coordinate for the text element
        and the adjusted y-coordinate for the tspan element.
    """
    center_y = y + height / 2
    tspan_y = center_y - width / 2 + padding
    return (x + width / 2, center_y, tspan_y)

has_single_child 🔗

has_single_child(data: _elkjs.ELKInputData | _elkjs.ELKInputChild) -> bool

Checks if data has a single or no child.

Source code in capellambse_context_diagrams/context.py
950
951
952
953
954
955
956
957
958
959
def has_single_child(data: _elkjs.ELKInputData | _elkjs.ELKInputChild) -> bool:
    """Checks if ``data`` has a single or no child."""
    if not data.children:
        return True

    for child in data.children:
        if not has_single_child(child):
            return False

    return len(data.children) == 1

stack_diagrams 🔗

stack_diagrams(first: cdiagram.Diagram, second: cdiagram.Diagram, axis: t.Literal['x', 'y'] = 'x') -> None

Add the diagram elements from right to left inline.

Source code in capellambse_context_diagrams/context.py
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
def stack_diagrams(
    first: cdiagram.Diagram,
    second: cdiagram.Diagram,
    axis: t.Literal["x", "y"] = "x",
) -> None:
    """Add the diagram elements from ``right`` to left inline."""
    if first.viewport:
        offset = first.viewport.pos + first.viewport.size
        offset @= (1, 0) if axis == "x" else (0, 1)
        for element in second:
            new = copy.deepcopy(element)
            new.move(offset)
            first += new
    else:
        for element in second:
            new = copy.deepcopy(element)
            first += new

try_to_layout 🔗

try_to_layout(data: _elkjs.ELKInputData) -> _elkjs.ELKOutputData

Try calling elkjs, raise a JSONDecodeError if it fails.

Source code in capellambse_context_diagrams/context.py
860
861
862
863
864
865
866
def try_to_layout(data: _elkjs.ELKInputData) -> _elkjs.ELKOutputData:
    """Try calling elkjs, raise a JSONDecodeError if it fails."""
    try:
        return _elkjs.call_elkjs(data)
    except json.JSONDecodeError as error:
        logger.error(json.dumps(data, indent=4))
        raise error