Search code examples
graphvizdotdirected-acyclic-graphs

Maintain horizontal ordering of nodes in Graphviz


I have the following the dot file contents:

digraph G {
    start -> {a0, b0} -> end;
    start -> c0 -> c1 -> c2 -> end;
    start -> d0 -> d1 -> d2 -> end;
    start -> {e0, f0} -> end;

    subgraph cluster_test {
        {
            rank = same;
            a0; b0; c0; d0; e0; f0;
        }

        {
            rank = same;
            c1; d1;
        }

        {
            rank = same;
            c2; d2;
        }
    }
}

The resulting graph is as follows: enter image description here

What I want is for the ordering of level 0 nodes to be maintained, i.e, I want a0, b0 to come before c0, d0 in the horizontal direction.

How do I achieve this?


Solution

  • Empty nodes, edges with weight and explicit ordering of the top row in the cluster helps. See code below with annotations:

    digraph so 
    {
        // we define all nodes in the beginning, before edges and clusters
        // may not be essential but I think it's good practice
        start
        a0 b0 c0 d0 e0 f0
        c1 d1 
        c2 d2
        end
        // we define "empty" nodes that can be used to route the edges
        node[ shape = point, height = 0 ];
        ax bx ex fx
    
        subgraph cluster_test 
        {
            // we need to keep explicit order of the top nodes in the cluster
            { rank = same; a0 -> b0 -> c0 -> d0 -> e0 ->  f0[ style = invis ] }
            // the original layout in the cluster, empty nodes added at the bottom
            { rank = same; c1 d1 }
            { rank = same; ax bx c2 d2 ex fx }
            c0 -> c1 -> c2;
            d0 -> d1 -> d2;
            // routing through invisible nodes keeps the position of all other nodes
            // edges with no arrowheads, strong weight to keep it vertical
            edge[ dir = none, weight = 10 ]
            a0 -> ax;
            b0 -> bx;
            e0 -> ex;
            f0 -> fx;
        }
    
        // connecting to the start and end node, normal edges again
        edge[ weight = 1, dir = forw ];
        start -> { a0 b0 c0 d0 e0 f0 }
        { ax bx  c2 d2 ex fx } -> end;
    }
    

    which gives you

    enter image description here