Skip to content

[Feature]: Flat Converter from ewoks execution graph to ELK layout graph #17#18

Open
LudoBroche wants to merge 2 commits into
mainfrom
17-feature-flat-converter-from-ewoks-execution-graph-to-elk-layout-graph
Open

[Feature]: Flat Converter from ewoks execution graph to ELK layout graph #17#18
LudoBroche wants to merge 2 commits into
mainfrom
17-feature-flat-converter-from-ewoks-execution-graph-to-elk-layout-graph

Conversation

@LudoBroche

Copy link
Copy Markdown
Member

Tip

Description
Implements convert_ewoks_to_elk_graph, converting a flat ewoks TaskGraph into an ELK JSON layout graph (children with width/height, edges with sources/targets, and layoutOptions sourced from constants.py).

Closes #17

Note

Changes Made

  • layout/elk_converter.py: convert_ewoks_to_elk_graph(ewoks_graph, task_sizes) -> ElkGraph.
  • svg/svg_task_group.py: new SvgTaskGroup(SvgGroup) — SvgClass to group tasks together will allow to perform various operation on all the tasks. For example in this context extract all the tasks sizes.
  • ewoksdraw/__init__.py: added build_svg_task_group(ewoks_graph) -> SvgTaskGroup, hiding the _get_all_node_inputs/_get_all_task_output_names node-to-SvgTask plumbing behind a single call.
  • examples/convert_ewoks_to_elk_graph.py: runnable usage example.
  • tests/test_elk_converter.py: unit tests covering top-level structure, children/task_sizes correspondence, single vs. multi data_mapping edges, empty graphs, counts across all ewokscore example graphs, and the task_sizes mismatch validation.

Warning

Note to Reviewer(s)

  • Scope matches the issue: flat mapping only, no subworkflow expansion, no ELK solver invocation, no SVG rendering of the ELK result.
  • ports were deliberately left out of scope — links are node-to-node, not port-to-port. This converter doesn't need it for layout purposes.
  • task_sizes is a required, caller-supplied input rather than computed internally, so the ELK layout logic stays independent of the svg package.

@LudoBroche LudoBroche self-assigned this Jul 8, 2026
@LudoBroche

Copy link
Copy Markdown
Member Author

Running the example looks like that :

pixi run python examples/convert_ewoks_to_elk_graph.py

Ewoks Graph:

{'task1': {'default_inputs': [{'name': 'a', 'value': 1}],
           'task_identifier': 'ewokscore.tests.examples.tasks.condsumtask.CondSumTask',
           'task_type': 'class'},
 'task2': {'default_inputs': [{'name': 'b', 'value': 1}],
           'task_identifier': 'ewokscore.tests.examples.tasks.condsumtask.CondSumTask',
           'task_type': 'class'},
 'task3': {'default_inputs': [{'name': 'b', 'value': 1}],
           'task_identifier': 'ewokscore.tests.examples.tasks.condsumtask.CondSumTask',
           'task_type': 'class'}}
[('task1',
  'task2',
  {'conditions': [{'source_output': 'too_small', 'value': True}],
   'data_mapping': [{'source_output': 'result', 'target_input': 'a'}]}),
 ('task2',
  'task3',
  {'conditions': [{'source_output': 'too_small', 'value': True}],
   'data_mapping': [{'source_output': 'result', 'target_input': 'a'}]}),
 ('task3',
  'task1',
  {'conditions': [{'source_output': 'too_small', 'value': True}],
   'data_mapping': [{'source_output': 'result', 'target_input': 'a'}]})]

TaskSizes data structure:

{'task1': (54.232, 63.0), 'task2': (54.232, 63.0), 'task3': (54.232, 63.0)}

ELK Graph:

{'children': [{'height': 63.0, 'id': 'task1', 'width': 54.232},
              {'height': 63.0, 'id': 'task2', 'width': 54.232},
              {'height': 63.0, 'id': 'task3', 'width': 54.232}],
 'edges': [{'id': 'edge_task1_task2_0',
            'sources': ['task1'],
            'targets': ['task2']},
           {'id': 'edge_task2_task3_0',
            'sources': ['task2'],
            'targets': ['task3']},
           {'id': 'edge_task3_task1_0',
            'sources': ['task3'],
            'targets': ['task1']}],
 'id': 'root',
 'layoutOptions': {'elk.layered.edgeRouting.splines.mode': 'CONSERVATIVE_SOFT',
                   'org.eclipse.elk.algorithm': 'layered',
                   'org.eclipse.elk.direction': 'RIGHT',
                   'org.eclipse.elk.edgeRouting': 'SPLINES',
                   'org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers': 80,
                   'org.eclipse.elk.spacing.edgeEdge': 20,
                   'org.eclipse.elk.spacing.nodeNode': 60}}

@LudoBroche LudoBroche changed the title Issue #17 - Added elk_converter helper and svg_task_group [Feature]: Flat Converter from ewoks execution graph to ELK layout graph #17 Jul 8, 2026
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.55072% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/ewoksdraw/svg/svg_task_group.py 96.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@LudoBroche LudoBroche requested a review from a team July 8, 2026 17:44
@LudoBroche LudoBroche marked this pull request as ready for review July 9, 2026 07:39

@loichuder loichuder left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First review round.

I don't understand how the introduction of SvgTaskGroup fits in the PR. Is it needed for the Elk layouting?

ELK_SPACING_TASKS = 60
ELK_SPACING_TASK_LAYERS = 80
ELK_SPACING_LINK = 20
ELK_ROUTING_MODE = "CONSERVATIVE_SOFT"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a usecase to access each constant individually?

If not, we could only have ELK_LAYOUT_OPTIONS as a constant.

@@ -0,0 +1 @@
from .elk_converter import convert_ewoks_to_elk_graph # noqa: F401

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah.

Comment on lines +34 to +37
:returns: an ELK graph, i.e.
``{"id": str, "layoutOptions": dict,
"children": [{"id", "width", "height"}, ...],
"edges": [{"id", "sources": [str], "targets": [str]}, ...]}``.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be way better if this was encoded in the type ElkGraph


edges = []
for source, target, link_attrs in ewoks_graph.graph.edges(data=True):
n_mappings = len(link_attrs.get("data_mapping") or []) or 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
n_mappings = len(link_attrs.get("data_mapping") or []) or 1
n_mappings = len(link_attrs.get("data_mapping", [])) or 1

from .svg_group import SvgGroup
from .svg_task import SvgTask

TaskSizes = dict[str, tuple[float, float]]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be best to have a namedtuple instead of tuple[float, float] since it is very easy to confuse width and height if they are only addressed by their index.

@LudoBroche

Copy link
Copy Markdown
Member Author

First review round.

I don't understand how the introduction of SvgTaskGroup fits in the PR. Is it needed for the Elk layouting?

Yes for the routing with ELK I need to have the sizes of eachs tasks box [{task_id:sizes},...].
I though the best API would be to do it from a tasks group class helper function.
Knowing also that in the future we will have to do more (i.e position all the taks correctly).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Flat Converter from ewoks execution graph to ELK layout graph

2 participants