Rendering networkx graphs or graphml files via Mermaid

Using python and networkx, you may create some beautiful graphs and store them as graphml file:

graph = nx.DiGraph()
graph.add_node('Node1')
graph.add_node('Node2')
graph.add_node('Node3')
graph.add_node('Node4')
graph.add_edge('Node1', 'Node2')
graph.add_edge('Node1', 'Node3')
graph.add_edge('Node2', 'Node4')
graph.add_edge('Node3', 'Node4')
nx.write_graphml(graph, 'dependency.graphml')

This will give us the following graphml:

<graphml xmlns=http://graphml.graphdrawing.org/xmlns xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd>
  <graph edgedefault=directed>
    <node id=Node1 />
    <node id=Node3 />
    <node id=Node2 />
    <node id=Node4 />
    <edge source=Node1 target=Node3 />
    <edge source=Node1 target=Node2 />
    <edge source=Node3 target=Node4 />
    <edge source=Node2 target=Node4 />
  </graph>
</graphml>

Unfortunately, rendering them the standard way by using draw and Graphviz is producing a bitmap file that I do not want to include in my documentation. For example:

graph = nx.read_graphml(path)
pos = graphviz_layout(graph, prog='dot')
nx.draw(graph, pos, with_labels=True)
plt.show()

Will look like:

Instead of a PNG file, I would rather have the graph as mermaid to include it into my markdown based documentation. A quick conversion may be done in a bash script via:

function convert
{
    echo 'graph TD;'
    xml_grep 'edge' ${1} | grep -P 'edge.*source' | sed -nr 's/.*=\(.*)\.*\(.*)\.*/\1-->\2/p'
}

echo '```mermaid'
convert ${1}
echo '```'

The resulting graph and the representation rendered by mermaid will look like:

graph TD;
Node1-->Node3
Node1-->Node2
Node3-->Node4
Node2-->Node4

To improve the script further, we will now add a view functionality by calling the mermaid-live-editor to present the diagram:

function view
{
    local DATA
    DATA=$(echo -n '{code:';convert ${1} | sed -z 's/\n/\\n/g;s/\\n$/\n/' ;echo -n ',mermaid:{theme:default}}')
    DATA=$(echo ${DATA} | base64 | tr '+' '-')
    xdg-open 'https://mermaidjs.github.io/mermaid-live-editor/#/view/'${DATA}
}

This will add the live-editor header and footer and encode it with base64 before calling the web browser. The translate replacing the plus to minus characters is necessary because + has a special meaning within a URL. The resulting URL will look like:

https://mermaidjs.github.io/mermaid-live-editor/#/view/eyJjb2RlIjoiZ3JhcGggVEQ7XG5Ob2RlMS0tPk5vZGUzXG5Ob2RlMS0tPk5vZGUyXG5Ob2RlMy0tPk5vZGU0XG5Ob2RlMi0tPk5vZGU0ICIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In19Cg==

Which you can try here.

You can find the full example scripts with my GitHub repository.

Limitations:
Graphml usually contains a lot more elements like shapes and labels. This example completely ignores them and uses only the edge information displaying the node-id as the label. This is fine for a quick result, but usually, the id is not meant to label something, only to identify the node. Most professional graphml tools will likely change your ids at some point within the workflow, so be warned.

Further reading: Graphml Primer