graphviz: minor tweaks to make the graph look nicer - graphviz

I have a test graph here that I would like to tweak to make it look nicer.
Here is the graphviz (dot) source, test6.dot:
digraph G {
ranksep=0.3; size="6.0,6.0";
node [fontsize=11];
subgraph clusterA {
X2 [shape=box];
node [style=filled];
1 -> 2 -> 3 -> X2 -> 5;
6;
7;
label = "A";
color=blue
}
X1 [shape=box];
subgraph clusterB {
node [style=filled];
8;
9;
10 -> 11 -> 12;
12 -> 9;
12 -> 8 -> 13;
13 -> 14;
label = "B";
color=blue
}
subgraph clusterC {
label = "C";
{
node [style="invis"];
gap;
}
node [shape=box];
edge [style="invis"];
X3 -> gap -> X4;
}
14 -> X4 -> 3;
6 -> X1 -> 10;
{ edge [dir="both"];
8 -> X3 -> 7;
}
9 -> X3
}
Questions / changes I would like to make:
I want the flow of nodes 10 -> 11 -> 12 -> 8 -> 13 -> 14 to be in a vertical line (swap 8 and 9 horizontally). How can I do this? (same with 1 -> 2 -> 3 -> X2 -> 5; swap 6 and 1)
I want X1 to be at the same vertical position as 10, and the same horizontal position as 6. How can I do this?
I want 8 and X3 and 7 to be at the same vertical position, also with 14 and X4 and 3. How can I do this?
The ranksep=0.3; statement works great except note that 8 -> 13 -> 14 has a larger gap, as does X3 -> gap -> X4. Why doesn't it obey the ranksep=0.3 rule, and how do I fix this?

Below is the best I can do: phantom nodes and edges help. But I can't seem to encourage a particular ordering in the transverse direction (the other direction from rankdir).
digraph G {
ranksep=0.3; size="6.0,6.0";
rankdir=TB;
node [fontsize=11];
subgraph clusterA {
X2 [shape=box];
label = "A";
color=blue;
node [style=filled];
/* force 1, 6, and 7 to be at the top together,
add enough phantoms to keep things in nice columns */
{
node [style="invis", label=""];
phantom3;
phantom4;
phantom5;
phantom6;
}
rank = same;
1 -> 2 -> 3 -> X2 -> 5;
edge [style="invis"];
6 -> phantom3 -> phantom5;
7 -> phantom4 -> phantom6;
}
subgraph clusterB {
node [style=filled];
label = "B";
color=blue;
/* create an invisible phantom node
to take up space */
{
node [style="invis",label=""];
phantom1;
phantom1b;
}
{ rank=same; 11;
phantom1;
}
10 -> 11 -> 12 -> 8 -> 13 -> 14;
12 -> 9;
phantom1 -> 9 -> phantom1b [style="invis"];
}
/* force X1 to be at the same vertical pos as 10
(this yields a warning though) */
{ rank = same;
X1 [shape=box];
10;
}
6 -> X1;
X1 -> 10 [weight=0.5];
subgraph clusterC {
label = "C";
phantom2 [style="invis", label=""];
node [shape=box];
edge [style="invis"];
X3 -> phantom2 -> X4;
}
9 -> X3 [weight=0.5];
{
edge [weight=20];
14 -> X4 -> 3;
3 -> X4 -> 14 [style="invis"];
/* add a reverse path so graphviz doesn't force 14 above X4 above 3 */
}
{
edge [dir="both", weight=20];
8 -> X3 -> 7;
7 -> X3 -> 8 [style="invis"];
edge [style="invis"];
X4 -> phantom6;
1 -> phantom2;
8 -> phantom2;
}
}

Related

Arranging subclusters with rank

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])

Draw a program dependence graph with graphviz

