Aligning Subgraphs, Ordering Nodes, and Relocating Edges in Graphviz
Asked Answered
N

3

7

I'm trying to draw a GraphViz graph (using version 2.38.0 (20140413.2041)), and having a lot of trouble getting it to lay out the way I want it. I've tried many different combinations of hidden edges, constraint manipulation, subgraphs (both cluster and non-cluster), etc., and nothing seems to be doing what I want.

Here's my current code:

digraph G {
  subgraph clustera {
    style=invis;rank=same
    A->B->C
  }

  subgraph clusterb {
    style=invis;rank=same;rankdir=LR
    D->E [constraint=false]
  }

  subgraph clusterc {
    style=invis;rank=same
    F->G [constraint=false]
  }

  C -> D
  D -> F  [constraint=false]
  E -> C

  F -> A  [constraint=false]
  F -> C  [constraint=false]
  F -> E  [constraint=false]
}

And here's how it renders with dot -Tpng:

current dot graph

(All the F edges have "constraint" turned off, because almost anything else distorts the graph horribly.)

What I want is:

  • node F above node G
  • F and G more or less centered vertically on the graph
  • F and G to the right of A through E
  • A through E in more or less the arrangement they're in now
  • the edges from F to A, C, and E, and from D to F, following more or less straight lines (i.e. not routing around the right-hand side of the F/G group)
  • as a bonus, I'd kind of like to get A through C to center properly above D and E, but that's less important

