Family tree layout with Dot/GraphViz - graphviz

I am trying to draw a family tree with Dot and GraphViz.
This is what I currently have:
# just graph set-up
digraph simpsons {
ratio = "auto"
mincross = 2.0
# draw some nodes
"Abraham" [shape=box, regular=1, color="blue"] ;
"Mona" [shape=box, regular=1, color="pink"] ;
"Clancy" [shape=box, regular=1, color="blue"] ;
"Jackeline" [shape=box, regular=1, color="pink"] ;
"Herb" [shape=box, regular=1, color="blue"] ;
"Homer" [shape=box, regular=1, color="blue"] ;
"Marge" [shape=box, regular=1, color="pink"] ;
"Patty" [shape=box, regular=1, color="pink"] ;
"Selma" [shape=box, regular=1, color="pink"] ;
"Bart" [shape=box, regular=1, color="blue"] ;
"Lisa" [shape=box, regular=1, color="pink"] ;
"Maggie" [shape=box, regular=1, color="pink"] ;
"Ling" [shape=box, regular=1, color="blue"] ;
# creating tiny nodes w/ no label, no color
"ParentsHomer" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
"ParentsMarge" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
"ParentsBart" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
# draw the edges
"Abraham" -> "ParentsHomer" [dir=none, weight=1] ;
"Mona" -> "ParentsHomer" [dir=none, weight=1] ;
"ParentsHomer" -> "Homer" [dir=none, weight=2] ;
"ParentsHomer" -> "Herb" [dir=none, weight=2] ;
"Clancy" -> "ParentsMarge" [dir=none, weight=1] ;
"Jackeline" -> "ParentsMarge" [dir=none, weight=1] ;
"ParentsMarge" -> "Marge" [dir=none, weight=2] ;
"ParentsMarge" -> "Patty" [dir=none, weight=2] ;
"ParentsMarge" -> "Selma" [dir=none, weight=2] ;
"Homer" -> "ParentsBart" [dir=none, weight=1] ;
"Marge" -> "ParentsBart" [dir=none, weight=1] ;
"ParentsBart" -> "Bart" [dir=none, weight=2] ;
"ParentsBart" -> "Lisa" [dir=none, weight=2] ;
"ParentsBart" -> "Maggie" [dir=none, weight=2] ;
"Selma" -> "Ling" [dir=none, weight=2] ;
}
If I run this through dot (dot simpsons.dot -Tsvg > simpsons.svg),
I get the following layout:
However, I'd like the edges to be more "family tree"-like: a T-junction between two married persons with the vertical line of the T again branching in an upside-down T-junction with small subdivisions for each of the children, like this mock-up, done in KolourPaint:
What is the dot syntax that I have to use to achieve this?

Try the following:
digraph simpsons {
subgraph Generation0 {
rank = same
Abraham [shape = box, color = blue]
Mona [shape = box, color = pink]
AbrahamAndMona [shape = point]
Abraham -> AbrahamAndMona [dir = none]
AbrahamAndMona -> Mona [dir = none]
Clancy [shape = box, color = blue]
Jackeline [shape = box, color = pink]
ClancyAndJackeline [shape = point]
Clancy -> ClancyAndJackeline [dir = none]
ClancyAndJackeline -> Jackeline [dir = none]
}
subgraph Generation0Sons {
rank = same
AbrahamAndMonaSons [shape = point]
HerbSon [shape = point]
HomerSon [shape = point]
HerbSon -> AbrahamAndMonaSons [dir = none]
HomerSon -> AbrahamAndMonaSons [dir = none]
MargeSon [shape = point]
PattySon [shape = point]
SelmaSon [shape = point]
MargeSon -> PattySon [dir = none]
PattySon -> SelmaSon [dir = none]
}
AbrahamAndMona -> AbrahamAndMonaSons [dir = none]
ClancyAndJackeline -> PattySon [dir = none]
subgraph Generation1 {
rank = same
Herb [shape = box, color = blue]
Homer [shape = box, color = blue]
Marge [shape = box, color = pink]
Patty [shape = box, color = pink]
Selma [shape = box, color = pink]
HomerAndMarge [shape = point]
Homer -> HomerAndMarge [dir = none]
Marge -> HomerAndMarge [dir = none]
}
HerbSon -> Herb [dir = none]
HomerSon -> Homer [dir = none]
MargeSon -> Marge [dir = none]
PattySon -> Patty [dir = none]
SelmaSon -> Selma [dir = none]
subgraph Generation1Sons {
rank = same
BartSon [shape = point]
LisaSon [shape = point]
MaggieSon [shape = point]
BartSon -> LisaSon [dir = none]
LisaSon -> MaggieSon [dir = none]
}
HomerAndMarge -> LisaSon [dir = none]
subgraph Generation2 {
rank = same
Bart [shape = box, color = blue]
Lisa [shape = box, color = pink]
Maggie [shape = box, color = pink]
Ling [shape = box, color = blue]
}
Selma -> Ling [dir = none]
BartSon -> Bart [dir = none]
LisaSon -> Lisa [dir = none]
MaggieSon -> Maggie [dir = none]
}
Produces:

