Force some connections to be horizontal - graphviz

I'm using DOT to visualize a lisp AST, and the picture that is generated currently looks like this:
Currently, the vertical lines are specified normally like parent -> child;, and the skewed ones are specified using constraint like so: parent -> child [constraint=false];.
This kind of works, but what I'm really looking for is a way to make the vertical connections stay the same where each connection puts the child one row downwards, but make the horizontal connections be actually horizontal. This would create something that looks more like this:
Is this possible?

You may be making it too complicated - this simple basic code does the job:
digraph so
{
# nodes
A[ label = "list" ];
B[ label = "ident: +" ];
C[ label = "literal: 1" ];
D[ label = "list" ];
E[ label = "ident: *" ];
F[ label = "literal: 3" ];
G[ label = "literal: 2" ];
# layout
{ rank = same; B C D }
{ rank = same; E F G }
# edges
A -> B;
B -> C -> D;
D -> E;
E -> F -> G;
}
compiled with dot -T png -o so.png so.dot yields what you want:

Related

Graphviz: drawing nodes in given order to correctly draw tree

I'm trying to draw a tree but have a problem with the following approach:
Use of 'invisible' nodes to connect levels of tree,
Use 'rank same' to draw nodes on the same level
Using this code I get following result
graph G{
edge [arrowhead = none];
splines = ortho;
rankdir = LR;
node [ shape="box" fixedsize = true width = 4 height = 1];
{ rank = same; "C" }
{ rank = same;
"B"
"A"
}
{ rank = same;
"F"
"D"
"E"
}
node [ shape="cricle" width = 0 height = 0 style=invis];
{ rank = same;
"B_Inv_Parent_1"
"C_Inv_Even_Children_0"
"A_Inv_Parent_1"
}
{ rank = same;
"F_Inv_Parent_2"
"D_Inv_Parent_2"
"A_Inv_Even_Children_1"
"E_Inv_Parent_2"
}
"C" -- "C_Inv_Even_Children_0";
"B_Inv_Parent_1" -- "C_Inv_Even_Children_0" -- "A_Inv_Parent_1";
"B_Inv_Parent_1" -- "B";
"A_Inv_Parent_1" -- "A";
"B" -- "F_Inv_Parent_2";
"F_Inv_Parent_2" -- "F";
"A" -- "A_Inv_Even_Children_1";
"D_Inv_Parent_2" -- "A_Inv_Even_Children_1" -- "E_Inv_Parent_2";
"D_Inv_Parent_2" -- "D";
"E_Inv_Parent_2" -- "E";
}
I have a problem in the 3rd level: D is drawn on top of the picture thus making a connection with E not ideal.
I would like to have the same results as with C, B and A.
I think the problem is with the order of nodes definition however, I can't manage to get it working whatever order I define them in.
Can anyone spot another problem with my code and suggest a fix?
I have cleaned up your code and re-arranged a few lines - after all, I think that introducing
F_Inv_Parent_2 -- D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
has been the key. You don't need to define edge arrows since you don't have a directed graph, and there is a typo in shape="cricle".
Here my edited version
graph G
{
splines = ortho;
rankdir = LR;
// node definitions
node [ shape="box" fixedsize = true width = 4 height = 1];
C
{ rank = same; B A }
{ rank = same; F D E }
node [ shape="point" width = 0 height = 0 ];
{ rank = same;
B_Inv_Parent_1
C_Inv_Even_Children_0
A_Inv_Parent_1 }
{ rank = same;
F_Inv_Parent_2
D_Inv_Parent_2
A_Inv_Even_Children_1
E_Inv_Parent_2 }
// edges
C -- C_Inv_Even_Children_0;
B_Inv_Parent_1 -- C_Inv_Even_Children_0 -- A_Inv_Parent_1;
B_Inv_Parent_1 -- B -- F_Inv_Parent_2;
A_Inv_Parent_1 -- A -- A_Inv_Even_Children_1;
F_Inv_Parent_2 -- D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
F_Inv_Parent_2 -- F;
D_Inv_Parent_2 -- D;
E_Inv_Parent_2 -- E;
}
and the result:
EDIT: I may have misunderstood your intention how you want to connect the third level - if so, replace
F_Inv_Parent_2 -- D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
with
F_Inv_Parent_2 -- D_Inv_Parent_2[ style = invis ];
D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
which gives you
EDIT No. 2, in response to yr comment:
Adding weight to the edge helps straightening it - I give the full code even though only two lines have changed (plus comments), for easier copy & paste:
graph G
{
splines = ortho;
rankdir = LR;
// node definitions
node [ shape="box" fixedsize = true width = 4 height = 1];
C
{ rank = same; B A }
{ rank = same; F D E }
node [ shape="point" width = 0 height = 0 ];
{ rank = same;
B_Inv_Parent_1
C_Inv_Even_Children_0
A_Inv_Parent_1 }
{ rank = same;
F_Inv_Parent_2
D_Inv_Parent_2
A_Inv_Even_Children_1
E_Inv_Parent_2 }
// edges
C -- C_Inv_Even_Children_0;
B_Inv_Parent_1 -- C_Inv_Even_Children_0 -- A_Inv_Parent_1;
// add extra weight to the continouous connection between four levels:
B_Inv_Parent_1 -- B -- F_Inv_Parent_2 -- F[ weight = 10 ];
// no weight here:
A_Inv_Parent_1 -- A -- A_Inv_Even_Children_1;
F_Inv_Parent_2 -- D_Inv_Parent_2[ style = invis ];
D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
// F_Inv_Parent_2 -- F; ### moved
D_Inv_Parent_2 -- D;
E_Inv_Parent_2 -- E;
}
Which gives you the disired straight line from B via F_Inv_Parent_2 to F which is actually the grandchild:

