I'd like to have my graph looks like this:
But I can only get this:
The problem is, rankdir does not work in subgraph.
So, how to emulate it?
The code:
digraph G {
node [shape = circle]
0 [style = invis]
0 -> "0A"
subgraph clusterA {
label=A
"0A"
"1A"
"2A" -> "0A" [label=•]
}
subgraph clusterB {
label=B
"0B"
"1B"
"2B" -> "0B" [label=•]
}
subgraph clusterC {
label=C
"0C"
"1C"
"2C" -> "0C" [label=•]
}
subgraph clusterD {
label=D
"0D"
"1D"
"2D" -> "0D" [label=•]
}
subgraph clusterE {
label=E
"0E"
"1E"
"2E" -> "0E" [label=•]
}
subgraph clusterF {
label=F
{node [shape = doublecircle] "0F" "1F"}
"2F" -> "0F" [label=•]
}
"0A" -> "1B" [label=a]
"1A" -> "2B" [label=a]
"0B" -> "1C" [label=b]
"1B" -> "2C" [label=b]
"0C" -> "1D" [label=c]
"1C" -> "2D" [label=c]
"0D" -> "1E" [label=d]
"1D" -> "2E" [label=d]
"0E" -> "1F" [label=e]
"1E" -> "2F" [label=e]
}
Reproducing particular graph layouts usually can be achieved with:
Invisible nodes and edges
rank constraints
Here's how I reproduced your graph - or at least a part of it:
digraph g {
rankdir="LR";
node[shape = circle, fontsize=14];
fontsize=18;
labeljust="l";
edge[style=invis, fontsize=12];
{ rank=same;
0 [style = invis];
01 [style = invis];
02 [style=invis];
0 -> 01 -> 02;
}
subgraph clusterA {
"0A" -> "1A" -> "2A";
"2A" -> "0A" [label=".", constraint=false, style=solid];
label="A";
}
subgraph clusterB {
"0B" -> "1B" -> "2B";
"2B" -> "0B" [label=".", constraint=false, style=solid];
label="B";
}
subgraph clusterC {
"0C" -> "1C" -> "2C";
"2C" -> "0C" [label=".", constraint=false, style=solid];
label="C";
}
0 -> "0A"[style=solid];
01 -> "0B"[style=invis];
02 -> "0C"[style=invis];
// edges between clusters
edge[constraint=false, style=solid];
"0A" -> "1B" [label=a]
"1A" -> "2B" [label=a]
"0B" -> "1C" [label=b]
"1B" -> "2C" [label=b]
}
This solution is not very intuitive. A couple of points to achieve this:
I chose rankdir="LR" which resulted in nicer edges than TB, though it does not really correspond with the direction of the graph
Invisible nodes and edges are use for the top rank nodes (0, 01, 02) in order to have the clusters align left.
The (invisible) top nodes are forced to the same rank and are linked by invisible edges - this will ensure that the clusters linked to each node appear in the correct order.
The result is:
It looks like rank=same might be a cleaner solution. Take a look at Placing clusters on the same rank in Graphviz.
You can also use 'constraint=false' and invisible edges to carefully control node rank. This is basically the same answer as the above.
digraph G {
newrank=true; // rank without respect to cluster
rankdir="LR";
node [shape = circle]
subgraph clusterA {
a0 -> a1 -> a2 [style = invis] // set node order in cluster
a2 -> a0 [constraint=false] //don't use this edge for ranking
}
subgraph clusterB {
b0 -> b1 -> b2 [style = invis]
b2 -> b0 [constraint=false]
}
a0 -> b1 [constraint=false]
a1 -> b2 [constraint=false]
}
Using constraint=false should get the nodes in your subgraphs to turn out the way you want
http://www.graphviz.org/doc/info/attrs.html#d:constraint
subgraph clusterB {
label=B
"0B"
"1B"
"2B" -> "0B" [constraint=false label=•]
}
After that you'll find that your subgraphs don't line up with each other the way you want. Something like this could resolve that.
"0A" -> "0B" -> "0C" -> "0D" -> "0E" [weight=999 style=invis];
An update on #marapet's answer using group
digraph g {
rankdir="LR";
node[shape = circle, fontsize=14];
fontsize=18;
labeljust="l";
edge[style=invis, fontsize=12];
{ rank=same;
0 [group=a style = invis];
01 [style = invis];
02 [group=b style=invis];
0 -> 01 -> 02;
}
subgraph clusterA {
"0A" [group=a]
"0A" -> "1A" -> "2A";
"2A" -> "0A" [label=".", constraint=false, style=solid];
label="A";
}
subgraph clusterB {
"0B" -> "1B" -> "2B";
"2B" -> "0B" [label=".", constraint=false, style=solid];
label="B";
}
subgraph clusterC {
"0C" [group=b]
"1C" [group=b]
"0C" -> "1C" -> "2C";
"2C" -> "0C" [label=".", constraint=false, style=solid];
label="C";
}
0 -> "0A"[style=solid];
01 -> "0B"[style=invis];
02 -> "0C"[style=invis];
// edges between clusters
edge[constraint=false, style=solid];
"0A" -> "1B" [label=a]
"1A" -> "2B" [label=a]
"0B" -> "1C" [label=b]
"1B" -> "2C" [label=b]
}
rankdir doesn't work directly in the subgraph, but if you add another set of curly braces - whatever that's called - rankdir works. See below. Then, obviously you need more tricks to restore the alignment and ordering you're after.
digraph G {
node [shape = circle]
0 [style = invis]
0 -> "0A"
subgraph clusterA {
label=A
{
rank=same
"0A"
"1A"
"2A" -> "0A" [label=•]
}
}
subgraph clusterB {
label=B
{
rank=same
"0B"
"1B"
"2B" -> "0B" [label=•]
}
}
subgraph clusterC {
label=C
{
rank=same
"0C"
"1C"
"2C" -> "0C" [label=•]
}
}
subgraph clusterD {
label=D
{
rank=same
"0D"
"1D"
"2D" -> "0D" [label=•]
}
}
subgraph clusterE {
label=E
{
rank=same
"0E"
"1E"
"2E" -> "0E" [label=•]
}
}
subgraph clusterF {
label=F
{
rank=same
{node [shape = doublecircle] "0F" "1F"}
"2F" -> "0F" [label=•]
}
}
"0A" -> "1B" [label=a]
"1A" -> "2B" [label=a]
"0B" -> "1C" [label=b]
"1B" -> "2C" [label=b]
"0C" -> "1D" [label=c]
"1C" -> "2D" [label=c]
"0D" -> "1E" [label=d]
"1D" -> "2E" [label=d]
"0E" -> "1F" [label=e]
"1E" -> "2F" [label=e]
}
Related
How do I align nodes with each other between subgraphs?
In the example, I would like all the 0 nodes aligned vertically as well as the 1, 2, 3 and 4 nodes. It would be good if all the right edges of subgraphs were extended as necessary to align too.
digraph AlignWhenMissing {
rankdir=LR;
node [shape=box]
subgraph clusterA {label = "A Shift a4 along (no a3)";
a0 -> a1;
a1 -> a2;
a2 -> a4;
}
subgraph clusterB {label = "B Shift b2 above a2";
b0 -> b2;
b2 -> b3;
}
subgraph clusterC {label = "C Shift c3 above b3";
c0 -> c3;
}
A -> a0[lhead=clusterA];
B -> b0[lhead=clusterB];
C -> c0[lhead=clusterC];
a0 -> b0[constraint=false];
b3 -> c3[constraint=false];
a2 -> b2[constraint=false];
}
The minlen attribute (https://graphviz.org/docs/attrs/minlen/) applies to edges to lengthen them (i.e. to push them "out" by N ranks).
Then added invisible nodes and edges to increase cluster dimension.
digraph AlignWhenMissing {
rankdir=LR;
node [shape=box]
subgraph clusterA {label = "A Shift a4 along (no a3)";
a0 -> a1;
a1 -> a2;
a2 -> a4 [minlen=2];
}
subgraph clusterB {label = "B Shift b2 above a2";
b0 -> b2 [minlen=2]
b2 -> b3;
b4 [style=invis]
b3 -> b4 [style=invis]
}
subgraph clusterC {label = "C Shift c3 above b3";
c0 -> c3 [minlen=3];
c4 [style=invis]
c3 -> c4 [style=invis]
}
A -> a0[lhead=clusterA];
B -> b0[lhead=clusterB];
C -> c0[lhead=clusterC];
a0 -> b0[constraint=false];
b3 -> c3[constraint=false];
a2 -> b2[constraint=false];
}
Giving:
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
*/
}
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
This is what I want to produce in a DOT graph:
I have the following code:
\digraph
[scale=0.7]{g1}
{
margin="0 0 0 0";
rankdir="TB";
"X" [shape=invhouse];
" " [shape=house];
"100" [shape=cylinder];
"X" -> "100"
"X" -> "+";
"100" -> "+"
"+" -> " ";
}
I also have the following code, which is closer in a sense but visually looks nothing like what I want:
digraph {
node[ shape = plaintext ];
a [label="X", shape = invhouse]
b [label="+", shape = ellipse]
ab1 [label="dummy", style=invis, shape=point]
ab2 [label="dummy", style=invis, shape=point]
c [label="100", shape = cylinder]
d [label=" ", shape=house]
subgraph cluster_0 {
style=invis
a -> ab1 [arrowhead=none];
ab1 -> c;
c -> ab2;
ab1 -> ab2 [arrowhead=none];
ab2 -> b;
b -> d;
}
}
How can I change my code(s) appropriately? Any help would be greatly appreciated.
the group attribute helps to bring nodes in line.
digraph {
node[ shape = plaintext group=abd];
a [label="X", shape = invhouse]
b [label="+", shape = ellipse]
ab1 [label="dummy", style=invis, shape=point]
ab2 [label="dummy", style=invis, shape=point]
c [label="100", shape = cylinder, group=c]
d [label=" ", shape=house]
subgraph cluster_0 {
style=invis
a -> ab1 [arrowhead=none];
ab1 -> c;
c -> ab2;
ab1 -> ab2 [arrowhead=none];
ab2 -> b;
b -> d;
}
}
My structure has two main chains with side nodes in sub graphs. Every thing looks nice but when i close the two chains all the boxes in the sub graphs jumps to the right side.
At the end of my code you can remove the "I"->"J" then you can see the best what I mean.
I am not a native English speaker, sorry about my English and I am a graphviz newbie.
digraph G {
size ="6,6";
node [color=black fontsize=12, shape=box, fontname=Helvetica];
subgraph {
rank = same;
"b"->"B"[arrowhead=none];
}
subgraph {
rank=same;
"c"->"C"[arrowhead=none];
}
subgraph {
rank=same;
"e"->"E" [arrowhead=none];
}
subgraph {
rank = same;
"f"->"F"[arrowhead=none];
}
subgraph {
rank = same;
"g"->"G"[arrowhead=none];
}
"0" -> "A" -> "B" -> "C"->"D" -> "E" -> "F" -> "G" -> "H"->"I";
"0" -> "K"->"L"->"M"->"N"->"O" ->"P"->"1";
subgraph {
rank = same;
"L"->"l"[arrowhead=none];
}
subgraph {
rank=same;
"M"->"m"[arrowhead=none];
}
subgraph {
rank=same;
"N"->"n" [arrowhead=none];
}
subgraph {
rank = same;
"O"->"o"[arrowhead=none];
}
subgraph {
rank = same;
"P"->"p"[arrowhead=none];
}
"1"->"J";
"I"->"J";
}
and with "I"->"J"; removed:
This is how I'd go about it: Create a cluster for each main chain with its side nodes:
digraph G {
size ="6,6";
node [color=black fontsize=12, shape=box, fontname=Helvetica];
subgraph[style=invis];
subgraph cluster0 {
A -> B -> C -> D -> E -> F -> G -> H -> I;
edge[arrowhead=none];
{rank = same; b->B;}
{rank = same; c->C;}
{rank = same; e->E;}
{rank = same; f->F;}
{rank = same; g->G;}
}
subgraph cluster1 {
K -> L -> M -> N -> O -> P -> 1 -> J;
edge[arrowhead=none];
{rank = same; L->l;}
{rank = same; M->m;}
{rank = same; N->n;}
{rank = same; O->o;}
{rank = same; P->p;}
}
0 -> A;
0 -> K;
I -> J;
}
Resulting in: