Graphviz non-overlapping tree - graphviz

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:

Related

i tried 2 style of nested loop in golang, but it has different output

i have this quiz, you should make an output like this, and i search youtube tutorials for "for golang" and it explain that it has 2 style of for in golang,
1
21
11
12
13
14
22
11
12
13
14
23
11
12
13
14
24
11
12
13
14
2
21
11
12
13
14
22
11
12
13
14
23
11
12
13
14
24
11
12
13
14
3
21
11
12
13
14
22
11
12
13
14
23
11
12
13
14
24
11
12
13
14
4
21
11
12
13
14
22
11
12
13
14
23
11
12
13
14
24
11
12
13
14
5
21
11
12
13
14
22
11
12
13
14
23
11
12
13
14
24
11
12
13
14
it should be vertically outputted, not horizontally, so i build 3 variable, i = 1, j = 21, and k = 11, and i use for to automatically increase the value, the 1st style worked, but the 2nd style somehow its different
yt vid : https://www.youtube.com/watch?v=jZ-llP_yKNo on 5:28 min he explain that for has 2 style
1st style :
for i:=1; i <= 5; i++{
fmt.Println(i)
for j:=21; j <= 24; j++ {
println(j)
for k:=11; k<=14; k++ {
fmt.Println(k)
}
}
}
2nd style :
i:=1
j:=21
k:=11
for i <= 5{
fmt.Println(i)
i++
for j <= 24 {
println(j)
j++
for k<=14 {
fmt.Println(k)
k++
}
}
}
It's not about the syntax but about your logic.
In the 1st style with for i := ..., whenever next loop run, you reset the value to the init state, means it always sets j to 21 and k to 11. So there will a many sub loop runs.
In contrast, 2nd style, you init value j and k right before going to loop. So in the second loop of i, j and k are still the same value with 25 and 15 in that order.
There are multiple options to print the output in the golang.
fmt.Println appends a new line in the end.
fmt.Printf prints content as it is.
For more details read the documentation.
for i := 1; i <= 5; i++ {
fmt.Printf("%v ", i)
for j := 21; j <= 24; j++ {
fmt.Printf("%v ", j)
for k := 11; k <= 14; k++ {
fmt.Printf("%v ", k)
}
}
}
Output
1 21 11 12 13 14 22 11 12 13 14 23 11 12 13 14 24 11 12 13 14 2 21 11 12 13 14 22 11 12 13 14 23 11 12 13 14 24 11 12 13 14 3 21 11 12 13 14 22 11 12 13 14 23 11 12 13 14 24 11 12 13 14 4 21 11 12 13 14 22 11 12 13 14 23 11 12 13 14 24 11 12 13 14 5 21 11 12 13 14 22 11 12 13 14 23 11 12 13 14 24 11 12 13 14
To add a new line use the \n escape sequence.
Check the running code link

Placement of nodes in a nested subgraph in 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:

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?

Detect cycle in an undirected graph

