Search code examples
graphvizdotpydot

Graphviz cluster changes layout order of internal nodes - how to correct?


The following graphviz nodes arrange into a C shape as expected when rendered using dot:

digraph G {
newrank=true;
"001_getCtInputChunk" [shape=rect, label="@disk_cache\ngetCtInputChunk"];
"004_augmentCtInputChunk" [shape=rect, label=augmentCtInputChunk];
"002_cache_dir" [shape=cylinder, label="Cache Dir\n(.pkl.gz)"];
"003_LunaDataset" [shape=box3d, label=LunaDataset];
"001_getCtInputChunk" -> "002_cache_dir";
"002_cache_dir" -> "001_getCtInputChunk";
"001_getCtInputChunk" -> "003_LunaDataset";
"003_LunaDataset" -> "004_augmentCtInputChunk";
subgraph  {
rank=same;
"001_getCtInputChunk" [shape=rect, label="@disk_cache\ngetCtInputChunk"];
"002_cache_dir" [shape=cylinder, label="Cache Dir\n(.pkl.gz)"];
}

subgraph  {
rank=same;
"004_augmentCtInputChunk" [shape=rect, label=augmentCtInputChunk];
"003_LunaDataset" [shape=box3d, label=LunaDataset];
}

}

enter image description here

When I put the nodes into a cluster as follows, the layout changes to a Z shape:

digraph G {
newrank=true;
subgraph cluster_dsets {
label="dsets.py";
shape=rect;
"001_getCtInputChunk" [label="@disk_cache\ngetCtInputChunk", shape=rect];
"004_augmentCtInputChunk" [label=augmentCtInputChunk, shape=rect];
"002_cache_dir" [label="Cache Dir\n(.pkl.gz)", shape=cylinder];
"003_LunaDataset" [label=LunaDataset, shape=box3d];
}

"001_getCtInputChunk" -> "002_cache_dir";
"002_cache_dir" -> "001_getCtInputChunk";
"001_getCtInputChunk" -> "003_LunaDataset";
"003_LunaDataset" -> "004_augmentCtInputChunk";
subgraph  {
rank=same;
"001_getCtInputChunk" [label="@disk_cache\ngetCtInputChunk", shape=rect];
"002_cache_dir" [label="Cache Dir\n(.pkl.gz)", shape=cylinder];
}

subgraph  {
rank=same;
"004_augmentCtInputChunk" [label=augmentCtInputChunk, shape=rect];
"003_LunaDataset" [label=LunaDataset, shape=box3d];
}

}

enter image description here

How can I force the clustered nodes to lay themselves out in the same C shape as the unclustered ones? I would prefer a general solution, since my actual graph is quite a bit more complicated, and has this issue in several places.

I'm currently using pydot to generate the graphs, in case that's relevant.


Solution

  • I changed several small details to get very close to the result you're looking for. nodesep gives a little better separation when dir=both is used (instead of two explicit edges), makes adequate room for the arrowheads. And of course dir-both draws the major direction to the left with rank=same so your nodes which were getting reversed now appear in the order declared. Finally, I changed the widths of the leftmost elements to make them align nicer.

    digraph G {
    
    nodesep=0.5;
    
    newrank=true;
    
    subgraph cluster_dsets {
        label="dsets.py";
        shape=rect;
        "001_getCtInputChunk" [label="@disk_cache\ngetCtInputChunk", shape=rect, width=1.8];
        "004_augmentCtInputChunk" [label=augmentCtInputChunk, shape=rect];
        "002_cache_dir" [label="Cache Dir\n(.pkl.gz)", shape=cylinder];
        "003_LunaDataset" [label=LunaDataset, shape=box3d, width=1.8];
        }
    
    "001_getCtInputChunk" -> "002_cache_dir" [dir=both];
    "001_getCtInputChunk" -> "003_LunaDataset";
    "003_LunaDataset" -> "004_augmentCtInputChunk";
    
    subgraph  {
        rank=same;
        "001_getCtInputChunk" [label="@disk_cache\ngetCtInputChunk", shape=rect];
        "002_cache_dir" [label="Cache Dir\n(.pkl.gz)", shape=cylinder];
        }
    
    subgraph  {
        rank=same;
        "004_augmentCtInputChunk" [label=augmentCtInputChunk, shape=rect];
        "003_LunaDataset" [label=LunaDataset, shape=box3d];
        }
    
    }
    

    enter image description here