Placement of nodes in a nested subgraph in Graphviz - graphviz

I am trying to create a plot of a binary, coloring and marking different nodes in different colors.
To get the borders around the subtrees I use subgraphs which works almost perfectly fine:
graph G
{
graph [ranksep="0.25", nodesep="0.25"]
rankdir = TB;
node [shape=ellipse, style=filled, fillcolor="#0068B4", color=white, fontcolor=white, penwidth=10]
edge [arrowtail="none"]
subgraph cluster_0 {
node [fillcolor="#99CC00"]
color="#99CC00"
style=filled
fillcolor=white
fontcolor="#99CC00"
label="12 is the root of\n26's left child\r"
18;
subgraph cluster_01 {
node [fillcolor="#00B0F0"]
color="#00B0F0"
fontcolor="#00B0F0"
style=filled
fillcolor=white
label="4 is the root of \n12's left child \r"
7 [fillcolor=white]
4 -- 13
4 -- 7 [style=invisible]
7 -- 13 [style=invisible]
{ rank=same; 7, 13 }
{ rank=same; 4, 18 }
}
12 -- {4,18}
{ rank=same; 12 }
}
subgraph cluster_1 {
node [fillcolor="#C00000"]
color="#C00000"
style=filled
fillcolor=white
fontcolor="#C00000"
label="32 is the root of\n26's right child\r"
35 [fillcolor=white]
32 -- 38
32 -- 35 [style=invisible]
35 -- 38 [style=invisible]
{ rank=same; 32 }
{ rank=same; 35, 38 }
}
26 -- {12, 32}
{ rank=same; 26 }
}
which leads to this output:
As you can see, the node 18 is placed inside the blue subcluster. Is there an easy way to move that node "out of the box" other than placing a blank dummy node (like the invisible nodes 7 and 35) between 4 and 18?

But, adding graph [newrank=true] and rearranging a few lines makes things better:
graph G
{
graph [ranksep="0.25", nodesep="0.25" newrank=true]
rankdir = TB;
node [shape=ellipse, style=filled, fillcolor="#0068B4", color=white, fontcolor=white, penwidth=10]
edge [arrowtail="none"]
subgraph cluster_0 {
node [fillcolor="#99CC00"]
color="#99CC00"
style=filled
fillcolor=white
fontcolor="#99CC00"
label="12 is the root of\n26's left child\r"
subgraph cluster_01 {
node [fillcolor="#00B0F0"]
color="#00B0F0"
fontcolor="#00B0F0"
style=filled
fillcolor=white
label="4 is the root of \n12's left child \r"
7 [fillcolor=white]
4 -- 13
4 -- 7 [style=invisible]
7 -- 13 [style=invisible]
{ rank=same; 7, 13 }
}
{ rank=same; 4, 18 }
12 -- {4,18}
{ rank=same; 12 }
}
subgraph cluster_1 {
node [fillcolor="#C00000"]
color="#C00000"
style=filled
fillcolor=white
fontcolor="#C00000"
label="32 is the root of\n26's right child\r"
35 [fillcolor=white]
32 -- 38
32 -- 35 [style=invisible]
35 -- 38 [style=invisible]
{ rank=same; 32 }
{ rank=same; 35, 38 }
}
26 -- {12, 32}
{ rank=same; 26 }
}
Gives:

Related

Graphviz non-overlapping tree

