graphviz : how to fix the order and alignment of clusters - graphviz

I try to represent a graph called "dynamic Bayesian network". This graph is composed of a sequence of cluster representing different timeslices (from 0 to N). In each timeslice, I would have the same node, in the same order. Edges only are between nodes in the same timeslice or from a timeslice to the next one.
For instance :
However, from time to time, the ordering of the clusters is not correct. Here timeslice 2 is before timeslice 1 ...
Here is the dot file I have for the second one :
digraph G {
rankdir=TD;
splines=ortho;
node [color="#000000", fillcolor=white, style=filled];
subgraph cluster_0 {
bgcolor="#DDDDDD";
label="Time slice 0";
rankdir=TD;
"P0" [label="P"];
"R0" [label="R"];
"dP0" [label="dP"];
"dR0" [label="dR"];
}
subgraph cluster_1 {
bgcolor="#DDDDDD";
label="Time slice 1";
rankdir=TD;
"P1" [label="P"];
"R1" [label="R"];
"dP1" [label="dP"];
"dR1" [label="dR"];
}
subgraph cluster_2 {
bgcolor="#DDDDDD";
label="Time slice 2";
rankdir=TD;
"P2" [label="P"];
"R2" [label="R"];
"dP2" [label="dP"];
"dR2" [label="dR"];
}
edge [color=blue, constraint=False];
"P0" -> "P1";
"P1" -> "dP1";
"P2" -> "dP2";
"R1" -> "R2";
"R1" -> "dP1";
"R0" -> "dP0";
"dR1" -> "R2";
"R2" -> "dR2";
"dR0" -> "R1";
"dP1" -> "P2";
"P0" -> "dP0";
"P1" -> "P2";
"R2" -> "dP2";
"R0" -> "dR0";
"dP0" -> "P1";
"R0" -> "R1";
"P0" -> "dR0";
"P1" -> "dR1";
"P2" -> "dR2";
"R1" -> "dR1";
edge [constraint=True, style=invis];
"P0" -> "R0";
"R0" -> "dP0";
"dP0" -> "dR0";
"P1" -> "R1";
"R1" -> "dP1";
"dP1" -> "dR1";
"P2" -> "R2";
"R2" -> "dP2";
"dP2" -> "dR2";
}
If I try just to add constraints such as "P0->P1;P1->P2", the order is correct but the clusters are not aligned any more ...
Does someone know how to fix the ordering between the clusters in this graph ?

Changed rankdir direction to guarantee correct sequence of clusters. That in-turn forced rank=same within each cluster, plus a few other tweaks.
digraph G {
rankdir=LR // was rankdir=TD;
splines=ortho;
node [color="#000000", fillcolor=white, style=filled];
subgraph cluster_0 {
bgcolor="#DDDDDD";
label="Time slice 0";
// only applies to Root graph: rankdir=TD;
{rank=same // because we changed rankdir
"P0" [label="P"];
"R0" [label="R"];
"dP0" [label="dP"];
"dR0" [label="dR"];
}
}
subgraph cluster_1 {
bgcolor="#DDDDDD";
label="Time slice 1";
{rank=same
"P1" [label="P"];
"R1" [label="R"];
"dP1" [label="dP"];
"dR1" [label="dR"];
}
}
subgraph cluster_2 {
bgcolor="#DDDDDD";
label="Time slice 2";
{rank=same
"P2" [label="P"];
"R2" [label="R"];
"dP2" [label="dP"];
"dR2" [label="dR"];
}
}
edge [color=blue, constraint=False];
"P0" -> "P1";
"P1" -> "dP1";
"P2" -> "dP2";
"R1" -> "R2";
"R1" -> "dP1";
"R0" -> "dP0";
"dR1" -> "R2";
"R2" -> "dR2";
"dR0" -> "R1";
"dP1" -> "P2";
"P0" -> "dP0";
"P1" -> "P2";
"R2" -> "dP2";
"R0" -> "dR0";
"dP0" -> "P1";
"R0" -> "R1";
"P0" -> "dR0";
"P1" -> "dR1";
"P2" -> "dR2";
"R1" -> "dR1";
// establish positions
edge [style=invis constraint=true]
P0 -> P1 -> P2
R0 -> R1 -> R2
dP0 -> dP1 -> dP2
dR0 -> dR1 -> dR2
}
Giving:

Related

Graphviz: Invert two nodes position inside a cluster

I am trying to inverse the position of two nodes (producción & funciones) that are inside a cluster (cluster_fp). Instead of producción on top and funciones at bottom, I need funciones on top and producción at bottom. How can I achieve that? They are in a cluster just because I thought it is the right approach, but probably it isn't. Because my reputation, I can't post images directly, so I leave the links to i.stack.imgur.com.
Code:
digraph tríada {
rankdir=LR;
edge [arrowhead=none];
label="* socialmente reconocido";
labeljust=left;
subgraph cluster_sinonimia_oa {
style=dashed;
label="sinonimia obra-texto";
subgraph cluster_texto {
style=striped;
label=texto;
selección [shape=rect];
}
obra [shape=rect, style=striped];
supuesto [label="supuesto\nexistencial", shape=plain];
}
subgraph cluster_autor {
style=striped;
label="autor*";
máquinas [shape=hexagon];
subgraph cluster_fp {
label="";
style=invis;
funciones [label="atribución o\napropiación", shape=plain];
producción [shape=plain];
}
subgraph cluster_sinonimia_nepa {
style=dashed;
label="sinonimia nombre-entidad-persona-autor";
personas [shape=hexagon];
entidad [shape=rect];
real [shape=diamond];
ficticia [shape=diamond];
nula [shape=diamond];
denotación [shape=plain];
nombre [shape=rect];
}
}
{personas máquinas} -> real [arrowhead=normal];
{real ficticia nula} -> entidad [arrowhead=normal];
nombre -> funciones -> obra -> supuesto -> selección -> producción -> entidad -> denotación -> nombre;
}
Live on dreampuf.github.io
Thanks!
Based on lots of experiments, the problem seems to be that dot's algorithm "weights" a multi-node edge more than a two-node edge.
Here is a much-edited input file that produces your desired output:
digraph tríada {
rankdir=LR;
edge [arrowhead=none];
label="* socialmente reconocido";
labeljust=left;
subgraph cluster_autor {
style=striped;
label="autor*";
subgraph cluster_sinonimia_nepa {
style=dashed;
label="sinonimia nombre-entidad-persona-autor";
personas [shape=hexagon];
entidad [shape=rect];
real [shape=diamond];
ficticia [shape=diamond];
nula [shape=diamond];
denotación [shape=plain];
nombre [shape=rect];
node [label="" shape=point width=.01]
// bogus1 & bogus2 are needed to flip/swap/invert the funciones & producción nodes
bogus1 bogus2
}
subgraph cluster_fp {
label="";
style=invis;
funciones [label="atribución o\napropiación", shape=plain];
producción [shape=plain];
}
máquinas [shape=hexagon];
{personas máquinas} -> real [arrowhead=normal];
{real ficticia nula} -> entidad [arrowhead=normal];
entidad -> denotación -> nombre
}
subgraph cluster_sinonimia_oa {
style=dashed;
label="sinonimia obra-texto";
subgraph cluster_texto {
style=striped;
label=texto;
selección [shape=rect];
}
obra [shape=rect, style=striped];
supuesto [label="supuesto\nexistencial", shape=plain];
}
nombre -> funciones -> obra -> supuesto -> selección
producción -> selección
entidad -> bogus1 [headclip=false ]
bogus1 -> bogus2 [tailclip=false, headclip=false]
bogus2 -> producción [tailclip=false]
}
(Yes, most of the edits were unnecessary)

GraphViz - how to render subgraph as an ascii with fixed ratio?