In order to detect cycle in undirected graph,
following code anf algorithm are given; I am using normal Breadth First traversal along with slight modifications :
void bfsUtil(int s,vector<bool> &visited,vector<int> adj[],vector<int> &visits) {
queue<int> q;
q.push(s);
visits[s]++;
visited[s]=true;
while(!q.empty()) {
int vertex=q.front();
q.pop();
for(int i=0;i<adj[vertex].size();i++) {
if(!visited[adj[vertex][i]]) {
visited[adj[vertex][i]]=true;
q.push(adj[vertex][i]);
visits[adj[vertex][i]]++;
} else {
visits[adj[vertex][i]]++;
}
}
}
}
/* This function is used to detect a cycle in undirected graph
* adj[]: array of vectors to represent graph
* V: number of vertices
*/
bool isCyclic(vector<int> adj[], int V)
{
vector<int> visits(V,0);
vector<bool> visited(V,false);
for(int i=0;i<V;i++){
if(!visited[i]) {
bfsUtil(i,visited,adj,visits);
}
}
for(int i=0;i<visits.size();i++) {
if(visits[i]>2) {
return true;
}
}
return false;
}
Algorithm:
1. Normal Breadth first search and maintaining a count aray for the no of visits of each vertex.
2. If no of visits>2
print cycle is present
else
print no cycle
But i am getting wrong anwer for below test case:
Input:
46 45
0 44 1 23 1 35 1 37 1 38 2 20 2 35 3 13 4 44 5 21 5 36 6 41 7 8 8 18 9 17 9 41 9 45 10 13 10 21 10 33 10 34 10 39 10 42 11 17 12 24 13 44 14 19 15 25 16 34 18 24 19 25 21 24 21 26 22 37 23 28 25 31 25 35 25 40 25 41 25 44 27 43 27 44 29 40 30 34 32 33
Its Correct output is:
0
And Your Code's output is:
1
Where is my algorithm going wrong ?
Your algorithm is wrong. consider a graph of the following edges:
0 - 1
0 - 2
When the current node is 1, it also checks 0 as there is an edge from 1 to 0 too. so it will increment the visits count of 0. Similarly, 2 will also increment the count. So your code will always detect cycles wrongly.
To resolve this, you should keep a parent node for each node, from where the node is visited. When you are checking, you should never consider the edge to the parent.
And finally, you don't need the visits array. If you find an adjacent node that is not parent of current node, but is still visited before, then you can conclude that there is a cycle.
Modifying your code:
bool bfsUtil(int s,vector<bool> &visited,vector<int> adj[],vector<int> &parent) {
queue<int> q;
q.push(s);
visited[s]=true;
while(!q.empty()) {
int vertex=q.front();
q.pop();
for(int i=0;i<adj[vertex].size();i++) {
if(adj[vertex][i] == parent[vertex])
continue;
if(!visited[adj[vertex][i]]) {
visited[adj[vertex][i]]=true;
q.push(adj[vertex][i]);
parent[adj[vertex][i]] = vertex;
} else {
//cycle detected;
return true;
}
}
}
return false;
}
/* This function is used to detect a cycle in undirected graph
* adj[]: array of vectors to represent graph
* V: number of vertices
*/
bool isCyclic(vector<int> adj[], int V)
{
vector<bool> visited(V,false);
vector<int> parent(V, -1); // -1 means no parent assigned
for(int i=0;i<V;i++){
if(!visited[i]) {
if(bfsUtil(i,visited,adj,parent)) return true;
}
}
return false;
}

How to prevent the subgraph cluster alignment order from being reversed?

If I have a graphviz dot script like this:
digraph g {
node [style=rounded, shape=box]
subgraph cluster1 {
style="invis"
1 -> 2 -> 3 -> 4 -> 5
}
subgraph cluster2 {
style="invis"
6 -> 7
7 -> 8 -> 11
7 -> 9 -> 11
7 -> 10 -> 11
}
edge[constraint=false];
splines="ortho"
5 -> 6 [weight=0]
}
I get an output that looks like this (what I want):
However, if the labels in some of the nodes at the end become too long, the arrangement gets reversed like this:
digraph g {
node [style=rounded, shape=box]
8 [label="very long label"]
9 [label="very long label"]
10 [label="very long label"]
subgraph cluster1 {
style="invis"
1 -> 2 -> 3 -> 4 -> 5
}
subgraph cluster2 {
style="invis"
6 -> 7
7 -> 8 -> 11
7 -> 9 -> 11
7 -> 10 -> 11
}
edge[constraint=false];
splines="ortho"
5 -> 6 [weight=0]
}
How can I prevent this and force the original ordering method to occur?
You will have to define your long labels after having defined the other; graphviz draws the nodes in the order the are defined.
digraph g {
node [style=rounded, shape=box]
subgraph cluster1 {
style="invis"
1 -> 2 -> 3 -> 4 -> 5
}
subgraph cluster2 {
style="invis"
6 -> 7
7 -> 8 -> 11
7 -> 9 -> 11
7 -> 10 -> 11
}
8 [label="very long label"]
9 [label="very long label"]
10 [label="very long label"]
edge[constraint=false];
splines="ortho"
5 -> 6 [weight=0]
}
yields

Resources