Sensible alignment of nodes in Graphviz dot - graphviz

I am trying to put together a family tree to help my understanding of a popular TV show and the project has grown legs.
To illustrate this tree I am using the dot function of graphviz, which is a tool I have used before to illustrate complex networks. Unfortunately for me this was a while ago and some of the basic changes I want to make are eluding me!
In the example below (image at this link), I would like to keep the obvious relationships close together and not have the nodes joined across the canvas. E.g. Sansa and Tyrion together by moving Sansa left, Eddard and Catelyn by moving Catelyn, and Lyanna and Rhaegar by moving Lyanna right.
I have tried clusters and groups, but can't figure out what I am doing wrong.
graph got {
subgraph gen2 {
rank = same
La2a [shape=box, label="Tywin Lanister"];
Tu2a [shape=box, label="Hoster Tully"];
S2a [shape=box, label="Rickard Stark"];
Ta2a [shape=box, label="Aerys II Targaryen"];
}
subgraph gen2sons {
rank = same
Tu2asons [shape=point];
S2asons [shape=point];
Ta2asons [shape=point];
La2asons [shape=point];
}
subgraph gen3 {
rank = same
S3a [shape=box, label="Eddard \"Ned\" Stark"];
S3b [shape=box, label="Catelyn Stark"];
S3aS3b [shape=point];
S3c [shape=box, label="Lyanna Stark"];
S3d [shape=box, label="Brandon Stark"];
S3e [shape=box, label="Benjen Stark"];
Ta3a [shape=box, label="Rhaegar Targaryen"];
Ta3b [shape=box, label="Daenerys Targaryen"];
Ta3c [shape=box, label="Jaehaerys Targaryen"];
S3cTa3a [shape=point];
La3a [shape=box, label="Jamie Lanister"];
La3b [shape=box, label="Cersei Lanister"];
}
subgraph gen3sons {
rank = same
S3aS3bsons [shape=point];
S3cTa3asons [shape=point];
}
subgraph gen4 {
rank = same
S4b [shape=box, label="Sansa Stark"];
S4a [shape=box, label="Rob Stark"];
S4c [shape=box, label="Arya Stark"];
S4d [shape=box, label="Brandon Stark"];
S4e [shape=box, label="Rickon Stark"];
Sn4a [shape=box, label="Jon Snow"];
La3c [shape=box, label="Tyrion Lanister"];
}
// Sons and Daughters
La2a -- La2asons
La2asons -- La3a
La2asons -- La3b
La2asons -- La3c
Tu2a -- Tu2asons
Tu2asons -- S3b
S2a -- S2asons
S2asons -- S3a
S2asons -- S3c
S2asons -- S3d
S2asons -- S3e
Ta2a -- Ta2asons
Ta2asons -- Ta3a
Ta2asons -- Ta3b
Ta2asons -- Ta3c
S3aS3b -- S3aS3bsons
S3aS3bsons -- S4a
S3aS3bsons -- S4b
S3aS3bsons -- S4c
S3aS3bsons -- S4d
S3aS3bsons -- S4e
S3cTa3a -- S3cTa3asons
S3cTa3asons -- Sn4a
// Marriage
S3a -- S3aS3b -- S3b
La3c -- S4b
S3c -- S3cTa3a -- Ta3a
}
.png output of the above code

Your graph is lengthy, but this answer of mine from a previous question may shed some light on how to accomplish this with invisible ranks and columns, more or less forcing your nodes into a "grid". I demonstrate in that example with a simpler example, but from what you've already done, I'm sure you're up to trying my approach on your own. Hope it works for you.

Related

how to avoid the overlap of the edge of graphviz