I am trying to use Graphviz to produce a tree such as the following:
I have it almost working, as shown below:
My problems are the following:
Subtrees should never overlap, but the PP tree and the (.) tree overlap.
Subtrees should always be fairly regular, so that if there are multiple children, the edges should go to the left and right of the parent. Again, this does not work properly for the PP tree.
I have fixed (1) by using subgraph clusters, however, this introduces a few new issues. Namely, the edges are not straight, and I can't figure out how to hide the borders without leaving tons of empty space.
Is there a better way to force the tree formatting? It feels like it shouldn't be too unusual.
My code is below (generated by Python, sorry for unhelpful names):
graph {
subgraph 0 {
subgraph 1 {
0 [label=ROOT group=0 shape=plain]
subgraph 8 {
1 [label=S group=1 shape=plain]
subgraph 11 {
2 [label=NP group=2 shape=plain]
subgraph 15 {
3 [label=PRP group=3 shape=plain]
4 [label=I shape=plain]
3 -- 4
4 [label=I group=3]
}
2 -- 3
3 [label=PRP group=2]
}
subgraph 24 {
5 [label=VP group=5 shape=plain]
subgraph 28 {
6 [label=VBD group=6 shape=plain]
7 [label=solved shape=plain]
6 -- 7
7 [label=solved group=6]
}
subgraph 41 {
8 [label=NP group=8 shape=plain]
subgraph 45 {
9 [label=DT group=9 shape=plain]
10 [label=the shape=plain]
9 -- 10
10 [label=the group=9]
}
subgraph 63 {
11 [label=NN group=11 shape=plain]
12 [label=problem shape=plain]
11 -- 12
12 [label=problem group=11]
}
8 -- 9
8 -- 11
}
subgraph 77 {
13 [label=PP group=13 shape=plain]
subgraph 81 {
14 [label=IN group=14 shape=plain]
15 [label=on shape=plain]
14 -- 15
15 [label=on group=14]
}
subgraph 89 {
16 [label=NP group=16 shape=plain]
subgraph 93 {
17 [label=DT group=17 shape=plain]
18 [label=the shape=plain]
17 -- 18
18 [label=the group=17]
}
subgraph 102 {
19 [label=NN group=19 shape=plain]
20 [label=bus shape=plain]
19 -- 20
20 [label=bus group=19]
}
16 -- 17
16 -- 19
}
13 -- 14
13 -- 16
}
5 -- 6
5 -- 8
5 -- 13
}
subgraph 114 {
21 [label="." group=21 shape=plain]
22 [label="." shape=plain]
21 -- 22
22 [label="." group=21]
}
1 -- 2
1 -- 5
1 -- 21
}
0 -- 1
1 [label=S group=0]
}
}
ranksep=0.2
}
You are correct, Graphviz has "problems" with trees. That said, here is your graph, with clusters (peripheries=0), splines=false, and margin=2:
graph {
graph [splines=false]
subgraph cluster_0 {
peripheries=0
margin=2
subgraph cluster_1 {
0 [label=ROOT group=0 shape=plain]
subgraph cluster_8 {
1 [label=S group=1 shape=plain]
subgraph cluster_11 {
2 [label=NP group=2 shape=plain]
subgraph cluster_15 {
3 [label=PRP group=3 shape=plain]
4 [label=I shape=plain]
3 -- 4
4 [label=I group=3]
}
2 -- 3
3 [label=PRP group=2]
}
subgraph cluster_24 {
5 [label=VP group=5 shape=plain]
subgraph cluster_28 {
6 [label=VBD group=6 shape=plain]
7 [label=solved shape=plain]
6 -- 7
7 [label=solved group=6]
}
subgraph cluster_41 {
8 [label=NP group=8 shape=plain]
subgraph cluster_45 {
9 [label=DT group=9 shape=plain]
10 [label=the shape=plain]
9 -- 10
10 [label=the group=9]
}
subgraph cluster_63 {
11 [label=NN group=11 shape=plain]
12 [label=problem shape=plain]
11 -- 12
12 [label=problem group=11]
}
8 -- 9
8 -- 11
}
subgraph cluster_77 {
13 [label=PP group=13 shape=plain]
subgraph cluster_81 {
14 [label=IN group=14 shape=plain]
15 [label=on shape=plain]
14 -- 15
15 [label=on group=14]
}
subgraph cluster_89 {
16 [label=NP group=16 shape=plain]
subgraph cluster_93 {
17 [label=DT group=17 shape=plain]
18 [label=the shape=plain]
17 -- 18
18 [label=the group=17]
}
subgraph cluster_102 {
19 [label=NN group=19 shape=plain]
20 [label=bus shape=plain]
19 -- 20
20 [label=bus group=19]
}
16 -- 17
16 -- 19
}
13 -- 14
13 -- 16
}
5 -- 6
5 -- 8
5 -- 13
}
subgraph cluster_114 {
21 [label="." group=21 shape=plain]
22 [label="." shape=plain]
21 -- 22
22 [label="." group=21]
}
1 -- 2
1 -- 5
1 -- 21
}
0 -- 1
1 [label=S group=0]
}
}
ranksep=0.2
}
Giving:

How to align subgraph to the bottom of another subgraph?

graph is built by Graphviz:
graph {
layout=circo;
subgraph cluster_0 {
1 -- { 2 3 4 5 6 }
2 -- { 3 4 5 6 }
3 -- { 4 5 6 }
4 -- { 5 6 }
5 -- { 6 }
};
subgraph cluster_1 {
a -- b;
a -- c;
a -- d;
1 -- a;
};
}
How to align cluster_1 to the bottom of cluster_0?

GraphViz temporal ordering of nodes

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:

How can I combine edges in an ortho graph?

I'm using splines=ortho and I was hoping for the edges to collapse together. To illustrate, I want to accomplish this:
I tried this:
digraph G {
splines=ortho;
edge [dir=none];
node [shape=diamond, label="", height=0.1, width=0.1];
start -> a [weight=10];
start -> b;
start -> c;
start -> d;
start -> e;
}
But it ends up looking like this:
Any clue on how I can make the edges overlap each other?
You need to create empty nodes on the same level as start and connect to them first, then draw the rest of your graph:
digraph G
{
node[ shape = point, label="", height=0, width=0 ] 01 02 03 04;
node[ shape=diamond, label="", height=0.1, width=0.1 ];
{ rank = same; start 01 02 03 04; }
edge [dir=none];
start -> 01 -> 02 -> 03 -> 04[ minlen = 2 ];
start -> a [weight=2];
01 -> b;
02 -> c;
03 -> d;
04 -> e;
}
yields

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];
}

Resources