Logo
  • Home

Tutorials

  • Your first diagram
  • Explore workflow diagrams
    • 1. Parsing
    • 2. PlantUML diagrams
      • 2.1 Activity diagram
      • 2.2 Component diagram
      • 2.3 Class diagram
      • 2.4 Sequence diagram
      • 2.5 State diagram

How-to guides

  • Convert workflows
  • Render with Python
  • Migrate the CLI

Reference

  • Command-line plugin
  • Python API

Explanation

  • How conversion works
CWL to PlantUML
  • Tutorials
  • Explore workflow diagrams
  • Edit on Transpiler-Mate/cwl2puml

Explore workflow diagrams¶

Follow this notebook to load a conditional workflow and compare five diagram types. Start with your first diagram if you are new to the Python API.

To run the notebook, use a Python 3.10+ Jupyter kernel. The installation cell requires package-index access; loading the workflow and rendering images require access to GitHub and the PlantUML server. The documentation site displays saved outputs without executing these requests.

The example uses the conditional-workflows CWL document.

In [1]:
Copied!
%pip install "cwl2puml>=0.48.0" "cwl-loader>=0.27.0" Pillow
%pip install "cwl2puml>=0.48.0" "cwl-loader>=0.27.0" Pillow
Requirement already satisfied: cwl-loader in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (0.25.0)
Requirement already satisfied: cwl-upgrader==1.2.15 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-loader) (1.2.15)
Requirement already satisfied: cwl-utils>=0.43 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-loader) (0.43)
Requirement already satisfied: loguru==0.7.3 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-loader) (0.7.3)
Requirement already satisfied: ruamel.yaml<0.20,>=0.16.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-upgrader==1.2.15->cwl-loader) (0.19.1)
Requirement already satisfied: schema_salad in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-upgrader==1.2.15->cwl-loader) (8.10.20260825112551)
Requirement already satisfied: packaging in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-utils>=0.43->cwl-loader) (26.3)
Requirement already satisfied: rdflib in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-utils>=0.43->cwl-loader) (7.6.0)
Requirement already satisfied: requests in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-utils>=0.43->cwl-loader) (2.34.2)
Requirement already satisfied: typing-extensions>=4.10.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from cwl-utils>=0.43->cwl-loader) (4.16.0)
Requirement already satisfied: mistune<3.4,>=3.3.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from schema_salad->cwl-upgrader==1.2.15->cwl-loader) (3.3.4)
Requirement already satisfied: CacheControl<0.15,>=0.13.1 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from CacheControl[filecache]<0.15,>=0.13.1->schema_salad->cwl-upgrader==1.2.15->cwl-loader) (0.14.4)
Requirement already satisfied: mypy_extensions in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from schema_salad->cwl-upgrader==1.2.15->cwl-loader) (1.1.0)
Requirement already satisfied: rich-argparse in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from schema_salad->cwl-upgrader==1.2.15->cwl-loader) (1.8.0)
Requirement already satisfied: msgpack<2.0.0,>=0.5.2 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from CacheControl<0.15,>=0.13.1->CacheControl[filecache]<0.15,>=0.13.1->schema_salad->cwl-upgrader==1.2.15->cwl-loader) (1.2.2)
Requirement already satisfied: filelock>=3.8.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from CacheControl[filecache]<0.15,>=0.13.1->schema_salad->cwl-upgrader==1.2.15->cwl-loader) (3.32.6)
Requirement already satisfied: pyparsing<4,>=2.1.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from rdflib->cwl-utils>=0.43->cwl-loader) (3.3.2)
Requirement already satisfied: charset_normalizer<4,>=2 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from requests->cwl-utils>=0.43->cwl-loader) (3.5.1)
Requirement already satisfied: idna<4,>=2.5 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from requests->cwl-utils>=0.43->cwl-loader) (3.19)
Requirement already satisfied: urllib3<3,>=1.26 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from requests->cwl-utils>=0.43->cwl-loader) (2.7.0)
Requirement already satisfied: certifi>=2023.5.7 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from requests->cwl-utils>=0.43->cwl-loader) (2026.7.22)
Requirement already satisfied: rich>=11.0.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from rich-argparse->schema_salad->cwl-upgrader==1.2.15->cwl-loader) (15.0.0)
Requirement already satisfied: markdown-it-py>=2.2.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from rich>=11.0.0->rich-argparse->schema_salad->cwl-upgrader==1.2.15->cwl-loader) (4.2.0)
Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from rich>=11.0.0->rich-argparse->schema_salad->cwl-upgrader==1.2.15->cwl-loader) (2.21.0)
Requirement already satisfied: mdurl~=0.1 in /home/stripodi/.local/share/hatch/env/virtual/cwl2puml/oge6zDjU/cwl2puml/lib/python3.12/site-packages (from markdown-it-py>=2.2.0->rich>=11.0.0->rich-argparse->schema_salad->cwl-upgrader==1.2.15->cwl-loader) (0.1.2)
Note: you may need to restart the kernel to use updated packages.

