Graphviz dot-file crazy edge positioning - graphviz

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:

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:

Force some connections to be horizontal

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:

Line between connectors of the same node

How can I do the drawing of arrow
A1:Port1 -> A1:Port2 [dir=both]
nicer
So at least same connection point at the same point as the other connector. See picture.
Line between connectors of the same node
Round line between connecoors of the same node
digraph G {
graph [rankdir = LR];
node[shape=record];
A1[label="{A1|{<Port1>Port 1|<Port2>Port 2 }}"];
A2[label="{{<Port1>Port 1|<Port2>Port 2 }|A2}"];
A1:Port1 -> A1:Port2 [dir=both]
A1:Port1 -> A2:Port1 [dir=both]
}
I would introduce an intermediate node:
digraph G {
graph [rankdir = LR];
node[shape=record];
A1[label="{A1|{<Port1>Port 1|<Port2>Port 2 }}"];
A2[label="{{<Port1>Port 1|<Port2>Port 2 }|A2}"];
C[shape=point];
A1:Port1 -> C;
C -> A1:Port2;
C -> A2:Port1;
}
so you get:
Posting it as an answer, so that the resulting graph is clear:
digraph G
{
graph[ rankdir = LR, splines=line] ;
node[ shape=record ];
A1[ label= "{A1|{<Port1>Port 1|<Port2>Port 2 }}" ];
A2[ label= "{{<Port1>Port 1|<Port2>Port 2 }|A2}" ];
A1:Port1:e -> A1:Port2:e [ dir=both ]
A1:Port1 -> A2:Port1 [ dir=both, minlen = 2 ]
}
producing

Graphviz .dot node ordering

I'm building a epsilon NFA to recognize a regular expression using the canonical construction. I'm using subgraphs to group various parts of the regular expression. The * operator is giving me particular trouble since dot has decided to move the order of the nodes around. I've tried adding edge weights to force particular edges to be short to keep the order of the edges in line but that does not seem to be working.
What I would like to do is force the nodes in a subgraph in to be placed in a particular order so that the output graph is recognizable as a particular type of (well known) construction. In the example below I would like edges 3, 4, 5 and 6 placed in that order, however the dot places them in the order 6, 3, 4, 5. Any pointers appreciated.
Note that the current weight parameter produces no difference than no weight parameter at all.
I have the following
digraph G {
rankdir = LR;
node [shape = none];
0 [label = "start"];
node [shape = circle];
1 [label = "q1"];
2 [label = "q2"];
3 [label = "q3"];
4 [label = "q4"];
5 [label = "q5"];
node [shape = doublecircle];
6 [label = "q6"];
subgraph re1 {
rank = same;
edge[label = "0"];
1 -> 2;
};
subgraph re2 {
rank = same;
edge[label = "ε"];
3 -> 4 [weight = 10];
edge[label = "1"];
4 -> 5 [weight = 10];
edge[label = "ε"];
5 -> 6 [weight = 10];
5 -> 4 [weight = 1];
6 -> 3 [weight = 1];
};
edge[color=black];
0 -> 1
edge[label = "ε"];
2 -> 3;
}
Here's how I'd write that graph:
First of all, to me this is a graph which goes from top to bottom, not left to right, therefore I removed the rankdir=LR and added rank=same only for nodes 0/1 and nodes 2/3.
I removed all the weights
Most importantly, I added constraint=false to the edges going against the direction of the graph - the one going from node 4 to node 5, and the one from node 6 to node 3.
Here the source:
digraph G {
0 [label = "start", shape = none];
node [shape = circle];
1 [label = "q1"];
2 [label = "q2"];
3 [label = "q3"];
4 [label = "q4"];
5 [label = "q5"];
6 [label = "q6", shape = doublecircle];
{rank = same; 0 -> 1; }
1 -> 2 [label = "0"];
{rank = same; 2 -> 3 [label = "ε"]; }
4 -> 5 [label = "1"];
edge [label = "ε"];
3 -> 4;
5 -> 6;
5 -> 4 [constraint = false];
6 -> 3 [constraint = false];
}
And here's the result:
Now if you want to, you could keep rankdir=LR, just take the markup you posted, remove the weights and add constraint=false to the same edges as I did, it works, too.

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