Controlling the ordering of nodes within a GraphViz subgraph cluster - graphviz

I've got two cluster subgraphs in GraphViz, with edges between the nodes in each subgraph. I'd like to be able to influence the top-to-bottom ordering of the nodes within the second subgraph so as to achieve symmetry across the horizontal axis, and have the nodes in the second subgraph ordered top-to-bottom as a, b, c, d.
digraph {
rankdir=LR
subgraph cluster_1 {
bx -> cx
by -> cy
}
subgraph cluster_2 {
a; b; c; d
}
bx -> a
cx -> b
cy -> c
by -> d
}
Right now, I get this:
Changing the ordering of node appearance within the cluster_2 subgraph doesn't seem to matter, nor does changing the ordering of the cross-cluster edges at the bottom.
Is there any way to get GraphViz to produce what I want here?

You can add some scaffolding edges and/or nodes i.e. invisible edges/nodes but it can be a bit triggy especially when clusters are involved
e.g.:
digraph {
rankdir=LR
subgraph cluster_1 {
bx -> cx
by -> _d [dir=none]
by -> cy
_a[shape=point height=0]
_d[shape=point height=0]
bx -> _a [dir=none]
}
subgraph cluster_2 {
a; b; c; d
}
//bx -> a
cx -> b
cy -> c
//by -> d
_a->a
_d->d
}

Related

How do I vertically align a node with the center of a cluster?

I am looking for a way to align individual nodes in graphviz with an entire subgraph/cluster.
I am currently teaching a small team of analysts to use rmarkdown and I want to allow them to include simple graphs and flowcharts in their documents. I therefore use DiagrammeR (and viz.js) to render charts written in dot. To increase user adoption, I want to minimize complexity and avoid HTML and use raw dot.
Our problem is that we frequently try to align nodes with subgraphs/clusters containing multiple nodes, but we cannot align the entire subgraph with the node. Alignment only works with the constituent nodes within the subgraph/cluster. (see nodes C,D,E and G,T below)
I have tried to create a record node using GT [shape = record label="{G | T}"] but that does not allow individual styling of the two nodes.
I have also tried creating an HTML record node which allows individual styling but increases complexity too much and requires users to know HTML.
Finally, I have tried to insert an invisible node inside the clusters to "simulate" the center and then use the invisible node for alignment. This unfortunately pushes G and T to far apart and doesn't achieve the intended effect.
digraph G {
graph [splines = false, ranksep = 0.2]
edge [style = "invis"]
node [shape = box, width = 7.5]
A B H
node [shape = circle, width = 1.5]
subgraph cluster_2 {
rank = same
C D E
}
subgraph cluster_1 {
G [shape = box]
T [shape = box]
}
A -> B
G -> T
B -> {C D E G}
{C D E T} -> H
}
The following gives the output:
In the picture above, the subgraph containing G and T is not aligned with the subgraph containing C,D,E.
Is there a way to vertically align the centers of the two subgraphs?
The problem is that GraphViz only align node rows and {C D E} is one row where as {G->T} is two rows so {C D E} can only be align with either G or T
You can however align {C D E} with the space between G and T though that is probably not what you want. E.g. like this:
digraph G {
graph [splines = false, ranksep = 0.2]
//edge [style = "invis"]
node [shape = box, width = 7.5]
A B H
node [shape = circle, width = 1.5]
subgraph cluster_2 {
rank = same
C D E
}
subgraph cluster_1 {
G [shape = box]
T [shape = box]
}
A -> B
G -> T[minlen=2]
B -> G
B -> {C D E} -> H [minlen=2]
T -> H
}
Resulting in:

How to make an edge with both direction in GraphViz?