I'm trying to draw a PDG, but when I add the data dependencies it gets malformed.
What I have
When I only draw the control dependencies the graph looks fine:
digraph {
4[label="4. int x=1"];
5[label="5. int y=2"];
6[label="6. while(x>0)"];
8[label="8. x=(y+x)"];
10[label="10. z=x+y"];
ENTRY -> 4[rank=same, splines=line];
ENTRY -> 5[rank=same, splines=line];
ENTRY -> 6[rank=same, splines=line];
ENTRY -> 10[rank=same, splines=line];
6 -> 8[splines=line];
}
When I try to add the data dependencies the graph gets malformed:
digraph {
4[label="4. int x=1"];
5[label="5. int y=2"];
6[label="6. while(x>0)"];
8[label="8. x=(y+x)"];
10[label="10. z=x+y"];
ENTRY -> 4[rank=same, splines=line];
ENTRY -> 5[rank=same, splines=line];
ENTRY -> 6[rank=same, splines=line];
ENTRY -> 10[rank=same, splines=line];
6 -> 8[splines=line];
4 -> 6[style=dashed, splines=curved, color=red];
8 -> 6[style=dashed, splines=curved, color=red];
4 -> 8[style=dashed, splines=curved, color=red];
5 -> 8[style=dashed, splines=curved, color=red];
4 -> 10[style=dashed, splines=curved, color=red];
5 -> 10[style=dashed, splines=curved, color=red];
8 -> 10[style=dashed, splines=curved, color=red];
}
I tried to add the attribute "splines=line" to draw straight lines (control dep.), but it doesnt't worked like expected. I also experimented with the attribute "weight" and "rank"...
Can someone give me a hint? Is it possible to set an order for the nodes?
Like:
Entry = first row and first element
Node 4 = second row and first element
...
Node 8 = third row and first element
Expected
Using rank = same properly, plus invisible edges to keep the order of the nodes in the middle should help:
digraph so
{
splines=true;
4[label="4. int x=1"];
5[label="5. int y=2"];
6[label="6. while(x>0)"];
8[label="8. x=(y+x)"];
10[label="10. z=x+y"];
{ rank = same; 4 5 6 10 }
ENTRY -> { 4 5 6 10 }
6 -> 8;
edge[style=dashed, color=red];
{ 4 8 } -> 6;
{ 4 5 } -> 8;
{ 4 5 8 } -> 10;
// keep graphViz from re-ordering these nodes:
4 -> 5 -> 6 -> 10[ style = invis ];
}
yields

Adding labels under subgraphs in Graphviz

