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).
Related
What I want to achieve is, if I have something like
Strict Digraph G {
a -> b [label = edge1]
a -> b [label = edge2]
a -> b
a -> b
a -> b [label = edge1]
}
then I should get a graph with 2 nodes and 3 edges between them (One with label edge1, one with edge2 and one without a label).
It doesn't seem to be possible, with the strict keyword with this input, it only draws one edge.
Sorry, not "legal". From https://graphviz.org/doc/info/lang.html
A graph may also be described as strict. This forbids the creation of multi-edges, i.e., there can be at most one edge with a given tail node and head node in the directed case.
When describing a graph with graphviz, I sometimes find I want two vertices to appear closer together than the layout engine I chose places them. Is there a way to hint that I want them closer?
I'm mostly interested in the case of two connected vertices, so an answer specific to that case is fine.
Concrete example:
digraph G {
node [shape="circle"];
Start [shape="none" label=""];
C [shape="doublecircle"];
Start -> A;
A -> B [label="0,1"];
B -> C [label="0,1"];
C -> D [label="0,1"];
D -> D [label="0,1"];
}
I want the vertices Start and A to be closer.
You can't do that, but you can make nearly everything else twice as big, here is a start.
(But you can't increase the size of an edge to self)
digraph G {
rankdir=LR
edge[minlen=2 fontsize=28 arrowsize=2 penwidth=2]
node[fontsize=28 height=1 penwidth=2]
graph[fontsize=28 penwidth=2]
node [shape="circle"];
Start [shape="none" label=""];
C [shape="doublecircle"];
Start -> A[minlen=1]; // not twice the size to get the requested effect
A -> B [label="0,1"];
B -> C [label="0,1"];
C -> D [label="0,1"];
D -> D [label="0,1"];
}
[this answer applies specifically to dot]
there is no edge-level attribute that explicitly sets or changes edge length
the graph-level nodesep attribute sets minimum distance between two nodes of same rank
so:
digraph G {
nodesep=.17
{
rank=same
node [shape="circle"];
Start [shape="none" label=""];
C [shape="doublecircle"];
Start -> A;
A -> B [label="0,1"];
B -> C [label="0,1"];
C -> D [label="0,1"];
D -> D [label="0,1"];
}
}
produces:
To increase the distance between the other nodes, you can add spaces to the labels.
I'm not wild about it either, but this change:
B -> C [label=" 0,1 "]; // pad to make label (and edge) longer
produced this:
I would like to indicate that a node should be there, but is currently lacking in the process.
Intuitively I would like to cross it out as shown in below image (now done manually in Paint):
Is there a node attribute in Graphviz that I can use for this?
I can't find an attribute or node shape to do what you want, but here are two ways to do it:
build an image outside of Graphviz (with the text and the X) and use the image attribute to use the image as the node (yes, a pain if you want to do this frequently):
b [image="myB.png"]
For every X'd out node, add 2 new edges from .ne to .sw and .nw to .se (see below) Each with this (new) attribute: straightline=1. Then run this command:
dot -Tdot Xout2.gv |gvpr -f straightline.gvpr -c | neato -n2 -Tpng >out.png
Where this is straightline.gvpr:
E[straightline==1]{
int i, n;
string pt[int];
double x1, y1, x2, y2, xI1, yI1, xI2, yI2;
n=split($.pos, pt, " ");
for (i=0;i<=1;i++){
if (match(pt[i],"e,")>=0){
print ("// BEFORE: ", pt[i]);
pt[n-1]=substr(pt[i],2);
print ("// AFTER: ", pt[i]);
pt[i]=pt[i+1];
}
}
for (i=0;i<=1;i++){
if (match(pt[i],"s,")>=0){
pt[0]=substr(pt[i],2);
}
}
sscanf (pt[0], "%f,%f", &x1, &y1);
sscanf (pt[n-1], "%f,%f", &x2, &y2);
xI1=x1+(x2-x1)*.3;
yI1=y1+(y2-y1)*.3;
xI2=x1+(x2-x1)*.7;
yI2=y1+(y2-y1)*.7;
$.pos=sprintf("%s %.3f,%.3f %.3f,%.3f %s", pt[0], xI1, yI1, xI2, yI2, pt[n-1]);
}
From this input:
digraph X{
graph [outputorder=edgefirst]
b [ label="X me"]
a -> b -> c
a -> d
d -> c
e -> f
g -> i -> k
edge [color="#ff000080" penwidth=2] // note translucent color
b:ne -> b:sw [straightline=1]
b:se -> b:nw [straightline=1]
edge [color="green" penwidth=2]
e:n -> e:s [straightline=1]
f:w -> f:se [straightline=1]
edge [color="orange" penwidth=2]
g:n -> g:se [dir=back straightline=1]
edge [color="blue" penwidth=2]
g:n -> g:sw [dir=back straightline=1]
i:e -> i:w [dir=none straightline=1]
k -> k:s [dir=both straightline=1]
}
Sorry, convoluted, but it works.
While the answer of sroush gives me the exact output I need, it requires that I understand how to introduce gvpr in my workflow which will take a bit of time.
In the meantime I came up with a dot only approach, which approximates crossing out a node sufficiently for my purpose.
In below graph I would like to cross out the node Some process:
digraph graphname {
rankdir=LR
node [fillcolor="lightblue3", style="filled"]
a
c
d
b [label="Some\nprocess"]
a -> b -> c
a -> d -> c
{rank=same a;d}
}
To do so I change:
the nodestyle of the Some process node to have a diagonal hard gradient
use a HTML-like label to strikethrough the text
Make the fontcolor and node outline a shade of gray
digraph graphname {
rankdir=LR
node [fillcolor="lightblue3", style="filled"]
a
c
d
node [fillcolor="lightblue3;0.5:white", style="filled", fontcolor="gray50", color="gray50", gradientangle=100]
b [label=<<s>Some<br/>process</s>>]
a -> b -> c
a -> d -> c
{rank=same a;d}
}
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'm trying to display edges going from right to left (i.e. backwards) using dot:
C <- A -> B
The best I could do was:
digraph {
a -> b;
c -> a [dir="back"];
{rank=same;c a b}
}
..which is fine, except I don't like using c -> a when the edge is directed the other way.
So I wanted to share this solution (which didn't seem to be mentioned on SO) and check if I'm missing something obvious.
See: http://www.graphviz.org/doc/info/attrs.html#k:dirType
I have no alternative to your usage of dir, but i can make it slightly shorter, if you want horizontal alignment, use the rankdir property of graph, to force direction from left to right.
digraph {
rankdir=LR;
a->b;
c->a [dir="back"];
}
To make edges point backwards by default:
digraph {
edge [dir="back"];
a -> b;
c -> a;
}
Then, override the default to point forwards:
c -> d [dir="forward"];