I have Graphviz as below:
digraph G {
node [fontname = "font-awesome"]; edge [dir=none];
A [label="A"];
B [label="B"];
c_A_B [shape=diamond];
{rank=same; A -> c_A_B -> B};
C [label="C"];
L1_0 [shape=circle,label="",height=0.01,width=0.01];
L1_0->C;
D [label="D"];
L1_1 [shape=circle,label="",height=0.01,width=0.01];
L1_1->D;
E [label="E"];
L1_2 [shape=circle,label="",height=0.01,width=0.01];
L1_2->E;
{rank=same; L1_0->L1_1->L1_2};
{rank=same; C; D; E;};
c_A_B->L1_1;
F [label="F"];
c_E_F [shape=diamond];
{rank=same; E->c_E_F->F};
L2_0 [shape=circle,label="",height=0.01,width=0.01];
c_E_F->L2_0;
}
which shows the graph as below, can anyone be kind to help me how to avoid the edge overlapping?
I this case in this case a solution for you can be an invisible edge in the form of:
C -> D [style=invis];
so your example would look like:
digraph G {
node [fontname = "font-awesome"]; edge [dir=none];
A [label="A"];
B [label="B"];
c_A_B [shape=diamond];
{rank=same; A -> c_A_B -> B};
C [label="C"];
L1_0 [shape=circle,label="",height=0.01,width=0.01];
L1_0->C;
D [label="D"];
L1_1 [shape=circle,label="",height=0.01,width=0.01];
L1_1->D;
C -> D [style=invis];
E [label="E"];
L1_2 [shape=circle,label="",height=0.01,width=0.01];
L1_2->E;
{rank=same; L1_0->L1_1->L1_2};
{rank=same; C; D; E;};
c_A_B->L1_1;
F [label="F"];
c_E_F [shape=diamond];
{rank=same; E->c_E_F->F};
L2_0 [shape=circle,label="",height=0.01,width=0.01];
c_E_F->L2_0;
}
And the resulting image is:

How to create a proper syntax diagram with Graphviz?

