Reputation: 161
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?
Upvotes: 2
Views: 792
Reputation: 6763
Here is an approximation. Done with ~225 lines of dot code and requiring a 3-step process:
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
*/
}
Upvotes: 3