Graphviz dot-file crazy edge positioning

I have a problem with the positions of the edges in my dot-file.
In the dot-file I used contrainsts=false to exclude the edges m and l from the ranking and gave it some headport and tailport (with pygraphviz: headport='e', tailport='e'.
They got a crazy shape. I want to have them on the right side of the nodes.
This is the dot-file:
strict digraph "" {
graph [bb="0,0,717.03,767.02",
edges="{'arrowsize': '4.0'}",
rankdir=LR,
size="100,100",
];
cen0
[height=0.5,
label=a,
rank=0,
];
3 [
label=b,
rank=1,
];
cen0 -> 3
[label=z,
pos=e];
0
[label=c,
rank=1,
];
cen0 -> 0
[label=z,
pos=e];
cor22
[label=d,
rank=2,
];
3 -> cor22
[label=2,
pos=e];
con23
[label=e,
rank=2,
];
3 -> con23
[label=1,
];
cor2
[label=g,
rank=2,
];
0 -> cor2
[label=4];
con4
[label=h,
rank=2,
];
0 -> con4
[label=3];
1
[label="Why I can't delete the attribute 'width'
from this node?:
Warning: Unable to reclaim box space in spline
routing for edge \"con4\" ->\"con23\". Something is
probably seriously wrong.
",
rank=2,
width=2.5731];
0 -> 1
[label=k];
cor2:e -> cor22:e
[constraint=false,
rank=3
label=l];
con4:e -> con23:e
[constraint=false,
rank=3
label="Why this way?"];
}
I also wondered about why there comes that warning, when I delete the one last "width"-attribute.
How could I get my edges in the way, I expected?
This is probably an automatically generated product with a lot of "noise" - I have taken the liberty to almost completely re-write the code, to make it easier for me to work and test, and to concentrate on the essentials. You will add what is important for you back in and find out whether or not some of that breaks it.
With a good amount of trial and error, I found four major changes necessary:
The four third level nodes need to be in the same rank (rank = 3 does not help)
They need to be connected in the desired order by invisible edges
The edges between these nodes need to maintain the right hierarchical level, with the arrow pointing backwards
xlabels rather than labels need to be used for the edges
So here my largely edited code
digraph so
{
rankdir = LR;
// edge[ arrowsize = 4 ]; // you don't want that
cen0[ label = "a" ];
3 [ label = "b" ];
0 [ label = "c" ];
cen0 -> { 3 0 }[ label = "z" ];
cor22[ label = "d" ];
con23[ label = "e" ];
3 -> cor22[ label = "2" ];
3 -> con23[ label = "1" ];
cor2[ label = "g" ];
con4[ label = "h" ];
1 [ label = "Why I can't delete the attribute 'width' from this node?:\nWarning: Unable to reclaim box space in spline routing for edge \"con4\" ->\"con23\".\nSomething is probably seriously wrong.\n--- Width attribute not present here! ---" ];
0 -> cor2[ label = "4"];
0 -> con4[ label = "3" ];
0 -> 1[ label = "k" ];
{rank = same; cor22 con23 cor2 con4 1 }
cor22 -> con23 -> cor2 -> con4[ style = invis ]
cor22:e -> cor2:e[ dir = back, xlabel = " l" ];
con23:e -> con4:e[ dir = back, xlabel = " Is this better?" ];
}
and here is the result:
The missing attribute is splines=curved, added to my graphviz code gives:

Graphviz Sharing Attributes between Nodes or Edges

I'm using Graphviz (namely Dot) to draw up a state machine for a Hypermedia API I'm planning on building. In my graph, nodes represent states, while edges represent links. What I'm trying to do is have edges (links) of the same "type" (ie, use the same verb or same rel) to share attributes like color.
I know you can define "global" attributes that apply to all nodes/edges, but I need something I can apply more generally to several different "types". The closest analogy I can come up with for what I want is HTML classes. I don't need multiple "classes" for my edges (although that would be nice) but repeating attributes like color=red, style=bold is cumbersome.
Is there a way in Dot to declare something like this? Or at least some way I don't have to repeat myself so often?
I've done this in two different ways:
Option (A): Write the dot file from another script. This is particularly useful when I'm using a script (in, say, Python or Perl) to rework the input data into dot format for drawing. In that case, as well as having the Python script write the data into dot format I can also have it write the attributes for each node and edge into the dot file. An example is shown below (not runnable because I've extracted it from a larger script that interprets the input data but you can see how the Perl is writing the dot code).
print "graph G {\n graph [overlap = scale, size = \"10,10\"]; node [fontname = \"Helvetica\", fontsize = 9]\n";
for ($j = 0; $j <= $#sectionList; $j++) {
print "n$j [label = \"$sectionList[$j]\", style = filled, fillcolor = $groupColour{$group{$sectionList[$j]}} ]\n";
}
for ($j = 0; $j <= $#sectionList; $j++) {
for ($i = $j+1; $i <= $#sectionList; $i++) {
$wt = ($collab{$sectionList[$j]}{$sectionList[$i]}+0)/
($collab{$sectionList[$j]}{$sectionList[$j]}+0);
if ($wt > 0.01) {
print "n$j -- n$i [weight = $wt, ";
if ($wt > 0.15) {
print "style = bold]\n";
}
elsif ($wt > 0.04) {
print "]\n";
} else {
print "style = dotted]\n";
}
}
}
print "\n";
}
print "}\n";
Option (B): If I'm writing the dot script by hand, I'll use a macro processor to define common elements. For example given the file polygon.dot.m4 containing the m4 macro define() as follows:
define(SHAPE1,square)
define(SHAPE2,triangle)
digraph G {
a -> b -> c;
b -> d;
a [shape=SHAPE1];
b [shape=SHAPE2];
d [shape=SHAPE1];
e [shape=SHAPE2];
}
... the command m4 <polygon.dot.m4 | dot -Tjpg -opolygon.jpg produces:
Changing the definitions of SHAPE1 and SHAPE2 at the top of the file will change the shapes drawn for each of the relevant nodes.

