subgraph cluster ranking in dot - graphviz

I'm trying to use graphviz on media wiki as a documentation tool for software.
First, I documented some class relationships which worked well. Everything was ranked vertically as expected.
But, then, some of our modules are dlls, which I wanted to seperate into a box. When I added the nodes to a cluster, they got edged, but clusters seem to have a LR ranking rule. Or being added to a cluster broke the TB ranking of the nodes as the cluster now appears on the side of the graph.
This graph represents what I am trying to do: at the moment, cluster1 and cluster2 appear to the right of cluster0.
I want/need them to appear below.
<graphviz>
digraph d {
subgraph cluster0 {
A -> {B1 B2}
B2 -> {C1 C2 C3}
C1 -> D;
}
subgraph cluster1 {
C2 -> dll1_A;
dll1_A -> B1;
}
subgraph cluster2 {
C3 -> dll2_A;
}
dll1_A -> dll2_A;
}
</graphviz>

The layout is an attempt by Dot to minimise the overall height.
One reason for the more compact than required layout is the use of the edge that goes in the reverse direction from dll1_a to B1. It tries to pull the cluster as close back to the destination node as possible. To avoid this edge affecting the graph, either relax the constraint on the upwards edges as shown, or draw the edge in the forward direction and use the dir attribute to reverse the arrow.
This will help with many layouts but it alone is not sufficient to fix the example given. To prevent Dot from maintaining the compact layout it prefers you can add a minlen attribute to edges that should remain (near) vertical. This may be difficult to calculate in general but is practical for manually tuned layouts.
digraph d {
subgraph cluster0 {
A -> {B1 B2}
B2 -> {C1 C2 C3}
C1 -> D;
}
subgraph cluster1 {
C2 -> dll1_A [minlen = 2];
dll1_A -> B1 [constraint = false];
/* B1 -> dll1_A [dir = back]; */
}
subgraph cluster2 {
C3 -> dll2_A;
}
dll1_A -> dll2_A;
}

My experience shows that constraint=false commonly gives unnecessarily convoluted edges. It seems that weight=0 gives better results:
digraph d {
subgraph cluster0 {
A -> {B1 B2}
B2 -> {C1 C2 C3}
C1 -> D;
}
subgraph cluster1 {
C2 -> dll1_A [minlen = 2];
dll1_A -> B1 [weight = 0];
/* B1 -> dll1_A [dir = back]; */
}
subgraph cluster2 {
C3 -> dll2_A;
}
dll1_A -> dll2_A;
}

This will produce the graph you are looking for:
digraph d {
subgraph cluster0 {
A -> {B1 B2}
B2 -> {C1 C2 C3}
C1 -> D;
}
subgraph {
rankdir="TB"
subgraph cluster1 {
C2 -> dll1_A;
dll1_A -> B1;
}
subgraph cluster2 {
C3 -> dll2_A;
}
}
dll1_A -> dll2_A;
}
What this does is creat a subgraph that is used only for layout purposes to provide the top to bottom ordering that you desire.

Related

Align nodes of subgraph with another subgraph nodes

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:

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

subgraph changed alignment when put into a cluster

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
}

Alignment issue with two clusters using Graphviz and Dot

I'm trying to get the following dot file to output two subgraphs. I want the bLoop node in cluster0 to align with the ISR struct in cluster 2. I'm using an invisible node to do this now, but with the unintended consequence of lot of gray space left in cluster0.
Is there a way to do what I want without the invisible node?
I can't post images yet, so here's the link.
digraph G {
ranksep=.75;
nodesep = 1.5;
node [shape = none]
node[fontsize=16,fixedsize=false,width=0.7,shape=rectangle];
edge[fontsize=16];
ratio=fill;
splines=false;
compound=true;
subgraph cluster0 {
node [style=filled];
style=filled;
color=lightgrey;
label = "Setup and Background Loop";
a0[label = "Peripheral Configs"];
a1[label = "Solar Library Block Configs"];
a2[label = "Enable Interrupts"];
bgLoop[label = "Start Background Loop"];
e0[shape=rectangle, style=invis, fixedsize=true, width=.01];
a0 -> a1 -> a2 -> bgLoop;
bgLoop ->e0[style=invis]
}
subgraph cluster1 {
node [style=filled, shape = "doublecircle"];
start
style="invis"
}
subgraph cluster2 {
node [shape=record,color=white];
style=filled;
color=lightgrey;
label = "ISRs";
struct1 [shape = record, color=white, label="{<f1> Slow ISR | <f2> Fast ISR }"];
}
concentrate = true;
struct1 -> bgLoop[lhead=cluster0, ltail=cluster4, constraint=true];
bgLoop -> struct1[lhead=cluster4, ltail=cluster0, constraint=true];
struct1 -> e0[style=invis, constraint=true];
start -> a0[lhead=cluster0];
}
you need helper nodes to get the correct rank for struct1.
digraph G {
ranksep=.75;
nodesep = 1.5;
node[fontsize=16,fixedsize=false,width=0.7,shape=rectangle];
edge[fontsize=16];
compound=true
subgraph cluster2 { rank="max"
node [shape=record,color=white];
style=filled;
color=lightgrey;
label = "ISRs";
struct1 [shape = record, color=white, label="{<f1> Slow ISR | <f2> Fast ISR }"];
}
subgraph cluster0 {
node [style=filled];
style=filled;
color=lightgrey;
label = "Setup and Background Loop";
a0[label = "Peripheral Configs"];
a1[label = "Solar Library Block Configs"];
a2[label = "Enable Interrupts"];
bgLoop[label = "Start Background Loop"];
a0 -> a1 -> a2 -> bgLoop;
}
subgraph cluster1 {
node [style=filled, shape = "doublecircle"];
start
style="invis"
}
{node [style=invis]; 0; 1; 2; 3; }
{edge [style=invis]; 0->1->2->3->struct1; }
struct1 -> bgLoop[lhead=cluster0, ltail=cluster2, constraint=false];
bgLoop -> struct1[lhead=cluster2, ltail=cluster0, constraint=false];
start -> a0[lhead=cluster0];
}

Graphviz - Box positioning Problem

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:

Resources