Forcing the edge between subgraphs to go left or right - graphviz

I have a PATRICA trie for which I'm generating a GraphViz file. The internal nodes are the skip values and the edges are dotted 0 and solid 1. It is preferred that 0 is to the left of 1, giving an alphabetical order of the leaves. I re-arranged the order I visit the graph so dot gives this result. However, when I group them in trees in a forest using subgraphs, I can't seem to force dot to reliably respect the order for inter-subgraph edges.
digraph {
rankdir=TB;
node [shape = box, style = filled, fillcolor = lightsteelblue];
// forest size 2.
subgraph cluster_tree0 {
style = filled; fillcolor = lightgray; label = "tree 0";
// branches
branch0_0 [label = "3", shape = none, fillcolor = none];
branch0_0 -> branch0_1;
branch0_1 [label = "0", shape = none, fillcolor = none];
branch0_1 -> branch0_2 [style = dashed];
branch0_2 [label = "1", shape = none, fillcolor = none];
branch0_2 -> leaf0_1 [style = dashed, color = royalblue];
branch0_2 -> leaf0_2 [color = royalblue];
branch0_1 -> branch0_3;
branch0_3 [label = "2", shape = none, fillcolor = none];
branch0_3 -> leaf0_3 [style = dashed, color = royalblue];
branch0_3 -> leaf0_4 [color = royalblue];
// leaves
leaf0_1 [label = "u"];
leaf0_2 [label = "v"];
leaf0_3 [label = "x"];
leaf0_4 [label = "y"];
}
branch0_0 -> branch1_0 [lhead = cluster_tree0, ltail = cluster_tree1, color = firebrick, style = dashed];
subgraph cluster_tree1 {
style = filled; fillcolor = lightgray; label = "tree 1";
// branches
branch1_0 [label = "0", shape = none, fillcolor = none];
branch1_0 -> leaf1_0 [style = dashed, color = royalblue];
branch1_0 -> branch1_1;
branch1_1 [label = "1", shape = none, fillcolor = none];
branch1_1 -> leaf1_1 [style = dashed, color = royalblue];
branch1_1 -> branch1_2;
branch1_2 [label = "0", shape = none, fillcolor = none];
branch1_2 -> leaf1_2 [style = dashed, color = royalblue];
branch1_2 -> leaf1_3 [color = royalblue];
// leaves
leaf1_0 [label = "f"];
leaf1_1 [label = "m"];
leaf1_2 [label = "n"];
leaf1_3 [label = "o"];
}
}
On one graph it works fine, but it the subgraphs are reversed to the order I want them.
I reversed the order in the file and it still looks the same. I played around with it and I could get it turned around by rank=same, ordering=out, and invis edges somehow, but I want it to be programmatic. Is there any easy way to draw the red dotted line, representing 0, to the left, instead of to the right, of the solid line, representing 1?

