Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Mermaid diagram in HTML DAG #4337

Merged
merged 6 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -1226,8 +1226,11 @@ The `run` command is used to execute a local pipeline script or remote pipeline
`-with-conda`
: Use the specified Conda environment package or file (must end with `.yml` or `.yaml`)

`-with-dag` (`dag-<timestamp>.dot`)
`-with-dag` (`dag-<timestamp>.html`)
: Create pipeline DAG file.
: :::{versionchanged} 23.10.0
The default format was changed from `dot` to `html`.
:::

`-with-docker`
: Enable process execution in a Docker container.
Expand Down
18 changes: 13 additions & 5 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,25 +511,33 @@ The `dag` scope controls the workflow diagram generated by Nextflow.
The following settings are available:

`dag.enabled`
: When `true` turns on the generation of the DAG file (default: `false`).
: When `true` enables the generation of the DAG file (default: `false`).

`dag.depth`
: :::{versionadded} 23.10.0
:::
: Controls the maximum depth at which to render sub-workflows (default: no limit; only supported by the Mermaid render).
: *Only supported by the HTML and Mermaid renderers.*
: Controls the maximum depth at which to render sub-workflows (default: no limit).

`dag.direction`
: :::{versionadded} 23.10.0
:::
: *Only supported by the HTML and Mermaid renderers.*
: Controls the direction of the DAG, can be `'LR'` (left-to-right) or `'TB'` (top-to-bottom) (default: `'TB'`).

`dag.file`
: Graph file name (default: `dag-<timestamp>.dot`).
: Graph file name (default: `dag-<timestamp>.html`).

`dag.overwrite`
: When `true` overwrites any existing DAG file with the same name (default: `false`).

`dag.verbose`
: :::{versionadded} 23.10.0
:::
: When `false`, channel names are omitted, operators are collapsed, and empty workflow inputs are removed (default: `false`; only supported by the Mermaid render).
: *Only supported by the HTML and Mermaid renderers.*
: When `false`, channel names are omitted, operators are collapsed, and empty workflow inputs are removed (default: `false`).

Read the {ref}`dag-visualisation` page to learn more about the execution graph that can be generated by Nextflow.
Read the {ref}`dag-visualisation` page to learn more about the workflow graph that can be generated by Nextflow.

(config-docker)=

Expand Down
2 changes: 1 addition & 1 deletion docs/images/dag.mmd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
flowchart TD
flowchart TB
subgraph " "
v0["Channel.fromFilePairs"]
v1["transcriptome"]
Expand Down
Binary file removed docs/images/dag.png
Binary file not shown.
69 changes: 42 additions & 27 deletions docs/tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Nextflow can create an HTML execution report: a single document which includes m
To enable the creation of this report add the `-with-report` command line option when launching the pipeline execution. For example:

```bash
nextflow run <pipeline name> -with-report [file name]
nextflow run <pipeline> -with-report [file name]
```

The report file name can be specified as an optional parameter following the report option.
Expand Down Expand Up @@ -151,7 +151,7 @@ Nextflow creates an execution tracing file that contains some useful information
In order to create the execution trace file add the `-with-trace` command line option when launching the pipeline execution. For example:

```bash
nextflow run <pipeline name> -with-trace
nextflow run <pipeline> -with-trace
```

It will create a file named `trace.txt` in the current directory. The content looks like the above example:
Expand Down Expand Up @@ -338,7 +338,7 @@ As each process can spawn many tasks, colors are used to identify those tasks be
To enable the creation of the timeline report add the `-with-timeline` command line option when launching the pipeline execution. For example:

```bash
nextflow run <pipeline name> -with-timeline [file name]
nextflow run <pipeline> -with-timeline [file name]
```

The report file name can be specified as an optional parameter following the timeline option.
Expand All @@ -347,45 +347,60 @@ The report file name can be specified as an optional parameter following the tim

## DAG visualisation

