Find Difficulty in Generating a Subgraph DAG using Graphviz - graphviz
I am using graphviz (version 2.40.1 (20161225.0304)) to convert a program-generated dot file to a png. Basically what I want to visualize by the dot file is a subgraph directed acyclic graph, i.e., subgraph DAG in short, where each node of the DAG is a subgraph. For the visualization, I need to present (1) the structure of the DAG; and (2) the topology of the subgraph of each DAG node.
For example, the following dot file generates the following png, where there are 3 DAG nodes and 2 DAG edges. I use cluster to represent the subgraph of each DAG node. I think it's still readable to human.
digraph plan_v1 {
rankdir=LR
compound=true
subgraph cluster28 {
color=black // not query
shape=box
penwidth=3
label="id: 28\ndag id: 0\ncardinality: 100"
{
rank=min
28.0 [shape=box label="id: 0\nlabel: 0"]
28.1 [shape=box label="id: 1\nlabel: 0"]
}
28.0 -> 28.1 [label="label: 0"]
}
subgraph cluster29 {
color=black // not query
shape=box
penwidth=3
label="id: 29\ndag id: 1\ncardinality: 301"
{
rank=min
29.0 [shape=box label="id: 0\nlabel: 0"]
29.1 [shape=box label="id: 1\nlabel: 0"]
}
{
rank=max
29.2 [shape=box label="id: 2\nlabel: 0"]
}
29.0 -> 29.1 [label="label: 0"]
29.0 -> 29.2 [label="label: 0"]
29.1 -> 29.2 [label="label: 0"]
}
28.1 -> 29.0 [ltail=cluster28 lhead=cluster29 penwidth=1 minlen=2 label="latency: 0\ncost: 0\npath cost: 0\nsub tree cost: 479"]
subgraph cluster15 {
color=black // not query
shape=box
penwidth=3
label="id: 15\ndag id: 2\ncardinality: 376"
{
rank=min
15.0 [shape=box label="id: 0\nlabel: 0"]
15.1 [shape=box label="id: 1\nlabel: 0"]
}
{
rank=max
15.2 [shape=box label="id: 2\nlabel: 0"]
}
15.0 -> 15.1 [label="label: 0"]
15.0 -> 15.2 [label="label: 0"]
15.2 -> 15.1 [label="label: 0"]
}
28.1 -> 15.0 [ltail=cluster28 lhead=cluster15 penwidth=1 minlen=2 label="latency: 0\ncost: 0\npath cost: 0\nsub tree cost: 2319"]
}
The problem is, when the number of vertices of the subgraph increases, graphviz uses large space to represent each DAG node that has a large subgraph. I want to reduce the space for large subgraph by controlling the layout of the subgraph vertices. Basically my strategy is, given a subgraph with n vertices, I give min rank to vertex id 0 and 1, max rank to vertex id n-1 and n-2, and I request the rank of vertex 2*i and 2*i+1 to be the same for 0<i<(n-1)/2. Forget to tell that I am a beginner of graphviz so there could be mistake for the design of the above strategy (but not implementation).
With the above strategy, I found that graphviz may not be able to generate png if the subgraph DAG is too complex. Here is an example: https://gist.github.com/zzxx-husky/50c5ad0cf56254dc0e01d7cb6b8389ad .
For the above gist example, if I directly use graphviz to convert it to png, graphviz throws me a segfault
libpath/shortest.c:324: triangulation failed
libpath/shortest.c:192: source point not in any triangle
Error: in routesplines, Pshortestpath failed
Segmentation fault (core dumped)
I tried to add rankdir=LR at the beginning, that may help convert the dot to png successfully, but graphviz still complains a lot of Warning: XXX -> YYY: head not inside head cluster clusterZZZ and the png is ugly (DAG nodes may overlap with each other).
Finally, I have to comment out all the rank=same in the dot if I want to convert the dot to a nice png successfully. However, those large DAG nodes in the png require a lot of space to present their subgraphs and the large subgraphs look a mess.
At the end, I wonder whether my use of rank=same is not correct and how can I reduce the space for presenting a large subgraph. Thanks in advance.
====== Updates at 20200810 ======
To answer #sroush's question, what I want is that those large subgraphs can use less space to present their topologies compactly. Here is how a subgraph with 7 vertices is presented (the left one below). The subgraph edges are too long and bend weirdly. But I hope less space is used, like the right one below, which is more neat and compact. One may point out that the figure below looks smaller is because I removed all the edge label. I wonder whether it is possible to make the subgraph neat while the subgraph edges still carry their labels.
Three possibilities - if you like any of them I'll post the input files. Coloring the edges would probably help.
Related
Graphviz - define the order of the clusters
I'm generating clustered nodes in graphviz/dot. Simplified example: digraph G { rankdir=LR n2a->n3 n1->n2b n2b->n2a n2b->n3 n3->n1 subgraph cluster_1 { label="cluster_1" n1 } subgraph cluster_2 { label="cluster_2" n2a n2b } subgraph cluster_3 { label="cluster_3" n3 } } I want to force dot to always put the clusters in ascending order from right to left (cluster 1 in the left, next is cluster 2 etc.), but to arrange the nodes inside each cluster as dot dictates automatically. I tried to play with clusterrank, rank, newrank, constraint=false and couldn't manage to make it happen. How can it be done?
You can "force" this to happen by adding edges to establish rank of every node in every cluster. Every node in cluster_1 has a lesser rank than every node in cluster_2, etc. Like so: digraph G { rankdir=LR n2a->n3 n1->n2b n2b->n2a n2b->n3 n3->n1 subgraph cluster_1 { label="cluster_1" n1 } subgraph cluster_2 { label="cluster_2" n2a n2b } subgraph cluster_3 { label="cluster_3" n3 } // simple-minded solution - force clusters based on (added) rank edge [style=invis] {n1} -> {n2a n2b} -> {n3} } Giving:
is there a way to consistently have dot subgraph order controlled?
The 'constraint=false'sometimes' allows the clusters to get out of order, even when doing so, causes longer edges. I wish to both have all subgraph clusters line up 'and' keep the order of the subgraph clusters intact. (which in my case, since I alway will only connect the edge to an node neighboring cluster, will result in edge that don't cross over an intervening subgraph. Sometimes it works as expected, but in the example I am posting, you can see the '2nd' subgraph for some reason shows up in the third position (which causes the links to go farther than they need to.) Is there a way to achieve both the lining up of all the tops of the subgraphs 'and' maintaining a specific order of subgraphs left to right? I have read many posts, and have tried many of the things suggested, but I can't seem to find a combination that works. When constraint=true, the 'order' seems to be correct, but the alignment is wrong. When constraint=false... The alignment is correct and 'sometimes' the order is correct, but other like the example posted, the order is invalid. digraph G { ranksep=.05; splines=line; subgraph cluster_1 { label="1"; choice0_0[label="1"]; choice0_1[label="2"]; choice0_2[label="3"]; choice0_0 -> choice0_1 -> choice0_2 [style="invis"]; } subgraph cluster_2 { label="2"; choice1_0[label="1"]; choice1_1[label="2"]; choice1_2[label="3"]; choice1_0 -> choice1_1 -> choice1_2 [style="invis"]; } subgraph cluster_3 { label="3"; choice2_0[label="1"]; choice2_1[label="2"]; choice2_2[label="3"]; choice2_0 -> choice2_1 -> choice2_2 [style="invis"]; } edge[constraint=false]; choice0_2 -> choice1_1; choice1_1 -> choice2_2; } dot -Tps x.gv -o x.ps (where x.gv contains the code pasted above) No errors are displayed when this is run, but this example the order of the 2nd and 3rd subgraph is swapped.
Order cluster nodes in graphviz
I have the following (simplified) graph which is generated by the following .dot: digraph Configurations { subgraph cluster_1 { s_0_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=yellowgreen] s_0_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=yellowgreen] } subgraph cluster_2 { s_1_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=yellowgreen] s_1_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=white] } subgraph cluster_3 { s_2_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=white] s_2_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=yellowgreen] } subgraph cluster_4 { s_3_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=white] s_3_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=white] } s_0_1 -> s_1_1 s_0_0 -> s_2_0 s_2_1 -> s_3_1 s_1_0 -> s_3_0 } I would like to be able to be able to enforce ordering inside the subgraphs so that the nodes of each subgraph are displayed in ascending order (each cluster should have nodes placed (0, 1), never (1, 0)). As I understand it, rankdir, which was my first attempt, is not supported in subgraphs, so what is a proper way to do this? I am looking for a solution which gives me a reasonably similar layout (which would then include more intersecting arrows) and is scalable, since the real graphs will be huge.
Turns out this could be solved by adding invisible edges inside and forcing same rank inside the graphs, like so: subgraph cluster_1 { {rank=same; s_0_0 s_0_1} s_0_0 -> s_0_1 [style=invis] s_0_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=yellowgreen] s_0_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=yellowgreen] }
If there are more nodes than 2 nodes, we need to change the solution. subgraph cluster1 { { HL_1_n HL_1_1 HL_1_2 HL_1_3 HL_1_m } HL_1_1 [label="Hidden Layer 1 Node 1" color=3] HL_1_2 [label="Hidden Layer 1 Node 2" color=3] HL_1_3 [label="Hidden Layer 1 Node 3" color=3] HL_1_m [label="Hidden Layer 1 Node ..." color=3] HL_1_n [label="Hidden Layer 1 Node H_1" color=3] label = "Hidden Layer" } It seems the order is determined, so we just need to change nodes' positions to fit the output. The solution does not use edge constraints and rank.
Placing clusters on the same rank in Graphviz
I would like these two nodes to appear on the same level: digraph G { subgraph cluster1 { label="Local Datacenter"; router1; host1; } subgraph cluster2 { label="Remote Datacenter"; router2; host2; } router1 -> router2; router2 -> host2; router1 -> host1; } I have tried using rank=same and rank=min, but they aren't giving me what I need. Interestingly, if I set rankdir=LR and comment out the two router-to-host edges, it gives me exactly the look I want - but I would like to leave the edges intact.
You may use the newrank graph attribute (added in GraphViz 2.30) to activate the new ranking algorithm which allows defining rank=same for nodes which belong to clusters. Add the following line at the top: newrank=true; Add the following line after the cluster definitions: { rank=same; router1; router2; } Here's the resulting graph:
You may simply modify the edge between the routers: router1 -> router2[constraint=false]; constraint indicates whether the edge should be used in the ranking of the nodes.
Rank attribute is confusing to me
Rank attribute on edge has five values "same", "min", "source", "max", "sink". Except "same", I have no idea when to use other values. min \begin{dotpic} rankdir=LR; size="7,5"; node[shape=circle]; C->A; {rank=min;A;B} B->D A->B; \end{dotpic} max \begin{dotpic} rankdir=LR; size="7,5"; node[shape=circle]; C->A; {rank=max;A;B} B->D A->B; \end{dotpic} source \begin{dotpic} rankdir=LR; size="7,5"; node[shape=circle]; C->A; {rank=source;A;B} B->D A->B; \end{dotpic} sink \begin{dotpic} rankdir=LR; size="7,5"; node[shape=circle]; C->A; {rank=sink;A;B} B->D A->B; \end{dotpic} With test on my vim environment, I can realize there is some difference btw these values. But don't know exactly what they are for.
Leaving the rank empty or using rank=same are used far more often. These other four are usually only used in special circumstances. When used alone, min and source have the same function: putting all those nodes on the minimum rank (the top row of a TB graph). The difference between them is that min will allow other subgraphs in the minimum rank. Source will not. Source only allows other subgraphs of min or source to be on the minimum rank. Consider the following graph snippet: { rank=source; a -> b; } { rank=same; c -> d; } You will end up with 2 rows. a -> b will be above c -> d. If you change source to min, you will only get one row. a -> b will be to left of c -> d, all in the min rank. { rank=min; a -> b; } { rank=same; c -> d; } Max and sink are the equivalents for the bottom of the graph.