Graphviz: how to arrange nodes with circo layout - graphviz

I'm trying to draw a graph with circle topology.
Here is what I'm expecting to see:
Here is my gv file:
digraph g1 {
layout="circo";
node [shape = doublecircle]; N4 N6;
node [shape = circle];
N0 -> N1 [ label = "{1,0}"];
N1 -> N2 [ label = "{1,0}"];
N2 -> N3 [ label = "{1,0}"];
N3 -> N4 [ label = "{1,0}"];
N4 -> N5 [ label = "{1,0}"];
N5 -> N6 [ label = "{1,0}"];
N6 -> N0 [ label = "{1,0}"];
N0 -> N4 [ label = "{1,0}"];
N1 -> N5 [ label = "{1,0}"];
N2 -> N6 [ label = "{1,0}"];
N3 -> N0 [ label = "{1,0}"];
N4 -> N1 [ label = "{1,0}"];
N5 -> N2 [ label = "{1,0}"];
N6 -> N3 [ label = "{1,0}"];
}
And here is an output image for graph above:
How can I arrange nodes in graphviz to make it look like 1?

If the goal is to have a graph which respects the order of the nodes, it's not that simple. You could calculate the position of the nodes with an external script and render it with neato.
Or you could first layout the nodes with the edges which determine the correct order of the nodes only:
digraph g1 {
node [shape = doublecircle]; N4 N6;
node [shape = circle];
edge[label="{1,0}"];
N0 -> N1 -> N2 -> N3 -> N4 -> N5 -> N6 -> N0;
}
with:
circo graph.gv > tempgraph.gv
Then add the remaining edges to tempgraph.gv - just copy-paste the following before the closing }:
N0 -> N4 [ label = "{1,0}"];
N1 -> N5 [ label = "{1,0}"];
N2 -> N6 [ label = "{1,0}"];
N3 -> N0 [ label = "{1,0}"];
N4 -> N1 [ label = "{1,0}"];
N5 -> N2 [ label = "{1,0}"];
N6 -> N3 [ label = "{1,0}"];
And render it with neato and the -n option:
neato -n tempgraph.gv -Tpng -O
You may want to fine-tune the position of the labels:

Related

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:

Sub-graph Selection Algorithm Problem (Dynamic Programming or NP)

We have an algorithm problem in hand, can you please write your ideas about this, thank you!
There are N many nodes with K different colors. Some of the nodes have direct connection between each other and some do not.
We want to select M nodes from these N total nodes, but these M nodes must be connected. Also, our selected group of M nodes must have minimum number of distinct colored neighbors. There might be more than one best combinations, finding any of them is the goal.
For example, we selected M nodes and in total, these M nodes have the following neighbors: 5 red, 3 blue, 1 green. In this case, we count the unique colors, so the number of distinct colored neighbors, in this case, is 3. We want to minimize this number by selecting the best possible combination of M nodes.
Example graph visualization :
In this example, let's assume M = 4, then the best possible combination of nodes would be {9, 10, 11, 12} since this group has only one neighbor which is yellow.
If we choose {0, 1, 3, 5}, the neighbors of this combination would be {2, 4, 6}, which consists of 2 red neighbors and 1 green neighbor; which results with score of 2 since we look for distinct number of colored neighbors.
Is this algorithm question NP-complete? How should we proceed? If this is not NP-complete, what is the best algorithm we can use to solve this problem?
Can we combine graph algorithms such as Prim’s, Kruskal's, Floyd Warshall or traversal algorithms?
If this is an NP problem, you could use ASP to solve it.
Given instance.lp
color(0,yellow).
color(3,yellow).
color(8,yellow).
color(10,yellow).
color(2,green).
color(5,green).
color(12,green).
color(7,blue).
color(1,red).
color(4,red).
color(6,red).
color(9,red).
color(11,red).
edge(0,5).
edge(0,1).
edge(0,2).
edge(0,6).
edge(5,3).
edge(5,4).
edge(6,4).
edge(3,4).
edge(2,7).
edge(7,8).
edge(8,9).
edge(5,3).
edge(9,10).
edge(9,11).
edge(9,12).
edge(11,12).
edge(B,A) :- edge(A,B).
and encoding.lp
node(X) :- color(X,_).
%select exactly one start node
1 {start(X) : node(X)} 1.
% start node is in sub graph
sub(X) :- start(X).
% for any node in the sub graph you can add any connected node
{sub(Y) : edge(X,Y)} :- sub(X).
% it is wrong if we do not have exactly m nodes in the sub graph
:- not m = #sum {1,X: sub(X)}.
#minimize {1,C : sub(X), edge(X,Y), not sub(Y), color(Y,C)}.
#show sub/1.
The call
clingo encoding.lp instance.lp --const m=4 gives you an optimal solution:
sub(3) sub(5) sub(4) sub(6)
The call
clingo encoding.lp instance.lp --const m=4 --opt-mode=optN --project
gives you all optimal solutions.
The tools can be found at https://potassco.org/
The subgraph { 4 3 5 6 } is also a good answer having one red neighbor.
I found this subgraph running a little program called subs.
C:\Users\James\code\subs>subs
l 0 1 1
l 0 6 1
l 0 5 1
l 0 2 1
l 2 7 1
l 3 5 1
l 3 4 1
l 4 6 1
l 4 5 1
l 7 8 1
l 8 9 1
l 9 10 1
l 9 11 1
l 9 12 1
l 11 12 1
n 0 yellow
n 1 red
n 2 green
n 3 yellow
n 4 red
n 5 green
n 6 red
n 7 blue
n 8 yellow
n 9 red
n 10 yellow
n 11 red
n 12 green
<-cPathFinder::read
n1 n0 n6 n5 colors 3
n1 n0 n6 n2 colors 3
n1 n0 n6 n4 colors 2
n1 n0 n5 n2 colors 3
n1 n0 n5 n3 colors 2
n1 n0 n5 n4 colors 3
n1 n0 n2 n7 colors 3
n0 n6 n5 n2 colors 3
n0 n6 n5 n3 colors 2
n0 n6 n5 n4 colors 3
n0 n6 n2 n7 colors 3
n0 n6 n2 n4 colors 4
n0 n6 n3 n4 colors 2
n0 n5 n2 n7 colors 2
n0 n5 n2 n3 colors 2
n0 n5 n2 n4 colors 3
n0 n5 n3 n4 colors 2
n0 n2 n7 n8 colors 2
n6 n5 n3 n4 colors 1
n2 n7 n8 n9 colors 3
n7 n8 n9 n10 colors 2
n7 n8 n9 n11 colors 2
n7 n8 n9 n12 colors 3
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n0 n6 n5 n2 colors 3
n0 n6 n5 n3 colors 2
n0 n6 n5 n4 colors 3
n0 n6 n2 n7 colors 3
n0 n6 n2 n4 colors 4
n0 n6 n3 n4 colors 2
n0 n5 n2 n7 colors 2
n0 n5 n2 n3 colors 2
n0 n5 n2 n4 colors 3
n0 n5 n3 n4 colors 2
n0 n2 n7 n8 colors 2
n6 n5 n3 n4 colors 1
n2 n7 n8 n9 colors 3
n7 n8 n9 n10 colors 2
n7 n8 n9 n11 colors 2
n7 n8 n9 n12 colors 3
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n6 n5 n3 n4 colors 1
n2 n7 n8 n9 colors 3
n7 n8 n9 n10 colors 2
n7 n8 n9 n11 colors 2
n7 n8 n9 n12 colors 3
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n2 n7 n8 n9 colors 3
n7 n8 n9 n10 colors 2
n7 n8 n9 n11 colors 2
n7 n8 n9 n12 colors 3
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n2 n7 n8 n9 colors 3
n7 n8 n9 n10 colors 2
n7 n8 n9 n11 colors 2
n7 n8 n9 n12 colors 3
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n7 n8 n9 n10 colors 2
n7 n8 n9 n11 colors 2
n7 n8 n9 n12 colors 3
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n8 n9 n10 n11 colors 2
n8 n9 n10 n12 colors 2
n8 n9 n11 n12 colors 2
n9 n10 n11 n12 colors 1
n9 n10 n11 n12 colors 1
subgraph n6, n5, n3, n4, has 1 differently colored neighbours
There is nothing clever about subs. It generates subgraphs and searches through them for the connected subgraph that has the fewest uniquely coloured neighbours. There are lots of nested loops, so it is not going to do well when there are thousands of nodes.
The code is at https://gist.github.com/JamesBremner/5a3965cc725c54dcaabd4beb44f9104f
An optimization has occured to me that should go a long way to handling large graphs. Assuming that the complete graph is connected ( every node can be reached from every other node ) then every subgraph must have at least one neighbour ( otherwise the nodes in the subgraph could not reach the nodes outside the subgraph ). So the best possible number of uniquely colored neighbours is 1 and no less. So the algorithm can stop as soon as the first subgraph with one uniquely colored neighbor has been found, since no better result can exist.

A function that counts the number '1's, '2's and '3's in a list, with count represented as, for example, s(s(s(0))) = 3

I want to create a predicate over the alphabet {1,2,3}, f/4(N1,N2,N3,L), such that N1, N2 and N3 are a count of the number of times a 1, a 2, and a 3 appeared in a list, respectively. The predicate should operate as the following:
?- f(N1,N2,N3,[1,2,3,3]).
N1 = s(0), N2 = s(0), N3 = s(s(0))
?- f(N1,N2,N3,L).
N1 = N2, N2 = N3, N3 = 0, L = [] ;
N1 = s(0), N2 = N3, N3 = 0, L = [1] ;
N1 = N3, N3 = 0, N2 = s(0), L = [2] ;
N1 = N2, N2 = 0, N3 = s(0), L = [3] ;
N1 = s(s(0)), N2 = N3, N3 = 0, L = [1,1] ;
...
I have come up with the following solution:
f(0,0,0,[]).
f(s(N1),N2,N3,[1|Xs]) :- f(N1,N2,N3,Xs).
f(N1,s(N2),N3,[2|Xs]) :- f(N1,N2,N3,Xs).
f(N1,N2,succ(N3),[3|Xs]) :- f(N1,N2,N3,Xs).
This solution works for the first query, however, for the second query, it outputs the following:
?- f(N1,N2,N3,L).
N1 = N2, N2 = N3, N3 = 0, L = [] ;
N1 = s(0), N2 = N3, N3 = 0, L = [1] ;
N1 = s(s(0)), N2 = N3, N3 = 0, L = [2] ;
N1 = s(s(s(0))), N2 = N3, N3 = 0, L = [3] ;
N1 = s(s(s(s(0)))), N2 = N3, N3 = 0, L = [1,1] ;
This seems to be an unfair enumeration, how do I fix this?
Due to the order of the clauses in your solution, each recursive call choose to increment N1, before trying to increment N2 or N3 (which are never incremented at all).
A possible solution is:
f(0, 0, 0, []).
f(N1, N2, N3, [X|Xs]) :-
f(M1, M2, M3, Xs),
member(X - [N1, N2, N3],
[1 - [s(M1), M2, M3],
2 - [M1, s(M2), M3],
3 - [M1, M2, s(M3)]]).
Here are some examples:
?- f(N1, N2, N3, [1,2,3,3,1,1,1]).
N1 = s(s(s(s(0)))),
N2 = s(0),
N3 = s(s(0)) ;
false.
?- forall( limit(20, f(N1,N2,N3,L)), writeln(L -> [N1,N2,N3]) ).
[] -> [0,0,0]
[1] -> [s(0),0,0]
[2] -> [0,s(0),0]
[3] -> [0,0,s(0)]
[1,1] -> [s(s(0)),0,0]
[2,1] -> [s(0),s(0),0]
[3,1] -> [s(0),0,s(0)]
[1,2] -> [s(0),s(0),0]
[2,2] -> [0,s(s(0)),0]
[3,2] -> [0,s(0),s(0)]
[1,3] -> [s(0),0,s(0)]
[2,3] -> [0,s(0),s(0)]
[3,3] -> [0,0,s(s(0))]
[1,1,1] -> [s(s(s(0))),0,0]
[2,1,1] -> [s(s(0)),s(0),0]
[3,1,1] -> [s(s(0)),0,s(0)]
[1,2,1] -> [s(s(0)),s(0),0]
[2,2,1] -> [s(0),s(s(0)),0]
[3,2,1] -> [s(0),s(0),s(0)]
[1,3,1] -> [s(s(0)),0,s(0)]
true.