I don’t think you can take an arbitrary family tree and auto-generate a dot file where it always looks good in GraphViz.
But I think you can always make it look good if you:
Use the rank=same other answers mentioned to get the 'T' connections
desired by the OP
Use the ordering trick Brian Blank did to prevent weird lines
Assume no second marriages and half-siblings
Draw only a
subset of the tree that obeys the following rules:
Let S be the “center” person
If S has siblings, make sure S is to right of all of them.
If S has a spouse and the spouse has siblings, make sure the spouse is to the left of all his/her siblings.
Don’t show nephews, nieces, aunts or uncles of S or S’s spouse
Don’t show spouses of siblings
Don’t show spouses of spouse’s siblings
Show children of S, but not their spouses or children
Show parents of S and parents of spouse
This will end up showing no more than 3 generations at once, with S in the middle generation.
In the picture below S=Homer (slightly modified from Brian Blank's version):
digraph G {
edge [dir=none];
node [shape=box];
graph [splines=ortho];
"Herb" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Homer" [shape=box, regular=0, color="blue", style="bold, filled" fillcolor="lightblue"] ;
"Marge" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Clancy" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Jackeline" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Abraham" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Mona" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Patty" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Selma" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Bart" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Lisa" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Maggie" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
a1 [shape=diamond,label="",height=0.25,width=0.25];
b1 [shape=circle,label="",height=0.01,width=0.01];
b2 [shape=circle,label="",height=0.01,width=0.01];
b3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Abraham -> a1 -> Mona};
{rank=same; b1 -> b2 -> b3};
{rank=same; Herb; Homer};
a1 -> b2
b1 -> Herb
b3 -> Homer
p1 [shape=diamond,label="",height=0.25,width=0.25];
q1 [shape=circle,label="",height=0.01,width=0.01];
q2 [shape=circle,label="",height=0.01,width=0.01];
q3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Homer -> p1 -> Marge};
{rank=same; q1 -> q2 -> q3};
{rank=same; Bart; Lisa; Maggie};
p1 -> q2;
q1 -> Bart;
q2 -> Lisa;
q3 -> Maggie;
x1 [shape=diamond,label="",height=0.25,width=0.25];
y1 [shape=circle,label="",height=0.01,width=0.01];
y2 [shape=circle,label="",height=0.01,width=0.01];
y3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Clancy -> x1 -> Jackeline};
{rank=same; y1 -> y2 -> y3};
{rank=same; Patty; Selma; Marge};
x1 -> y2;
y1 -> Marge;
y2 -> Patty;
y3 -> Selma;
}
This yields the following tree by GraphViz (with annotations I added with Power Point):

Gramps (www.gramps-project.org) generates dot files for family trees, with or without marriage nodes.
There is also a way to see this in the Gramps interface itself. http://gramps-project.org/wiki/index.php?title=Graph_View
So I would say, look at the output of your family tree as created by Gramps

