Layout subgraph into a grid

I am trying to layout the top-level subgraph into a grid. I have tried putting an anchor node in each of the subgraphs and using a high weight to pull the location, but it is still not working. Do you have any suggestions on what could be done?

[dot fit=true verbose=true height=238 width=800]

digraph G {

packmode="array_c4i";

rankdir=TB;

layout=dot;

subgraph cluster_0_0 {

label="tile_0_0_NULL";

margin=15;

style=rounded;

rank=source;

anchor_X0Y0 [style=invis];

}

subgraph cluster_0_1 {

label="tile_0_1_W_IO";

margin=15;

style=rounded;

rank=source;

subgraph "cluster_0_1_c0.W_IO" {

label="c0.W_IO";

"X0Y1.bel_c0.W_IO" [label="bel_c0.W_IO(z=0x0000)", shape=box];

"X0Y1.c0.W_IO.from_fabric" [label="from_fabric", shape=hexagon];

"X0Y1.c0.W_from_fabric";

"X0Y1.c0.W_from_fabric" -> "X0Y1.c0.W_IO.from_fabric";

"X0Y1.c0.W_IO.from_fabric" -> "X0Y1.bel_c0.W_IO";

"X0Y1.c0.W_IO.in" [label=in, shape=hexagon];

"X0Y1.c0.W_in";

"X0Y1.c0.W_in" -> "X0Y1.c0.W_IO.in";

"X0Y1.c0.W_IO.in" -> "X0Y1.bel_c0.W_IO";

"X0Y1.c0.W_IO.to_fabric" [label="to_fabric", shape=hexagon];

"X0Y1.bel_c0.W_IO" -> "X0Y1.c0.W_IO.to_fabric";

"X0Y1.c0.W_to_fabric";

"X0Y1.c0.W_IO.to_fabric" -> "X0Y1.c0.W_to_fabric";

"X0Y1.c0.W_IO.out" [label=out, shape=hexagon];

"X0Y1.bel_c0.W_IO" -> "X0Y1.c0.W_IO.out";

"X0Y1.c0.W_out";

"X0Y1.c0.W_IO.out" -> "X0Y1.c0.W_out";

}

"X0Y1.c0.out1_internal";

"X0Y1.c0.out1";

"X0Y1.c0.out1_internal" -> "X0Y1.c0.out1";

"X0Y1.c0.W_to_fabric" -> "X0Y1.c0.out1_internal";

"X0Y1.c0.in1";

"X0Y1.c0.in1" -> "X0Y1.c0.W_from_fabric";

anchor_X0Y1 [style=invis];

}

"X1Y1.c0.in3";

"X0Y1.c0.out1" -> "X1Y1.c0.in3" [dir=none, color=blue, weight=10000];

subgraph cluster_0_2 {

label="tile_0_2_NULL";

margin=15;

style=rounded;

rank=source;

anchor_X0Y2 [style=invis];

}

subgraph cluster_1_0 {

label="tile_1_0_S_IO";

margin=15;

style=rounded;

rank=source;

subgraph "cluster_1_0_c0.S_IO" {

label="c0.S_IO";

"X1Y0.bel_c0.S_IO" [label="bel_c0.S_IO(z=0x0000)", shape=box];

"X1Y0.c0.S_IO.from_fabric" [label="from_fabric", shape=hexagon];

"X1Y0.c0.S_from_fabric";

"X1Y0.c0.S_from_fabric" -> "X1Y0.c0.S_IO.from_fabric";

"X1Y0.c0.S_IO.from_fabric" -> "X1Y0.bel_c0.S_IO";

"X1Y0.c0.S_IO.in" [label=in, shape=hexagon];

"X1Y0.c0.S_in";

"X1Y0.c0.S_in" -> "X1Y0.c0.S_IO.in";

"X1Y0.c0.S_IO.in" -> "X1Y0.bel_c0.S_IO";

"X1Y0.c0.S_IO.to_fabric" [label="to_fabric", shape=hexagon];

"X1Y0.bel_c0.S_IO" -> "X1Y0.c0.S_IO.to_fabric";

"X1Y0.c0.S_to_fabric";

"X1Y0.c0.S_IO.to_fabric" -> "X1Y0.c0.S_to_fabric";

"X1Y0.c0.S_IO.out" [label=out, shape=hexagon];

"X1Y0.bel_c0.S_IO" -> "X1Y0.c0.S_IO.out";

"X1Y0.c0.S_out";

"X1Y0.c0.S_IO.out" -> "X1Y0.c0.S_out";

}

"X1Y0.c0.out0_internal";

"X1Y0.c0.out0";

"X1Y0.c0.out0_internal" -> "X1Y0.c0.out0";

"X1Y0.c0.S_to_fabric" -> "X1Y0.c0.out0_internal";

"X1Y0.c0.in0";

"X1Y0.c0.in0" -> "X1Y0.c0.S_from_fabric";

anchor_X1Y0 [style=invis];

}

"X1Y1.c0.in2";

"X1Y0.c0.out0" -> "X1Y1.c0.in2" [dir=none, color=blue, weight=10000];

subgraph cluster_1_1 {

label="tile_1_1_PE";

margin=15;

style=rounded;

rank=source;

subgraph cluster_1_1_CLK_DRV {

label="CLK_DRV";

"X1Y1.bel_CLK_DRV" [label="bel_CLK_DRV(z=0xffff)", shape=box];

"X1Y1.CLK_DRV.CLK_O" [label="CLK_O", shape=hexagon];

"X1Y1.bel_CLK_DRV" -> "X1Y1.CLK_DRV.CLK_O";

"X1Y1.user_clk_o";

"X1Y1.CLK_DRV.CLK_O" -> "X1Y1.user_clk_o";

}

subgraph "cluster_1_1_c0.ALU" {

label="c0.ALU";

"X1Y1.bel_c0.ALU" [label="bel_c0.ALU(z=0x0000)", shape=box];

"X1Y1.c0.ALU.data_in1" [label="data_in1", shape=hexagon];

"X1Y1.c0.data_in1";

"X1Y1.c0.data_in1" -> "X1Y1.c0.ALU.data_in1";

"X1Y1.c0.ALU.data_in1" -> "X1Y1.bel_c0.ALU";

"X1Y1.c0.ALU.data_in2" [label="data_in2", shape=hexagon];

"X1Y1.c0.data_in2";

"X1Y1.c0.data_in2" -> "X1Y1.c0.ALU.data_in2";

"X1Y1.c0.ALU.data_in2" -> "X1Y1.bel_c0.ALU";

"X1Y1.c0.ALU.data_in3" [label="data_in3", shape=hexagon];

"X1Y1.c0.data_in3";

"X1Y1.c0.data_in3" -> "X1Y1.c0.ALU.data_in3";

"X1Y1.c0.ALU.data_in3" -> "X1Y1.bel_c0.ALU";

"X1Y1.c0.ALU.data_out" [label="data_out", shape=hexagon];

"X1Y1.bel_c0.ALU" -> "X1Y1.c0.ALU.data_out";

"X1Y1.c0.data_out";

"X1Y1.c0.ALU.data_out" -> "X1Y1.c0.data_out";

}

subgraph "cluster_1_1_c0.const_unit" {

label="c0.const_unit";

"X1Y1.bel_c0.const_unit" [label="bel_c0.const_unit(z=0x0001)", shape=box];

"X1Y1.c0.const_unit.const_out" [label="const_out", shape=hexagon];

"X1Y1.bel_c0.const_unit" -> "X1Y1.c0.const_unit.const_out";

"X1Y1.c0.const_out";

"X1Y1.c0.const_unit.const_out" -> "X1Y1.c0.const_out";

}

subgraph "cluster_1_1_c0.RES_reg_unit" {

label="c0.RES_reg_unit";

"X1Y1.bel_c0.RES_reg_unit" [label="bel_c0.RES_reg_unit(z=0x0002)", shape=box];

"X1Y1.c0.RES_reg_unit.en" [label=en, shape=hexagon];

"X1Y1.c0.RES_en";

"X1Y1.c0.RES_en" -> "X1Y1.c0.RES_reg_unit.en";

"X1Y1.c0.RES_reg_unit.en" -> "X1Y1.bel_c0.RES_reg_unit";

"X1Y1.c0.RES_reg_unit.reg_in" [label="reg_in", shape=hexagon];

"X1Y1.c0.RES_reg_in";

"X1Y1.c0.RES_reg_in" -> "X1Y1.c0.RES_reg_unit.reg_in";

"X1Y1.c0.RES_reg_unit.reg_in" -> "X1Y1.bel_c0.RES_reg_unit";

"X1Y1.c0.RES_reg_unit.rst" [label=rst, shape=hexagon];

"X1Y1.c0.RES_rst";

"X1Y1.c0.RES_rst" -> "X1Y1.c0.RES_reg_unit.rst";

"X1Y1.c0.RES_reg_unit.rst" -> "X1Y1.bel_c0.RES_reg_unit";

"X1Y1.c0.RES_reg_unit.reg_out" [label="reg_out", shape=hexagon];

"X1Y1.bel_c0.RES_reg_unit" -> "X1Y1.c0.RES_reg_unit.reg_out";

"X1Y1.c0.RES_reg_out";

"X1Y1.c0.RES_reg_unit.reg_out" -> "X1Y1.c0.RES_reg_out";

"X1Y1.c0.RES_reg_unit.clk" [label=clk, shape=hexagon];

"X1Y1.c0.RES_reg_unit_clk_i";

"X1Y1.c0.RES_reg_unit_clk_i" -> "X1Y1.c0.RES_reg_unit.clk";

"X1Y1.c0.RES_reg_unit.clk" -> "X1Y1.bel_c0.RES_reg_unit";

}

subgraph "cluster_1_1_c0.N_reg_unit" {

label="c0.N_reg_unit";

"X1Y1.bel_c0.N_reg_unit" [label="bel_c0.N_reg_unit(z=0x0003)", shape=box];

"X1Y1.c0.N_reg_unit.en" [label=en, shape=hexagon];

"X1Y1.c0.N_en";

"X1Y1.c0.N_en" -> "X1Y1.c0.N_reg_unit.en";

"X1Y1.c0.N_reg_unit.en" -> "X1Y1.bel_c0.N_reg_unit";

"X1Y1.c0.N_reg_unit.reg_in" [label="reg_in", shape=hexagon];

"X1Y1.c0.N_reg_in";

"X1Y1.c0.N_reg_in" -> "X1Y1.c0.N_reg_unit.reg_in";

"X1Y1.c0.N_reg_unit.reg_in" -> "X1Y1.bel_c0.N_reg_unit";

"X1Y1.c0.N_reg_unit.rst" [label=rst, shape=hexagon];

"X1Y1.c0.N_rst";

"X1Y1.c0.N_rst" -> "X1Y1.c0.N_reg_unit.rst";

"X1Y1.c0.N_reg_unit.rst" -> "X1Y1.bel_c0.N_reg_unit";

"X1Y1.c0.N_reg_unit.reg_out" [label="reg_out", shape=hexagon];

"X1Y1.bel_c0.N_reg_unit" -> "X1Y1.c0.N_reg_unit.reg_out";

"X1Y1.c0.N_reg_out";

"X1Y1.c0.N_reg_unit.reg_out" -> "X1Y1.c0.N_reg_out";

"X1Y1.c0.N_reg_unit.clk" [label=clk, shape=hexagon];

"X1Y1.c0.N_reg_unit_clk_i";

"X1Y1.c0.N_reg_unit_clk_i" -> "X1Y1.c0.N_reg_unit.clk";

"X1Y1.c0.N_reg_unit.clk" -> "X1Y1.bel_c0.N_reg_unit";

}

subgraph "cluster_1_1_c0.E_reg_unit" {

label="c0.E_reg_unit";

"X1Y1.bel_c0.E_reg_unit" [label="bel_c0.E_reg_unit(z=0x0004)", shape=box];

"X1Y1.c0.E_reg_unit.en" [label=en, shape=hexagon];

"X1Y1.c0.E_en";

"X1Y1.c0.E_en" -> "X1Y1.c0.E_reg_unit.en";

"X1Y1.c0.E_reg_unit.en" -> "X1Y1.bel_c0.E_reg_unit";

"X1Y1.c0.E_reg_unit.reg_in" [label="reg_in", shape=hexagon];

"X1Y1.c0.E_reg_in";

"X1Y1.c0.E_reg_in" -> "X1Y1.c0.E_reg_unit.reg_in";

"X1Y1.c0.E_reg_unit.reg_in" -> "X1Y1.bel_c0.E_reg_unit";

"X1Y1.c0.E_reg_unit.rst" [label=rst, shape=hexagon];

"X1Y1.c0.E_rst";

"X1Y1.c0.E_rst" -> "X1Y1.c0.E_reg_unit.rst";

"X1Y1.c0.E_reg_unit.rst" -> "X1Y1.bel_c0.E_reg_unit";

"X1Y1.c0.E_reg_unit.reg_out" [label="reg_out", shape=hexagon];

"X1Y1.bel_c0.E_reg_unit" -> "X1Y1.c0.E_reg_unit.reg_out";

"X1Y1.c0.E_reg_out";

"X1Y1.c0.E_reg_unit.reg_out" -> "X1Y1.c0.E_reg_out";

"X1Y1.c0.E_reg_unit.clk" [label=clk, shape=hexagon];

"X1Y1.c0.E_reg_unit_clk_i";

"X1Y1.c0.E_reg_unit_clk_i" -> "X1Y1.c0.E_reg_unit.clk";

"X1Y1.c0.E_reg_unit.clk" -> "X1Y1.bel_c0.E_reg_unit";

}

subgraph "cluster_1_1_c0.S_reg_unit" {

label="c0.S_reg_unit";

"X1Y1.bel_c0.S_reg_unit" [label="bel_c0.S_reg_unit(z=0x0005)", shape=box];

"X1Y1.c0.S_reg_unit.en" [label=en, shape=hexagon];

"X1Y1.c0.S_en";

"X1Y1.c0.S_en" -> "X1Y1.c0.S_reg_unit.en";

"X1Y1.c0.S_reg_unit.en" -> "X1Y1.bel_c0.S_reg_unit";

"X1Y1.c0.S_reg_unit.reg_in" [label="reg_in", shape=hexagon];

"X1Y1.c0.S_reg_in";

"X1Y1.c0.S_reg_in" -> "X1Y1.c0.S_reg_unit.reg_in";

"X1Y1.c0.S_reg_unit.reg_in" -> "X1Y1.bel_c0.S_reg_unit";

"X1Y1.c0.S_reg_unit.rst" [label=rst, shape=hexagon];

"X1Y1.c0.S_rst";

"X1Y1.c0.S_rst" -> "X1Y1.c0.S_reg_unit.rst";

"X1Y1.c0.S_reg_unit.rst" -> "X1Y1.bel_c0.S_reg_unit";

"X1Y1.c0.S_reg_unit.reg_out" [label="reg_out", shape=hexagon];

"X1Y1.bel_c0.S_reg_unit" -> "X1Y1.c0.S_reg_unit.reg_out";

"X1Y1.c0.S_reg_out";

"X1Y1.c0.S_reg_unit.reg_out" -> "X1Y1.c0.S_reg_out";

"X1Y1.c0.S_reg_unit.clk" [label=clk, shape=hexagon];

"X1Y1.c0.S_reg_unit_clk_i";

"X1Y1.c0.S_reg_unit_clk_i" -> "X1Y1.c0.S_reg_unit.clk";

"X1Y1.c0.S_reg_unit.clk" -> "X1Y1.bel_c0.S_reg_unit";

}

subgraph "cluster_1_1_c0.W_reg_unit" {

label="c0.W_reg_unit";

"X1Y1.bel_c0.W_reg_unit" [label="bel_c0.W_reg_unit(z=0x0006)", shape=box];

"X1Y1.c0.W_reg_unit.en" [label=en, shape=hexagon];

"X1Y1.c0.W_en";

"X1Y1.c0.W_en" -> "X1Y1.c0.W_reg_unit.en";

"X1Y1.c0.W_reg_unit.en" -> "X1Y1.bel_c0.W_reg_unit";

"X1Y1.c0.W_reg_unit.reg_in" [label="reg_in", shape=hexagon];

"X1Y1.c0.W_reg_in";

"X1Y1.c0.W_reg_in" -> "X1Y1.c0.W_reg_unit.reg_in";

"X1Y1.c0.W_reg_unit.reg_in" -> "X1Y1.bel_c0.W_reg_unit";

"X1Y1.c0.W_reg_unit.rst" [label=rst, shape=hexagon];

"X1Y1.c0.W_rst";

"X1Y1.c0.W_rst" -> "X1Y1.c0.W_reg_unit.rst";

"X1Y1.c0.W_reg_unit.rst" -> "X1Y1.bel_c0.W_reg_unit";

"X1Y1.c0.W_reg_unit.reg_out" [label="reg_out", shape=hexagon];

"X1Y1.bel_c0.W_reg_unit" -> "X1Y1.c0.W_reg_unit.reg_out";

"X1Y1.c0.W_reg_out";

"X1Y1.c0.W_reg_unit.reg_out" -> "X1Y1.c0.W_reg_out";

"X1Y1.c0.W_reg_unit.clk" [label=clk, shape=hexagon];

"X1Y1.c0.W_reg_unit_clk_i";

"X1Y1.c0.W_reg_unit_clk_i" -> "X1Y1.c0.W_reg_unit.clk";

"X1Y1.c0.W_reg_unit.clk" -> "X1Y1.bel_c0.W_reg_unit";

}

"X1Y1.user_clk_o" -> "X1Y1.c0.RES_reg_unit_clk_i";

"X1Y1.user_clk_o" -> "X1Y1.c0.N_reg_unit_clk_i";

"X1Y1.user_clk_o" -> "X1Y1.c0.E_reg_unit_clk_i";

"X1Y1.user_clk_o" -> "X1Y1.c0.S_reg_unit_clk_i";

"X1Y1.user_clk_o" -> "X1Y1.c0.W_reg_unit_clk_i";

"X1Y1.c0.out0_internal";

"X1Y1.c0.out0";

"X1Y1.c0.out0_internal" -> "X1Y1.c0.out0";

"X1Y1.c0.out1_internal";

"X1Y1.c0.out1";

"X1Y1.c0.out1_internal" -> "X1Y1.c0.out1";

"X1Y1.c0.out2_internal";

"X1Y1.c0.out2";

"X1Y1.c0.out2_internal" -> "X1Y1.c0.out2";

"X1Y1.c0.out3_internal";

"X1Y1.c0.out3";

"X1Y1.c0.out3_internal" -> "X1Y1.c0.out3";

"X1Y1.c0.data_out" -> "X1Y1.c0.out0_internal";

"X1Y1.c0.RES_reg_out" -> "X1Y1.c0.out0_internal";

"X1Y1.c0.in2";

"X1Y1.c0.in2" -> "X1Y1.c0.out0_internal";

"X1Y1.c0.data_out" -> "X1Y1.c0.out1_internal";

"X1Y1.c0.RES_reg_out" -> "X1Y1.c0.out1_internal";

"X1Y1.c0.in3";

"X1Y1.c0.in3" -> "X1Y1.c0.out1_internal";

"X1Y1.c0.data_out" -> "X1Y1.c0.out2_internal";

"X1Y1.c0.RES_reg_out" -> "X1Y1.c0.out2_internal";

"X1Y1.c0.in0";

"X1Y1.c0.in0" -> "X1Y1.c0.out2_internal";

"X1Y1.c0.data_out" -> "X1Y1.c0.out3_internal";

"X1Y1.c0.RES_reg_out" -> "X1Y1.c0.out3_internal";

"X1Y1.c0.in1";

"X1Y1.c0.in1" -> "X1Y1.c0.out3_internal";

"X1Y1.c0.in0" -> "X1Y1.c0.data_in1";

"X1Y1.c0.in1" -> "X1Y1.c0.data_in1";

"X1Y1.c0.in2" -> "X1Y1.c0.data_in1";

"X1Y1.c0.in3" -> "X1Y1.c0.data_in1";

"X1Y1.c0.RES_reg_out" -> "X1Y1.c0.data_in1";

"X1Y1.c0.N_reg_out" -> "X1Y1.c0.data_in1";

"X1Y1.c0.E_reg_out" -> "X1Y1.c0.data_in1";

"X1Y1.c0.S_reg_out" -> "X1Y1.c0.data_in1";

"X1Y1.c0.W_reg_out" -> "X1Y1.c0.data_in1";

"X1Y1.c0.in0" -> "X1Y1.c0.data_in2";

"X1Y1.c0.in1" -> "X1Y1.c0.data_in2";

"X1Y1.c0.in2" -> "X1Y1.c0.data_in2";

"X1Y1.c0.in3" -> "X1Y1.c0.data_in2";

"X1Y1.c0.const_out" -> "X1Y1.c0.data_in2";

"X1Y1.c0.RES_reg_out" -> "X1Y1.c0.data_in2";

"X1Y1.c0.N_reg_out" -> "X1Y1.c0.data_in2";

"X1Y1.c0.E_reg_out" -> "X1Y1.c0.data_in2";

"X1Y1.c0.S_reg_out" -> "X1Y1.c0.data_in2";

"X1Y1.c0.W_reg_out" -> "X1Y1.c0.data_in2";

"X1Y1.c0.in0" -> "X1Y1.c0.data_in3";

"X1Y1.c0.in1" -> "X1Y1.c0.data_in3";

"X1Y1.c0.in2" -> "X1Y1.c0.data_in3";

"X1Y1.c0.in3" -> "X1Y1.c0.data_in3";

"X1Y1.c0.const_out" -> "X1Y1.c0.data_in3";

"X1Y1.c0.data_out" -> "X1Y1.c0.RES_reg_in";

"X1Y1.c0.in0" -> "X1Y1.c0.N_reg_in";

"X1Y1.c0.N_reg_out" -> "X1Y1.c0.N_reg_in";

"X1Y1.c0.in1" -> "X1Y1.c0.E_reg_in";

"X1Y1.c0.E_reg_out" -> "X1Y1.c0.E_reg_in";

"X1Y1.c0.in2" -> "X1Y1.c0.S_reg_in";

"X1Y1.c0.S_reg_out" -> "X1Y1.c0.S_reg_in";

"X1Y1.c0.in3" -> "X1Y1.c0.W_reg_in";

"X1Y1.c0.W_reg_out" -> "X1Y1.c0.W_reg_in";

anchor_X1Y1 [style=invis];

}

"X1Y2.c0.in2";

"X1Y1.c0.out0" -> "X1Y2.c0.in2" [dir=none, color=blue, weight=10000];

"X2Y1.c0.in3";

"X1Y1.c0.out1" -> "X2Y1.c0.in3" [dir=none, color=blue, weight=10000];

"X1Y1.c0.out2" -> "X1Y0.c0.in0" [dir=none, color=blue, weight=10000];

"X1Y1.c0.out3" -> "X0Y1.c0.in1" [dir=none, color=blue, weight=10000];

subgraph cluster_1_2 {

label="tile_1_2_N_IO";

margin=15;

style=rounded;

rank=source;

subgraph "cluster_1_2_c0.N_IO" {

label="c0.N_IO";

"X1Y2.bel_c0.N_IO" [label="bel_c0.N_IO(z=0x0000)", shape=box];

"X1Y2.c0.N_IO.from_fabric" [label="from_fabric", shape=hexagon];

"X1Y2.c0.N_from_fabric";

"X1Y2.c0.N_from_fabric" -> "X1Y2.c0.N_IO.from_fabric";

"X1Y2.c0.N_IO.from_fabric" -> "X1Y2.bel_c0.N_IO";

"X1Y2.c0.N_IO.in" [label=in, shape=hexagon];

"X1Y2.c0.N_in";

"X1Y2.c0.N_in" -> "X1Y2.c0.N_IO.in";

"X1Y2.c0.N_IO.in" -> "X1Y2.bel_c0.N_IO";

"X1Y2.c0.N_IO.to_fabric" [label="to_fabric", shape=hexagon];

"X1Y2.bel_c0.N_IO" -> "X1Y2.c0.N_IO.to_fabric";

"X1Y2.c0.N_to_fabric";

"X1Y2.c0.N_IO.to_fabric" -> "X1Y2.c0.N_to_fabric";

"X1Y2.c0.N_IO.out" [label=out, shape=hexagon];

"X1Y2.bel_c0.N_IO" -> "X1Y2.c0.N_IO.out";

"X1Y2.c0.N_out";

"X1Y2.c0.N_IO.out" -> "X1Y2.c0.N_out";

}

"X1Y2.c0.out2_internal";

"X1Y2.c0.out2";

"X1Y2.c0.out2_internal" -> "X1Y2.c0.out2";

"X1Y2.c0.N_to_fabric" -> "X1Y2.c0.out2_internal";

"X1Y2.c0.in2";

"X1Y2.c0.in2" -> "X1Y2.c0.N_from_fabric";

anchor_X1Y2 [style=invis];

}

"X1Y2.c0.out2" -> "X1Y1.c0.in0" [dir=none, color=blue, weight=10000];

subgraph cluster_2_0 {

label="tile_2_0_NULL";

margin=15;

style=rounded;

rank=source;

anchor_X2Y0 [style=invis];

}

subgraph cluster_2_1 {

label="tile_2_1_E_IO";

margin=15;

style=rounded;

rank=source;

subgraph "cluster_2_1_c0.E_IO" {

label="c0.E_IO";

"X2Y1.bel_c0.E_IO" [label="bel_c0.E_IO(z=0x0000)", shape=box];

"X2Y1.c0.E_IO.from_fabric" [label="from_fabric", shape=hexagon];

"X2Y1.c0.E_from_fabric";

"X2Y1.c0.E_from_fabric" -> "X2Y1.c0.E_IO.from_fabric";

"X2Y1.c0.E_IO.from_fabric" -> "X2Y1.bel_c0.E_IO";

"X2Y1.c0.E_IO.in" [label=in, shape=hexagon];

"X2Y1.c0.E_in";

"X2Y1.c0.E_in" -> "X2Y1.c0.E_IO.in";

"X2Y1.c0.E_IO.in" -> "X2Y1.bel_c0.E_IO";

"X2Y1.c0.E_IO.to_fabric" [label="to_fabric", shape=hexagon];

"X2Y1.bel_c0.E_IO" -> "X2Y1.c0.E_IO.to_fabric";

"X2Y1.c0.E_to_fabric";

"X2Y1.c0.E_IO.to_fabric" -> "X2Y1.c0.E_to_fabric";

"X2Y1.c0.E_IO.out" [label=out, shape=hexagon];

"X2Y1.bel_c0.E_IO" -> "X2Y1.c0.E_IO.out";

"X2Y1.c0.E_out";

"X2Y1.c0.E_IO.out" -> "X2Y1.c0.E_out";

}

"X2Y1.c0.out3_internal";

"X2Y1.c0.out3";

"X2Y1.c0.out3_internal" -> "X2Y1.c0.out3";

"X2Y1.c0.E_to_fabric" -> "X2Y1.c0.out3_internal";

"X2Y1.c0.in3";

"X2Y1.c0.in3" -> "X2Y1.c0.E_from_fabric";

anchor_X2Y1 [style=invis];

}

"X2Y1.c0.out3" -> "X1Y1.c0.in1" [dir=none, color=blue, weight=10000];

subgraph cluster_2_2 {

label="tile_2_2_NULL";

margin=15;

style=rounded;

rank=source;

anchor_X2Y2 [style=invis];

}

anchor_X0Y0 -> anchor_X1Y0 [style=invis, weight=10000];

anchor_X0Y1 -> anchor_X1Y1 [style=invis, weight=10000];

anchor_X0Y2 -> anchor_X1Y2 [style=invis, weight=10000];

anchor_X1Y0 -> anchor_X2Y0 [style=invis, weight=10000];

anchor_X1Y1 -> anchor_X2Y1 [style=invis, weight=10000];

anchor_X1Y2 -> anchor_X2Y2 [style=invis, weight=10000];

anchor_X0Y0 -> anchor_X0Y1 [style=invis, rank=same, weight=10000];

anchor_X1Y0 -> anchor_X1Y1 [style=invis, rank=same, weight=10000];

anchor_X2Y0 -> anchor_X2Y1 [style=invis, rank=same, weight=10000];

anchor_X0Y1 -> anchor_X0Y2 [style=invis, rank=same, weight=10000];

anchor_X1Y1 -> anchor_X1Y2 [style=invis, rank=same, weight=10000];

anchor_X2Y1 -> anchor_X2Y2 [style=invis, rank=same, weight=10000];

}