How to make primary arrows straight with Graphviz when there are reverse links to the same nodes?

Given the following graph:
digraph g {
rankdir=LR;
node [shape=box];
A;
{ rank = same;
B; C; D; E;
};
A -> B [label="144"];
B -> A [label="261"; constraint=false];
B -> C [label="144"];
C -> B [label="261"; constraint=false];
C -> D [label="144"];
D -> C [label="261"; constraint=false];
D -> E [label="144"];
E -> D [label="261"; constraint=false];
B -> n1 [label="144"];
n1 -> B [label="261"; constraint=false];
n1 -> n2 [label="144"];
n2 -> n1 [label="261"; constraint=false];
C -> n3 [label="144"];
n3 -> C [label="261"; constraint=false];
n3 -> n4 [label="144"];
n4 -> n3 [label="261"; constraint=false];
D -> n5 [label="144"];
n5 -> D [label="261"; constraint=false];
n5 -> n6 [label="144"];
n6 -> n5 [label="261"; constraint=false];
E -> n7 [label="144"];
n7 -> E [label="261"; constraint=false];
n7 -> n8 [label="144"];
n8 -> n7 [label="261"; constraint=false];
};
The resulting output is:
This is almost what I want (in particular it took a lot of trouble to figure out how to make that straight line of letter nodes in the second rank), but my problem is with the way that the edge arrows are drawn in the vertical nodes.
What I want is for the "forward" arrow (the one going right/down in the graph, and the one without constraint=false) to be straight, and the "reverse" arrow (going left/up in the graph, with constraint=false) to be curved. And in both cases I want the labels to be out of the way of each other. (For the vertical arrows, this probably means pushing the label to the other side.)
I've tried playing with setting groups and weights but so far nothing has seemed to help swap the vertical arrows. And I haven't found anything that will move the label to the other side.
I also tried using the splines setting but it doesn't do anything.
Managing edge placement is very difficult.
Does this meet your requirements - it uses ports to tweak the edge placement.
digraph g {
rankdir=LR;
node [shape=box];
A;
{ rank = same;
B; C; D; E;
};
A -> B [label="144"];
B -> A [label="261"; constraint=false];
B -> C [label="144"];
C -> B:se [label="261"; constraint=false];
C -> D [label="144"];
D -> C:se [label="261"; constraint=false];
D -> E [label="144"];
E -> D:se [label="261"; constraint=false];
B -> n1 [label="144"];
n1 -> B [label="261"; constraint=false];
n1 -> n2 [label="144"];
n2 -> n1 [label="261"; constraint=false];
C -> n3 [label="144"];
n3 -> C [label="261"; constraint=false];
n3 -> n4 [label="144"];
n4 -> n3 [label="261"; constraint=false];
D -> n5 [label="144"];
n5 -> D [label="261"; constraint=false];
n5 -> n6 [label="144"];
n6 -> n5 [label="261"; constraint=false];
E -> n7 [label="144"];
n7 -> E [label="261"; constraint=false];
n7 -> n8 [label="144"];
n8 -> n7 [label="261"; constraint=false];
}

Family tree layout with Dot/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?

Resources