(One thing I very much don't want is for F to appear above A, as if it were the root of the graph.)

Here's an approximation of what I'm looking for, laid out by hand in yEd:

yEd graph

Is this doable in GraphViz?

(I should note that I'm perfectly willing to use one of the other GraphViz tools, it's just that dot is the only one I'm at all familiar with.)

Nehemiah answered 7/2, 2015 at 23:54 Comment(0)
A
5

Here's my approach without subgraphs and weigths, only groups to vertically align nodes, and constraint=false as well as dir=back to preserve layout distortion.

digraph G {
  // nodes without a group
  D;
  E;

  // group left side
  node[group=left];
  A -> B -> C -> D;
  C -> E [dir=back];
  D -> E [constraint=false];

  // group right side
  node[group=right];
  F -> G;

  // inter group edges
  F -> C;
  edge [constraint=false];
  D -> F;
  F -> A;
  F -> E;
}

The result can be seen here and corresponds to your approximation.

Awhirl answered 15/2, 2015 at 12:17 Comment(3)
nice! I didn't know group. Only, there is a way to swap D / E ?Groveman
@Groveman To swap D and E, just change the order of the first mention of those nodes (swap the first two lines of the graph and mention E before D).Awhirl
@Awhirl ... I didn't realise the effects of first mention and flow (and controlling them with dir=back and constraint = false)! Amazing to compare the diagram just toggling those two line s "C -> E [dir=back];" and "D -> E [constraint=false]" to "E->C;"! and "D-> E"!Returnable
A
2

Interpreting your requirement with a little freedom you may have a graph without edges crossing

digraph G { rankdir = LR ranksep = 1.2 nodesep = 0.5
  { rank=same A -> B -> C -> D -> E }
  D -> F
  { rank=same F -> G }
  edge [constraint=false]
  E -> C
  F -> A
  F -> C
  F -> E
}

<!--?xml version="1.0" encoding="UTF-8" standalone="no"?-->

<!-- Generated by graphviz version 2.28.0 (20110507.0327)
 -->
<!-- Title: G Pages: 1 -->
<svg width="250pt" height="332pt" viewBox="0.00 0.00 250.29 332.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 328)">
<title>G</title>
<polygon fill="white" stroke="white" points="-4,5 -4,-328 247.294,-328 247.294,5 -4,5"></polygon>
<!-- A -->
<g id="node2" class="node"><title>A</title>
<ellipse fill="none" stroke="black" cx="75.2936" cy="-306" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="75.2936" y="-301.8" font-family="Times,serif" font-size="14.00">A</text>
</g>
<!-- B -->
<g id="node4" class="node"><title>B</title>
<ellipse fill="none" stroke="black" cx="75.2936" cy="-234" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="75.2936" y="-229.8" font-family="Times,serif" font-size="14.00">B</text>
</g>
<!-- A&#45;&gt;B -->
<g id="edge3" class="edge"><title>A-&gt;B</title>
<path fill="none" stroke="black" d="M75.2936,-287.859C75.2936,-279.268 75.2936,-270.677 75.2936,-262.085"></path>
<polygon fill="black" stroke="black" points="78.7937,-262 75.2936,-252 71.7937,-262 78.7937,-262"></polygon>
</g>
<!-- C -->
<g id="node5" class="node"><title>C</title>
<ellipse fill="none" stroke="black" cx="75.2936" cy="-162" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="75.2936" y="-157.8" font-family="Times,serif" font-size="14.00">C</text>
</g>
<!-- B&#45;&gt;C -->
<g id="edge4" class="edge"><title>B-&gt;C</title>
<path fill="none" stroke="black" d="M75.2936,-215.859C75.2936,-207.268 75.2936,-198.677 75.2936,-190.085"></path>
<polygon fill="black" stroke="black" points="78.7937,-190 75.2936,-180 71.7937,-190 78.7937,-190"></polygon>
</g>
<!-- D -->
<g id="node6" class="node"><title>D</title>
<ellipse fill="none" stroke="black" cx="75.2936" cy="-90" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="75.2936" y="-85.8" font-family="Times,serif" font-size="14.00">D</text>
</g>
<!-- C&#45;&gt;D -->
<g id="edge5" class="edge"><title>C-&gt;D</title>
<path fill="none" stroke="black" d="M75.2936,-143.859C75.2936,-135.268 75.2936,-126.677 75.2936,-118.085"></path>
<polygon fill="black" stroke="black" points="78.7937,-118 75.2936,-108 71.7937,-118 78.7937,-118"></polygon>
</g>
<!-- E -->
<g id="node7" class="node"><title>E</title>
<ellipse fill="none" stroke="black" cx="75.2936" cy="-18" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="75.2936" y="-13.8" font-family="Times,serif" font-size="14.00">E</text>
</g>
<!-- D&#45;&gt;E -->
<g id="edge6" class="edge"><title>D-&gt;E</title>
<path fill="none" stroke="black" d="M75.2936,-71.8594C75.2936,-63.2681 75.2936,-54.6768 75.2936,-46.0854"></path>
<polygon fill="black" stroke="black" points="78.7937,-46 75.2936,-36 71.7937,-46 78.7937,-46"></polygon>
</g>
<!-- F -->
<g id="node9" class="node"><title>F</title>
<ellipse fill="none" stroke="black" cx="215.294" cy="-90" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="215.294" y="-85.8" font-family="Times,serif" font-size="14.00">F</text>
</g>
<!-- D&#45;&gt;F -->
<g id="edge8" class="edge"><title>D-&gt;F</title>
<path fill="none" stroke="black" d="M102.575,-90C123.965,-90 154.385,-90 178.082,-90"></path>
<polygon fill="black" stroke="black" points="178.11,-93.5001 188.11,-90 178.11,-86.5001 178.11,-93.5001"></polygon>
</g>
<!-- E&#45;&gt;C -->
<g id="edge13" class="edge"><title>E-&gt;C</title>
<path fill="none" stroke="black" d="M52.7625,-28.3877C36.2645,-37.3556 15.1112,-52.027 5.2936,-72 -1.76453,-86.3591 -1.76453,-93.6409 5.2936,-108 13.4238,-124.54 29.3279,-137.445 43.9243,-146.485"></path>
<polygon fill="black" stroke="black" points="42.3564,-149.621 52.7625,-151.612 45.8691,-143.567 42.3564,-149.621"></polygon>
</g>
<!-- F&#45;&gt;A -->
<g id="edge15" class="edge"><title>F-&gt;A</title>
<path fill="none" stroke="black" d="M204.475,-106.621C185.434,-138.661 141.876,-211.016 102.294,-270 99.7106,-273.849 96.9068,-277.876 94.1283,-281.785"></path>
<polygon fill="black" stroke="black" points="91.1877,-279.879 88.1817,-290.038 96.8671,-283.971 91.1877,-279.879"></polygon>
</g>
<!-- F&#45;&gt;C -->
<g id="edge17" class="edge"><title>F-&gt;C</title>
<path fill="none" stroke="black" d="M193.492,-100.853C170.263,-112.973 132.471,-132.69 106.103,-146.447"></path>
<polygon fill="black" stroke="black" points="104.2,-143.492 96.9536,-151.221 107.438,-149.698 104.2,-143.492"></polygon>
</g>
<!-- F&#45;&gt;E -->
<g id="edge19" class="edge"><title>F-&gt;E</title>
<path fill="none" stroke="black" d="M193.492,-79.1472C170.263,-67.0274 132.471,-47.31 106.103,-33.5528"></path>
<polygon fill="black" stroke="black" points="107.438,-30.3018 96.9536,-28.7791 104.2,-36.5079 107.438,-30.3018"></polygon>
</g>
<!-- G -->
<g id="node12" class="node"><title>G</title>
<ellipse fill="none" stroke="black" cx="215.294" cy="-18" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="215.294" y="-13.8" font-family="Times,serif" font-size="14.00">G</text>
</g>
<!-- F&#45;&gt;G -->
<g id="edge11" class="edge"><title>F-&gt;G</title>
<path fill="none" stroke="black" d="M215.294,-71.8594C215.294,-63.2681 215.294,-54.6768 215.294,-46.0854"></path>
<polygon fill="black" stroke="black" points="218.794,-46 215.294,-36 211.794,-46 218.794,-46"></polygon>
</g>
</g>
</svg>

alternatively with bottom nodes on the same height

digraph G { rankdir = LR ranksep = 1.2 nodesep = 0.5
  { rank=same A -> B -> C -> D }
  D -> E
  B -> F [style=invis]
  { rank=same F -> G }
  edge [constraint=false]
  E -> C
  F -> A
  F:w -> C
  D -> F
  F:e -> E:e
}

<!--?xml version="1.0" encoding="UTF-8" standalone="no"?-->

<!-- Generated by graphviz version 2.28.0 (20110507.0327)
 -->
<!-- Title: G Pages: 1 -->
<svg width="250pt" height="260pt" viewBox="0.00 0.00 250.27 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">
<title>G</title>
<polygon fill="white" stroke="white" points="-4,5 -4,-256 247.27,-256 247.27,5 -4,5"></polygon>
<!-- A -->
<g id="node2" class="node"><title>A</title>
<ellipse fill="none" stroke="black" cx="27" cy="-234" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="27" y="-229.8" font-family="Times,serif" font-size="14.00">A</text>
</g>
<!-- B -->
<g id="node4" class="node"><title>B</title>
<ellipse fill="none" stroke="black" cx="27" cy="-162" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="27" y="-157.8" font-family="Times,serif" font-size="14.00">B</text>
</g>
<!-- A&#45;&gt;B -->
<g id="edge3" class="edge"><title>A-&gt;B</title>
<path fill="none" stroke="black" d="M27,-215.859C27,-207.268 27,-198.677 27,-190.085"></path>
<polygon fill="black" stroke="black" points="30.5001,-190 27,-180 23.5001,-190 30.5001,-190"></polygon>
</g>
<!-- C -->
<g id="node5" class="node"><title>C</title>
<ellipse fill="none" stroke="black" cx="27" cy="-90" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="27" y="-85.8" font-family="Times,serif" font-size="14.00">C</text>
</g>
<!-- B&#45;&gt;C -->
<g id="edge4" class="edge"><title>B-&gt;C</title>
<path fill="none" stroke="black" d="M27,-143.859C27,-135.268 27,-126.677 27,-118.085"></path>
<polygon fill="black" stroke="black" points="30.5001,-118 27,-108 23.5001,-118 30.5001,-118"></polygon>
</g>
<!-- F -->
<g id="node10" class="node"><title>F</title>
<ellipse fill="none" stroke="black" cx="167" cy="-162" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="167" y="-157.8" font-family="Times,serif" font-size="14.00">F</text>
</g>
<!-- B&#45;&gt;F -->
<!-- D -->
<g id="node6" class="node"><title>D</title>
<ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="27" y="-13.8" font-family="Times,serif" font-size="14.00">D</text>
</g>
<!-- C&#45;&gt;D -->
<g id="edge5" class="edge"><title>C-&gt;D</title>
<path fill="none" stroke="black" d="M27,-71.8594C27,-63.2681 27,-54.6768 27,-46.0854"></path>
<polygon fill="black" stroke="black" points="30.5001,-46 27,-36 23.5001,-46 30.5001,-46"></polygon>
</g>
<!-- E -->
<g id="node8" class="node"><title>E</title>
<ellipse fill="none" stroke="black" cx="167" cy="-18" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="167" y="-13.8" font-family="Times,serif" font-size="14.00">E</text>
</g>
<!-- D&#45;&gt;E -->
<g id="edge7" class="edge"><title>D-&gt;E</title>
<path fill="none" stroke="black" d="M54.2816,-18C75.6717,-18 106.092,-18 129.789,-18"></path>
<polygon fill="black" stroke="black" points="129.816,-21.5001 139.816,-18 129.816,-14.5001 129.816,-21.5001"></polygon>
</g>
<!-- D&#45;&gt;F -->
<g id="edge20" class="edge"><title>D-&gt;F</title>
<path fill="none" stroke="black" d="M42.2487,-32.8682C66.5235,-58.1984 116.031,-109.859 144.521,-139.587"></path>
<polygon fill="black" stroke="black" points="142.176,-142.199 151.622,-146.997 147.23,-137.355 142.176,-142.199"></polygon>
</g>
<!-- E&#45;&gt;C -->
<g id="edge14" class="edge"><title>E-&gt;C</title>
<path fill="none" stroke="black" d="M145.199,-28.8528C121.969,-40.9726 84.1776,-60.69 57.8095,-74.4472"></path>
<polygon fill="black" stroke="black" points="55.9069,-71.4921 48.66,-79.2209 59.1449,-77.6982 55.9069,-71.4921"></polygon>
</g>
<!-- F&#45;&gt;A -->
<g id="edge16" class="edge"><title>F-&gt;A</title>
<path fill="none" stroke="black" d="M145.199,-172.853C121.969,-184.973 84.1776,-204.69 57.8095,-218.447"></path>
<polygon fill="black" stroke="black" points="55.9069,-215.492 48.66,-223.221 59.1449,-221.698 55.9069,-215.492"></polygon>
</g>
<!-- F&#45;&gt;C -->
<g id="edge18" class="edge"><title>F:w-&gt;C</title>
<path fill="none" stroke="black" d="M140,-162C103.148,-162 68.7605,-134.078 48.0591,-113.01"></path>
<polygon fill="black" stroke="black" points="50.4865,-110.483 41.0722,-105.623 45.4009,-115.293 50.4865,-110.483"></polygon>
</g>
<!-- F&#45;&gt;E -->
<g id="edge22" class="edge"><title>F:e-&gt;E:e</title>
<path fill="none" stroke="black" d="M194,-162C254.5,-162 257.809,-33.3193 203.926,-19.2449"></path>
<polygon fill="black" stroke="black" points="204.358,-15.7717 194,-18 203.487,-22.7173 204.358,-15.7717"></polygon>
</g>
<!-- G -->
<g id="node13" class="node"><title>G</title>
<ellipse fill="none" stroke="black" cx="167" cy="-90" rx="27" ry="18"></ellipse>
<text text-anchor="middle" x="167" y="-85.8" font-family="Times,serif" font-size="14.00">G</text>
</g>
<!-- F&#45;&gt;G -->
<g id="edge12" class="edge"><title>F-&gt;G</title>
<path fill="none" stroke="black" d="M167,-143.859C167,-135.268 167,-126.677 167,-118.085"></path>
<polygon fill="black" stroke="black" points="170.5,-118 167,-108 163.5,-118 170.5,-118"></polygon>
</g>
</g>
</svg>
Aggressive answered 9/3, 2015 at 12:18 Comment(0)
A
1

Only needed one cluster to keep the ABCDE group aligned. Backward directional arrows and weighting helped a lot.

digraph g
{
    subgraph cluster_subCDE {
        color=invis;
        A; B; C; D; E;
    }
    A->B [weight=10];
    A->F [dir=back];
    B->C [weight=10];
    F->C;
    C->E [color=invis];
    C->D;
    D->E [constraint=false];
    E->C;
    F->G [weight=10];
    F->D [dir=back];
    F->E;
}

Agnesagnese answered 10/2, 2015 at 5:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.