How to structure multiple subgraphs in Graphviz? - graphviz

My ultimate aim is to write a python script that will automatically generate graphviz graphs based on some input data. However, I'm first focusing just on the graphviz.
This is currently what I have:
digraph G {
compound=true;
node [shape=box];
edge [dir=none];
subgraph cluster_overall{
subgraph cluster_top{
apple;
banana;
}
subgraph clustermsc{
basket1;
basket2;
label="Baskets";
}
subgraph cluster_bottom{
orange;
kiwi;
}
label="Test";
}
apple -> basket1;
banana -> basket2;
orange -> basket1;
kiwi -> basket2;
}
Current: https://i.imgur.com/76GCx0f.png
This is what I want my final graph to look like. With the number of fruits evenly distributed between the top and bottom section (based on the input date):
Final: https://i.imgur.com/OHFsAdd.png
How do I structure the page to have 3 static, separate sections. Currently the fruit's placement constantly changes based on node they point to.
Please let me know if I wasn't clear in my explanation, I'll try better explaining it. Thanks.
Don't have enough repuation to directly post images.

In graphviz, it is important to produce the hierarchy as the tool sees it, not reproducing the logic that is on your mind. simply reversing the edges from your baskets to the "lower" fruits does the job:
digraph G {
compound=true;
node [shape=box];
edge [dir=none];
subgraph cluster_overall{
subgraph cluster_top{
apple;
banana;
}
subgraph clustermsc{
basket1;
basket2;
label="Baskets";
}
subgraph cluster_bottom{
orange;
kiwi;
}
label="Test";
}
apple -> basket1;
banana -> basket2;
basket1 -> orange; // !!!
basket2-> kiwi; // !!!
}
gives you
If you want to force a certain order of items (such as apple being to the left of banana), you can do so by replacing your definition with
subgraph cluster_top{
{ rank = same; apple -> banana[ style = invis ] }
}

If I correctly understood you, you need to connect clusters with invisible edges to force their position.
Here I've added a dummy node into each cluster (because to connect clusters you have to connect nodes in these clusters and then add lhead and ltail attributes).
Then I've connected these clusters in the correct order with invisible edges. Also I've added an extremely big weight to these edges to give them priority over other edges.
Is that what you need?
digraph G {
compound=true;
node [shape=box];
edge [dir=none];
subgraph cluster_overall{
subgraph cluster_top{
dummy_top [shape=point width=0 style=invis]
apple;
banana;
}
subgraph clustermsc{
dummy_msc [shape=point width=0 style=invis]
basket1;
basket2;
label="Baskets";
}
subgraph cluster_bottom{
dummy_bottom [shape=point width=0 style=invis]
orange;
kiwi;
}
label="Test";
}
dummy_top -> dummy_msc [
style=invis
weight=100
lhead="clustermsc"
ltail="cluster_top"
]
dummy_msc -> dummy_bottom [
style=invis
weight=100
lhead="cluster_bottom"
ltail="clustermsc"
]
apple -> basket1;
banana -> basket2;
orange -> basket1;
kiwi -> basket2;
}

Related

How to have multiple label one above and one below the edges in graphviz?

I've the following output currently I want to place a label below the edge between p and z in the figure.Is it possible to do in graphviz I've tried using xlabels but it doesn't work.
Current Code:
digraph GPG{
node [shape=box];
subgraph cluster0{
node[shape=circle];
0[label=0,style=invis];
}
subgraph cluster1{
node[shape=circle];
1[label=1,style=invis];
p->z [label="2 | 1",minlen=1];
{
rank = same;
p;z;
}
}
subgraph cluster2{
node[shape=circle];
2[label=2,style=invis];
}
0->1
1->2
}
I want a label below edge p->z as well above the edge.Is it possible in graphviz?
Kind of ugly, but:
digraph overunder{
splines=false
{ rank=same
a -> b [label=" over " ]
a -> b [label="under" penwidth=0.0 dir=none]
}
}
Produces:
You may have to add the non-breaking space characters (see above) because Graphviz seems to position labels based on the length of the text - longer labels are placed above shorter labels.

Graphviz: How to place nodes only in lower semi-circle using circo layout?

In the attached figure, the nodes are arranged in a circle around the node. Is there a (possibly generic) way to arrange the nodes only in the lower semi-circle, without having to provide fixed coordinates for the nodes?
Edit: Would like to achieve something like shown in the image attached below. As one can see - all the nodes are arranged in the lower semi-circular region (this figure was made using CMap Tools).
The code is trivial, but pasting it anyway.
digraph semicircle {
rankdir="TD"
graph [nodesep="0.1", ranksep="0.3", center=true]
mindist="0.4"
S [label="Root", style="filled", fillcolor="greenyellow", shape="box"]
subgraph cluster1 {
rank="same"
A; B; C; D;
S -> {A, B, C, D};
} }
using dot/circo : graphviz version 2.40.1
I noted that circo placed nodes counter-clockwise, starting at 3 o'clock.
I added enough invisible nodes to fill the 2 through 10 o'clock positions.
To make the inter-nodal distances even more uniform I added:
node [shape=square style=rounded]
The result I got is this:
Try this:
digraph semicircle {
rankdir="TD"
graph [nodesep="0.1", ranksep="0.3", center=true, root=S]
mindist="0.4"
S [label="Root", style="filled", fillcolor="greenyellow", shape="box"]
subgraph cluster1 {
rank="same"
A
z1[style=invis label=""]
z2[style=invis label=""]
B; C; D;
S -> A
S -> z1,z2 [style=invis]
S -> { B, C, D};
}
}