1. Parsing¶

It is needed to read first a CWL document from a remote public URL:

In [2]:
Copied!
from collections.abc import Mapping

from cwl_loader import load_cwl_from_location
from cwl_loader.utils import to_index
from cwl_utils.parser import Process

cwl_document: Process | list[Process] = load_cwl_from_location('https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl')
cwl_index: Mapping[str, Process] = to_index(cwl_document) if isinstance(cwl_document, list) else to_index([cwl_document])
from collections.abc import Mapping from cwl_loader import load_cwl_from_location from cwl_loader.utils import to_index from cwl_utils.parser import Process cwl_document: Process | list[Process] = load_cwl_from_location('https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl') cwl_index: Mapping[str, Process] = to_index(cwl_document) if isinstance(cwl_document, list) else to_index([cwl_document])
2026-09-15 19:17:31.145 | DEBUG    | cwl_loader:load_cwl_from_location:368 - Loading CWL document from https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl...
2026-09-15 19:17:31.581 | DEBUG    | cwl_loader:_load_cwl_from_stream:371 - Reading stream from https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl...
2026-09-15 19:17:31.593 | DEBUG    | cwl_loader:load_cwl_from_stream:338 - CWL data of type <class 'ruamel.yaml.comments.CommentedMap'> successfully loaded from stream
2026-09-15 19:17:31.593 | DEBUG    | cwl_loader:load_cwl_from_yaml:261 - No needs to update the Raw CWL document since it targets already the v1.2
2026-09-15 19:17:31.594 | DEBUG    | cwl_loader:load_cwl_from_yaml:265 - Parsing the raw CWL document to the CWL Utils DOM...
2026-09-15 19:17:34.600 | DEBUG    | cwl_loader:load_cwl_from_yaml:274 - Raw CWL document successfully parsed to the CWL Utils DOM!
2026-09-15 19:17:34.601 | DEBUG    | cwl_loader:load_cwl_from_yaml:276 - Dereferencing the steps[].run...
2026-09-15 19:17:34.601 | DEBUG    | cwl_loader._dereference:_dereference_step:143 - Checking if https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl#stac must be externally imported...
2026-09-15 19:17:34.602 | DEBUG    | cwl_loader._dereference:_dereference_step:145 - run_url: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl - uri: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl
2026-09-15 19:17:34.602 | DEBUG    | cwl_loader._dereference:_dereference_step:143 - Checking if https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl#rio_stack must be externally imported...
2026-09-15 19:17:34.602 | DEBUG    | cwl_loader._dereference:_dereference_step:145 - run_url: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl - uri: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl
2026-09-15 19:17:34.602 | DEBUG    | cwl_loader._dereference:_dereference_step:143 - Checking if https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl#rio_warp_stack must be externally imported...
2026-09-15 19:17:34.602 | DEBUG    | cwl_loader._dereference:_dereference_step:145 - run_url: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl - uri: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl
2026-09-15 19:17:34.602 | DEBUG    | cwl_loader._dereference:_dereference_step:143 - Checking if https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl#rio_color must be externally imported...
2026-09-15 19:17:34.602 | DEBUG    | cwl_loader._dereference:_dereference_step:145 - run_url: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl - uri: https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl
2026-09-15 19:17:34.603 | DEBUG    | cwl_loader:load_cwl_from_yaml:285 - steps[].run successfully dereferenced! Dereferencing the FQNs...
2026-09-15 19:17:34.603 | DEBUG    | cwl_loader:load_cwl_from_yaml:289 - CWL document successfully dereferenced! Now verifying steps[].run integrity...
2026-09-15 19:17:34.603 | DEBUG    | cwl_loader:load_cwl_from_yaml:295 - All steps[].run link are resolvable! 
2026-09-15 19:17:34.603 | DEBUG    | cwl_loader:load_cwl_from_yaml:298 - Sorting Process instances by dependencies....
2026-09-15 19:17:34.604 | DEBUG    | cwl_loader:load_cwl_from_yaml:300 - Sorting process is over.
2026-09-15 19:17:34.604 | DEBUG    | cwl_loader:_load_cwl_from_stream:381 - Stream from https://raw.githubusercontent.com/eoap/how-to/refs/heads/main/cwl-workflows/conditional-workflows.cwl successfully load!