Although you can't control node placement, I found you can help node placement by ordering the nodes in a different order. I re-ordered some of the nodes as shown below and got a graph that produced no cross-overs.
The following code:
digraph G {
edge [dir=none];
node [shape=box];
"Herb" [shape=box, regular=1, color="blue"] ;
"Homer" [shape=box, regular=1, color="blue"] ;
"Marge" [shape=box, regular=1, color="pink"] ;
"Clancy" [shape=box, regular=1, color="blue"] ;
"Jackeline" [shape=box, regular=1, color="pink"] ;
"Abraham" [shape=box, regular=1, color="blue"] ;
"Mona" [shape=box, regular=1, color="pink"] ;
"Patty" [shape=box, regular=1, color="pink"] ;
"Selma" [shape=box, regular=1, color="pink"] ;
"Bart" [shape=box, regular=1, color="blue"] ;
"Lisa" [shape=box, regular=1, color="pink"] ;
"Maggie" [shape=box, regular=1, color="pink"] ;
"Ling" [shape=box, regular=1, color="blue"] ;
a1 [shape=circle,label="",height=0.01,width=0.01];
b1 [shape=circle,label="",height=0.01,width=0.01];
b2 [shape=circle,label="",height=0.01,width=0.01];
b3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Abraham -> a1 -> Mona};
{rank=same; b1 -> b2 -> b3};
{rank=same; Herb; Homer};
a1 -> b2
b1 -> Herb
b3 -> Homer
p1 [shape=circle,label="",height=0.01,width=0.01];
q1 [shape=circle,label="",height=0.01,width=0.01];
q2 [shape=circle,label="",height=0.01,width=0.01];
q3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Homer -> p1 -> Marge};
{rank=same; q1 -> q2 -> q3};
{rank=same; Bart; Lisa; Maggie};
p1 -> q2;
q1 -> Bart;
q2 -> Lisa;
q3 -> Maggie;
x1 [shape=circle,label="",height=0.01,width=0.01];
y1 [shape=circle,label="",height=0.01,width=0.01];
y2 [shape=circle,label="",height=0.01,width=0.01];
y3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Clancy -> x1 -> Jackeline};
{rank=same; y1 -> y2 -> y3};
{rank=same; Marge; Patty; Selma};
{rank=same; Bart; Ling}
x1 -> y2;
y1 -> Marge;
y2 -> Patty;
y3 -> Selma;
Selma -> Ling;
}
now produces this:
I don't fully understand why it's working, but here is the thought process into the changes that I made.
I placed Clancy/Jackeline before Abraham/Mona thinking that they were on the wrong side. This changed the picture, but still wasn't perfect.
I placed Homer/Marge first thinking that the software had to consider these pieces first and maybe place all other nodes relative to Homer/Marge. This further helped, but still wasn't perfect.
Herb was still mis-placed, so I put Herb first so that graphviz might consider placement of herb first.
It worked, but I still can't devise an algorithm that would ensure consistent trees with no overlapping edges. I feel that graphviz should do a better job without these hints. I don't know the algorithm used, but if they consider an objective function to minimize or eliminate overlapping edges, it should be possible to devise a better algorithm.

To do this in graphviz is fairly straightforward; there are a couple of syntax patterns you need:
(i) syntax to represent the line-to-line connection (the "T"-junction in your plots above); (ii) syntax to enforce the hierarchical structure (i.e., nodes of same generation on the same plane on the vertical axis). It's easier to show:
digraph G {
nodesep=0.6;
edge [arrowsize=0.3];
"g1" -> "g2" -> "g3" -> "g4"
{ rank = same;
"g1"; "King"; "ph1"; "Queen";
};
{ rank = same;
"g2"; "ph2"; "ph2L"; "ph2R"; "ph2LL"; "ph2RR"
};
{ rank = same;
"g3"; "ps1"; "ps2"; "pr1"; "pr2"
};
"King" -> "ph1" [arrowsize=0.0];
"ph1" -> "Queen" [arrowsize=0.0];
"ph1" -> "ph2" [arrowsize=0.0];
"ph2LL" -> "ph2L" [arrowsize=0.0];
"ph2L" -> "ph2" [arrowsize=0.0];
"ph2" -> "ph2R" [arrowsize=0.0];
"ph2R" -> "ph2RR" [arrowsize=0.0];
"ph2LL" -> "ps1" [arrowsize=0.0];
"ph2L"-> "pr1" [arrowsize=0.0];
"ph2R" -> "ps2" [arrowsize=0.0];
"ph2RR" -> "pr2" [arrowsize=0.0];
}
The code above will produce the graph below (i omitted the code i used to color the nodes). I left vislble the "guide" on the left (g1->g2....) just to show you how i enforced the positions among nodes of equal rank, you'll probably want to make it invisible in your own plots. Finally, the nodes with the labels beginning with 'ph' are the placeholder nodes for the "T-junctions."