I’ve been struggling for awhile on how to keep subgraph within rectangle instead of “Tetris” shapes when edge is being added and layout becomes more complex.
on Layer 2 in the codes below you’ll clearly notice “C”-shaped subgraph.
Is it possible to fix the subgraph’s shape ratio to rectangle as an ascii or any attribute to handle this?
digraph G {
subgraph cluster_0 {
subgraph cluster_3 {
label="Layer 3";
"3-1" -> "3-2" -> "3-3";
}
subgraph cluster_2 {
label="Layer 2";
"2-1" -> "2-2" -> "2-3";
}
subgraph cluster_1 {
label="Layer 1";
"1-1" -> "1-2" -> "1-3";
}
}
"1-1" -> "2-1";
"1-3" -> "2-1";
"1-1" -> "2-2";
"1-2" -> "2-2";
"1-2" -> "2-3";
"1-3" -> "2-3";
"2-1" -> {"3-1" "3-2"};
"2-3" -> {"3-1" "3-3"};
}
here is an img explanation:
.

graphviz - how to place subgraphs horizontally

How can i place the following diagram with subgraphs layout horizontally, not vertically?
Up until now I had the understanding that rankdir parameter is responsible for that - and that's why I've set it to LR. However this does not work.
I've been trying to fiddle around with ratio options, but none of those tried gave anything useful.
digraph {
rankdir=LR
ratio="expand"
subgraph cluster_3 {
label=C
style=filled
color=lightgrey
"39649811_plecak-nike-szkolny-sportowy-ba5405-010-b-r_after_time_decay"
"10023965_wojna-swiatow-wells-vesper-twarda-oprawa_after_time_decay"
"11097750_aldous-huxley-nowy-wspanialy-swiat-________after_time_decay"
"11097750_stanislaw-lem-pamietnik-znaleziony-w-wannie-______after_time_decay"
"6740469_pozdrawiam-moje-miasto-jozef-ratajczak-1968_after_time_decay"
"6740469_nowy-korbut-bibliografia-literatury-polskiej-14-t_after_time_decay"
"6740469_superkomputery-bez-tajemnic-david-loshin-1997_after_time_decay"
"21424429_wojny-w-cyberprzestrzeni-guisnel-jean-znak_after_time_decay"
"38901148_koniec-swieta-eisuke-nakazono_after_time_decay"
"17346660_podstawy-informatyki-kolodziejczak-zielinski_after_time_decay"
"6740469_urzadzenie-wewnetrzne-miast-wolnych-sejm-wielki_after_time_decay"
"15528768_ddd-kompendium-wiedzy-vaughn-vernon_after_time_decay"
"138008_matematyka-dyskretna-dla-informatykow_after_time_decay"
"45702657_polski-fiat-125pfso-125p_after_time_decay"
"43306282_unity-w-akcji-joe-hocking_after_time_decay"
"46889202_eng-victor-eijkhout-tex-by-topic_after_time_decay"
"4276139_wallace-wang-internet-hakerzy-wirusy-ladnyegz_after_time_decay"
"38901148_micro-prolog-keith-l-clark_after_time_decay"
"46889202_eng-victor-eijkhout-tex-by-topic_after_time_decay"
}
subgraph cluster_2 {
label=B
style=filled
color=lightgrey
"39649811_plecak-nike-szkolny-sportowy-ba5405-010-b-r"
"10023965_wojna-swiatow-wells-vesper-twarda-oprawa"
"11097750_aldous-huxley-nowy-wspanialy-swiat-_______"
"11097750_stanislaw-lem-pamietnik-znaleziony-w-wannie-_____"
"6740469_pozdrawiam-moje-miasto-jozef-ratajczak-1968"
"6740469_nowy-korbut-bibliografia-literatury-polskiej-14-t"
"6740469_superkomputery-bez-tajemnic-david-loshin-1997"
"21424429_wojny-w-cyberprzestrzeni-guisnel-jean-znak"
"38901148_koniec-swieta-eisuke-nakazono"
"17346660_podstawy-informatyki-kolodziejczak-zielinski"
"6740469_urzadzenie-wewnetrzne-miast-wolnych-sejm-wielki"
"6740469_superkomputery-bez-tajemnic-david-loshin-1997"
"15528768_ddd-kompendium-wiedzy-vaughn-vernon"
"138008_matematyka-dyskretna-dla-informatykow"
"45702657_polski-fiat-125pfso-125p"
"43306282_unity-w-akcji-joe-hocking"
"46889202_eng-victor-eijkhout-tex-by-topic"
"4276139_wallace-wang-internet-hakerzy-wirusy-ladnyegz"
"38901148_micro-prolog-keith-l-clark"
"46889202_eng-victor-eijkhout-tex-by-topic"
}
subgraph cluster_1 {
label=A
style=filled
color=lightgrey
7440293919
7316212119
7459478910
7496246732
7220215448
7030101965
7307790911
7498596862
7465256747
7477936369
6957447807
7307790911
7426854990
7476186414
7152887795
7318012429
7195398720
7474847554
6968472561
7195397122
}
7440293919 -> "39649811_plecak-nike-szkolny-sportowy-ba5405-010-b-r" [label="2018-08-13T15:43:02.127" constraint=false]
7316212119 -> "10023965_wojna-swiatow-wells-vesper-twarda-oprawa" [label="2018-08-11T23:54:52.740" constraint=false]
7459478910 -> "11097750_aldous-huxley-nowy-wspanialy-swiat-_______" [label="2018-08-11T23:53:55.626" constraint=false]
7496246732 -> "11097750_stanislaw-lem-pamietnik-znaleziony-w-wannie-_____" [label="2018-08-11T23:53:21.720" constraint=false]
7220215448 -> "6740469_pozdrawiam-moje-miasto-jozef-ratajczak-1968" [label="2018-08-11T23:52:12.432" constraint=false]
7030101965 -> "6740469_nowy-korbut-bibliografia-literatury-polskiej-14-t" [label="2018-08-11T23:52:08.754" constraint=false]
7307790911 -> "6740469_superkomputery-bez-tajemnic-david-loshin-1997" [label="2018-08-11T23:52:03.990" constraint=false]
7498596862 -> "21424429_wojny-w-cyberprzestrzeni-guisnel-jean-znak" [label="2018-08-11T23:05:59.337" constraint=false]
7465256747 -> "38901148_koniec-swieta-eisuke-nakazono" [label="2018-08-11T23:04:31.077" constraint=false]
7477936369 -> "17346660_podstawy-informatyki-kolodziejczak-zielinski" [label="2018-08-11T23:02:58.123" constraint=false]
6957447807 -> "6740469_urzadzenie-wewnetrzne-miast-wolnych-sejm-wielki" [label="2018-08-11T23:01:58.357" constraint=false]
7307790911 -> "6740469_superkomputery-bez-tajemnic-david-loshin-1997" [label="2018-08-11T23:01:42.263" constraint=false]
7426854990 -> "15528768_ddd-kompendium-wiedzy-vaughn-vernon" [label="2018-08-11T22:55:01.702" constraint=false]
7476186414 -> "138008_matematyka-dyskretna-dla-informatykow" [label="2018-08-11T22:54:26.675" constraint=false]
7152887795 -> "45702657_polski-fiat-125pfso-125p" [label="2018-08-11T22:47:26.011" constraint=false]
7318012429 -> "43306282_unity-w-akcji-joe-hocking" [label="2018-08-11T22:45:34.938" constraint=false]
7195398720 -> "46889202_eng-victor-eijkhout-tex-by-topic" [label="2018-08-11T22:44:44.794" constraint=false]
7474847554 -> "4276139_wallace-wang-internet-hakerzy-wirusy-ladnyegz" [label="2018-08-11T22:42:30.278" constraint=false]
6968472561 -> "38901148_micro-prolog-keith-l-clark" [label="2018-08-11T22:41:27.522" constraint=false]
7195397122 -> "46889202_eng-victor-eijkhout-tex-by-topic" [label="2018-08-11T22:39:47.893" constraint=false]
"39649811_plecak-nike-szkolny-sportowy-ba5405-010-b-r" -> "39649811_plecak-nike-szkolny-sportowy-ba5405-010-b-r_after_time_decay" [label=0.8711024820449741 constraint=false]
"10023965_wojna-swiatow-wells-vesper-twarda-oprawa" -> "10023965_wojna-swiatow-wells-vesper-twarda-oprawa_after_time_decay" [label=0.7220784976320539 constraint=false]
"11097750_aldous-huxley-nowy-wspanialy-swiat-_______" -> "11097750_aldous-huxley-nowy-wspanialy-swiat-________after_time_decay" [label=0.7220292630457892 constraint=false]
"11097750_stanislaw-lem-pamietnik-znaleziony-w-wannie-_____" -> "11097750_stanislaw-lem-pamietnik-znaleziony-w-wannie-______after_time_decay" [label=0.7220000378705059 constraint=false]
"6740469_pozdrawiam-moje-miasto-jozef-ratajczak-1968" -> "6740469_pozdrawiam-moje-miasto-jozef-ratajczak-1968_after_time_decay" [label=0.7219403226503834 constraint=false]
"6740469_nowy-korbut-bibliografia-literatury-polskiej-14-t" -> "6740469_nowy-korbut-bibliografia-literatury-polskiej-14-t_after_time_decay" [label=0.72193715306945 constraint=false]
"6740469_superkomputery-bez-tajemnic-david-loshin-1997" -> "6740469_superkomputery-bez-tajemnic-david-loshin-1997_after_time_decay" [label=0.7219330476524938 constraint=false]
"21424429_wojny-w-cyberprzestrzeni-guisnel-jean-znak" -> "21424429_wojny-w-cyberprzestrzeni-guisnel-jean-znak_after_time_decay" [label=0.7195584388992393 constraint=false]
"38901148_koniec-swieta-eisuke-nakazono" -> "38901148_koniec-swieta-eisuke-nakazono_after_time_decay" [label=0.7194828881206028 constraint=false]
"17346660_podstawy-informatyki-kolodziejczak-zielinski" -> "17346660_podstawy-informatyki-kolodziejczak-zielinski_after_time_decay" [label=0.7194033364179696 constraint=false]
"6740469_urzadzenie-wewnetrzne-miast-wolnych-sejm-wielki" -> "6740469_urzadzenie-wewnetrzne-miast-wolnych-sejm-wielki_after_time_decay" [label=0.7193521968901969 constraint=false]
"15528768_ddd-kompendium-wiedzy-vaughn-vernon" -> "15528768_ddd-kompendium-wiedzy-vaughn-vernon_after_time_decay" [label=0.7189958827772579 constraint=false]
"138008_matematyka-dyskretna-dla-informatykow" -> "138008_matematyka-dyskretna-dla-informatykow_after_time_decay" [label=0.7189659445411196 constraint=false]
"45702657_polski-fiat-125pfso-125p" -> "45702657_polski-fiat-125pfso-125p_after_time_decay" [label=0.7186065898565137 constraint=false]
"43306282_unity-w-akcji-joe-hocking" -> "43306282_unity-w-akcji-joe-hocking_after_time_decay" [label=0.7185117650305968 constraint=false]
"46889202_eng-victor-eijkhout-tex-by-topic" -> "46889202_eng-victor-eijkhout-tex-by-topic_after_time_decay" [label=0.7184689644772201 constraint=false]
"4276139_wallace-wang-internet-hakerzy-wirusy-ladnyegz" -> "4276139_wallace-wang-internet-hakerzy-wirusy-ladnyegz_after_time_decay" [label=0.7183541723056891 constraint=false]
"38901148_micro-prolog-keith-l-clark" -> "38901148_micro-prolog-keith-l-clark_after_time_decay" [label=0.7183006310417779 constraint=false]
"46889202_eng-victor-eijkhout-tex-by-topic" -> "46889202_eng-victor-eijkhout-tex-by-topic_after_time_decay" [label=0.7182156473959604 constraint=false]
}