I use the following code to produce a graph using dot in Graphviz. I have manually included the coordinates of nodes, as I require four disjoint subgraphs placed adjacent to one another, as in the picture.
I would love to add labels under each of the subgraphs: $G_0$, $G_1$, etc. Adding label under subgraph creates a box and ignores my coordinates alignment. Is there any other way, like placing arbitrary text at specified coordinates? I use "dot -Teps -Kfdp -n trees -o t.eps" for compilation.
digraph Trees {
node [shape=circle, style="filled", fixedsize=true,width=0.6]; 0; 1;2; 3;4; 5;6; 7; 8;9;10;11;12;13;14;15;
0[pos = "0,1!"]
1[fillcolor=red, pos = "-1,2!"]
2[pos = "1,2!"]
3 [pos = "0,-0.5!"]
5[label=1, fillcolor=red, pos = "2,2!"]
4[label=0, fillcolor=red, pos = "3,1!"]
6[label=2, pos = "4,2!"]
7[label=3, pos = "3, -0.5!"]
9[label=1, fillcolor=red, pos = "5,2!"]
8[label=0, fillcolor=red, pos = "6,1!"]
10[label=2, pos = "7,2!"]
11[label=3, fillcolor=red, pos = "6, -0.5!"]
12[label=1, fillcolor=red, pos = "8,2!"]
13[label=0, fillcolor=green, pos = "9,1!"]
14[label=2, pos = "10, 2!"]
15[label=3, fillcolor=green, pos = "9, -0.5!"]
overlap=false;
fontsize=10;
subgraph 1{
edge [dir=none] 1->0 2->0 3->0;
}
subgraph 2{
edge [color=red] 5->4;
edge[color=black, dir=none] 6->4 7->4;
}
subgraph 3{
edge [color=red] 9->8 8->11;
edge [color=black, dir=none] 8->10;
}
subgraph 4{
edge [color=green] 12->13; 13->15;
edge [color=black, dir=none] 13->14;
}
}
The sub-graphs can be made disjoint using clusters and the dot layout engine. The same approach will also permit the introduction of cluster labels. They can be placed at the bottom of the cluster as required without creating dummy nodes.
This way, no absolute positions are required, and, the layout is automatically generated even if other nodes are added. The exact position of the nodes change, but the graphs remain topologically unchanged.
digraph Trees { node [shape = circle, style = "filled", fixedsize = true, width=0.4];
edge [dir = none];
layout = dot; overlap = false; fontsize = 10;
graph [labelloc = "b", penwidth = 0];
{ node [fillcolor = "red"];
1; 5 [label = 1]; 4 [label = 0]; 9 [label = 1];
8 [label = 0]; 11 [label = 3]; 12 [label = 1];
}
2; 0; 3; 6 [label = 2]; 7 [label = 3];
10 [label = 2]; 14 [label = 2];
{ node [fillcolor = "green"];
13 [label = 0]; 15 [label = 3];
}
subgraph cluster1{
label = "Subgraph 1";
{ 1; 2; } -> 0 -> 3;
}
subgraph cluster2{
label = "Subgraph 2";
5 -> 4 [color = red, dir = fwd];
6 -> 4 -> 7;
}
subgraph cluster3{
label = "Subgraph 3";
9 -> 8-> 11 [color=red, dir = fwd];
10 -> 8 [color=black];
}
subgraph cluster4{
label = "Subgraph 4";
12 -> 13 -> 15 [color=green, dir = fwd];
14-> 13;
}
}
Instead of using explicit node positions, you may use a simple directed graph combined with some rank constraints, invisible edges and text nodes instead of subgraph labels:
digraph Trees {
fontsize=10;
node [shape=circle, style="filled", fixedsize=true,width=0.6];
{rank=same;
a1[label=1, fillcolor=red];
a2[label=2];
a3[label=1, fillcolor=red];
a4[label=2];
a5[label=1, fillcolor=red];
a6[label=2];
a7[label=1, fillcolor=red];
a8[label=2];
}
node[label=0];
b1;
b2[fillcolor=red];
b3[fillcolor=red];
b4[fillcolor=green];
node[label=3];
c1;
c2;
c3[fillcolor=red];
c4[fillcolor=green];
node[shape=none, fillcolor=transparent];
d1[label="Label 1"];
d2[label="Label 2"];
d3[label="Label 3"];
d4[label="Label 4"];
edge[dir=none];
a1->b1;
a2->b1;
b1->c1;
c1->d1[style=invis];
a3->b2[dir=forward, fillcolor=red, color=red];
a4->b2;
b2->c2;
c2->d2[style=invis];
a5->b3[dir=forward, fillcolor=red, color=red];
a6->b3[dir=forward, fillcolor=red, color=red];
b3->c3;
c3->d3[style=invis];
a7->b4[dir=forward, fillcolor=green, color=green];
a8->b4[dir=forward, fillcolor=green, color=green];
b4->c4;
c4->d4[style=invis];
edge[style=invis];
a2 -> a3;
a4 -> a5;
a6 -> a7;
}

GraphViz ignores my node positions