OK, a total kludge, but probably fully scriptable.
First, your input somewhat reworked:
digraph {
rankdir=TB;
newrank=true // helps
graph [splines=false]
node [shape = box, style = filled, fillcolor = lightsteelblue];
// forest size 2.
subgraph cluster_tree1 {
style = filled; fillcolor = lightgray; label = "tree 1";
// branches
branch1_0 [label = "0", shape = none, fillcolor = none];
branch1_0 -> leaf1_0 [style = dashed, color = royalblue];
branch1_0 -> branch1_1;
branch1_1 [label = "1", shape = none, fillcolor = none];
branch1_1 -> leaf1_1 [style = dashed, color = royalblue];
branch1_1 -> branch1_2;
branch1_2 [label = "0", shape = none, fillcolor = none];
branch1_2 -> leaf1_2 [style = dashed, color = royalblue];
branch1_2 -> leaf1_3 [color = royalblue];
// leaves
leaf1_0 [label = "f"];
leaf1_1 [label = "m"];
leaf1_2 [label = "n"];
leaf1_3 [label = "o"];
}
subgraph cluster_tree0 {
style = filled; fillcolor = lightgray; label = "tree 0";
// branches
branch0_0 [label = "3", shape = none, fillcolor = none];
branch0_0 -> branch0_1;
branch0_1 [label = "0", shape = none, fillcolor = none];
branch0_1 -> branch0_2 [style = dashed];
branch0_2 [label = "1", shape = none, fillcolor = none];
branch0_2 -> leaf0_1 [style = dashed, color = royalblue];
branch0_2 -> leaf0_2 [color = royalblue];
branch0_1 -> branch0_3;
branch0_3 [label = "2", shape = none, fillcolor = none];
branch0_3 -> leaf0_3 [style = dashed, color = royalblue];
branch0_3 -> leaf0_4 [color = royalblue];
// leaves
leaf0_1 [label = "u"];
leaf0_2 [label = "v"];
leaf0_3 [label = "x"];
leaf0_4 [label = "y"];
}
// position the clusters (trees)
{rank=same branch1_0 -> branch0_1 [style=invis weight=0]}
// a kludge, we'll add this edge in later
graph [comment="branch0_0 -> branch1_0 [color = firebrick, style = dashed constraint=false weight=0 ];"]
}
The "problem" is the cluster-to-cluster branch, so we remove it (for the first dot pass). And we add the invisible edge to position the clusters where we want them.
Run this input into dot -Tdot >myfile.dot. This sets positions for all nodes & edges.
Run that thru gawk (any language) to un-comment the commented branch(s) and insert into the file.
Finally, neato -n2 -Tpng fixedfile >fixed.png
(yuck, but it works)
f=atrie4.gv;
T=png; F=`basename $f .gv`;dot -Tdot $f >$F.dot;
gawk '
$1~/comment/{
sub(/[\t ]*comment="/,"")
sub(/"[\],;]?[\t ]*$/,"")
add[++a]=$0
next
}
{oline[++o]=$0}
END{
for (i=1;i<o;i++)print oline[i]
for (i=1;i<=a;i++)print add[i]
print oline[o]
}' $F.dot|
neato -n2 -Tpng >$F.$T
firefox $F.$T

Related

graphviz: dotted box around "same"-grouped boxes

I have a number of boxes that are put on the same level as such:
via multiple {rank=same a3 b3_1 b3_2 c3_1 c3_2 d3_1 d3_2}; lines whereas I define my elements with a3 [label = "Assigned"]; lines.
I'd like to get a (dotted, if possible) box around all elements that are on the same level, as such (mockup via editor):
The whole source looks as follows:
digraph customer {
layout=dot
label = "some diagram";
labelloc = "t"; // place the label at the top
node [shape=record];
{rank=same a1 b1 c1 d1};
{rank=same a2 b2 c2 d2};
{rank=same a3 b3_1 b3_2 c3_1 c3_2 d3_1 d3_2};
{rank=same a4 b4_1_1 b4_1_2 b4_2_1 b4_2_2 c4_1_1 c4_1_2 c4_2_1 c4_2_2 d4_1_1 d4_1_2 d4_2_1 d4_2_2};
{rank=same a5 b5_1 b5_2 b5_3 b5_4 c5_1 c5_2 c5_3 c5_4 d5_1 d5_2 d5_3 d5_4};
{rank=same a6 b6_1 b6_2 b6_3 b6_4 c6_1 c6_2 c6_3 c6_4 d6_1 d6_2 d6_3 d6_4};
a1 [label = "Level 1"];
a2 [label = "Level 2"];
a3 [label = "Level 3"];
a4 [label = "Level 4"];
a5 [label = "Level 5"];
a6 [label = "Level 6"];
a1 -> a2 -> a3 -> a4; a4 -> a5 [label = "case ..." ]; a5 -> a6;
b1 [label = "Text A"];
b2 [label = "false"];
b3_1 [label = "no"];
b3_2 [label = "yes"];
b4_1_1 [label = "same"];
b4_1_2 [label = "different"];
b4_2_1 [label = "same"];
b4_2_2 [label = "different"];
b5_1 [label = "no", fillcolor = red, style=filled];
b5_2 [label = "no", fillcolor = red, style=filled];
b5_3 [label = "no", fillcolor = red, style=filled];
b5_4 [label = "yes", fillcolor = green, style=filled];
b6_1 [label = "yes", fillcolor = green, style=filled];
b6_2 [label = "yes", fillcolor = green, style=filled];
b6_3 [label = "yes", fillcolor = green, style=filled];
b6_4 [label = "yes", fillcolor = green, style=filled];
b1 -> b2;
b2 -> b3_1; b3_1 -> b4_1_1; b4_1_1 -> b5_1 [label = "A" ]; b5_1 -> b6_1;
b3_1 -> b4_1_2; b4_1_2 -> b5_2 [label = "B" ]; b5_2 -> b6_2;
b2 -> b3_2; b3_2 -> b4_2_1; b4_2_1 -> b5_3 [label = "C" ]; b5_3 -> b6_3;
b3_2 -> b4_2_2; b4_2_2 -> b5_4 [label = "D" ]; b5_4 -> b6_4;
subgraph clusterone {
a1; b1; c1; d1;
label="level 1";
graph[style=dotted];
}
c1 [label = "Text B"];
c2 [label = "true"];
c3_1 [label = "no"];
c3_2 [label = "yes"];
c4_1_1 [label = "same"];
c4_1_2 [label = "different"];
c4_2_1 [label = "same"];
c4_2_2 [label = "different"];
c5_1 [label = "no", fillcolor = red, style=filled];
c5_2 [label = "no", fillcolor = red, style=filled];
c5_3 [label = "yes", fillcolor = green, style=filled];
c5_4 [label = "yes", fillcolor = green, style=filled];
c6_1 [label = "yes", fillcolor = green, style=filled];
c6_2 [label = "yes", fillcolor = green, style=filled];
c6_3 [label = "yes", fillcolor = green, style=filled];
c6_4 [label = "yes", fillcolor = green, style=filled];
c1 -> c2;
c2 -> c3_1; c3_1 -> c4_1_1; c4_1_1 -> c5_1 [label = "E" ]; c5_1 -> c6_1;
c3_1 -> c4_1_2; c4_1_2 -> c5_2 [label = "F" ]; c5_2 -> c6_2;
c2 -> c3_2; c3_2 -> c4_2_1; c4_2_1 -> c5_3 [label = "G" ]; c5_3 -> c6_3;
c3_2 -> c4_2_2; c4_2_2 -> c5_4 [label = "H" ]; c5_4 -> c6_4;
d1 [label = "(else)"];
d2 [label = "???", fillcolor = yellow, style=filled];
d3_1 [label = "no"];
d3_2 [label = "yes"];
d4_1_1 [label = "same"];
d4_1_2 [label = "different"];
d4_2_1 [label = "same"];
d4_2_2 [label = "different"];
d5_1 [label = "no", fillcolor = red, style=filled];
d5_2 [label = "no", fillcolor = red, style=filled];
d5_3 [label = "no", fillcolor = red, style=filled];
d5_4 [label = "no", fillcolor = red, style=filled];
d6_1 [label = "yes", fillcolor = green, style=filled];
d6_2 [label = "yes", fillcolor = green, style=filled];
d6_3 [label = "yes", fillcolor = green, style=filled];
d6_4 [label = "yes", fillcolor = green, style=filled];
d1 -> d2;
d2 -> d3_1; d3_1 -> d4_1_1; d4_1_1 -> d5_1 [label = "I" ]; d5_1 -> d6_1;
d3_1 -> d4_1_2; d4_1_2 -> d5_2 [label = "J" ]; d5_2 -> d6_2;
d2 -> d3_2; d3_2 -> d4_2_1; d4_2_1 -> d5_3 [label = "K" ]; d5_3 -> d6_3;
d3_2 -> d4_2_2; d4_2_2 -> d5_4 [label = "L" ]; d5_4 -> d6_4;
}
By some reason it conflicts with rank=same declaration.
Try removing it and use cluster instead with rank=same inside, like this:
subgraph cluster_one {
label="cluster one";
rank=same;
style=dotted;
a1 b1 c1 d1
};
subgraph cluster_two {
label="cluster two";
rank=same;
style=dotted;
a2 b2 c2 d2
};
or even shorter (one line):
subgraph cluster_one { label="cluster one" rank=same style=dotted a1 b1 c1 d1 }
Keep in mind, that width of subgraphs will not be the same, as it used to be.

How to set a graph-filling-area?

How to set the graph to try to fill the area allocated to it? With an increase in the number of nodes, it simply decreases in size, but also remains in one line, although the vertical size (40) allows placement down. If you remove the rankdir, then it places vertically, but also in one line.
digraph "test_graph"{
rankdir = LR;
bgcolor = whitesmoke;
graph [size = "15, 40"];
node [shape = circle,
style = filled,
margin = 0,
fontsize = 14,
color = sandybrown];
edge [fontsize = 10,
arrowhead = vee];
1->2 [label = "R"];
2->3 [label = "R"];
3->4 [label = "R"];
3->5 [label = "B"];
4->1 [label = "R"];
5->6 [label = "U"];
6->7 [label = "U"];
7->8 [label = "U"];
7->9 [label = "F"];
8->5 [label = "U"];
9->10 [label = "F"];
10->11 [label = "D"];
11->12 [label = "D"];
12->13 [label = "D"];
13->10 [label = "D"];
13->14 [label = "L"];
14->15 [label = "L"];
15->16 [label = "D"];
16->17 [label = "D"];
17->18 [label = "D"];
17->19 [label = "L"];
18->15 [label = "D"];
19->20 [label = "F"];
20->21 [label = "F"];
21->22 [label = "F"];
21->23 [label = "L"];
22->19 [label = "F"];
23->24 [label = "L"];
24->25 [label = "F"];
}
You will need to select suitable nodes that
are connected by one edge
connect to other nodes in a way that fills the available width as you like it
and then
connect them in the desired order by invisible edges (so that you avoid graphviz reordering them)
ranking them on the same lavel so that they appear one below the other
In concrete terms this means that adding
1 -> 10 -> 19[ style = invis ];
{ rank = same; 1 10 19 }
just before the closing curly brace, as the last two lines, will produce
which is, as far as I understand your requirement, what you want.

How to set bend direction for edges with splines="curved" in GraphViz? (using neato)

I am creating a graph with manually positioned nodes and use the splines="curved" type of edges between them.
digraph graphname {
splines="curved";
node[shape = box, margin="0.03,0.03", fontsize=11, height=0.1, width=0.1, fixedsize=false];
"LeftFoot\nRightHand" [pos="-150,-150!"];
"RightFoot\nRightHand" [pos="-90,-150!"];
"LeftFoot\nRightFoot" [pos="0,-150!"];
...
edge[style = solid,fontsize=11];
"LeftFoot\nRightFoot":n -> "RightFoot\nRightHand":n [label = "3", penwidth = 1, color = "red"];
"LeftFoot\nRightFoot":s -> "LeftFoot\nRightHand":s [label = "7", penwidth = 1, color = "red"];
...
}
The problem is that one of the edges is bent to the wrong side, so it passes through a node:
Is there an easy way to fix this, like e.g. "bend left" or "bend right" in TikZ?
I tried to use the pos attribute on the edge to set a spline control point to change the bend, however this does not appear to change the edge at all.
In Grapvhiz 2.38 this seems to be fixed. I've scaled the pos slightly but left the rest of the code alone:
Dot source:
digraph graphname {
splines="curved";
node[shape = box, margin="0.03,0.03", fontsize=11, height=0.1, width=0.1, fixedsize=false];
"LeftFoot\nRightHand" [pos="-2,-2!"];
"RightFoot\nRightHand" [pos="-1.2,-2!"];
"LeftFoot\nRightFoot" [pos="0,-2!"];
edge[style = solid,fontsize=11];
"LeftFoot\nRightFoot":n -> "RightFoot\nRightHand":n [label = "3", penwidth = 1, color = "red"];
"LeftFoot\nRightFoot":s -> "LeftFoot\nRightHand":s [label = "7", penwidth = 1, color = "red"];
}
Command:
dot -Kneato -Tpng input.gv > output.png
Output:

graphviz - how to create a 'roundtrip' flow

I'm trying to create a 'round trip' graph using the graphviz. Given the result below, my objective is to have the PINK squares between the NET and the COM (note from the picture below that they are pushed to the right after the NET).
the COM must be the first node on the LEFT.
the dot code:
digraph {
rankdir = LR;
graph [fontname = "helvetica" ];
node [fontname = "helvetica"];
edge [fontname = "helvetica"];
COM [shape = circle, fillcolor = yellow, style = filled];
NET [shape = circle, fillcolor = yellow, style = filled];
fn1 [shape = BOX, fillcolor = green, style = filled, label = "PORT006"];
clazz1 [shape = BOX, fillcolor = red, style = filled, label = "O"];
ddate1 [shape = BOX, fillcolor = red, style = filled, label = "21-Apr-13"];
status1 [shape = BOX, fillcolor = red, style = filled, label = "OJ3COM6M"];
clazz1exch [shape = BOX, fillcolor = green, style = filled, label = "G"];
ddate1exch [shape = BOX, fillcolor = green, style = filled, label = "13-May-13"];
status1exch [shape = BOX, fillcolor = green, style = filled, label = "GJ3COM6M"];
fn2 [shape = BOX, fillcolor = pink, style = filled, label = "PORT005"];
rbd2 [shape = BOX, fillcolor = pink, style = filled, label = "O"];
ddate2 [shape = BOX, fillcolor = pink, style = filled, label = "29-Apr-13"];
fare2 [shape = BOX, fillcolor = pink, style = filled, label = "OJ3COM6M"];
{ rank=same; clazz1 -> clazz1exch; }
{ rank= same; ddate1 -> ddate1exch; }
{ rank=same; status1 -> status1exch; }
COM -> fn1 -> clazz1exch -> ddate1exch -> status1exch -> NET;
NET -> fn2 -> rbd2 -> ddate2 -> fare2 -> COM;
}
If you simply reverse the direction of the edges going back (dir=back) by changing the line
NET -> fn2 -> rbd2 -> ddate2 -> fare2 -> COM;
into
edge[dir=back];
COM -> fare2 -> ddate2 -> rbd2 -> fn2 -> NET;
you should get:

Why does Graphviz/Dot act so weirdly to this particular code?

I am using GraphViz 2.28 (the current stable version) on Windows 7, and Graphviz/Dot crashes for the following code.
digraph G {
ranksep = 1.0; size = "10,10";
{
node [shape = plaintext, fontsize = 20];
GAWM1 -> GAWM2 -> 0;
}
node [shape = box];
{rank = same;0;wx1;wx2;rx1;}
wx1 -> wx2;
wx2 -> rx1;
wx1 -> rx1[color = blue];
subgraph struct
{
node [shape = record];
rx11 [shape = record, label = "rx1 | [x=[wx2]]"];
}
{rank = same; GAWM1; "rx11";}
// W'WR Order:
wx2 -> wx1[style = dashed, color = red, label = "1"]; }
Things become weird when I perform some experiments on this example:
It works well when only the last statement "wx2 -> wx1[style = dashed, color = red, label = "1"];" is removed;
It works well when only the eighth line "{rank = same;0;wx1;wx2;rx1;}" is removed;
It also works well when only the label (that is ", label = "1"") in the last statement is removed.
I have reported the problem to Graphviz Issue Tracker, without reply yet. Could you help to find out the reason?
Thank you.
The following variation of your script does not crash:
digraph G {
ranksep = 1.0; size = "10,10";
{
node [shape = plaintext, fontsize = 20];
GAWM1 -> GAWM2 -> 0;
}
node [shape = box];
{rank = same;0;wx1;wx2;rx1;}
wx1 -> wx2;
wx2 -> rx1;
wx1 -> rx1[color = blue];
subgraph struct
{
node [shape = record];
rx11 [shape = record, label = "rx1 | [x=[wx2]]"];
}
{rank = same; GAWM1; "rx11";}
// W'WR Order:
//wx2 -> wx1[style = dashed, color = red, label = "1"];
wx2 -> wx1 [style=dashed, color=red];
}
Looks like a bug with the label of the short edge between wx1 and wx2.

Resources