I have this graph:
digraph G{
rankdir = TB;
hyb[label="Hybrid calculation"];
k1[label=<k<SUB>1</SUB>>];
k2[label=<k<SUB>2</SUB>>];
kn[label=<k<SUB>n</SUB>>];
// subgraph cluster_k1q {
k1q1[label=<q<SUB>1</SUB>>];
k1q2[label=<q<SUB>2</SUB>>];
k1qn[label=<q<SUB>n</SUB>>];
graph[style=dotted];
{rank=same; k1q1;k1q2;k1qn}
// }
// subgraph cluster_k2q {
k2q1[label=<q<SUB>1</SUB>>];
k2q2[label=<q<SUB>2</SUB>>];
k2qm[label=<q<SUB>m</SUB>>];
graph[style=dotted];
{rank=same; k2q1;k2q2;k2qm}
// }
// subgraph cluster_knq {
knq1[label=<q<SUB>1</SUB>>];
knq2[label=<q<SUB>2</SUB>>];
knql[label=<q<SUB>l</SUB>>];
graph[style=dotted];
{rank=same; knq1;knq2;knql}
// }
hyb -> k1;
hyb -> k2;
hyb -> kn;
k1 -> k1q1;
k1 -> k1q2;
k1 -> k1qn;
k2 -> k2q1;
k2 -> k2q2;
k2 -> k2qm;
kn -> knq1;
kn -> knq2;
kn -> knql;
bands1 -> k1q2;
bands1 -> k2qm;
bands1 -> knq1
bands2 -> k1qn;
bands2 -> knq1;
bands3 -> knql;
bands3 -> k1q1;
{edge[ style=invis];
k1->k2->kn;
k1q1->k1q2->k1qn->k2q1->k2q2->k2qm->knq1->knq2->knql;
}
{ rank=min; hyb}
{ rank=same; k1;k2;kn}
{ rank=same; k1q1;k1q2;k1qn;k2q1;k2q1;k2qm;knq1;knq2;knql}
{ rank=max; bands1;bands2;bands3}
}
Resulting in this graph:
All the ks are on one level, all the qs are one level and so are the bands. Then I would like to draw some boxes around the qs using clusters. So if I uncomment the subgraph in above code I have to comment this line:
{ rank=same; k1q1;k1q2;k1qn;k2q1;k2q1;k2qm;knq1;knq2;knql}
and I get:
Here the bands get thrown in same level with the qs. How can I get the levels from the top graph with the nice boxes from the bottom graph?
add this: newrank=true
See: https://graphviz.org/docs/attrs/newrank/
(you could also probably accomplish it by changing the direction of the bandX->qY edges, like so: k1q2->bands1 [dir=back])
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
The graph I would like contains a top row; the rightmost node (T3) then points to A. A through E are in a vertical column, C and F are vertically aligned and H, I and J are vertically aligned. Additionally, C, F and H are horizontally aligned and E, G and J are horizontally aligned.
When I add subgraph cluster_0 in front of the already existing subgraphs, i.e. subgraph cluster_0 { rank=same; A -> B -> C-> D-> E; }, the subgraph becomes horizontally aligned...
How can I introduce the cluster without this occurring? Also, the edge from T3 to A is nearly straight. I would be nice if it went straight down, right angled to the left then right angled down to A.
Here is what works:
digraph G { rankdir = LR ranksep = 1.2 nodesep = 0.5
T1 -> T2 -> T3;
{ rank=same; A -> B -> C -> D -> E; }
C -> F
{ rank=same F -> G[style=invis] }
E->G
{ rankdir=LR rank=same H -> I -> J}
F -> H [style=dotted]
G -> J [style=invis]
edge [constraint=false]
T3->A
}
And here is what doesn't work
digraph G { rankdir = LR ranksep = 1.2 nodesep = 0.5
T1 -> T2 -> T3;
subgraph cluster_0 { rank=same; A -> B -> C -> D -> E; }
C -> F
subgraph cluster_1 { rank=same F -> G[style=invis] }
E->G
subgraph cluster_2 { rankdir=LR rank=same H -> I -> J}
F -> H [style=dotted]
G -> J [style=invis]
edge [constraint=false]
T3->A
}
This is about as close as I can get, but the clusters definitely introduce some differences. Also the "almost straight" lines I corrected with splines=ortho. I moved the ABCDE subgraph over with an invisible edge to T1.
digraph G { rankdir=TB ranksep = 0.5 nodesep = 0.5 splines=ortho
{rank=same T1 -> T2 -> T3;}
T1->A [style=invis]
subgraph cluster_0 {rank=min A -> B -> C -> D -> E; }
C -> F
subgraph cluster_1 { rank=same F -> G[style=invis] }
E->G
subgraph cluster_2 { rankdir=LR rank=same H -> I -> J}
F -> H [style=dotted]
G -> J [style=invis]
edge [constraint=false]
T3->A
}
I'm new to graphviz and have generated a graph that contains temporal constraints. That is, the order of nodes from left to right matters, but only locally. Here's the ruleset I'm trying to enforce:
1) Only and all 'box'-shaped nodes should be at the bottom of the graph. These represent terminal nodes.
2) Any rule at a 'doublecircle'-shaped node has temporal constraints (i.e. ordering matters).
Here's an attempt of enforcing these rules:
digraph G {
0 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
1 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
2 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
3 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
4 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
5 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
6 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
7 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
8 [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
9 [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
9 -> 0 [penwidth=3, weight=3]
9 -> 2 [penwidth=3, weight=3]
{
rank=same;
0->2[color=white]
rankdir=LR;
}
10 [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
10 -> 9 [penwidth=3, weight=3]
10 -> 5 [penwidth=3, weight=3]
{
rank=same;
9->5[color=white]
rankdir=LR;
}
11 [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
11 -> 4 [penwidth=3, weight=3]
11 -> 10 [penwidth=3, weight=3]
{
rank=same;
4->10[color=white]
rankdir=LR;
}
12 [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
12 -> 10 [penwidth=3, weight=3]
12 -> 11 [penwidth=3, weight=3]
{
rank=same;
10->11[color=white]
rankdir=LR;
}
13 [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
13 -> 4 [penwidth=3, weight=3]
13 -> 9 [penwidth=3, weight=3]
{
rank=same;
4->9[color=white]
rankdir=LR;
}
14 [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
14 -> 26 [penwidth=3, weight=3]
14 -> 8 [penwidth=3, weight=3]
{
rank=same;
26->8[color=white]
rankdir=LR;
}
15 [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
15 -> 12 [penwidth=3, weight=3]
15 -> 13 [penwidth=3, weight=3]
{
rank=same;
12->13[color=white]
rankdir=LR;
}
26 [shape=circle, fillcolor=palegreen1, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
26 -> 12[label = "0.50", penwidth=2.0, weight=3 ]
26 -> 15[label = "0.50", penwidth=2.0, weight=3 ]
}
From the ruleset, node 9 should have 0 as the left child and 2 as the right child, and so forth. This graph also does not enforce that all 'box;-shaped nodes should be at the bottom of the graph. Is it possible to build such a graph with GraphViz?
Thanks!
I'm not entirely sure how you would like this graph to look, but I have made an attempt. All boxes are at the bottom, this is done using a cluster subgraph (you can change the styling if you do not like the box). To prevent the edges from "special" edges (white in your code, red in mine because the background is also white) from interfering with the ordering, I specified a constraint = false on those edges. Let me know if this helps.
The code:
digraph G {
subgraph clusterSquares {
rank = same
node [shape=box, fillcolor=lightgrey, style=filled, ranksep=0.5, nodesep=0.5]
0; 1; 2; 3; 4; 5; 6; 7; 8;
}
{
node [shape=doublecircle, fillcolor=palegreen3, style=filled, color=blue, ranksep=0.5, nodesep=0.5]
edge [penwidth=3, weight=3]
9 -> { 0; 2; }
10 -> { 5; 9; }
11 -> { 4; 10 }
12 -> { 10; 11; }
13 -> { 4; 9; }
14 -> { 26; 8; }
15 -> { 12; 13; }
26 -> { 12; 15; }
}
{
edge [color = red, constraint = false]
0 -> 2
9 -> 5
4 -> 10
10 -> 11
4 -> 9
26 -> 8
13 -> 13
}
}
The resulting image: