How can I draw a graph with Graphviz and annotate its nodes and edges?
For example:
(a: level=0) --3--> (b: level=1)
(a: level=0) --2--> (c: level=1)
It is quite simple, here's a dot file for your example (test.dot):
strict digraph {
1 [label="a: level=0"];
2 [label="b: level=1"];
3 [label="c: level=1"];
1 -> 2 [label="3"];
1 -> 3 [label="2"];
}
which with dot -Tpng -o test.png test.dot will output:
There are way more parameters you can set to get the layout that you want. I suggest you look through the Graphviz documentation.
Related
i am trying to graph a doubly linked circular list in .dot language but it does not display as i want. Both of the circular edges are under the nodes but i want 1 of them above
this is what i want:
expected result
but i get this instead:
given result
here is my .dot code: https://dreampuf.github.io/GraphvizOnline/#digraph%20{%0A%20%20node[shape=record];%0A%20%20graph[pencolor=transparent];%0A%20%20rankdir=LR;%0A%20%20p1[label=%22{%3Cprev%3E|%3Cdata%3E%2012|%3Cnext%3E}%22];%0A%20%20p2[label=%22{%3Cprev%3E|%3Cdata%3E%2012|%3Cnext%3E}%22];%0A%20%20p3[label=%22{%3Cprev%3E|%3Cdata%3E%2012|%3Cnext%3E}%22];%0A%0A%0A%20%20%20%20p1:next%20-%3E%20p2:prev;%0A%20%20p2:next%20-%3E%20p3:prev;%0A%20%20p2:prev%20-%3E%20p1:next;%0A%20%20p3:prev%20-%3E%20p2:next;%0A%20%20%20%20edge[tailclip=false,dir=%22forward%22%20splines=%22compound%22%20constraint=%20%22false%22];%0A%20%0A%20%0Ap3:next%20-%3E%20p1:prev;%0A%0Ap1:prev%20-%3E%20p3:data;%0A%0A%20%20%20%20%0A}
thank you
Main change was to add a port position (https://graphviz.org/docs/attr-types/portPos/) to the head & tail of the edge. Also removed some unneeded bits.
digraph {
node[shape=record];
graph[pencolor=transparent];
rankdir=LR;
p1[label="{<prev>|<data> 12|<next>}"];
p2[label="{<prev>|<data> 12|<next>}"];
p3[label="{<prev>|<data> 12|<next>}"];
p1:next -> p2:prev;
p2:next -> p3:prev;
p2:prev -> p1:next;
p3:prev -> p2:next;
p1:prev:n -> p3:data:n;
// edge[tailclip=false,dir="forward" splines="compound" constraint= "false"];
p3:next -> p1:prev;
}
Giving:
I'm creating some multilevel SEM graphs and I'm running into a small problem. The latent variable at the bottom of the graph (labeled "WF") is supposed to have a double-headed edge to and from it but the edge should go under the node. Note the correct orientation of the topmost node. Seems and easy fix but I can find it. Thanks in advance. (BTW, I've provided only a snippet of the original model, but this is sufficient for the purpose.)
digraph stackex {
{rank=min;
bf [shape=ellipse]
bf:nw -> bf:ne [dir = both]}
{node[shape=square]
bf -> i1
i1[label=X1]
i1 -> wf [dir=back]}
{wf [shape=ellipse]
wf:sw -> wf:se [dir = both]}
}
And here's what it produces:
The double-headed arrow should go under the node labled "WF".
Based on experimentation, it appears that the only way to get
wf:sw -> wf:se [dir = both]
to do what you want is to add
graph [rankdir=TB]
Unfortunately, rankdir affects the entire graph (not just a subgraph or cluster). So you can fix one loop, but you break the other.
The only way I've found to accomplish your goal is to hand-modify the pos of the offending edge (spline). This:
digraph stackex {
graph [bb="0,0,82.583,216"];
node [label="\N",
shape=square
];
bf [height=0.5,
pos="41.292,162",
shape=ellipse,
width=0.75];
bf:nw -> bf:ne [dir=both,
pos="s,26.292,177 e,56.292,177 22.277,186.17 18.135,200.16 21.792,216 41.292,216 60.792,216 64.448,200.16 60.306,186.17"];
i1 [height=0.5,
label=X1,
pos="41.292,90",
width=0.5];
bf -> i1 [pos="e,41.292,108.1 41.292,143.7 41.292,135.98 41.292,126.71 41.292,118.11"];
wf [height=0.5,
pos="41.292,18",
shape=ellipse,
width=0.75];
i1 -> wf [dir=back,
pos="s,41.292,71.697 41.292,61.665 41.292,53.054 41.292,43.791 41.292,36.104"];
wf:se -> wf:sw [dir=both,
pos="s,56.292,3 e,26.292,3
65.002,8.3185
92.908,0.389
88.823,-20
41.292,-20
-6.2395,-20
-10.324,0.389
17.582,8.3185"];
}
And this command
neato -n2 -Tpng doubleheaded3.fixed.dot >doubleheaded3.fixed.png
Gives this:
All in all, I'd suggest the pic/gpic/dpic language. Lower-level, but probably easier to use in the long run.
I have the following source code for a graph in dot:
digraph name {
rankdir="LR";
node [shape="record"];
1 [label="OUTPUT"];
A [label="FWD|<i>i|<r_in>r_in|<r_out>r_out|<o>o"];
B [label="FIFO|<r_in>r_in|<o>o"];
C [label="Cons|<i>i|<r_out>r_out|<o>o"];
A:o:e -> C:i:w;
C:r_out:w -> A:r_in:e;
B:o:e -> A:i:w;
C:o:e -> 1:w;
A:r_out:w -> B:r_in:e;
}
It consists of 4 nodes, which essentially could be placed one after another, in the order B -> A -> C -> OUTPUT. If dot would place the nodes in this order, only few edge would cross between two nodes.
However, calling dot like this:
dot mygraph.dot -Tpng -o mygraph.png
creates the following mess:
Edit: It seems, the order of the nodes in the source is important. However, as the source is generated from a program, outputting its internal signal flow structure, I cannot rely on it to put the nodes in the right order. I thought, dot and its graph layout engine can figure out on its own, which nodes are the first ones, such that the wires do not cross.
Just define the nodes in the desired order:
digraph name {
rankdir="LR";
node [shape="record"];
B [label="FIFO|<r_in>r_in|<o>o"];
A [label="FWD|<i>i|<r_in>r_in|<r_out>r_out|<o>o"];
C [label="Cons|<i>i|<r_out>r_out|<o>o"];
1 [label="OUTPUT"];
A:o:e -> C:i:w;
C:r_out:w -> A:r_in:e;
B:o:e -> A:i:w;
C:o:e -> 1:w;
A:r_out:w -> B:r_in:e;
}
yields
Need draw a graph with dot/graphviz like this image:
The texts can be above arrows, like graphviz does it. But how to achieve the T-layout? Need make a cluster for the top row?
This is one possibility using rank=same for a subgraph:
digraph g {
node[shape=point, width=0.2];
{
rank=same;
p1 -> n [label="text1"];
n -> p2 [label="text2"];
}
n -> p3 [label="text3", dir=back];
n[label="node", shape=rect, style=rounded];
}
You could also use a left-right layout instead of top-down.
An other possibility is to disable the effect of some edges using constraint=false:
digraph g {
node[shape=point, width=0.2];
p1 -> n [label="text1", constraint=false];
n -> p2 [label="text2", constraint=false];
n -> p3 [label="text3", dir=back];
n[label="node", shape=rect, style=rounded];
}
The result is the same.
dot usually layouts trees in layers. To force an edge to not be a layer separation you can add the constraint=false option. So something like:
digraph {
A [shape=point]
B [shape=point]
C [shape=point]
N [label="node"]
A -> N [label="text1", constraint=false]
N -> B [label="text2", constraint=false]
N -> C [label="text3", dir=back]
}
should work.
Note that the edge from the lower node to "node" has to be backwards, since dot layouts trees from top to bottom. Therefore the logical edge direction has to be from top to bottom, even though the display direction might be the other way round (which is the case here).
I'm trying to use Graphviz dot (but am willing to use something else) to generate a graph with a long "main line" of nodes, and many small branches. I'd like the main line to be straight from left to right, with the small branches above or below it. However, Graphviz "balances" the two branches, so I end up with a crooked graph.
To illustrate, here's a sketch similar to what I currently get:
And this is what I actually want:
Is there any way to force or encourage Graphviz to generate a graph like the second one? I may be able to use "dummy" second branches to have it do a 3-way layout, and then hide/delete the dummies afterward, but if there's a better option that would be preferable.
Here is a solution using the weight attribute of edges:
digraph G {
rankdir="LR";
node[width=0.15, height=0.15, shape=point];
edge[weight=2, arrowhead=none];
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8;
edge[weight=1];
2 -> 9 -> 10 ;
5-> 11 -> 12;
}
Result:
A second solution using the group attribute of nodes - again a directed graph:
From the graphviz dot reference:
If the end points of an edge belong to
the same group, i.e., have the same
group attribute, parameters are set to
avoid crossings and keep the edges
straight.
So here we go:
digraph g{
rankdir="LR";
node[width=0.15, height=0.15, shape=point, group=main];
edge[arrowhead=none];
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8;
node[group=branches];
2 -> 9 -> 10;
5 -> 11 -> 12;
}
Output is exactly the same as in my first answer.