[/dot]

I apologize. I have messed up the formatting of this post and can’t seem to figure out how to undo my mess.

While waiting for someone to correct my blunder,
I’ll look at your graph

The graph has 4 modest-sized clusters and one large cluster. How do you want them arranged? (the input seems to say columns of four, based on input sequence)

I’ve reverted the post to the original and added fit=true verbose=true height=238 width=800 to show the DOT source and adjust the rendered graph a bit.

1 Like

I am trying to lay it out as a 3x3 grid. Towards the bottom, there is the section:

anchor_X0Y0 -> anchor_X1Y0 [style=invis, weight=10000];

anchor_X0Y1 -> anchor_X1Y1 [style=invis, weight=10000];

anchor_X0Y2 -> anchor_X1Y2 [style=invis, weight=10000];

anchor_X1Y0 -> anchor_X2Y0 [style=invis, weight=10000];

anchor_X1Y1 -> anchor_X2Y1 [style=invis, weight=10000];

anchor_X1Y2 -> anchor_X2Y2 [style=invis, weight=10000];

anchor_X0Y0 -> anchor_X0Y1 [style=invis, rank=same, weight=10000];

anchor_X1Y0 -> anchor_X1Y1 [style=invis, rank=same, weight=10000];

anchor_X2Y0 -> anchor_X2Y1 [style=invis, rank=same, weight=10000];