I'm trying to recreate the following syntax diagram using Graphviz (which will eventually be embedded in Sphinx):
Using the DOT language, I defined the following diagram:
digraph numexpr {
bgcolor="transparent"
{rank = same;
p_0[shape=point];
n_1[shape=block, label="constant", group=g1];
p_1[shape=point]}
n_2[shape=block, label="enumerated-list", group=g1]
n_3[shape=block, label="reference", group=g1]
n_4[shape=block, label="function-call", group=g1]
n_5[shape=block, label="operator-expression", group=g1]
n_6[shape=block, label="iterative-expression", group=g1]
n_7[shape=block, label="conditional-expression", group=g1]
n_8[shape=block, label="logical-expression", group=g1]
{rank = same;
c_1[shape=circle, label="("];
n_9[shape=block, label="numerical-expression", group=g1];
c_2[shape=circle, label=")"]}
p_0 -> n_1 [arrowsize=.5]
p_0 -> n_2 [arrowsize=.5]
p_0 -> n_3 [arrowsize=.5]
p_0 -> n_4 [arrowsize=.5]
p_0 -> n_5 [arrowsize=.5]
p_0 -> n_6 [arrowsize=.5]
p_0 -> n_7 [arrowsize=.5]
p_0 -> n_8 [arrowsize=.5]
p_0 -> c_1 [arrowsize=.5]
c_1 -> n_9 [arrowsize=.5]
n_1 -> p_1 [arrowsize=.5]
n_2 -> p_1 [arrowsize=.5]
n_3 -> p_1 [arrowsize=.5]
n_4 -> p_1 [arrowsize=.5]
n_5 -> p_1 [arrowsize=.5]
n_6 -> p_1 [arrowsize=.5]
n_7 -> p_1 [arrowsize=.5]
n_8 -> p_1 [arrowsize=.5]
n_9 -> c_2 [arrowsize=.5]
c_2 -> p_1 [arrowsize=.5]
edge[style=invis];
n_1 -> n_2
n_2 -> n_3
n_3 -> n_4
n_4 -> n_5
n_5 -> n_6
n_6 -> n_7
n_7 -> n_8
n_8 -> n_9
}
Rendering as follows:
Close but no cigar. How can one manipulate the edges such that the render will look more similar to the original syntax diagram?
Here is an approximation. Done with ~225 lines of dot code and requiring a 3-step process:
dot -Tdot ... >somefile
hand editing somefile to add 18 horizontal edges and adding layout=neato
dot -Tpng somefile >somefile.png
If I had to do it again, I'd generate pos values for both nodes and edges.
digraph numexpr {
nodesep=.7
ranksep=.22
bgcolor="transparent"
node[pin=true]
subgraph clusterLeftSide {
peripheries=0
margin=30
node [shape=point width=.01 qlabel="" style=solid ordering=out]
nls1; nls2; nls3; nls4; nls5; nls6; nls7; nls8; nls9
ls1; ls2; ls3; ls4; ls5; ls6; ls7; ls8;
ls9 [style=invis]
node [shape=point width=.01 qlabel="" style=invis ordering=out]
fls1; fls2; fls3; fls4; fls5; fls6; fls7; fls8; fls9
edge [tailclip=false headclip=false dir=none]
{
rank=same
fls1->ls1 [style=solid]
ls1->nls1 [style=solid]
}
{
rank=same
fls2->ls2 [style=invis]
ls2->nls2 [style=invis]
}
{
rank=same
fls3->ls3 [style=invis]
ls3->nls3 [style=invis]
}
{
rank=same
fls4->ls4 [style=invis]
ls4->nls4 [style=invis]
}
{
rank=same
fls5->ls5 [style=invis]
ls5->nls5 [style=invis]
}
{
rank=same
fls6->ls6 [style=invis]
ls6->nls6 [style=invis]
}
{
rank=same
fls7->ls7 [style=invis]
ls7->nls7 [style=invis]
}
{
rank=same
fls8->ls8 [style=invis]
ls8->nls8 [style=invis]
}
{
rank=same
fls9->ls9 [style=invis]
ls9->nls9 [style=invis]
}
fls1->fls2->fls3->fls4->fls5->fls6->fls7->fls8->fls9 [style=invis]
node [shape=point width=.01 label="" style=zinvis]
edge [dir=none style=solid tailclip=false headclip=false]
ls1->ls2->ls3->ls4->ls5->ls6->ls7->ls8 [style=solid]
ls8->ls9 [style=invis]
}
subgraph clusterMain {
peripheries=0
margin=30
n1[shape=box label="constant",xleft=1 xright=1 ];
n2[shape=box label="enumerated-list",xleft=1 xright=1 ]
n3[shape=box label="reference",xleft=1 xright=1 ]
n4[shape=box label="function-call",xleft=1 xright=1 ]
n5[shape=box label="operator-expression",xleft=1 xright=1 ]
n6[shape=box label="iterative-expression",xleft=1 xright=1 ]
n7[shape=box label="conditional-expression",xleft=1 xright=1 ]
n8[shape=box label="logical-expression",xleft=1 xright=1 ]
{
rank = same;
c9a[shape=circle, label="(" xleft=1 ];
n9[shape=box width=2.7 label="numerical-expression" ];
c9b[shape=circle, label=")" xright=1 ]
c9a -> n9 -> c9b
}
edge[style=invis];
n1 -> n2
n2 -> n3
n3 -> n4
n4 -> n5
n5 -> n6
n6 -> n7
n7 -> n8
n8 -> n9
}
subgraph clusterRightSide {
peripheries=0
margin=30
node [shape=point width=.01 qlabel="" style=solid ordering=out]
nrs1; nrs2; nrs3; nrs4; nrs5; nrs6; nrs7; nrs8; nrs9
rs1; rs2; rs3; rs4; rs5; rs6; rs7; rs8;
rs9 [style=invis]
node [shape=point width=.01 qlabel="" style=invis ordering=out]
frs1; frs2; frs3; frs4; frs5; frs6; frs7; frs8; frs9
edge [tailclip=false headclip=false zdir=none]
{
rank=same
nrs1->rs1 [style=solid dir=none]
rs1->frs1 [style=solid]
}
{
rank=same
nrs2->rs2 [style=invis]
rs2->frs2 [style=invis]
}
{
rank=same
nrs3->rs3 [style=invis]
rs3->frs3 [style=invis]
}
{
rank=same
nrs4->rs4 [style=invis]
rs4->frs4 [style=invis]
}
{
rank=same
nrs5->rs5 [style=invis]
rs5->frs5 [style=invis]
}
{
rank=same
nrs6->rs6 [style=invis]
rs6->frs6 [style=invis]
}
{
rank=same
nrs7->rs7 [style=invis]
rs7->frs7 [style=invis]
}
{
rank=same
nrs8->rs8 [style=invis]
rs8->frs8 [style=invis]
}
{
rank=same
nrs9->rs9 [style=invis]
rs9->frs9 [style=invis]
}
nrs1->nrs2->nrs3->nrs4->nrs5->nrs6->nrs7->nrs8 [style=invis]
nrs8->nrs9 [style=invis]
node [shape=point width=.01 label="" style=zinvis]
edge [dir=none style=solid tailclip=false headclip=false]
rs1->rs2 [dir=back]
rs2->rs3->rs4->rs5->rs6->rs7->rs8 [style=solid]
rs8->rs9 [style=invis]
frs1->frs2->frs3->frs4->frs5->frs6->frs7->frs8->frs9 [style=invis]
}
edge [dir=none]
ls1:s->nls2:w
ls2:s->nls3:w
ls3:s->nls4:w
ls4:s->nls5:w
ls5:s->nls6:w
ls6:s->nls7:w
ls7:s->nls8:w
ls8:s->nls9:w
nrs2:e->rs1:s
nrs3:e->rs2:s
nrs4:e->rs3:s
nrs5:e->rs4:s
nrs6:e->rs5:s
nrs7:e->rs6:s
nrs8:e->rs7:s
nrs9:e->rs8:s
/* add these lines to the output of: dot -Tdot
edge [dir=forward]
nls1->n1
nls2->n2
nls3->n3
nls4->n4
nls5->n5
nls6->n6
nls7->n7
nls8->n8
nls9->c9a
edge [dir=none]
n1->nrs1
n2->nrs2
n3->nrs3
n4->nrs4
n5->nrs5
n6->nrs6
n7->nrs7
n8->nrs8
c9b->nrs9
*/
}