How to make an edge with both direction in GraphViz?
I am trying to make an curved edge with both direction.
But the only plot I can make is:
I want to make the edge between x1 and x2 curved with both direction.
The code I used:
digraph {
rankdir=LR
node [shape=box ]
x1;x2
node [shape=oval ]
y
x1->y[dir=back label=0.77]
x2->y[dir=back label=0.42]
x1:w -> x2:w[dir=both constraint=false]
}
I would appreciate any help.
I think there should be a better solution but the following did work for me:
digraph {
rankdir=LR
node [shape=box ]
x1;x2
node [shape=oval ]
y
x1->y[dir=back label=0.77]
x2->y[dir=back label=0.42]
x1:w -> x2:w[dir=both constraint=false]
x2:w -> x1:w[dir=both constraint=false]
}
based on the answer from Changing edge direction in dot:
digraph g {
rankdir=LR
node [shape=box ]
{rank=same x1;x2}
node [shape=oval ]
y
x1 -> y[dir=back label=0.77]
x2 -> y[dir=back label=0.42]
x1:w -> x2:w[dir=both label=0.34]
}

GraphViz - alignment of subgraph

I'd like to draw a diagram like this.
But the only diagram I can draw is:
The code I used :
graph [rankdir = LR]
node [shape=box]
x1;x2;x3;y1;y2;y3;y4;y5;y6;y7;y8;
node [shape=oval]
ind60;dem60;dem65
{x1,x2,x3} -> ind60[arrowhead=none arrowtail=normal dir=both]
{y1,y2,y3,y4} -> dem60[arrowhead=none arrowtail=normal dir=both]
dem65 -> {y5,y6,y7,y8}
ind60->dem60 dem60->dem65 ind60->dem65
How can I draw the desired plot?
A first step in what you want to achieve, using rank=same, invisible edges, groups, and constraint=false:
digraph {
node [shape=box]
{
rank=same;
y1;y2;y3;y4;
}
dem60[shape=oval];
{y1;y2;y3;y4} -> dem60 [dir=back];
{
rank=same;
x2 [group=left];
ind60[shape=oval];
dem65[shape=oval];
y6 [group=right];
x2 -> ind60 [dir=back];
ind60 -> dem65
dem65 -> y6;
}
// Invisible edges to order vertically node groups
edge[style=invis];
x1[group=left];
x3[group=left];
x1 -> x2 -> x3;
node[group=right];
y5 -> y6 -> y7 -> y8;
node[group=""]
edge[style=solid]
ind60->dem60
dem60->dem65
edge[constraint=false];
ind60 -> x1;
ind60 -> x3;
dem65 -> y5;
dem65 -> y7;
dem65 -> y8;
}
group enforces vertical alignement of nodes (of the same group).
rank=same makes nodes stay on the same rank.
Invisible edges enforce rank order within a vertical group.
constraint=false removes constraint calculation for some edges.
dir=back reverses displayed edge direction.

Nesting nodes in GraphViz