How to darw a node with label is '*' using dot (graphviz)?

I want to draw a node that the node label only displays a char : '*' .
digraph {
node2[label="*"];
}
But when the image generated, the label displays a empty string. Is that possiable to draw a node only displays a '*' ?
digraph G {
a [shape="none", label="*"] ;
b [shape="box", label="*"] ;
a -> b ;
}
Works fine.

Graphviz: how to set 'default' arrow style?

Consider this dot language code:
digraph graphname {
subgraph clusterA {
node [shape=plaintext,style=filled];
1 -> 2 [arrowhead=normal,arrowtail=dot];
2 -> 3 -> X2 -> 5;
6;
7;
label = "A";
color=blue
}
}
In the above example, only the 1 -> 2 connection will have the arrowhead=normal,arrowtail=dot style applied; all the other arrows will be of the "default" style.
My question is - how do I set the arrow style (for the entire subgraph - or for the entire graph), without having to copy paste "[arrowhead=normal,arrowtail=dot];" next to each edge connection?
EDIT: Just for reference - the answer from Jesse didn't contain any code; I wrote that snippet and had it in this space here - for unknown reasons, a moderator cut it off from here and pasted it into Jesse's answer.
Use the edge attribute statement, as stated in the DOT Language documentation.
digraph graphname {
subgraph clusterA {
node [shape=plaintext,style=filled];
edge [arrowhead=normal,arrowtail=dot];
1 -> 2 ;
2 -> 3 -> X2 -> 5;
6;
7;
label = "A";
color=blue
}
}
Just like you did for nodes, but using edge, e.g. edge[style=dashed]

Resources