Make a Graphviz plot more square - graphviz

I am trying to make plot of several disconnected graphs.
digraph {
// rankdir=RL
subgraph template {
node [shape=square]
edge [color=black]
subgraph top {
node [group=1]
A
B
C
D
E
}
subgraph bottom {
node [group=2]
F
G
H
}
}
C -> c
F -> f
subgraph s1 {
edge [color=red]
A -> a
B -> b1
D -> d1
E -> e1
G -> g1
H -> h1
}
subgraph s2 {
edge [color=blue]
A -> b1
B -> a
D -> d2
E -> e2
G -> g2
H -> h2
}
subgraph s3 {
edge [color=green]
A -> a
B -> b1
D -> d2
E -> e3
G -> g3
H -> h1
}
subgraph s4 {
edge [color=purple]
A -> b1
B -> a
D -> e1
E -> e2
G -> g4
H -> h1
}
subgraph s5 {
edge [ color=orange]
A -> b1
B -> a
D -> d5
E -> e1
G -> g5
H -> h1
}
subgraph s6 {
edge [ color=brown]
A -> a
B -> b1
D -> d1
E -> e6
G -> g6
H -> h1
}
subgraph s6 {
edge [ color=tan]
A -> a
B -> b2
D -> d2
E -> e6
G -> g6
H -> h1
}
}
This creates a short, wide graph.
I would like to have a taller, narrower graph. For example, moving the F, G and H trees under the A-E nodes would be good.
I tried size, which just made the nodes bigger or smaller.
I tried ratio, which stretched the graph but did not move nodes around.
I tried using group and/or rankdir, but neither did what I wanted.
I have mostly tried using fdp, but also tried dot.
I am happy with a solution that either automatically moves the nodes around or requires me to manually move them.
Any suggestions on how to achieve this?

Here are two ways:
(easiest)
make each top-level cluster a stand-alone graph.
run each graph through dot -Tdot myfileX.gv >myfileX.dot
use gvpack (https://graphviz.org/pdf/gvpack.1.pdf) to combine the individual files into one combo graph
run the combo graph through neato -n2 -Tpng >mycombo.png (see https://www.graphviz.org/faq/#FaqDotWithCoords)
gvpack -array_ib1 myfiles*.dot |neato -Tpng -n2 >oooo.png
OR
use invisible edges to connect the nodes from one cluster to another a->C. Unfortunately, this quickly becomes tedious, trying to get all the nodes to line up as you want.

Related

Graphviz: align nodes horizontally

I thought the following would be simple, but for some reason, it really isn't...
Let's start with this:
digraph G {
rankdir=LR
A -> B -> C -> E -> F
}
This is the output:
Now, let's add a backwards relationship:
digraph G {
rankdir=LR
A -> B -> C -> E -> F
E -> A
}
I get this:
In the end, what I want is for the nodes to be aligned horizontally, and the backwards arrow to go around. I'm thinking, easy, with rank=same:
digraph G {
rankdir=LR
{rank=same;A -> B -> C -> E -> F}
E -> A
}
Oops:
Now, it's not even aligned horizontally or even sequentially (it's E, F, A, B, C). So how do I get a layout as in the very first output, with an arrow from E to A going around?
How about:
digraph G {
//rankdir=LR
{rank=same;A -> B -> C -> E -> F}
E -> A
}
the rank=same forces the LR

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:

In graphviz, can you bring two vertices closer together?

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:

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

How can I create symmetric edges in Graphviz?

I would like the edges between two nodes to be symmetric about a horizontal line. For example, this code:
digraph G {
rankdir=LR
s [style=invisible]
A [peripheries=2]
D [peripheries=2]
B [peripheries=2]
s -> A
A -> C [label="1"]
C -> D [label="0"]
D -> C [label="1"]
A -> B [label="0"]
}
Produces this graph:
I would prefer the edges between C and D to look more like this:
Is there a way to get Graphviz to do this?
You can place a third edge and make the middle one invisible:
C -> D [label="0"];
D -> C [style=invis];
D -> C [label="1"];

Resources