I'm almost there, inspired by an old response on the graphviz-interest mailinglist and doug's answer.
The following code:
digraph G {
edge [dir=none];
node [shape=box];
"Abraham" [shape=box, regular=1, color="blue"] ;
"Mona" [shape=box, regular=1, color="pink"] ;
"Clancy" [shape=box, regular=1, color="blue"] ;
"Jackeline" [shape=box, regular=1, color="pink"] ;
"Herb" [shape=box, regular=1, color="blue"] ;
"Homer" [shape=box, regular=1, color="blue"] ;
"Marge" [shape=box, regular=1, color="pink"] ;
"Patty" [shape=box, regular=1, color="pink"] ;
"Selma" [shape=box, regular=1, color="pink"] ;
"Bart" [shape=box, regular=1, color="blue"] ;
"Lisa" [shape=box, regular=1, color="pink"] ;
"Maggie" [shape=box, regular=1, color="pink"] ;
"Ling" [shape=box, regular=1, color="blue"] ;
a1 [shape=circle,label="",height=0.01,width=0.01];
b1 [shape=circle,label="",height=0.01,width=0.01];
b2 [shape=circle,label="",height=0.01,width=0.01];
b3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Abraham -> a1 -> Mona};
{rank=same; b1 -> b2 -> b3};
{rank=same; Herb; Homer};
a1 -> b2
b1 -> Herb
b3 -> Homer
p1 [shape=circle,label="",height=0.01,width=0.01];
q1 [shape=circle,label="",height=0.01,width=0.01];
q2 [shape=circle,label="",height=0.01,width=0.01];
q3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Homer -> p1 -> Marge};
{rank=same; q1 -> q2 -> q3};
{rank=same; Bart; Lisa; Maggie};
p1 -> q2;
q1 -> Bart;
q2 -> Lisa;
q3 -> Maggie;
x1 [shape=circle,label="",height=0.01,width=0.01];
y1 [shape=circle,label="",height=0.01,width=0.01];
y2 [shape=circle,label="",height=0.01,width=0.01];
y3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Clancy -> x1 -> Jackeline};
{rank=same; y1 -> y2 -> y3};
{rank=same; Marge; Patty; Selma};
{rank=same; Bart; Ling}
x1 -> y2;
y1 -> Marge;
y2 -> Patty;
y3 -> Selma;
Selma -> Ling;
}
now produces this:
So, looks good except for that strange edge around Homer.If I could find a way to move Abraham, Mona and Herb to the left hand side of the picture then I would have a perfectly aligned picture.
Any ideas on how to achieve that?

Related

How to prevent Graphviz from moving nodes to accomodate an edge

I'm trying to reproduce the following figure using Graphviz:
Here's what I came up with so far:
digraph
{
rankdir="LR";
splines=polyline;
b [shape=circle, label="", style=filled, color=gray, width=0.2, height=0.2];
c [shape=box, label="C(s)", style=filled, color=gray, xlabel=controller];
d [shape=box, label="P(s)", style=filled, color=gray, xlabel=plant];
a [shape=point, color=transparent, label="a"];
e [shape=point, color=transparent, label="e"];
f [shape=point, color=transparent, label="f"];
c -> d [label="u"]
b -> c [label="e"]
a -> b [label="r"]
d -> e [dir=none]
e -> f [label="y"]
e -> b
}
This gets me close but not quite there yet, as dot seems to move the nodes to accomodate the edge from e to b and not the other way round:
How do I get it so that the edge from e to b bends around the nodes rather than displacing them?
(lots of trial-and-error)
used html records to contrail external label positioning
constraint=false & dir=back for e->b edge
turned off edge clipping as needed to improve edges
digraph {
// lines were rearranged just to simplify my comprehension
rankdir="LR";
splines=polyline;
//splines=ortho; // might work, if edges use xlabels
a [shape=point, color=transparent, label="a"];
b [shape=circle, label="", style=filled, fillcolor=gray, width=0.2, height=0.2];
// c & d use html tables to better position exterior labels
c [shape=plaintext label=<<TABLE BORDER="0" >
<TR> <TD>controller</TD> </TR>
<TR> <TD border="1" port="p0" bgcolor="grey">C(s)</TD> </TR>
</TABLE>>];
d [shape=plaintext label=<<TABLE BORDER="0">
<TR> <TD>plant</TD> </TR>
<TR> <TD border="1" port="p0" bgcolor="grey">C(s)</TD> </TR>
</TABLE>>];
e [shape=point width=.01 label=""];
f [shape=point width=.00 label="" color=white];
a -> b [label="r"]
b -> c:p0 [label="e"]
c:p0:e -> d:p0:w [label="u"]
d:p0 -> e [dir=none headclip=false]
e -> f [label="y" tailclip=false headclip=false]
b -> e [dir=back constraint=false]
}
Giving:
Based on the above, wouldn't changing:
e -> b
into
e -> b [dir=none constraint=false]
i.e.
digraph
{
rankdir="LR";
splines=polyline;
b [shape=circle, label="", style=filled, color=gray, width=0.2, height=0.2];
c [shape=box, label="C(s)", style=filled, color=gray, xlabel=controller];
d [shape=box, label="P(s)", style=filled, color=gray, xlabel=plant];
a [shape=point, color=transparent, label="a"];
e [shape=point, color=transparent, label="e"];
f [shape=point, color=transparent, label="f"];
c -> d [label="u"]
b -> c [label="e"]
a -> b [label="r"]
d -> e [dir=none]
e -> f [label="y"]
e -> b [dir=none constraint=false]
}
as on: http://www.webgraphviz.com/
I get:
(Disadvantage we still have a small gap at the line labeled y).