Problem with "rank=same" in subgraphs and clusters

When switching from "normal" subgraphs to clusters, rank=same doesn't apprear to work anymore.
To show my problem, please have a look at the following example graph.
digraph INV_X1 {
rankdir = "LR";
edge [penwidth="2"];
/* Component styles */
M_i_0 [shape=none;image="res/nmos.jpg"];
M_i_1 [shape=none;image="res/pmos.jpg"];
/* Node styles */
A [style=filled;color=green];
ZN [style=filled;color=green];
/* Connections */
M_i_0:n -> ZN;
A -> M_i_0:w;
/* Put M_i_0 and _VSS_0 on the same rank. */
subgraph g_VSS_0 {
rank=same;
label="_VSS_0";
_VSS_0 [shape=none;image="res/gnd.jpg";label=""];
M_i_0 -> _VSS_0 [arrowhead=none];
}
M_i_1:s -> ZN;
A -> M_i_1:w;
/* Put M_i_1 and _VDD_1 on the same rank. */
subgraph g_VDD_1 {
rank=same;
label="_VDD_1";
_VDD_1 [shape=none;image="res/pwr.jpg";label=""];
_VDD_1 -> M_i_1 [arrowhead=none];
}
}
The output is shown in the following picture. I hope it's not too confusing as I used some images for nodes. I created two subgraphs to group two nodes each and put them on the same rank. One subgraph is at the center top, the other on the center bottom.
Now I want to switch from subgraphs to clusters to make sure that the grouped nodes are always placed close to one another, and I want to have borders and labels to make the clusters visible. But when I just change the subgraph names to "cluster_..." it looks like this.
What is the problem here? Why is rank=same no longer working as expected? Also the given port position is no longer working as expected (edge is no longer connected on the south/north of the node).
I tried to pull rank=same out of the cluster into an own statement but that seems to completely overwrite the previous cluster statement as border and labels disappear. Also, I tried to use constraint=false on the node connections but that messes up the node order so I wasn't really satisfied with that approach.
Any help is appreciated. You can find the used images here if you want to recreate the graph.
You are right, as documentation states, "rank" attribute works only with subgraphs (cluster is not a subgraph anymore). But what's the problem, put another subgraph inside your cluster!
digraph INV_X1 {
rankdir = "LR";
edge [penwidth="2"];
/* Component styles */
M_i_0 [shape=none;image="res/nmos.jpg"];
M_i_1 [shape=none;image="res/pmos.jpg"];
/* Node styles */
A [style=filled;color=green];
ZN [style=filled;color=green];
/* Connections */
M_i_0:n -> ZN;
A -> M_i_0:w;
subgraph cluster_a{
/* Put M_i_0 and _VSS_0 on the same rank. */
label="_VSS_0";
subgraph g_VSS_0 {
rank=same;
_VSS_0 [shape=none;image="res/gnd.jpg";label=""];
_VSS_0 -> M_i_0 [arrowhead=none];
}
}
M_i_1:s -> ZN;
A -> M_i_1:w;
/* Put M_i_1 and _VDD_1 on the same rank. */
subgraph cluster_b {
label="_VDD_1";
subgraph g_VDD_1 {
rank=same;
_VDD_1 [shape=none;image="res/pwr.jpg";label=""];
M_i_1 -> _VDD_1 [arrowhead=none];
}
}
}
Also note that I've changed the order of your edges M_i_1 -> _VDD_1 and _VSS_0 -> M_i_0, for some reason they were inversed.
Result:

Graphviz: Intersecting but non-recursive clusters

I was wondering if it's possible to do something like this in Graphviz:
As you can see, node "two" is inside two clusters while the clusters aren't recursive.
Note: Image made with Dia.
No, this is currently not possible
Just rewriting Jens' comment as an answer.
While Graphviz won't produce overlapping clusters directly, it will allow you to create overlapping clusters with a bit of editing. (For more info see: https://www.graphviz.org/faq/#FaqDotWithCoords)
Start with:
digraph o {
graph [newrank=true nodesep=.5]
subgraph cluster1 {
graph [margin=50 label="Subgraph 1"]
{rank=same
one-> two [style=invis]
}
}
subgraph cluster2 {
graph [label="Subgraph 2"]
three
}
{rank=same
one two three
}
}
run this command: dot -Tdot myfile.gv >myfile.dot
Then edit myfile.dot to change the boundary box of cluster2. Like so:
digraph o {
graph [bb="0,0,398,175",
newrank=true,
nodesep=.5
];
node [label="\N"];
{
graph [rank=same];
one [height=0.5,
pos="85,76",
width=0.75827];
two [height=0.5,
pos="176,76",
width=0.77632];
three [height=0.5,
pos="340,76",
width=0.99297];
}
subgraph cluster1 {
graph [bb="8,8,254,167",
label="Subgraph 1",
lheight=0.21,
lp="131,155.5",
lwidth=1.17,
margin=50
];
{
graph [rank=same];
one;
two;
one -> two [pos="e,147.67,76 112.37,76 120.74,76 129.1,76 137.46,76",
style=invis];
}
}
subgraph cluster2 {
graph [bb="135,50,390,125", // X1 edited
label="Subgraph 2",
lheight=0.21,
lp="340,113.5",
lwidth=1.17
];
three;
}
}
run this command on the edited file: neato -n2 -Tpng myfile.dot >myfile.png
Giving:

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

Resources