Graphviz: how to set 'default' arrow style? - graphviz

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]

Related

Arranging subclusters with rank

I have this graph:
digraph G{
rankdir = TB;
hyb[label="Hybrid calculation"];
k1[label=<k<SUB>1</SUB>>];
k2[label=<k<SUB>2</SUB>>];
kn[label=<k<SUB>n</SUB>>];
// subgraph cluster_k1q {
k1q1[label=<q<SUB>1</SUB>>];
k1q2[label=<q<SUB>2</SUB>>];
k1qn[label=<q<SUB>n</SUB>>];
graph[style=dotted];
{rank=same; k1q1;k1q2;k1qn}
// }
// subgraph cluster_k2q {
k2q1[label=<q<SUB>1</SUB>>];
k2q2[label=<q<SUB>2</SUB>>];
k2qm[label=<q<SUB>m</SUB>>];
graph[style=dotted];
{rank=same; k2q1;k2q2;k2qm}
// }
// subgraph cluster_knq {
knq1[label=<q<SUB>1</SUB>>];
knq2[label=<q<SUB>2</SUB>>];
knql[label=<q<SUB>l</SUB>>];
graph[style=dotted];
{rank=same; knq1;knq2;knql}
// }
hyb -> k1;
hyb -> k2;
hyb -> kn;
k1 -> k1q1;
k1 -> k1q2;
k1 -> k1qn;
k2 -> k2q1;
k2 -> k2q2;
k2 -> k2qm;
kn -> knq1;
kn -> knq2;
kn -> knql;
bands1 -> k1q2;
bands1 -> k2qm;
bands1 -> knq1
bands2 -> k1qn;
bands2 -> knq1;
bands3 -> knql;
bands3 -> k1q1;
{edge[ style=invis];
k1->k2->kn;
k1q1->k1q2->k1qn->k2q1->k2q2->k2qm->knq1->knq2->knql;
}
{ rank=min; hyb}
{ rank=same; k1;k2;kn}
{ rank=same; k1q1;k1q2;k1qn;k2q1;k2q1;k2qm;knq1;knq2;knql}
{ rank=max; bands1;bands2;bands3}
}
Resulting in this graph:
All the ks are on one level, all the qs are one level and so are the bands. Then I would like to draw some boxes around the qs using clusters. So if I uncomment the subgraph in above code I have to comment this line:
{ rank=same; k1q1;k1q2;k1qn;k2q1;k2q1;k2qm;knq1;knq2;knql}
and I get:
Here the bands get thrown in same level with the qs. How can I get the levels from the top graph with the nice boxes from the bottom graph?
add this: newrank=true
See: https://graphviz.org/docs/attrs/newrank/
(you could also probably accomplish it by changing the direction of the bandX->qY edges, like so: k1q2->bands1 [dir=back])

trying to create ranked subgraphs in graphviz

