From 5bff4a1511a85ae77e4f1c7efc5b27d8135df5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernst=20W=C3=BCrger?= Date: Fri, 26 Apr 2024 13:11:24 +0200 Subject: [PATCH] fix!(realization-view): Remove whitespace in diagram Fix-realization-view (#90): - Added `layer_sizing` option `INDIVIDUAL`. - Also set default `layer_sizing` to `WIDTH` for best layout. - Update `elkjs` to `v0.9.2` _*Depends on [py-capellambse #413](https://github.com/DSD-DBS/py-capellambse/pull/413)*_ --- capellambse_context_diagrams/_elkjs.py | 2 +- capellambse_context_diagrams/context.py | 8 +- capellambse_context_diagrams/serializers.py | 3 +- docs/gen_images.py | 14 +- docs/realization_view.md | 150 +++++++++++++++++++- docs/tree_view.md | 2 +- tests/test_realization_views.py | 8 +- 7 files changed, 162 insertions(+), 25 deletions(-) diff --git a/capellambse_context_diagrams/_elkjs.py b/capellambse_context_diagrams/_elkjs.py index 5c1c02bc..7a7bc2c1 100644 --- a/capellambse_context_diagrams/_elkjs.py +++ b/capellambse_context_diagrams/_elkjs.py @@ -43,7 +43,7 @@ NODE_HOME = Path(capellambse.dirs.user_cache_dir, "elkjs", "node_modules") PATH_TO_ELK_JS = Path(__file__).parent / "elk.js" REQUIRED_NPM_PKG_VERSIONS: t.Dict[str, str] = { - "elkjs": "0.9.0", + "elkjs": "0.9.2", } """npm package names and versions required by this Python module.""" diff --git a/capellambse_context_diagrams/context.py b/capellambse_context_diagrams/context.py index fd2e37b6..174c6d77 100644 --- a/capellambse_context_diagrams/context.py +++ b/capellambse_context_diagrams/context.py @@ -512,8 +512,8 @@ def _create_diagram(self, params: dict[str, t.Any]) -> cdiagram.Diagram: params.setdefault( "search_direction", params.get("search_direction", "ALL") ) - params.setdefault("show_owners", params.get("show_owners", True)) - params.setdefault("layer_sizing", params.get("layer_sizing", "UNION")) + params.setdefault("show_owners", True) + params.setdefault("layer_sizing", "WIDTH") data, edges = realization_view.collector(self, params) layout = try_to_layout(data) adjust_layer_sizing(data, layout, params["layer_sizing"]) @@ -601,9 +601,9 @@ def adjust_layer_sizing( def calculate_min(key: t.Literal["width", "height"] = "width") -> float: return max(child["size"][key] for child in layout["children"]) # type: ignore[typeddict-item] - if layer_sizing not in {"UNION", "WIDTH", "HEIGHT"}: + if layer_sizing not in {"UNION", "WIDTH", "HEIGHT", "INDIVIDUAL"}: raise NotImplementedError( - "For ``layer_sizing`` only UNION, WIDTH or HEIGHT is supported" + "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 diff --git a/capellambse_context_diagrams/serializers.py b/capellambse_context_diagrams/serializers.py index 21a87fc3..c7b0a3a2 100644 --- a/capellambse_context_diagrams/serializers.py +++ b/capellambse_context_diagrams/serializers.py @@ -193,8 +193,7 @@ class type that stores all previously named classes. else: attr_name = "labels" - labels = getattr(parent, attr_name) - if labels: + if labels := getattr(parent, attr_name): label_box = labels[-1] label_box.label += " " + child["text"] label_box.size = diagram.Vector2D( diff --git a/docs/gen_images.py b/docs/gen_images.py index 3f0ee981..c09bfe8a 100644 --- a/docs/gen_images.py +++ b/docs/gen_images.py @@ -130,17 +130,19 @@ def generate_realization_view_images() -> None: for uuid in (realization_fnc_uuid, realization_comp_uuid): obj = model.by_uuid(uuid) diag = obj.realization_view - with mkdocs_gen_files.open(f"{str(dest / diag.name)}.svg", "w") as fd: - print( - diag.render( + for layer_sizing in ("UNION", "HEIGHT", "WIDTH", "INDIVIDUAL"): + with mkdocs_gen_files.open( + str(dest / f"{diag.name} {layer_sizing}.svg"), "wb" + ) as fd: + diag.save( + fd, "svg", depth=3, search_direction="ALL", show_owners=True, transparent_background=False, - ), - file=fd, - ) + layer_sizing=layer_sizing, + ) def generate_data_flow_image() -> None: diff --git a/docs/realization_view.md b/docs/realization_view.md index bbc4558c..948b531c 100644 --- a/docs/realization_view.md +++ b/docs/realization_view.md @@ -15,7 +15,7 @@ implement currently. The diagram elements are collected from the `ABOVE` and `.realizing_components` or `.realizing_functions` for direction `BELOW`. -??? example "Realization View Diagram of `LogicalFunction` `advise Harry`" +??? example "Realization View Diagram of `LogicalFunction` `advise Harry` with `layer_sizing=WIDTH`" ``` py import capellambse @@ -27,15 +27,15 @@ implement currently. The diagram elements are collected from the depth=3, # 1-3 search_direction="ALL", # BELOW; ABOVE and ALL show_owners=True, - layer_sizing="UNION", # UNION; WIDTH and HEIGHT + layer_sizing="WIDTH", # UNION; WIDTH, HEIGHT and INDIVIDUAL ).save(pretty=True) ```
- +
[CDB] Realization View Diagram of advise Harry
-??? example "Realization View Diagram of `PhysicalComponent` `Physical System`" +??? example "Realization View Diagram of `PhysicalComponent` `Physical System` with `layer_sizing=WIDTH`" ``` py import capellambse @@ -47,18 +47,154 @@ implement currently. The diagram elements are collected from the depth=3, search_direction="ALL", show_owners=True, - layer_sizing="UNION", + layer_sizing="WIDTH", ).save(pretty=True) ```
- +
[CDB] Realization View Diagram of Physical System
Additional rendering parameters enable showing owning functions or components, as well as the depth of traversion (i.e. `1`-`3`) and control on sizing of the layer boxes. They are put to display the maximum amount of diagram elements per -default. +default. The available options: + +1. search_direction - The direction to traverse the realiz(ing/ed) elements. + - ALL (default) + - ABOVE + - BELOW +2. show_owners - Collect parent boxes for every realiz(ing/ed) element. + - True (default) + - False +3. layer_sizing - Control even layer box sizing. + - WIDTH (default) + - HEIGHT + - UNION - WIDTH + HEIGHT + - INDIVIDUAL - Every layer box has minimal size to just contain its + children. + +## Examples + +??? example "Realization View Diagram of `LogicalFunction` `advise Harry` for `layer_sizing=HEIGHT`" + + ``` py + import capellambse + + model = capellambse.MelodyModel("tests/data/ContextDiagram.aird") + diag = model.by_uuid("beaf5ba4-8fa9-4342-911f-0266bb29be45").realization_view + diag.render( + "svgdiagram", + depth=3, + search_direction="ALL", + show_owners=True, + layer_sizing="HEIGHT", + ).save(pretty=True) + ``` +
+ +
[CDB] Realization View Diagram of advise Harry
+
+ +??? example "Realization View Diagram of `PhysicalComponent` `Physical System` for `layer_sizing=HEIGHT`" + + ``` py + import capellambse + + model = capellambse.MelodyModel("tests/data/ContextDiagram.aird") + diag = model.by_uuid("b9f9a83c-fb02-44f7-9123-9d86326de5f1").realization_view + diag.render( + "svgdiagram", + depth=3, + search_direction="ALL", + show_owners=True, + layer_sizing="HEIGHT", + ).save(pretty=True) + ``` +
+ +
[CDB] Realization View Diagram of Physical System
+
+ +??? example "Realization View Diagram of `LogicalFunction` `advise Harry` for `layer_sizing=UNION`" + + ``` py + import capellambse + + model = capellambse.MelodyModel("tests/data/ContextDiagram.aird") + diag = model.by_uuid("beaf5ba4-8fa9-4342-911f-0266bb29be45").realization_view + diag.render( + "svgdiagram", + depth=3, + search_direction="ALL", + show_owners=True, + layer_sizing="UNION", + ).save(pretty=True) + ``` +
+ +
[CDB] Realization View Diagram of advise Harry
+
+ +??? example "Realization View Diagram of `PhysicalComponent` `Physical System` for `layer_sizing=UNION`" + + ``` py + import capellambse + + model = capellambse.MelodyModel("tests/data/ContextDiagram.aird") + diag = model.by_uuid("b9f9a83c-fb02-44f7-9123-9d86326de5f1").realization_view + diag.render( + "svgdiagram", + depth=3, + search_direction="ALL", + show_owners=True, + layer_sizing="UNION", + ).save(pretty=True) + ``` +
+ +
[CDB] Realization View Diagram of Physical System
+
+ +??? example "Realization View Diagram of `LogicalFunction` `advise Harry` for `layer_sizing=INDIVIDUAL`" + + ``` py + import capellambse + + model = capellambse.MelodyModel("tests/data/ContextDiagram.aird") + diag = model.by_uuid("beaf5ba4-8fa9-4342-911f-0266bb29be45").realization_view + diag.render( + "svgdiagram", + depth=3, + search_direction="ALL", + show_owners=True, + layer_sizing="INDIVIDUAL", + ).save(pretty=True) + ``` +
+ +
[CDB] Realization View Diagram of advise Harry
+
+ +??? example "Realization View Diagram of `PhysicalComponent` `Physical System` for `layer_sizing=INDIVIDUAL`" + + ``` py + import capellambse + + model = capellambse.MelodyModel("tests/data/ContextDiagram.aird") + diag = model.by_uuid("b9f9a83c-fb02-44f7-9123-9d86326de5f1").realization_view + diag.render( + "svgdiagram", + depth=3, + search_direction="ALL", + show_owners=True, + layer_sizing="INDIVIDUAL", + ).save(pretty=True) + ``` +
+ +
[CDB] Realization View Diagram of Physical System
+
??? bug "Alignment of diagram elements" diff --git a/docs/tree_view.md b/docs/tree_view.md index ee7de1f4..654b6185 100644 --- a/docs/tree_view.md +++ b/docs/tree_view.md @@ -36,7 +36,7 @@ ELK. The available options are: - mr.tree - ... Have a look for [all available ELK algorithms](https://eclipse.dev/elk/reference/algorithms.html). 3. direction - The flow direction for the ELK Layered algortihm. - - DOWN (DEFAULT) + - DOWN (default) - UP - RIGHT - LEFT diff --git a/tests/test_realization_views.py b/tests/test_realization_views.py index 5c27207b..f3046c52 100644 --- a/tests/test_realization_views.py +++ b/tests/test_realization_views.py @@ -21,13 +21,13 @@ def test_tree_view_gets_rendered_successfully( @pytest.mark.parametrize("uuid", [TEST_FNC_UUID, TEST_CMP_UUID]) -@pytest.mark.parametrize("depth", list(range(1, 4))) @pytest.mark.parametrize("search_direction", ["ABOVE", "BELOW"]) @pytest.mark.parametrize("show_owners", [True, False]) -@pytest.mark.parametrize("layer_sizing", ["UNION", "WIDTH", "HEIGHT"]) +@pytest.mark.parametrize( + "layer_sizing", ["WIDTH", "UNION", "HEIGHT", "INDIVIDUAL"] +) def test_tree_view_renders_with_additional_params( model: capellambse.MelodyModel, - depth: int, search_direction: str, show_owners: bool, layer_sizing: str, @@ -39,7 +39,7 @@ def test_tree_view_renders_with_additional_params( assert diag.render( "svgdiagram", - depth=depth, + depth=3, search_direction=search_direction, show_owners=show_owners, layer_sizing=layer_sizing,