When rankdir is LR, why are the nodes in the same rank ordered bottom to top instead of top to bottom?

In the following example, the nodes in the subgraphs are ordered from the bottom to the top instead of from top to bottom. How can that be reversed, so that the start is top-left and the nodes in the subgraphs are ordered from top to bottom (A1-A4 and B1-B4)?
digraph ab
{
rankdir=LR
splines=ortho
ranksep=1
node[shape = record]
subgraph cluster_0
{
label="A"
{
rank = "same"
state0_anchor [label="", style=invis, width=0]
state0_step0 [label="A1"]
state0_step1 [label="A2"]
state0_step2 [label="A3"]
state0_step3 [label="A4"]
}
state0_anchor->state0_step0[style = invis]
state0_step0 -> state0_step1 -> state0_step2 -> state0_step3
}
state0_step3 -> state0_step0 [constraint=false]
state0_step3 -> state1_step0 [constraint=false]
subgraph cluster_state1
{
label="B"
{
rank = "same"
state1_anchor [label="", style=invis, width=0, height=0]
state1_step0 [label="B1"]
state1_step1 [label="B2"]
state1_step2 [label="B3"]
state1_step3 [label="B4"]
}
state1_anchor->state1_step0[style = invis]
state1_step0 -> state1_step1 -> state1_step2 -> state1_step3
}
state1_step3 -> state0_step0 [constraint=false]
state0_anchor -> state1_anchor[style = invis]
start -> state0_step0
}
In your example, when direction of the edges within the subgraphs are reversed, the nodes will be ordered the way you'd like. Something like this:
state0_step3 -> state0_step2 [dir=rev]
state0_step2 -> state0_step1 [dir=rev]
state0_step1 -> state0_step0 [dir=rev]
state0_step0 -> state0_anchor [style = invis]
The same for state1-nodes.
Details about transformations when going LR can be found in https://stackoverflow.com/a/9592856/63733

Edge crossing each other

