I made a graph and it looks like I want it to with one exception: the cluster containing nodes D and E should be placed between nodes B and C.
Here is the .dot:
digraph {
node[shape=rectangle]
graph [
newrank=true
];
Z
A
B
C
{
rank=same;
A -> B -> D;
D -> C[style=invis];
}
subgraph clusterSS {
style=dashed;
D[group=ss]
E[group=ss]
D -> E[style="dashed"; dir = none];
}
Z -> A
Z -> B
Z -> D
Z -> C
A -> P[dir = back]
B -> S
S -> B[constraint = false];
C -> S
S -> E[constraint = false]
E -> S[label = "Label"]
}
I expected that having edges between nodes
{
rank=same;
A -> B -> D;
D -> C[style=invis];
}
would ensure correct ordering, but it doesn't.
The ordering becomes correct once I delete the edge label between S and E, but I do need to keep the labels.
[non-trivial, not guaranteed to work as desired in any other circumstance]
Added clusters, invisible nodes,and more. ugh
digraph {
node[shape=rectangle]
graph [
newrank=true
];
{
rank=same;
A -> B -> D;
D -> C[style=invis];
}
subgraph clusterSS {
style=dashed;
D [group=ss]
E [group=ss]
D -> E[style="dashed"; dir = none];
}
subgraph clusterAP {
peripheries=0
A -> P[dir = back]
}
subgraph clusterB {
peripheries=0
B
bogus [style=invis shape=plain]
B->bogus [style=invis]
}
Z -> A
Z -> B
Z -> D
Z -> C
S [group=ss]
B -> S:nw
B -> S:w [dir=back]
C -> S
S -> E[constraint = false]
E -> S[label = "Label"]
}
Giving:
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 have a program that autogenerates a graphviz .dot file, the contents of which are a tree of subgraphs. When I observe how this file is rendered, the tree seems to be 'flattened', poorly displaying the hierarchical structure. I would like to know how to correct this issue, and properly render this tree.
In the past, I have used the fdp layout program to render this graph. It was able to show the hierarchical structure of the tree, but the contents of the nodes, which are subgraphs, were not very readable. I want to use the dot layout program since it does a better job layering the nodes of the subgraphs, and is said to be ideal for hierarchical graphs.
Please see the image below for a sample graph that shows the poorly rendered tree.
The code that generates this figure is:
digraph G {
compound=true
subgraph cluster_649 {label = EPISODE649count3
subgraph cluster_STATE650 {
label = State_1;
EPISODE649HEIGHT643[label="HEIGHT",shape=oval,color=blue];
EPISODE649LEN642[label="LEN",shape=oval,color=blue];
EPISODE649Y641[label="Y",shape=oval,color=blue];
EPISODE649X640[label="X",shape=oval,color=blue];
EPISODE649BLOCK639[label="BLOCK",shape=oval,color=blue];
EPISODE649HEIGHT638[label="HEIGHT",shape=oval,color=blue];
EPISODE649LEN637[label="LEN",shape=oval,color=blue];
EPISODE649Y636[label="Y",shape=oval,color=blue];
EPISODE649X635[label="X",shape=oval,color=blue];
EPISODE649TRIANGLE634[label="TRIANGLE",shape=oval,color=blue];
EPISODE649ON645[label="ON",shape=oval,color=blue];
EPISODE649ON555[label="ON",shape=oval,color=blue];
EPISODE649CLEAR647[label="CLEAR",shape=oval,color=blue];
EPISODE649CLEAR557[label="CLEAR",shape=oval,color=blue];
EPISODE649CLEAR558[label="CLEAR",shape=oval,color=blue];
EPISODE649ON556[label="ON",shape=oval,color=blue];
EPISODE649BLOCK545[label="BLOCK",shape=oval,color=blue];
EPISODE649X546[label="X",shape=oval,color=blue];
EPISODE649Y547[label="Y",shape=oval,color=blue];
EPISODE649LEN548[label="LEN",shape=oval,color=blue];
EPISODE649HEIGHT549[label="HEIGHT",shape=oval,color=blue];
EPISODE649BLOCK550[label="BLOCK",shape=oval,color=blue];
EPISODE649X551[label="X",shape=oval,color=blue];
EPISODE649Y552[label="Y",shape=oval,color=blue];
EPISODE649LEN553[label="LEN",shape=oval,color=blue];
EPISODE649HEIGHT554[label="HEIGHT",shape=oval,color=blue];
EPISODE649BLOCK639 -> EPISODE649HEIGHT643;
EPISODE649BLOCK639 -> EPISODE649LEN642;
EPISODE649BLOCK639 -> EPISODE649Y641;
EPISODE649BLOCK639 -> EPISODE649X640;
EPISODE649TRIANGLE634 -> EPISODE649HEIGHT638;
EPISODE649TRIANGLE634 -> EPISODE649LEN637;
EPISODE649TRIANGLE634 -> EPISODE649Y636;
EPISODE649TRIANGLE634 -> EPISODE649X635;
EPISODE649ON645 -> EPISODE649HEIGHT643;
EPISODE649ON645 -> EPISODE649LEN642;
EPISODE649ON645 -> EPISODE649Y641;
EPISODE649ON645 -> EPISODE649X640;
EPISODE649ON645 -> EPISODE649BLOCK639;
EPISODE649ON645 -> EPISODE649HEIGHT638;
EPISODE649ON645 -> EPISODE649LEN637;
EPISODE649ON645 -> EPISODE649Y636;
EPISODE649ON645 -> EPISODE649X635;
EPISODE649ON645 -> EPISODE649TRIANGLE634;
EPISODE649ON555 -> EPISODE649ON645;
EPISODE649ON555 -> EPISODE649ON556;
EPISODE649CLEAR647 -> EPISODE649HEIGHT638;
EPISODE649CLEAR647 -> EPISODE649LEN637;
EPISODE649CLEAR647 -> EPISODE649Y636;
EPISODE649CLEAR647 -> EPISODE649X635;
EPISODE649CLEAR647 -> EPISODE649TRIANGLE634;
EPISODE649CLEAR557 -> EPISODE649CLEAR647;
EPISODE649CLEAR557 -> EPISODE649CLEAR558;
EPISODE649CLEAR558 -> EPISODE649BLOCK545;
EPISODE649CLEAR558 -> EPISODE649X546;
EPISODE649CLEAR558 -> EPISODE649Y547;
EPISODE649CLEAR558 -> EPISODE649LEN548;
EPISODE649CLEAR558 -> EPISODE649HEIGHT549;
EPISODE649ON556 -> EPISODE649BLOCK545;
EPISODE649ON556 -> EPISODE649X546;
EPISODE649ON556 -> EPISODE649Y547;
EPISODE649ON556 -> EPISODE649LEN548;
EPISODE649ON556 -> EPISODE649HEIGHT549;
EPISODE649ON556 -> EPISODE649BLOCK550;
EPISODE649ON556 -> EPISODE649X551;
EPISODE649ON556 -> EPISODE649Y552;
EPISODE649ON556 -> EPISODE649LEN553;
EPISODE649ON556 -> EPISODE649HEIGHT554;
EPISODE649BLOCK545 -> EPISODE649X546;
EPISODE649BLOCK545 -> EPISODE649Y547;
EPISODE649BLOCK545 -> EPISODE649LEN548;
EPISODE649BLOCK545 -> EPISODE649HEIGHT549;
EPISODE649BLOCK550 -> EPISODE649X551;
EPISODE649BLOCK550 -> EPISODE649Y552;
EPISODE649BLOCK550 -> EPISODE649LEN553;
EPISODE649BLOCK550 -> EPISODE649HEIGHT554;
}
649[shape=point style=invis]
}
subgraph cluster_559 {label = EPISODE559count1
subgraph cluster_STATE651 {
label = State_1;
EPISODE559CLEAR557[label="CLEAR",shape=oval,color=blue];
EPISODE559CLEAR558[label="CLEAR",shape=oval,color=blue];
EPISODE559ON555[label="ON",shape=oval,color=blue];
EPISODE559ON556[label="ON",shape=oval,color=blue];
EPISODE559BLOCK545[label="BLOCK",shape=oval,color=blue];
EPISODE559X546[label="X",shape=oval,color=blue];
EPISODE559Y547[label="Y",shape=oval,color=blue];
EPISODE559LEN548[label="LEN",shape=oval,color=blue];
EPISODE559HEIGHT549[label="HEIGHT",shape=oval,color=blue];
EPISODE559BLOCK550[label="BLOCK",shape=oval,color=blue];
EPISODE559X551[label="X",shape=oval,color=blue];
EPISODE559Y552[label="Y",shape=oval,color=blue];
EPISODE559LEN553[label="LEN",shape=oval,color=blue];
EPISODE559HEIGHT554[label="HEIGHT",shape=oval,color=blue];
EPISODE559CLEAR557 -> EPISODE559CLEAR558;
EPISODE559CLEAR558 -> EPISODE559BLOCK545;
EPISODE559CLEAR558 -> EPISODE559X546;
EPISODE559CLEAR558 -> EPISODE559Y547;
EPISODE559CLEAR558 -> EPISODE559LEN548;
EPISODE559CLEAR558 -> EPISODE559HEIGHT549;
EPISODE559ON555 -> EPISODE559ON556;
EPISODE559ON556 -> EPISODE559BLOCK545;
EPISODE559ON556 -> EPISODE559X546;
EPISODE559ON556 -> EPISODE559Y547;
EPISODE559ON556 -> EPISODE559LEN548;
EPISODE559ON556 -> EPISODE559HEIGHT549;
EPISODE559ON556 -> EPISODE559BLOCK550;
EPISODE559ON556 -> EPISODE559X551;
EPISODE559ON556 -> EPISODE559Y552;
EPISODE559ON556 -> EPISODE559LEN553;
EPISODE559ON556 -> EPISODE559HEIGHT554;
EPISODE559BLOCK545 -> EPISODE559X546;
EPISODE559BLOCK545 -> EPISODE559Y547;
EPISODE559BLOCK545 -> EPISODE559LEN548;
EPISODE559BLOCK545 -> EPISODE559HEIGHT549;
EPISODE559BLOCK550 -> EPISODE559X551;
EPISODE559BLOCK550 -> EPISODE559Y552;
EPISODE559BLOCK550 -> EPISODE559LEN553;
EPISODE559BLOCK550 -> EPISODE559HEIGHT554;
}
559[shape=point style=invis]
}
649 -> 559 [ltail=cluster_649 lhead=cluster_559];
subgraph cluster_625 {label = EPISODE625count1
subgraph cluster_STATE652 {
label = State_1;
EPISODE625CLEAR623[label="CLEAR",shape=oval,color=blue];
EPISODE625CLEAR624[label="CLEAR",shape=oval,color=blue];
EPISODE625ON621[label="ON",shape=oval,color=blue];
EPISODE625ON622[label="ON",shape=oval,color=blue];
EPISODE625BLOCK611[label="BLOCK",shape=oval,color=blue];
EPISODE625X612[label="X",shape=oval,color=blue];
EPISODE625Y613[label="Y",shape=oval,color=blue];
EPISODE625LEN614[label="LEN",shape=oval,color=blue];
EPISODE625HEIGHT615[label="HEIGHT",shape=oval,color=blue];
EPISODE625BLOCK616[label="BLOCK",shape=oval,color=blue];
EPISODE625X617[label="X",shape=oval,color=blue];
EPISODE625Y618[label="Y",shape=oval,color=blue];
EPISODE625LEN619[label="LEN",shape=oval,color=blue];
EPISODE625HEIGHT620[label="HEIGHT",shape=oval,color=blue];
EPISODE625CLEAR623 -> EPISODE625CLEAR624;
EPISODE625CLEAR624 -> EPISODE625BLOCK611;
EPISODE625CLEAR624 -> EPISODE625X612;
EPISODE625CLEAR624 -> EPISODE625Y613;
EPISODE625CLEAR624 -> EPISODE625LEN614;
EPISODE625CLEAR624 -> EPISODE625HEIGHT615;
EPISODE625ON621 -> EPISODE625ON622;
EPISODE625ON622 -> EPISODE625BLOCK611;
EPISODE625ON622 -> EPISODE625X612;
EPISODE625ON622 -> EPISODE625Y613;
EPISODE625ON622 -> EPISODE625LEN614;
EPISODE625ON622 -> EPISODE625HEIGHT615;
EPISODE625ON622 -> EPISODE625BLOCK616;
EPISODE625ON622 -> EPISODE625X617;
EPISODE625ON622 -> EPISODE625Y618;
EPISODE625ON622 -> EPISODE625LEN619;
EPISODE625ON622 -> EPISODE625HEIGHT620;
EPISODE625BLOCK611 -> EPISODE625X612;
EPISODE625BLOCK611 -> EPISODE625Y613;
EPISODE625BLOCK611 -> EPISODE625LEN614;
EPISODE625BLOCK611 -> EPISODE625HEIGHT615;
EPISODE625BLOCK616 -> EPISODE625X617;
EPISODE625BLOCK616 -> EPISODE625Y618;
EPISODE625BLOCK616 -> EPISODE625LEN619;
EPISODE625BLOCK616 -> EPISODE625HEIGHT620;
}
625[shape=point style=invis]
}
649 -> 625 [ltail=cluster_649 lhead=cluster_625];
subgraph cluster_648 {label = EPISODE648count1
subgraph cluster_STATE653 {
label = State_1;
EPISODE648CLEAR646[label="CLEAR",shape=oval,color=blue];
EPISODE648CLEAR647[label="CLEAR",shape=oval,color=blue];
EPISODE648ON644[label="ON",shape=oval,color=blue];
EPISODE648ON645[label="ON",shape=oval,color=blue];
EPISODE648TRIANGLE634[label="TRIANGLE",shape=oval,color=blue];
EPISODE648X635[label="X",shape=oval,color=blue];
EPISODE648Y636[label="Y",shape=oval,color=blue];
EPISODE648LEN637[label="LEN",shape=oval,color=blue];
EPISODE648HEIGHT638[label="HEIGHT",shape=oval,color=blue];
EPISODE648BLOCK639[label="BLOCK",shape=oval,color=blue];
EPISODE648X640[label="X",shape=oval,color=blue];
EPISODE648Y641[label="Y",shape=oval,color=blue];
EPISODE648LEN642[label="LEN",shape=oval,color=blue];
EPISODE648HEIGHT643[label="HEIGHT",shape=oval,color=blue];
EPISODE648CLEAR646 -> EPISODE648CLEAR647;
EPISODE648CLEAR647 -> EPISODE648TRIANGLE634;
EPISODE648CLEAR647 -> EPISODE648X635;
EPISODE648CLEAR647 -> EPISODE648Y636;
EPISODE648CLEAR647 -> EPISODE648LEN637;
EPISODE648CLEAR647 -> EPISODE648HEIGHT638;
EPISODE648ON644 -> EPISODE648ON645;
EPISODE648ON645 -> EPISODE648TRIANGLE634;
EPISODE648ON645 -> EPISODE648X635;
EPISODE648ON645 -> EPISODE648Y636;
EPISODE648ON645 -> EPISODE648LEN637;
EPISODE648ON645 -> EPISODE648HEIGHT638;
EPISODE648ON645 -> EPISODE648BLOCK639;
EPISODE648ON645 -> EPISODE648X640;
EPISODE648ON645 -> EPISODE648Y641;
EPISODE648ON645 -> EPISODE648LEN642;
EPISODE648ON645 -> EPISODE648HEIGHT643;
EPISODE648TRIANGLE634 -> EPISODE648X635;
EPISODE648TRIANGLE634 -> EPISODE648Y636;
EPISODE648TRIANGLE634 -> EPISODE648LEN637;
EPISODE648TRIANGLE634 -> EPISODE648HEIGHT638;
EPISODE648BLOCK639 -> EPISODE648X640;
EPISODE648BLOCK639 -> EPISODE648Y641;
EPISODE648BLOCK639 -> EPISODE648LEN642;
EPISODE648BLOCK639 -> EPISODE648HEIGHT643;
}
648[shape=point style=invis]
}
649 -> 648 [ltail=cluster_649 lhead=cluster_648];
}
Observe that in order to draw edges from cluster to cluster, I've created invisible nodes in each cluster, like: 625[shape=point style=invis] and connected two invisible nodes if there is a parent/child relation between the two clusters, like: 649 -> 625 [ltail=cluster_649 lhead=cluster_625];
Thanks for your help!
Your invisible nodes were a good idea, but you got caught by dot's (unwritten?) rule that all nodes should be on the same rank unless there is a command the "forces" a new rank. If you change "invisible" to "dotted", you will see what happened to those nodes.
I tried to find a straightforward way to get dot to play nicely with those extra nodes, but failed.
Eventually I used some of the existing nodes to accomplish what I assume is the goal.
I left these edges visible so you could easily see what I changed.
I also added peripheries and margin attributes.
A cut-down version of the program:
digraph G {
compound = true
// a dummy cluster to pad the left side
subgraph cluster_dummy{
label="" ; peripheries=0;node[style=invis]; {rank=same _a; _b }
}
peripheries=0
subgraph cluster_649 {
label = EPISODE649count3
subgraph cluster_STATE650 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
subgraph cluster_559 {
label = EPISODE559count1
subgraph cluster_STATE651 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
subgraph cluster_625 {
label = EPISODE625count1
subgraph cluster_STATE652 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
subgraph cluster_648 {
label = EPISODE648count1
subgraph cluster_STATE653 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
EPISODE649HEIGHT638 -> EPISODE559ON555 [weight=0 style=dotted]
EPISODE649HEIGHT638 -> EPISODE625ON621 [weight=0 style=dotted]
EPISODE649HEIGHT638 -> EPISODE648ON644 [weight=0 style=dotted]
}
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
}