Graphviz enforce ordering between nodes of different levels - graphviz

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?)

Related

Graphviz nested subgraph orientation

I recently came across the image below. I know it was created with graphviz/dot, but the source code is not available (lost to time).
Desired Output:
I have been trying to find a way to reverse engineer the source code, but the horizontal ordering of the nested subgraphs has been giving me difficulty. A bare minimum mostly-working example looks like this in code
digraph G {
A
B
subgraph cluster_0 {
edge [style=invis]
subgraph cluster_0_0 {
D -> E -> F
}
C -> D -> E -> F -> G
}
A -> C
A -> B
A -> G
B -> { D E F }
}
However, that gives me this output:
Adding newrank=true to the outer subgraph gives me the horizontal orientation I'm looking for:
digraph G {
A
B
subgraph cluster_0 {
newrank=true
edge [style=invis]
subgraph cluster_0_0 {
D -> E -> F
}
C -> D -> E -> F -> G
}
A -> C
A -> B
A -> G
B -> { D E F }
}
But this sets the nodes in the wrong order:
I hope there is a better solution, but here is one (the rest of the node labels should be evident):
digraph G {
newrank=true
splines=false // A->C edge gets wacky without this
node [shape=Mrecord]
// Mrecords produce this Warning:
// flat edge between adjacent nodes one of which has a record shape - replace records with HTML-like labels
// but Mrecords still seem to work, so maybe ignore warning ??
// hoped that ordering or weight or group attributes would
// position C and G as desired, but nope
// instead, clusters and constraint attribute worked, why?
A [group=T label="{Measure|4/4}"]
B [group=T]
A -> B
{
rank=same C F E D G // declare right-to-left ??
}
subgraph clusterCDEFG {
graph [style=rounded]
// within a rank, layout tends to be right-to-left
// so, declare right-to-left ??
// why do these clusters help position C & G ???
subgraph clusterG { peripheries=0
G
}
subgraph clusterDEF {
// declare right-to-left
F
E [group=T]
D
edge [style=invis]
// D -> E -> F
}
// why do these clusters help position C & G ???
subgraph clusterC { peripheries=0
C
}
}
A -> C [constraint=false] // why does this impact position within rank ??
A -> G [constraint=false] // why does this impact position within rank ??
B -> { F E D } // declare right-to-left ??
edge [style=invis]
// C -> D // Mrecord shape has problems
// F -> G // Mrecord shape has problems
}
Giving:

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 Vertical Ordering

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

Mixed directed/undirected graph [duplicate]

For my application I need to represent simultaneously (on the same graph) two relations: one is simmetric, the other is not.
Targets:
Ideally the two relation should result in edges having different colors;
For the symmetric relation I would like not to have double-edges;
Is there a way of doing this with dot?
digraph {
A; B; C
subgraph Rel1 {
edge [dir=none, color=red]
A -> B -> C -> A
}
subgraph Rel2 {
edge [color=blue]
B -> C
C -> A
}
}
You can pass dir=none as an edge property to the undirected graph connections:
digraph {
A; B; C
A -> B
B -> C
C -> A [dir=none]
}

How can I reverse the direction of every edge in a Graphviz (dot language) graph?

I have a directed graph specified in Graphviz's dot language, e.g.
digraph G { A -> B [label="foo"]; A -> B [label="bar"]; B -> A; C; }
I want to automatically process this into a graph with its edges reversed, i.e.
digraph G { B -> A [label="foo"]; B -> A [label="bar"]; A -> B; C; }
I would like to use a robust solution (i.e. one that understands the graph and therefore probably doesn't use sed) that preserves any existing edge labels and other attributes. Note that I am not merely talking about getting dot to render my graph with the arrows pointing backward; I really need a graph whose edges are reversed. (In this case, I intend to reverse the edges, apply prune, then reverse the edges again.)
How can I reverse the direction of every edge in a Graphviz (dot-language) graph?
Easiest way is to include a graph-level dir statement where you reverse the direction of the arrows. By default, the direction is forward. If you reverse it at the top of your graph, then without changing a single other line, the graph will show up the way you want.
What you have now is this:
digraph G
{
edge [dir="forward"]; /* implied */
A -> B [label="foo"];
A -> B [label="bar"];
B -> A;
C;
}
What you want is this:
digraph G
{
edge [dir="back"]; /* note the change to this line */
A -> B [label="foo"];
A -> B [label="bar"];
B -> A;
C;
}
The best I've come up with so far is
BEG_G {
graph_t g = graph($.name + " reversed", "D");
int edge_id = 0;
}
N {
clone(g, $);
}
E {
node_t newHead = clone(g, $.head);
node_t newTail = clone(g, $.tail);
edge_t newEdge = edge_sg(g, newHead, newTail, edge_id);
copyA($, newEdge);
edge_id++;
}
END_G {
$O = g;
}
which I then invoke with gvpr.
This does add a "key" attribute to all resultant edges, but I'm not sure how to avoid that and still preserve multiple edges between the same pair of nodes.
When I do echo 'digraph G { A -> B [label="foo"]; A -> B [label="bar"]; B -> A; C; }' | gvpr -f reverseAllEdges.gvpr, I get:
digraph "G reversed" {
A -> B [key=2];
B -> A [key=0, label=foo];
B -> A [key=1, label=bar];
C;
}
I don't know how robust this will prove to be, but it looks promising.
The Python library NetworkX has a directed multigraph type, MultiDiGraph, which has a reverse() method. It also uses pydot for loading and writing DOT files.

Resources