I've tried to make something like this using Graphviz:
x y z
| | |
# | |
a#__\| |
# /#b |
# #__\|
# # /#c
# d#/__#
# #\ x
# # |
e#/__# |
#\ # |
But ranking doesn't seem to be working as I expect. I want e to be below all of the other nodes.
digraph x
{
rankdir = tb;
size = "7.5, 7.5";
rank = source;
a -> b -> c -> d -> e;
subgraph "cluster x"
{
style=filled;
color=lightgrey;
label="x";
a -> e [style=invis];
}
subgraph "cluster y"
{
label="y";
b -> d [style=invis];
}
subgraph "cluster z"
{
label="z";
c;
}
}
I've tried to use clusterrank = global which sort of works, but then the subgraphs are not separated into a more obvious column and there's overlap over the columns. It also is not going to the right like I want. The following image highlights one of the overlaps in red, but as you can see there are 4.
digraph x
{
rankdir = tb;
rankstep=equally;
clusterrank = global;
size = "7.5, 7.5";
a -> b -> c -> d -> e;
subgraph "cluster x"
{
style=filled;
color=lightgrey;
label="x";
a -> e [style=invis];
}
subgraph "cluster y"
{
label="y";
b -> d [style=invis];
}
subgraph "cluster z"
{
label="z";
c;
}
}
I've tried to make a separate cluster that is going to have a guaranteed top to bottom ranking and then rank the appropriate clusters together, but it does the same as the previous attempt, removing the boxes seen the the first attempt and causing unwanted overlapping.
digraph x
{
rankdir = tb;
1 -> 2 -> 3 -> 4 -> 5;
a -> b -> c -> d -> e;
{ rank=same; 1; a; }
{ rank=same; 2; b; }
{ rank=same; 3; c; }
{ rank=same; 4; d; }
{ rank=same; 5; e; }
subgraph "cluster x"
{
style=filled;
color=lightgrey;
label="x";
a -> e [style=invis];
}
subgraph "cluster y"
{
label="y";
b -> d [style=invis];
}
subgraph "cluster z"
{
label="z";
c;
}
}
Anyone have any ideas as to try and get the layout I want?
As a side note, I tried to login to the Graphviz forum regarding this matter, but found that logging in from this page doesn't seem to work. I keep getting a long timeout problem. I check my email account and nothing is there. I try creating a new account with the same email and it says that the account is already in use. I then try and get them to reset my password and I get another timeout problem.
Does anyone know who I can contact to try and fix that annoying login problem? Maybe someone who is already logged in can post that for me?
Run dot with -Gnewrank. That will get you what you want based on your sketch. If more tweaks are needed, please specify what you are after.
Your last solution will work as soon as you do a minor tuning
Use newrank=true to avoid of "unboxing" clusters
Play with splines=... to adjust arrows
Define label as separate nodes.
digraph x
{
rankdir = tb;
newrank=true;
splines=ortho;
0 -> 1 -> 2 -> 3 -> 4 -> 5;
X; Y; Z;
a -> b -> c -> d -> e;
{ rank=same; 0 X Y Z}
{ rank=same; 1; a; }
{ rank=same; 2; b; }
{ rank=same; 3; c; }
{ rank=same; 4; d; }
{ rank=same; 5; e; }
subgraph "cluster x"
{
style=filled;
color=lightgrey;
a -> e [style=invis];
}
subgraph "cluster y"
{
b -> d [style=invis];
}
subgraph "cluster z"
{
c;
}
}

Center last node of a graph

digraph {
1 -> 2 -> 3;
2 -> { rank = sink; end};
}
How can I force the "end" node to be centered horizontally (in the same column as the first node)?
You may use the group attribute of the nodes:
digraph {
3[group=b];
node[group=a]
1 -> 2 -> end;
2 -> 3;
}
See also this and this answer.

Avoid edge intersection in graphviz

Suppose we have the following simple graph:
digraph Test {
Start[shape = doublecircle];
Foo[shape = square];
Bar[shape = diamond];
Baz[shape = square];
Xyz[shape = square];
Start -> Foo;
Foo:s -> Bar:n;
Bar:w -> Baz:n;
Bar:e -> Xyz:n;
Baz:s -> Foo:n;
}
Which is rendered as follows:
Is there a way to tell graphviz to draw edge Baz -> Foo without intersections with Foo -> Bar nor Bar -> Baz?
when it comes to graphviz layout, the best you can do is trying as much as possible to not interfere :)
taking out compass_pt from your file:
digraph Test {
Start[shape = doublecircle];
Foo[shape = square];
Bar[shape = diamond];
Baz[shape = square];
Xyz[shape = square];
Start -> Foo;
Foo -> Bar;
Bar -> Baz;
Bar -> Xyz;
Baz -> Foo;
}
and you get:
Adding an invisible node should do the trick:
digraph Test {
Start[shape = doublecircle];
Foo[shape = square];
Bar[shape = diamond];
Baz[shape = square];
Xyz[shape = square];
// "invisible" node to connect baz to foo
BazToFoo [shape=none, label="", height=0, width=0]
Start -> Foo;
Foo:s -> Bar:n;
Bar:w -> Baz:n;
Bar:e -> Xyz:n;
Baz:s -> BazToFoo [dir=none] // remove the arrowhead
BazToFoo -> Foo:n;
}
While I agree with Guy's answer to keep it simple, here's an alternative approach with some changes to eliminate the edge crossings.
digraph Test {
Start[shape = doublecircle, group=a];
Foo[shape = square, group=a];
Bar[shape = diamond, group=a];
Xyz[shape = square];
Baz[shape = square];
Start -> Foo;
Foo:s -> Bar:n;
Bar:e -> Baz:n;
Bar:w -> Xyz:n;
Baz:s -> Foo:n[constraint=false];
}
I found that graphviz's layout doesn't easily route edges back up along the outer left side of a graph. Probably the way the layout algorithm works, allowing the graph to expand to the right and bottom only.
That's why I switched the positions of the bottom nodes, having the node with the returning edge at the right side.

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.

Resources