How do I order nodes in graphviz when using edges doesn't work?

I'm trying to create a flow control graph in graphviz, but I can't get the nodes to stay in the order. I tried prefixing them with a number as that is the only way I could get clusters to go in the right order (by trial an error), but this doesn't work for nodes.
I gave a weight of 100 to the nodes for ordering (which I intend to make invisible once they actually WORK) to no avail.
digraph G {
rankdir=LR;
splines=ortho;
subgraph cluster_I {
color=lightgrey;
style=filled;
label="Incoming Numbers";
newrank="true";
node [color=white,
style=filled];
"thisExtention" [color=lightskyblue1,
shape=square,
style="rounded, filled",
label="Extension 20"];
"+15412362468" [color=azure,
shape=rectangle,
style="rounded, filled"];
"+15412362468" -> "thisExtention" [tailport=e];
"+12069732753" [color=azure,
shape=rectangle,
style="rounded, filled"];
"+12069732753" -> "thisExtention" [tailport=e];
"+441134037186" [color=azure,
shape=rectangle,
style="rounded, filled"];
"+441134037186" -> "thisExtention" [tailport=e];
{
rank=same;
"+15412362468";
"+12069732753";
"+441134037186";
}
}
subgraph cluster_A {
color=blue;
subgraph cluster_1W {
color=lightgrey;
style=filled;
"actionstart" [label="Start Inbound Action Steps\n(can be interrupted by menu dial)"];
"thisExtention" -> "actionstart" [tailport=e];
}
subgraph cluster_2G {
color=aquamarine2;
style=filled;
"2if" [color=azure,
shape=diamond,
label="IF MENUKEY does equal 4"];
"3if" [color=azure,
shape=diamond,
label="IF SUM does equal 2\nAND INSIDE “BUSINESS HOURS”"];
"4ring" [color=azure,
shape=rectangle,
label="ring"];
"6playrecording" [color=azure,
shape=rectangle,
label="playrecording"];
}
subgraph cluster_3Y {
color=salmon1;
style=filled;
"7else" [color=azure,
shape=diamond,
label=ELSE];
"8playrecording" [color=azure,
shape=rectangle,
label="playrecording"];
}
subgraph cluster_W4 {
color=lightgrey;
style=filled;
"9transfer" [color=azure,
shape=rectangle,
label="transfer"];
}
subgraph cluster_5G {
color=aquamarine2;
style=filled;
"10else" [color=azure,
shape=diamond,
label=ELSE];
"11hangup" [color=azure,
shape=rectangle,
label="hangup"];
}
subgraph cluster_O {
color=lightgray;
style=filled;
label="Dial Menu";
"17ring" [color=azure,
shape=rectangle,
label="DIAL (#):\nring"];
"18set" [color=azure,
shape=rectangle,
label="DIAL ①:\nset"];
"19playrecording" [color=azure,
shape=rectangle,
label="DIAL ②:\nplayrecording"];
"20huntgroup" [color=azure,
shape=rectangle,
label="DIAL ③:\nRing HuntGroup: test hunt group"];
"21transfer" [color=azure,
shape=rectangle,
label="DIAL ④:\ntransfer"];
"22huntgroup" [color=azure,
shape=rectangle,
label="DIAL ⑤:\nRing HuntGroup: test hunt group"];
}
{
rank="same";
"actionstart";
"2if";
"3if";
"4ring";
"6playrecording";
"7else";
"8playrecording";
"9transfer";
"10else";
"11hangup";
"17ring";
"18set";
"19playrecording";
"20huntgroup";
"21transfer";
"22huntgroup";
}
"actionstart" -> "2if" [weight=100];
"2if" -> "3if" [weight=100];
"3if" -> "4ring" [weight=100];
"4ring" -> "6playrecording" [weight=100];
"6playrecording" -> "7else" [weight=100];
"7else" -> "8playrecording" [weight=100];
"8playrecording" -> "9transfer" [weight=100];
"9transfer" -> "10else" [weight=100];
"10else" -> "11hangup" [weight=100];
"11hangup" -> "17ring" [weight=100];
"17ring" -> "18set" [weight=100];
"18set" -> "19playrecording" [weight=100];
"19playrecording" -> "20huntgroup" [weight=100];
"20huntgroup" -> "21transfer" [weight=100];
"21transfer" -> "22huntgroup" [weight=100];
}
subgraph columnthree {
"Extension 10" [shape=square,
style="rounded, filled",
fillcolor=lightskyblue1];
"9transfer" -> "Extension 10" [weight=0,
tailport=e];
"HuntGroup 2" [shape=septagon,
style="filled",
fillcolor=lightcyan1];
"20huntgroup" -> "HuntGroup 2" [weight=0,
tailport=e];
"Extension 10" [shape=square,
style="rounded, filled",
fillcolor=lightskyblue1];
"21transfer" -> "Extension 10" [weight=0,
tailport=e];
"HuntGroup 2" [shape=septagon,
style="filled",
fillcolor=lightcyan1];
"22huntgroup" -> "HuntGroup 2" [weight=0,
tailport=e];
}
}