I can't get GraphViz to respect some node positions, even though they have pos attributes with !. E.g.:
digraph Versions {
ranksep=0.05;
node [style=filled, shape=point, fillcolor=black, fixedsize=true, width=0.3, height=0.1, fontname="Helvetica", fontsize=8, fontcolor=white];
edge [arrowhead=none, len=0.1];
2 [pos="0,0!", fillcolor=red];
3 [pos="20,0!", fillcolor=red];
4 [pos="40,0!", fillcolor=red];
5 [pos="60,0!", fillcolor=red];
6 [pos="80,0!", fillcolor=red];
7 [pos="100,0!", fillcolor=red];
8 [pos="120,0!", fillcolor=red];
9 [pos="140,0!", fillcolor=red];
10 [pos="160,0!", fillcolor=red];
11 [pos="180,0!", fillcolor=red];
12 [pos="200,0!", fillcolor=red];
13 [pos="220,0!", fillcolor=red];
2 -> 14;
14 -> 15;
3 -> 16;
16 -> 17;
11 -> 18;
18 -> 19;
6 -> 20;
20 -> 21;
10 -> 22;
22 -> 23;
13 -> 24;
24 -> 25;
9 -> 26;
26 -> 27;
4 -> 28;
28 -> 29;
7 -> 30;
30 -> 31;
5 -> 32;
32 -> 33;
8 -> 34;
34 -> 35;
12 -> 36;
36 -> 37;
15 -> 38;
38 -> 39;
17 -> 40;
40 -> 41;
19 -> 42;
42 -> 43;
// etc.
}
The top most rank should be evenly distributed, but is not. The horizontal spacing between the top most nodes is not the same:
From the documentation of the pos attribute:
In neato and fdp, pos can be used to set the initial position of a node.
Are you using neato or fdp? Because dot does not respect this attribute.
Assuming you're using neato, here's an excerpt from the manual:
-n[1|2] (no-op) If set, neato assumes nodes have already been positioned and all nodes have a pos attribute giving the positions
This means you can render a graph with
neato -n2 -Tpng mygraph.gv -o mygraph.png
and have neato respect the pos attributes (in points) of the nodes.
This also states that all nodes must have a pos attribute.
Since some nodes of your graph do not have a pos attribute, this will lead to an error.

Graphviz .dot node ordering

I'm building a epsilon NFA to recognize a regular expression using the canonical construction. I'm using subgraphs to group various parts of the regular expression. The * operator is giving me particular trouble since dot has decided to move the order of the nodes around. I've tried adding edge weights to force particular edges to be short to keep the order of the edges in line but that does not seem to be working.
What I would like to do is force the nodes in a subgraph in to be placed in a particular order so that the output graph is recognizable as a particular type of (well known) construction. In the example below I would like edges 3, 4, 5 and 6 placed in that order, however the dot places them in the order 6, 3, 4, 5. Any pointers appreciated.
Note that the current weight parameter produces no difference than no weight parameter at all.
I have the following
digraph G {
rankdir = LR;
node [shape = none];
0 [label = "start"];
node [shape = circle];
1 [label = "q1"];
2 [label = "q2"];
3 [label = "q3"];
4 [label = "q4"];
5 [label = "q5"];
node [shape = doublecircle];
6 [label = "q6"];
subgraph re1 {
rank = same;
edge[label = "0"];
1 -> 2;
};
subgraph re2 {
rank = same;
edge[label = "ε"];
3 -> 4 [weight = 10];
edge[label = "1"];
4 -> 5 [weight = 10];
edge[label = "ε"];
5 -> 6 [weight = 10];
5 -> 4 [weight = 1];
6 -> 3 [weight = 1];
};
edge[color=black];
0 -> 1
edge[label = "ε"];
2 -> 3;
}
Here's how I'd write that graph:
First of all, to me this is a graph which goes from top to bottom, not left to right, therefore I removed the rankdir=LR and added rank=same only for nodes 0/1 and nodes 2/3.
I removed all the weights
Most importantly, I added constraint=false to the edges going against the direction of the graph - the one going from node 4 to node 5, and the one from node 6 to node 3.
Here the source:
digraph G {
0 [label = "start", shape = none];
node [shape = circle];
1 [label = "q1"];
2 [label = "q2"];
3 [label = "q3"];
4 [label = "q4"];
5 [label = "q5"];
6 [label = "q6", shape = doublecircle];
{rank = same; 0 -> 1; }
1 -> 2 [label = "0"];
{rank = same; 2 -> 3 [label = "ε"]; }
4 -> 5 [label = "1"];
edge [label = "ε"];
3 -> 4;
5 -> 6;
5 -> 4 [constraint = false];
6 -> 3 [constraint = false];
}
And here's the result:
Now if you want to, you could keep rankdir=LR, just take the markup you posted, remove the weights and add constraint=false to the same edges as I did, it works, too.

Resources