Family tree layout with Dot/GraphViz
Solution 1:
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:
Solution 2:
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):
Solution 3:
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
Solution 4:
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.
Solution 5:
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."