2. PlantUML diagrams¶

The samples below show how to render CWL document to a specific PlantUML diagram:

In [3]:
Copied!
from cwl2puml import (
    to_puml,
    DiagramType
)
from cwl_utils.parser import InputEnumSchema
from io import (
    StringIO,
    BytesIO
)
from IPython.display import display_png
from plantuml import deflate_and_encode
from PIL import Image
from urllib.request import urlopen

def render(
    diagram_type: DiagramType,
    debug: bool = False
):
    out = StringIO()
    to_puml(
        cwl_document=cwl_index,
        workflow_id='main', # 'main' by default, but define it for demo purposes
        diagram_type=diagram_type,
        output_stream=out
    )

    clear_output = out.getvalue()

    if debug:
        print(clear_output)

    encoded = deflate_and_encode(clear_output)
    diagram_url = f"https://uml.planttext.com/plantuml/png/{encoded}"

    with urlopen(diagram_url) as url:
        img = Image.open(BytesIO(url.read()))
    display_png(img)
from cwl2puml import ( to_puml, DiagramType ) from cwl_utils.parser import InputEnumSchema from io import ( StringIO, BytesIO ) from IPython.display import display_png from plantuml import deflate_and_encode from PIL import Image from urllib.request import urlopen def render( diagram_type: DiagramType, debug: bool = False ): out = StringIO() to_puml( cwl_document=cwl_index, workflow_id='main', # 'main' by default, but define it for demo purposes diagram_type=diagram_type, output_stream=out ) clear_output = out.getvalue() if debug: print(clear_output) encoded = deflate_and_encode(clear_output) diagram_url = f"https://uml.planttext.com/plantuml/png/{encoded}" with urlopen(diagram_url) as url: img = Image.open(BytesIO(url.read())) display_png(img)

2.1 Activity diagram¶

The activity diagram represents the overall CWL document instructions.

In [4]:
Copied!
render(DiagramType.ACTIVITY)
render(DiagramType.ACTIVITY)
No description has been provided for this image

2.2 Component diagram¶

The component diagram represents the CWL document like chips on a motherboard.

In [5]:
Copied!
render(DiagramType.COMPONENT)
render(DiagramType.COMPONENT)
No description has been provided for this image

2.3 Class diagram¶

The class diagram represents the CWL document like specifications of the previously illustrated chips on a motherboard.

In [6]:
Copied!
render(DiagramType.CLASS)
render(DiagramType.CLASS)
No description has been provided for this image

2.4 Sequence diagram¶

The sequence diagram represents how the previously illustrated chips on a motherboard are triggered and interact with each other.

In [7]:
Copied!
render(DiagramType.SEQUENCE)
render(DiagramType.SEQUENCE)
No description has been provided for this image

2.5 State diagram¶

The state diagram represents the dependencies between the inputs/outputs of the previously illustrated chips on a motherboard.

In [8]:
Copied!
render(DiagramType.STATE)
render(DiagramType.STATE)
No description has been provided for this image
Previous Next

Apache License, Version 2.0

Built with MkDocs using a theme provided by Read the Docs.
Transpiler-Mate/cwl2puml « Previous Next »