A Nextflow pipeline is implicitly modelled by a direct acyclic graph (DAG). The vertices in the graph represent the pipeline's processes and operators, while the edges represent the data connections (i.e. channels) between them.
A Nextflow pipeline can be represented as a direct acyclic graph (DAG). The vertices in the graph represent the pipeline's processes and operators, while the edges represent the data dependencies (i.e. channels) between them.

The pipeline execution DAG can be outputted by adding the `-with-dag` option to the run command line. It creates a file named `dag.dot` containing a textual representation of the pipeline execution graph in the [DOT format](http://www.graphviz.org/content/dot-language).
To render the workflow DAG, run your pipeline with the `-with-dag` option. By default, it creates a file named `dag-<timestamp>.html` with the workflow DAG rendered as a [Mermaid](https://mermaid.js.org/) diagram.

The execution DAG can be rendered in a different format by specifying an output file name which has an extension corresponding to the required format. For example:
The workflow DAG can be rendered in a different format by specifying an output file name with a different extension based on the desired format. For example:

```bash
nextflow run <script-name> -with-dag flowchart.png
nextflow run <pipeline> -with-dag flowchart.png
```

List of supported file formats:

| Extension | File format |
| --------- | ------------------------------- |
| dot | Graphviz DOT file |
| html | HTML file |
| mmd | Mermaid diagram |
| pdf | PDF file (\*) |
| png | PNG file (\*) |
| svg | SVG file (\*) |
| gexf | Graph Exchange XML file (Gephi) |
:::{versionadded} 22.06.0-edge
You can use the `-preview` option with `-with-dag` to render the workflow DAG without executing any tasks.
:::

:::{note}
File formats marked with "\*" require the [Graphviz](http://www.graphviz.org) tool to be installed.
:::{versionchanged} 23.10.0
The default output format was changed from DOT to HTML.
:::

The DAG produced by Nextflow for the [Unistrap](https://github.com/cbcrg/unistrap/) pipeline:
The following file formats are supported:

```{image} images/dag.png
```
`dot`
: Graphviz [DOT](http://www.graphviz.org/content/dot-language) file

### Mermaid diagram
`gexf`
: Graph Exchange XML file (Gephi)

:::{versionadded} 22.04.0
:::
`html`
: HTML file with Mermaid diagram
: :::{versionchanged} 23.10.0
The HTML format was changed to render a Mermaid diagram instead of a Cytoscape diagram.
:::

Nextflow can render the DAG as a [Mermaid](https://mermaid-js.github.io/) diagram. Mermaid diagrams are particularly useful because they can be embedded in [GitHub Flavored Markdown](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) without having to render them yourself. You can customize the diagram with CSS, and you can even add links! Visit the [Mermaid documentation](https://mermaid-js.github.io/mermaid/#/flowchart?id=styling-and-classes) for details.
`mmd`
: :::{versionadded} 22.04.0
:::
: Mermaid diagram

`pdf`
: *Requires [Graphviz](http://www.graphviz.org) to be installed*
: Graphviz PDF file

`png`
: *Requires [Graphviz](http://www.graphviz.org) to be installed*
: Graphviz PNG file

`svg`
: *Requires [Graphviz](http://www.graphviz.org) to be installed*
: Graphviz SVG file

Here is the Mermaid diagram produced by Nextflow for the [rnaseq-nf](https://github.com/nextflow-io/rnaseq-nf) pipeline (using the [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor/edit) with the `default` theme):

```bash
nextflow run rnaseq-nf -preview -with-dag
```

```{mermaid} images/dag.mmd
```

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,31 @@
*/

package nextflow.dag

import java.nio.file.Path

/**
* Render the DAG in HTML using Cytoscape.js
* to the specified file.
* See http://js.cytoscape.org for more info.
* Render the DAG as a Mermaid diagram embedded in an HTML document.
* See https://mermaid.js.org/ for more info.
*
* @author Paolo Di Tommaso <[email protected]>
* @author Mike Smoot <[email protected]>
* @author Ben Sherman <[email protected]>
*/
class CytoscapeHtmlRenderer implements DagRenderer {
class MermaidHtmlRenderer implements DagRenderer {

@Override
void renderDocument(DAG dag, Path file) {
String tmplPage = readTemplate()
String network = CytoscapeJsRenderer.renderNetwork(dag)
file.text = tmplPage.replaceAll(~/\/\* REPLACE_WITH_NETWORK_DATA \*\//, network)
final template = readTemplate()
final network = new MermaidRenderer().renderNetwork(dag)
file.text = template.replace('REPLACE_WITH_NETWORK_DATA', network)
}

private String readTemplate() {
StringWriter writer = new StringWriter();
def res = CytoscapeHtmlRenderer.class.getResourceAsStream('cytoscape.js.dag.template.html')
final writer = new StringWriter()
final res = MermaidHtmlRenderer.class.getResourceAsStream('mermaid.dag.template.html')
int ch
while( (ch=res.read()) != -1 ) {
writer.append(ch as char);
writer.append(ch as char)
}
writer.toString();
writer.toString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ class MermaidRenderer implements DagRenderer {

private int depth = session.config.navigate('dag.depth', -1) as int

private boolean verbose = session.config.navigate('dag.verbose', false)
private String direction = session.config.navigate('dag.direction', 'TB')

private boolean verbose = session.config.navigate('dag.verbose', false);

{
if( direction !in ['TB','LR'] ) {
log.warn "Invalid configuration property `dag.direction = '$direction'` - use either: 'TB' (top-bottom) or 'LR' (left-right)"
this.direction = 'TB'
}
}

@Override
void renderDocument(DAG dag, Path file) {
Expand Down Expand Up @@ -70,7 +79,7 @@ class MermaidRenderer implements DagRenderer {

// render diagram
def lines = [] as List<String>
lines << "flowchart TD"
lines << "flowchart ${direction}".toString()

// render nodes
renderNodeTree(lines, null, nodeTree)
Expand Down Expand Up @@ -254,23 +263,23 @@ class MermaidRenderer implements DagRenderer {
*
* @param nodeLookup
*/
private Map getNodeTree(Map<DAG.Vertex,Node> nodeLookup) {
private Map<String,Object> getNodeTree(Map<DAG.Vertex,Node> nodeLookup) {
// infer subgraphs of operator nodes
final inferredKeys = inferSubgraphKeys(nodeLookup)

// construct node tree
def nodeTree = [:]
def nodeTree = [:] as Map<String,Object>

for( def node : nodeLookup.values() ) {
final vertex = node.vertex

// determine the vertex subgraph
def keys = []
def keys = [] as List<String>

if( vertex.type == DAG.Type.PROCESS ) {
// extract keys from fully qualified name
final result = getSubgraphKeys(vertex.label)
keys = (List)result[0]
keys = (List<String>)result[0]
node.label = (String)result[1]
}
else if( vertex.type == DAG.Type.OPERATOR ) {
Expand Down Expand Up @@ -306,7 +315,7 @@ class MermaidRenderer implements DagRenderer {
* @param nodeLookup
*/
private Map<Node,List> inferSubgraphKeys(Map<DAG.Vertex,Node> nodeLookup) {
def inferredKeys = [:]
def inferredKeys = [:] as Map<Node,List>
def queue = nodeLookup
.values()
.findAll( n -> n.vertex.type == DAG.Type.OPERATOR ) as List<Node>
Expand All @@ -332,7 +341,7 @@ class MermaidRenderer implements DagRenderer {

// extract keys from fully qualified process name
final keys = process
? getSubgraphKeys(process.vertex.label)[0]
? getSubgraphKeys(process.vertex.label)[0] as List
: []

// save inferred keys
Expand Down
Loading
Loading