anchor_X0Y1 -> anchor_X0Y2 [style=invis, rank=same, weight=10000];

anchor_X1Y1 -> anchor_X1Y2 [style=invis, rank=same, weight=10000];

anchor_X2Y1 -> anchor_X2Y2 [style=invis, rank=same, weight=10000];

Which is trying to do that. I have put an anchor as an invisible node within each cluster. You should find anchor_X0Y0 in cluster_0_0. But seems like is not enough.

I have also tried to put each row into a cluster, but do not seem to be working.

Ideally, I would like to have each cluster positioned relative to the cluster coordinate.

I have a smaller example that might work better for discussion. That graph is generated, and I can fit the principle later.

[dot fit=true verbose=true height=238 width=800]

digraph G {

  subgraph cluster_0 {
    style=filled;
    color=lightgrey;
    node [style=filled,color=white];
    a0 -> a1 -> a2 -> a3;
    label = "process #0";
    anchor0[style=invis]
  }

  subgraph cluster_1 {
    node [style=filled];
    b0 -> b1 -> b2;
    label = "process #1";
    color=blue
    anchor1[style=invis]
  }
  
    subgraph cluster_2 {
    node [style=filled];
    c0 -> c1;
    label = "process #2";
    color=blue
    anchor2[style=invis]
  }
  
    subgraph cluster_3 {
    node [style=filled];
    d0 -> d1 -> d2 -> d3;
    label = "process #3";
    color=blue
    anchor3[style=invis]
  }
anchor0 -> anchor1[weight=1000, style=invis]
anchor0 -> anchor2[weight=1000, style=invis]
anchor1 -> anchor3[weight=1000, style=invis]
anchor2 -> anchor3[weight=1000, style=invis]
}

