Retain the cluster orderings when re-render the src with modified edges

I have a use case where the edges should be shown on the button click.
Let’s say, we have a graph with nested clusters without edges.
the edges between nodes and clusters should be shown based on interaction.
This works fine when I call the renderDot function again with a modified src but sometimes the position or order of clusters gets changed.
The first cluster goes to 3r place and vice versa.
Do we have any attribute to force the cluster to place in sequential order?
Note: I only modified edges not adding or removing clusters and even the ordering changed when the same src files passed multiple times. I understand that the issue is not because of edges.

render(src) {
graphviz(‘#id’).renderDot(src)
}

onClick(modifiedEdgesSrc) {
this.render(modifiedEdgesSrc)
}

There is no such attribute, though maybe not difficult, maybe a good summer intern project. Also, the submitted merge to fix “nondeterministic layout in fdp” might help a lot.

Edges affect the layout of nodes. So adding and removing edges will inherently affect the node positions.

To achieve what you want, I think rendering once with the edges as you want them and once with the edges set to transparent or the same color as the background may do what you want.

I have used the styles i.e. link.classed(“edges_on”, true) to solve my use case.

Note: Not only adding the edges but adding the nodes changed the position of the clusters.
Adding support to retain the cluster position would give more addition to the interaction point of view.

**UPDATED : **

digraph G {

pack=true;
packMode="clust";
compound = "true";
    
 subgraph cluster_B {
    sortv=2;
    node [label="B1"] B1;
    node [label="B2"] B2;
    node [label="B3"] B3;
    
    B1->B2;
    B1->B3;
}
subgraph cluster_A {
 
    sortv=3;
    node [label="A1"] A1;
    node [label="A2"] A2;
    node [label="A3"] A3;
         
    A1->A2;
    A1->A3;
}      
     

 
subgraph cluster_C {
    sortv=1;
            
    node [label="C1"] C1;
    node [label="C2"] C2;
    node [label="C3"] C3;
      
    C1->C2;
    C1->C3;

}

}

I have tried the packMode attr to order it but it doesn’t work as expected.
Any idea about this?

From what I’ve been able to discern pack=true is fairly broken, regression: dot pack/packmode removes edge labels when there are disconnected subgraphs (#1616) · Issues · graphviz / graphviz · GitLab

Not sure I understand (other than clusters have a mind of their own!), but here goes:

If you can consistently get the clusters positioned how you want before any changes, then you can use this multi-step approach:

  • run dot -Tdot against the starting version of your graph. This gives an input file with all objects fully positioned.
  • every time you add, change, or delete the edges, run the result through neato -n. This will keep all the clusters and nodes in place, but will re-route the edges (FAQ | Graphviz).

If you cannot always get to a happy starting placement (yes, clusters are hard to position), you can try putting each cluster in a separate graph, run dot on each, and then use gvpack (https://graphviz.org/pdf/gvpack.1.pdf) to combine all the clusters in a 1-dimensional or 2-dimensional array.

I started exploring the fdp layout based on your suggestion to place the nodes using pos attribute.
So that I can retain the cluster position/order even after re-rendering some additional nodes(including pos for new nodes).
I am trying to achieve the below diagram using pos and it is working when I have one subgraph.
not sure what values need to be given for other subgraph nodes.
I use d3-graphviz library for rendering.

Adding to this.
Below is the sample code that I used

graph G {
layout = fdp;
overlap = false;
splines = true;
node [shape=box, style=filled, fillcolor=lightblue];
subgraph cluster_Vpc {
{rank=same; rankdir=LR; subgraph cluster_1 {
label = “Cluster 1”;
// pos = “0,0!”; // Manually specify position
node [fillcolor=lightyellow];
Node1[pos=“1,0.!”];
Node2[pos=“2,0!”];
Node5[pos=“3,0!”];
Node6[pos=“4,0!”];
Node7[pos=“1,-1!”]
Node8[pos=“2,-1!”];
}}

{rank=same; rankdir=LR; subgraph cluster_2 {
label = “Cluster 2”;
node [fillcolor=lightgreen];
Node3[pos=“5,0!”];
Node4[pos=“6,0!”];
Node25[pos=“7,0!”];
Node26[pos=“8,0!”];

}}

}

}

You can use dot -Tdot to layout the “starting” graph (it will produce explicit pos values), and then add/remove/change edges all you want to the output of the dot -Tdot command.

  • running that result through neato -n
    OR (since you are using a library)
  • use layout=nop inside the graph after changes (the equivalent to neato -n on the command line, see nop2 | Graphviz)