I'm trying to draw bigraphs in GraphViz (something like this)
Is it possible to nest nodes directly in GraphViz?
If not is it possible to change the shape of a subgraph/cluster?
I have found a post about how to import images of graphs into nodes but that seems like more effort than drawing them in powerpoint.
I can also make clusters visible, but they will include nodes from outside the cluster and as far as I can tell have a fixed shape.
Thanks for your help.
Nest nodes is impossible, but nest clusters is possible.
Subgraph/cluster has some predefined styles. Also nodes has predefines shapes. I don't know about manual editing path of border shapes for nodes in graphviz in different layouts (or alternatives like representing the border as a chain of nodes), maybe someone else can tell us.
You can get nested nodes in neato layout engine, but in fact they will be nested only visually, because you just set their coordinates with pos attribute, which means they overlap each other.
Example image:
and script:
graph {
layout=neato
node [shape=circle pin=true ]
foo [height=0.6 pos="0.7,1.5" ]
bar [height=2 pos="1,2" ]
baz [height=1 pos="2,2" ]
}
You can import images as backgrounds into nodes as described in this answer. For example for Windows you can use this official archive, it comes with a cairo.dll, which will avoid errors like Warning: No loadimage plugin for "jpeg:cairo" when you run the command $ dot -Tpng input.dot -o output.png.
The image from your question can be drawn like this:
Script:
digraph {
graph [
layout=dot,
ranksep=1,
overlap=false,
compound=true, // to enable `lhead`, `ltail` features
newrank=true, // to enable ranking between nodes in clusters
splines=true,
splines=curved]
edge[color=lime arrowhead=none]
node[shape=plaintext]
y0 [label=<<FONT><I>y</I><SUB>0</SUB></FONT>>]
y1 [label=<<FONT><I>y</I><SUB>1</SUB></FONT>>]
y2 [label=<<FONT><I>y</I><SUB>2</SUB></FONT>>]
x0 [label=<<FONT><I>x</I><SUB>0</SUB></FONT>>]
x1 [label=<<FONT><I>x</I><SUB>1</SUB></FONT>>]
subgraph cluster_r0{
style="rounded, dashed"
margin=20
label=<<FONT><I>r</I><SUB>0</SUB></FONT>>
v2 [shape=circle]
noname_dot[shape=point height=0]
subgraph cluster_v0{
style="rounded"
label=<<FONT><I>v</I><SUB>0</SUB></FONT>>
invis_dot_1 [style=invis shape=point]
subgraph cluster_v1{
style="rounded";
label=<<FONT><I>v</I><SUB>1</SUB></FONT>>
subgraph cluster_s0{
label=<<FONT><I>s</I><SUB>0</SUB></FONT>>
fillcolor=lightgrey
style="filled, rounded"
invis_dot_2 [style=invis shape=point]
}
}
}
}
y0 -> noname_dot
noname_dot -> invis_dot_2 [lhead="cluster_v1"]
noname_dot -> invis_dot_1 [lhead="cluster_v0"]
noname_dot -> v2 [constraint=false]
y1 -> v2
subgraph cluster_r1{
style="rounded, dashed"
margin=20
label=<<FONT><I>r</I><SUB>1</SUB></FONT>>
noname_dot_2 [shape=point height=0]
subgraph cluster_s3{
label=<<FONT><I>s</I><SUB>3</SUB></FONT>>
fillcolor=lightgrey
style="filled, rounded"
invis_dot_s3 [style=invis shape=point]
}
subgraph cluster_v3{
style="rounded"
label=<<FONT><I>v</I><SUB>3</SUB></FONT>>
subgraph cluster_s2{
label=<<FONT><I>s</I><SUB>2</SUB></FONT>>
fillcolor=lightgrey
style="filled, rounded"
invis_dot_s2 [style=invis shape=point]
}
}
}
y2 -> noname_dot_2
noname_dot_2 -> x0
v2 -> noname_dot_2 [weight=0]
noname_dot_2 -> invis_dot_s2 [lhead="cluster_v3"]
invis_dot_s2 -> x1 [ltail="cluster_v3"]
// Vertical alignment (`rank`) of the desired nodes:
{rank=same; noname_dot; noname_dot_2; v2 }
{rank=same; invis_dot_s3; invis_dot_s2 }
{rank=same; x0; x1;}
{rank=same; y0; y1; y2;}
}

Draw two subgraph without connection, one under the other, in DOT?

For example:
digraph G {
rankdir = TB;
subgraph A {
a -> {a0, a1};
};
subgraph B {
b -> {b0, b1, b2};
};
};
I want to put B at the bottom of A, how to do it?
You'll have to tell graphviz that the subgraphs are not equal. One way to do it is simply to add invisible edges between the graphs:
digraph G {
rankdir = TB;
subgraph A {
a -> {a0, a1};
};
subgraph B {
b -> {b0, b1, b2};
};
a0 -> b [style=invis];
a1 -> b [style=invis];
};
By adding two invisible edges the subgraphs are neatly aligned.

Resources