how to sort by levels in graphviz

I want to separate the rectangles like this
or (3 items per line)
You were quite close. Most of the changes are just for (my) clarity. rank=same and dir=back
// https://stackoverflow.com/questions/72449201/how-to-sort-by-levels-in-graphviz
digraph {
{rank=same; a -> b -> c}
{rank=same; edge [dir=back] f -> e -> d }
{rank=same; g -> h -> i}
{rank=same; edge [dir=back] l -> k -> j }
c -> d
f -> g
i->j
}
Giving:

Forcing a node to stay on top when creating a cycle

I have the following graph:
digraph G {
u1, u2, u3, u5 [ shape = oval, style=filled, fillcolor="palegreen"];
u3 -> v3 -> v5_0 -> v5_1 -> v1;
u5 -> v8 -> v5_1;
v1 -> v5_2 -> v2;
u1 -> v2;
v2 -> u2;
}
Now, I want u2 and u3 to be the same node, in the sense that I want the last vertex on the bottom to have an edge go up to u3 at the top of the rendered graph. But if I render:
digraph G {
u1, u2, u3, u5 [ shape = oval, style=filled, fillcolor="palegreen"];
u3 -> v3 -> v5_0 -> v5_1 -> v1;
u5 -> v8 -> v5_1;
v1 -> v5_2 -> v2;
u1 -> v2;
v2 -> u3;
}
The u3 node ends up in the middle of the graph. How do I force u3 to be at the top? I tried using rank=min on it, but that didn't help.
2 possible solutions:
use constraint=false on the "offending" edge (https://graphviz.org/docs/attrs/constraint/)
u2 -> u3 [constraint=false]
this produces a correct, but very ugly, edge:
use dir=back to reverse the "offending" edge
u3 -> u2 [dir=back]
Giving:

Layout Problem between Labels Dot Language Graphviz

I am having issues on keeping Marge near Homer and Herb near Lucia to avoid this above-line (check the image). Basicly i need to keep married couples together and push aside brothers to fix the lines from mixing.
Here is my source code:
digraph G {
edge [dir=none];
node [shape=box];
graph [splines=ortho];
"Abraham" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Mona" [shape=box, regular=0, color="red", style="filled" fillcolor="pink"] ;
a1 [shape=diamond,label="",height=0.25,width=0.25];
{rank=same; Abraham -> a1 -> Mona};
"Herb" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Lucia" [shape=box, regular=0, color="red", style="filled"fontcolor="", fillcolor="pink"] ;
"Homer" [shape=box, regular=0, color="blue",fontcolor="blue", style="bold, filled" fillcolor="lightblue"] ;
"Marge" [shape=box, regular=0, color="red", style="bold,filled"fontcolor="red", fillcolor="pink"] ;
p2 [shape=diamond,label="",style="",height=0.25,width=0.25];
{rank=same; Herb -> p2 -> Lucia };
{rank=same; Herb; Homer}
b1 [shape=circle,label="",height=0.01,width=0.01];
b2 [shape=circle,label="",height=0.01,width=0.01];
b3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; b1 -> b2 -> b3};
a1 -> b2;
b1 -> Herb;
b3 -> Homer;
"Gendry" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
Herb -> Gendry;
p2 -> c2;
c1 -> Bob;
c3-> John;
{rank=same; c1 -> c2 -> c3}
c1 [shape=circle,label="",height=0.01,width=0.01];
"Bob" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
c2 [shape=circle,label="",height=0.01,width=0.01];
"John" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
c3 [shape=circle,label="",height=0.01,width=0.01];
p1 [shape=diamond,label="",style="bold",height=0.25,width=0.25];
{rank=same; Homer -> p1 -> Marge};
{rank=same; Bob; John; Gendry}
}
family-tree-image
What you want should be straight-forward using dot, but as you found, it is impressively difficult. Two techniques that should get you there are adding weight attributes to edges to keep nodes close to each other and/or using clusters to explicitly group the couples close. Using clusters does keep the couples together, but it resulted in ugly edges. Adding weights helped to get the invisible nodes placed "correctly" and resulted in nicer-looking edges.
digraph G {
edge [dir=none];
node [shape=box];
graph [splines=ortho];
subgraph cluster1{
peripheries=0
"Abraham" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Mona" [shape=box, regular=0, color="red", style="filled" fillcolor="pink"] ;
a1 [shape=diamond,label="",height=0.25,width=0.25];
{rank=same; Abraham -> a1 -> Mona};
}
subgraph cluster3{
peripheries=0
"Homer" [shape=box, regular=0, color="blue",fontcolor="blue", style="bold, filled" fillcolor="lightblue"] ;
"Marge" [shape=box, regular=0, color="red", style="bold,filled"fontcolor="red", fillcolor="pink"] ;
{rank=same; Homer -> p1 -> Marge};
p1 [shape=diamond,label="",style="bold",height=0.25,width=0.25];
}
subgraph cluster2{
peripheries=0
"Herb" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Lucia" [shape=box, regular=0, color="red", style="filled"fontcolor="", fillcolor="pink"] ;
{rank=same; Herb -> p2 -> Lucia };
p2 [shape=diamond,label="",style="",height=0.25,width=0.25];
}
b1 [shape=point style=invis width=0 label=""] //,height=0.01,width=0.01];
b2 [shape=point style=invis width=0 label=""] //,height=0.01,width=0.01];
b3 [shape=point style=invis width=0 label=""] //,height=0.01,width=0.01];
{rank=same; weight=0 b1 -> b2 -> b3};
{
a1 -> b2;
b1 -> Herb [weight=9]
b3 -> Homer [weight=9]
}
"Gendry" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
{rank=same; weight=0 c1 -> c2 -> c3}
c1 [shape=circle,label="",height=0.01,width=0.01];
"Bob" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
c2 [shape=circle,label="",height=0.01,width=0.01];
"John" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
c3 [shape=circle,label="",height=0.01,width=0.01];
Herb -> Gendry;
p2 -> c2 weight=99;
c1 -> Bob weight=99;
c3-> John weight=99;
{rank=same; Bob; John; Gendry}
}
Produces this (not great, but better):