Clusters in Graphviz won't space symmetrically

I'm trying to get multiple clusters of nodes to space evenly in Graphviz.
I think the image best explains what I'm trying to do:
As you can see from the image, there is extra spacing between layers 2 and 3. The space between 2 and 3 should be the same as the space between 1 and 2.
The spacing also needs to scale with more than 3 layers. When I tried more than 3 layers, the 4th layer is spaced as bad as the 3rd layer.
Here is my graph file:
digraph G {
nodesep=1.25;
splines=false;
node[width=1, shape=circle];
edge[style=invis];
subgraph cluster_1 {
label="Layer 1";
"1-1" -> "1-2" -> "1-3";
}
subgraph cluster_2 {
label="Layer 2";
"2-1" -> "2-2" -> "2-3";
}
subgraph cluster_3 {
label="Layer 3";
"3-1" -> "3-2" -> "3-3";
}
edge[style=solid, penwidth=1, constraint=false];
"1-1" -> "2-1";
"1-3" -> "2-1";
"1-1" -> "2-2";
"1-2" -> "2-2";
"1-2" -> "2-3";
"1-3" -> "2-3";
"2-1" -> "3-1";
"2-3" -> "3-1";
"2-1" -> "3-2";
"2-2" -> "3-2";
"2-2" -> "3-3";
"2-3" -> "3-3";
}
How can I go about getting my spacing symmetrical? Any help would be much appreciated. Thanks.
Update:
I have managed to get the spacing even, but it is not a perfect solution.
By placing an invisible node with invisible edges above the graph and connecting it to the top node in each layer, the layers space evenly. However, this node messes up spacing for things that need to be added above the image shown. So, is there a better way to do this?
Adding an Outer Cluster
Bounding box of outer cluster shown for clarity
Nesting the clusters cluster_1, cluster_2, and cluster_3 inside another cluster causes the layout engine to space them evenly.
Working With the Layout Engine
However, the bottom to top rankdir reverses the left to right display ordering to (cluster_3, cluster_2, cluster_1). Reversing the order in the source file fixes [kludges over] that.
Working Code
digraph G {
nodesep=1.25;
splines=false;
clusterrank=local;
node[width=1, shape=circle];
edge[style=invis];
subgraph cluster_0 {
subgraph cluster_3 {
label="Layer 3";
"3-1" -> "3-2" -> "3-3";
}
subgraph cluster_2 {
label="Layer 2";
"2-1" -> "2-2" -> "2-3";
}
subgraph cluster_1 {
label="Layer 1";
"1-1" -> "1-2" -> "1-3";
}
}
edge[style=solid, penwidth=1, constraint=false];
"1-1" -> "2-1";
"1-3" -> "2-1";
"1-1" -> "2-2";
"1-2" -> "2-2";
"1-2" -> "2-3";
"1-3" -> "2-3";
"2-1" -> {"3-1" "3-2"};
"2-3" -> {"3-1" "3-3"};
"2-2" -> {"3-2" "3-3"};
}
Notes
The new outer cluster can be styled so that it's bounding box is not visible.

Resources