is there a way to eliminate the crossing of edges?
I tried many ways, nothing helped.
digraph graphname {
graph [splines=ortho,];
node [shape=box,];
l;
l_a [shape=diamond,label="",height=0.20,width=0.20];
l_a_s [shape=point];
l_a_i [shape=point];
l_a_ii [shape=point];
l_a -> l_a_s;
{rank=same; a -> l_a -> l}
{rank=same; l_a_i -> l_a_s -> l_a_ii}
l_a_i -> i;
l_a_ii -> ii;
l_c [shape=diamond,label="",height=0.20,width=0.20];
l_c_s [shape=point];
l_c_t [shape=point];
l_c_n [shape=point];
l_c -> l_c_s;
{rank=same; l -> l_c -> c}
{rank=same; l_c_t -> l_c_s -> l_c_n}
l_c_t -> t;
l_c_n -> n;
}
some more details:
All you need to do is to reorganize your node/edge definitions a little bit, no additional edges needed.
for example:
digraph graphname {
graph [splines=ortho,];
node [shape=box,];
a;
l_a [shape=diamond,label="",height=0.20,width=0.20];
l;
l_c [shape=diamond,label="",height=0.20,width=0.20];
c;
{rank=same; a -> l_a -> l -> l_c -> c}
l_a_s [shape=point];
l_c_s [shape=point];
l_a -> l_a_s;
l_c -> l_c_s;
l_a_i [shape=point];
l_a_ii [shape=point];
l_c_t [shape=point];
l_c_n [shape=point];
{rank=same;
l_a_i -> l_a_s -> l_a_ii;
l_c_t -> l_c_s -> l_c_n;}
l_a_i -> i;
l_a_ii -> ii;
l_c_t -> t;
l_c_n -> n;
}
Adding this invisible edge solves your problem:
l_a_i -> l_c_s [constraint=false style=invis]
I can't prove mathematically why this works, but in such situation it usually helps to play with order in which nodes/edges are defined, or try adding invisible adges to nudge the layout in the direction you need

How can I direct dot to use a shorter edge path?

The diagram below is laid out almost perfectly, apart from the edge from the left "named pipe" node to "cat", which takes a long circuitous route, instead of the obvious short one I've marked with red on the diagram below. Is there a way to direct dot to use the short edge path? Note that the sequence diagram on the diagram's bottom, must be rendered as it currently appears, i.e. in the left to right order.
This is the code that draws the diagram.
digraph D {
fontname="Arial";
subgraph cluster_async {
label="Asynchronous processes";
style=filled;
color=lightgrey;
node [shape=box, style=solid, fillcolor=white, fontname="Arial"];
{
rank=same;
npi_0_0_0 [label="named\npipe"];
npi_0_3_0 [label="named\npipe"];
npi_0_2_0 [label="named\npipe"];
}
node [shape=box, style=bold];
tee [label="sgsh-tee"];
"ls -l" -> tee;
tee -> npi_0_0_0;
tee -> npi_0_3_0;
tee -> npi_0_2_0;
NBYTES [label="sgsh-writeval -s NBYTES"];
npi_0_3_0 -> "awk '{s += $5} END {print s}'" -> NBYTES;
NDIRS [label="sgsh-writeval -s NDIRS"];
npi_0_2_0 -> "grep -c '^d'" -> NDIRS;
// Put some order in the appearance
{
rank=same;
NDIRS;
NBYTES;
}
}
subgraph clustersync {
label="Synchronous sequence";
style=dashed;
start [shape=circle, style=filled, label="", fillcolor=black, width=.2];
node [shape=box, style=bold, fontname="Arial"];
npi_0_0_0:sw -> cat:nw [constraint=false];
"sgsh-readval -s NDIRS" -> echo;
"sgsh-readval -s NBYTES" -> echo;
NBYTES -> "sgsh-readval -s NBYTES";
NDIRS -> "sgsh-readval -s NDIRS";
end [shape=doublecircle, style=filled, label="", fillcolor=black, width=.2];
{
rank=same;
edge [arrowhead=open];
start -> cat -> echo -> end;
}
}
}
(In case you're interested, the diagram illustrates the setup of an example from sgsh.)
For this graph, setting splines=ortho will produce a desirable result.

Resources