[/dot]

And format to

process 0 | process 1
process 2 | process 3
  • the first graph tries to use two conflicting techniques to build the grid:
    • “anchors” - dicey at best and probably doomed with wildly varying cluster sizes
      • no easy way to place the “anchors”
      • can’t use rank=same across clusters
      • hard to align columns, though group might help
    • packmode (packing) - a good idea, but seems to fail if there are edges between the clusters (as found in the first graph)
  • the second graph is probably over-simplified
    • all the clusters are about the same size
    • there are no edges between the clusters

This needs more thought

Here is work-in-progress - using packmode only

  • removed all inter-cluster edges (going forward they would be replaced later)
  • removed all anchor->anchor edges
  • tweaked the packmode statement (packmode=“array_ri3”; )
  • colored the clusters for my eyes

Is this in any way close to what is desired?
If not, what needs to be changed?

That placement will be good enough for me.

A side question: Is the pack feature only available for a more recent version of Graphviz? TxDOT is leading to a double free, and the VSCode extension for viewing dot graphs is not rendering it correctly.

Yes, packmode was fixed about 8 months ago (setting pack attributes can cause dot to crash (#2555) · Issues · graphviz / graphviz · GitLab)
As an alternative, you can:

  • split your graph into 9 separate/independent graphs
  • run each through dot to establish positioning
  • feed all 9 to gvpack (another Graphviz program)
  • finally, feed the gvpack output to neato -n

It is not as bad as it sounds.
I have a program that will split one graph into multiple, based on top-level clusters and will publish if you need it.

I can split the graph myself, I just need to make some changes in how I create the graph.

However, if I use this method, do I add the inter-cluster edge after neato?

I suggest to take a look at the osage layout, where you have much more control over how clusters are positioned.
full explanation can be found here, comment from @jjlong: Top Rank Node is not center aligned over some subgraphs - #5 by jjlong

other example:Is there a way to draw "desks" (2 boxes side by side and 2 below them) without using arrows on graphviz?

Thanks. Maybe osage is the tool I want. Can I mix layout engine? Since the middle layer cluster might work better with dot…