Graphviz Dot vertical alignment of nodes

I got this dot graph and want the nodes A and D, B and E and C and F to be aligned. Here is the related dot code:
digraph{
A
B
C
D
E
F
{rank = same; B; C}
{rank = same; E; F}
A -> B [label="2", weight=2]
A -> C [label="0", style=dashed, weight=2]
B -> C [label="0", style=dashed, weight=2]
B -> D [label="2", style=dashed, weight=2]
C -> D [label="0", weight=2]
D -> E [label="1", style=dashed, weight=2]
D -> F [label="0", weight=2]
E -> F [label="0", weight=2]
F -> A
}
As you can see I already tried to apply weights to the edges, but that didn't work out
It is possible to use the group attribute of the nodes to suggest aligning the edges between nodes of the same group in a straight line.
Declare the nodes with the group attribute:
A [group=g1]
{rank = same; B[group=g2]; C[group=g3]}
D [group=g1]
{rank = same; E[group=g2]; F[group=g3]}
Then make sure all of those nodes have an (invisible) edge between them:
edge[style=invis];
A -> D
B -> E
C -> F
Everything together:
digraph G {
A [group=g1]
{rank = same; B[group=g2]; C[group=g3]}
D [group=g1]
{rank = same; E[group=g2]; F[group=g3]}
A -> B [label="2", weight=2]
A -> C [label="0", style=dashed, weight=2]
B -> C [label="0", style=dashed, weight=2]
B -> D [label="2", style=dashed, weight=2]
C -> D [label="0", weight=2]
D -> E [label="1", style=dashed, weight=2]
D -> F [label="0", weight=2]
E -> F [label="0", weight=2]
F -> A
edge[style=invis];
A -> D
B -> E
C -> F
}

Resources