Graphviz Vertical Ordering - graphviz

I have a set of GraphViz nodes such that:
digraph {
A->B;
A->C;
A->D;
}
But B, C, and D happen sequentially in time!
It would be great if there was some way to indicate the vertical level each node should appear upon (where the number of levels may be unknown beforehand).
Does anyone have thoughts on how to accomplish this?

One option to have a node display on a different rank (vertical level) than an other node is to add invisible edges.
Assigning those nodes the same group indicates graphviz to lay them out in a straight line if possible.
For example:
digraph g{
A;
node[group=a];
B;C;D;
A -> B;
A -> C;
A -> D;
edge[style=invis];
B->C->D;
}
An other option is to have one vertical line of (invisible) nodes, then force the same rank by defining the nodes of the same rank within the same subgraph with rank=same:
digraph g{
{rank=same; l1[style=invis, shape=point]; A;}
{rank=same; l2[style=invis, shape=point]; B;}
{rank=same; l3[style=invis, shape=point]; C;}
{rank=same; l4[style=invis, shape=point]; D;E;F;}
A -> B;
A -> C;
A -> D;
edge[style=invis];
l1->l2->l3->l4;
}

Related

Graphviz enforce ordering between nodes of different levels

I have the following graph:
digraph {
stylesheet = "..."
subgraph cluster {
b; c; g;
{rank=same; b; g;}
}
a -> b;
b -> c;
c -> d;
c -> e;
f -> c;
{rank=same; a; f;}
}
Is there any way to force/encourage the edge f -> c to pass between nodes b and g? I've tried a number of different strategies and graphviz refuses to both:
keep b and g within the border, and
allow g to appear of to the side and not interfere with the rest of the graph.
Any suggestions would be much appreciated!
Indeed, the dot algorithm does not want to route the f->c edge as you want. However, the neato edge routing algorithm produces a closer result. So we use dot to position the nodes and neato -n to route the edges. Like so:
dot -Tdot myfile.gv >out.dot
neato -n -Tpng out.dot >myfile.png
Using this input:
digraph {
stylesheet = "https://g3doc.corp.google.com/frameworks/g3doc/includes/graphviz-style.css"
nodesep=.5 // optional
subgraph cluster {
b
c; g
{rank=same; b; g;}
}
f -> g [style=invis]
f:se -> c:nw [constraint=false]
a -> b;
b -> c;
c -> d;
c -> e;
}
Giving:
See https://graphviz.org/faq/#FaqDotWithNodeCoords
And https://graphviz.org/docs/outputs/canon/
(Close enough?)

How can I cross out a node in Graphviz?

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}
}

GraphViz: how to connect a node to the containing subgraph

I just learned how to connect nodes and subgraphs here on Stackoverflow. However, I want to connect a node to the containing subgraph:
digraph G {
compound=true;
subgraph cluster0 {
a -> b;
a -> c;
c -> {a b c} [lhead=cluster0];
}
c -> d;
d -> {a b c} [lhead=cluster0];
}
A quick sketch what I mean:
I want to connect d -> {a b c}, but for clarity reasons, I don't want to draw three different arrows, but just one arrow to the grouping of nodes. One way to do that is only list one arrow, like d -> a. That works, but is there a way to "collapse" three arrows into one when the head points to a cluster?
However, c -> {a b c} is not possible to point to a cluster, because c is part of that cluster. Is there a way to go around this?
you will need some scaffolding i.e. invisible node (and maybe edges) e.g.:
digraph top {
compound=true
node[shape=rectangle]
subgraph cluster1 {
a->{b c}
}
c->d
d->b[lhead=cluster1]
ca[shape=point height=0] // make ca invisible
a->ca:n[dir=back ltail=cluster1] // by drawing the arrow backward we get more control of the layout, n and s compass make the edge go smooth when enter and exiting ca
ca:s->c[dir=none] // no arrow on the tail part
}
rendered on viz-js.com:

How to put all unlinked nodes to the right?

digraph
{
rankdir=LR
a -> b
c -> b
b -> d
e // unlinked node
}
There are some nodes which are not linked to any of the other nodes in my dot file. Without explicitly using rank to define those nodes, is there any graceful way to put them to the right most position since it is a hard work to reparse the whole relations for finding them out and it is almost impossible to figure it out the maximum depth of the generated graph due to the opaqueness of node rearrangement policy?
You could put the unlinked nodes in a subgraph and use rank="max" to achieve this:
digraph
{
rankdir=LR;
a -> b;
c -> b;
b -> d;
{ rank="max"; e; }
}

Change edge placement from beneath to above nodes in Graphviz

It took me some time to make the graph below look like it does right now, and I'm almost satisfied. The one thing that still bothers me is that the connection between D and B should be above all nodes for the sake of aesthetics.
The funny thing is, that supplying the ports for the edge doesn't impress dot which just makes the edge cross the connected nodes.
Do you have an idea on how to avoid this?
digraph {
graph [splines=ortho, nodesep=0.2, fontname="DejaVu Sans", rankdir=LR]
node [shape=box, fontsize=8]
edge [arrowsize=0.5]
subgraph cluster {
style=invis;
A -> B -> C;
A -> B -> C;
A -> B -> C -> D;
D -> E;
D:nw -> B:ne;
}
{
D -> F -> { C; E };
}
}
PS: You need the latest Graphviz version in order to get orthogonal edges.
It may be a function of the version of the engine you use. I'm not sure what version of dot the GraphViz Workspace http://graphviz-dev.appspot.com/ uses but it does run your problem connector across the top.

Resources