Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a script optimally layout a pure hierarchical graphviz/dot graph?

I am about to write a script that generates graphviz/dot graphs with the following two characteristics:

  1. All except one node have excactly one parent node (so, it's a tree).
  2. If two or more node share the sampe parent node, they themselves are in a specific order.

With these characteristics, I'd like my resulting (that is dot-generated graph) to look like so:

  1. No edges should cross
  2. Nodes with the same parent should have the same distance from the graphs top border.
  3. Nodes with the same parent should be drawn from left to right according to their ordering

However, I can't make dot behave the way I'd like. Here's a dot file to demonstrate my problem:

digraph G {

  node [shape=plaintext fontname="Arial"];

  0  [label="zero"      ];
  1  [label="one"       ];
  2  [label="two"       ];
  3  [label="three"     ];
  4  [label="four"      ];
  5  [label="five"      ];
  6  [label="six"       ];
  7  [label="seven"     ];
  8  [label="eight"     ];
  9  [label="nine"      ];
  10 [label="ten"       ];
  11 [label="eleven"    ];
  12 [label="twelve"    ];
  13 [label="thirteen"  ];
  14 [label="fourteen"  ];
  15 [label="fivteen"   ];
  16 [label="sixteen"   ];
  17 [label="seventeen" ];
  18 [label="eighteen"  ];
  19 [label="nineteen"  ];
  20 [label="twenty"    ];
  21 [label="twenty-one"];
  22 [label="twenty-two"];

  0  -> 1  [arrowhead=none];
  1  -> 2  [arrowhead=none];
  2  -> 7  [arrowhead=none];
  7  -> 8  [arrowhead=none];
  8  -> 9  [arrowhead=none];
  8  -> 10 [arrowhead=none];
  9  -> 10 [color="#aaaaaa" constraint=false];
  10 -> 11 [arrowhead=none];
  10 -> 12 [arrowhead=none];
  11 -> 12 [color="#aaaaaa" constraint=false];
  7  -> 13 [arrowhead=none];
  8  -> 13 [color="#aaaaaa" constraint=false];
  13 -> 14 [arrowhead=none];
  7  -> 15 [arrowhead=none];
  13 -> 15 [color="#aaaaaa" constraint=false];
  15 -> 16 [arrowhead=none];
  15 -> 17 [arrowhead=none];
  16 -> 17 [color="#aaaaaa" constraint=false];
  2  -> 3  [arrowhead=none];
  7  -> 3  [color="#aaaaaa" constraint=false];
  3  -> 4  [arrowhead=none];
  2  -> 5  [arrowhead=none];
  3  -> 5  [color="#aaaaaa" constraint=false];
  5  -> 6  [arrowhead=none];
  2  -> 18 [arrowhead=none];
  5  -> 18 [color="#aaaaaa" constraint=false];
  18 -> 19 [arrowhead=none];
  19 -> 20 [arrowhead=none];
  19 -> 21 [arrowhead=none];
  20 -> 21 [color="#aaaaaa" constraint=false];
  18 -> 22 [arrowhead=none];
  19 -> 22 [color="#aaaaaa" constraint=false];
}

results in

Resulting graph

Note, the ordering between siblings is indicated by the grey edges (arrows).

So, for example, I am happy with the seven -> three -> five -> eighteen siblings, since they are drawn from left to right in their correct order (as indicated by the arrows).

But I am unhappy with the siblings eight -> thirteen -> fivteen because their edges cross other edges and because their ordering is not from left to right, as I'd like.

Also, nine -> ten, twenty -> twenty-one and nineteen -> twenty-two are in the wrong direction.

I am aware that I could probably get to a picture as I want if I used additional (invisible) edges and the weight attribute and possibly even more features. But as the graphs (and there are many of those) are generated by a script, I can't do that manually.

So, is there a way to achieve what I want?

like image 800
René Nyffenegger Avatar asked Feb 11 '12 07:02

René Nyffenegger


1 Answers

In this case it's actually very simple: The order of appearance of the nodes in the script does matter. In your script they appear from node 0 to node 22 and are layed out to respect this as much as possible. However, they should appear in the order you added the edges (0,1,2,7,3,5,18, ...). Therefore the simplest solution is to move the block which defines the labels after the block which defines the edges, and you'll get:

ordered graph

No weights, no invisible edges and no invisible nodes.

like image 148
marapet Avatar answered Sep 28 '22 16:09

marapet