Skip to content

Instantly share code, notes, and snippets.

@steveroush
Created April 9, 2025 02:45
Show Gist options
  • Save steveroush/3e8548bd185161021f231b1701022fbd to your computer and use it in GitHub Desktop.
Save steveroush/3e8548bd185161021f231b1701022fbd to your computer and use it in GitHub Desktop.
clusterEdges.gvpr - create edges to/from clusters in dot (Graphviz) graphs
/********************************************************************
see help below
********************************************************************/
BEGIN{
graph_t tmpG, aGraph, Root; //, Cluster[];
edge_t newE;
node_t aNode, tNode, hNode;
graph_t tailCluster, headCluster;
int i, Gcnt;
string BB[];
string help;
//////////////// help /////////////////////////////////////////////
// *INDENT-OFF* turn off pretty-printing, there is a string-related bug in astyle
help="clusterEdges.gvpr - creates edges to/from clusters for dot graphs
clusterEdges.gvpr requires 2 input graphs
- the 1st is the graph without the desires edges to/from clusters
to get the desired layout, invisible edges may be required
- the 2nd is a pdeudo graph, consisting solely of edges to/from clusters
Arguments:
none
Usage examples:
dot myfile.gv |gvpr -f cluster2clusterEdges.gvpr|neato -n2 -Tpng -o myfile.png
"; // *INDENT-ON* NOTE: place on line with end-of-string
////////////////////////////////////////////////////////////////////////////
node_t makeOverlay(graph_t Cluster, graph_t bigG){
string newName, newPos;
double MinX,MinY,MaxX,MaxY, newX, newY;
newName=(string)Cluster.name + "_overlay";
print("// makeOverlay : ", Cluster.name," ",BB[Cluster.name]);
aNode=isNode(bigG,newName);
if (aNode==NULL){
aNode=node(bigG, newName);
aNode.shape="rect";
sscanf (BB[Cluster.name], "%lf,%lf,%lf,%lf", &MinX, &MinY, &MaxX, &MaxY);
newX=MinX+(MaxX-MinX)/2;
newY=MinY+(MaxY-MinY)/2;
newPos=(string)newX +","+(string)newY;
aNode.pos=newPos;
aNode.Xbb=BB[Cluster.name];
aNode.width=(MaxX-MinX)/72.;
aNode.height=(MaxY-MinY)/72.;
aNode.label="";
aNode.peripheries="0";
//aNode.style="filled"; // turn on for testing
//aNode.fillcolor="#ff000022"; // turn on for testing
}
return aNode;
}
graph_t graphTraverse(graph_t thisG) {
for (aGraph = fstsubg(thisG); aGraph; aGraph = nxtsubg(aGraph)) {
if (match(aGraph.name,"cluster")==0 || (hasAttr(aGraph, "cluster") && aGraph.cluster=="true")){
print ("// CLUSTER ",aGraph.name, " ", aGraph.bb);
BB[aGraph.name]=aGraph.bb;
}
aGraph = graphTraverse(aGraph);
}
return thisG;
} // end of graphTraverse
Gcnt=0;
}
BEG_G {
Root=$G;
Gcnt++;
if (Gcnt==1){
tmpG=cloneG($G,"");
graphTraverse($G);
}
}
E[Gcnt==2]{
if (isNode(tmpG, $.tail.name)==NULL){
tailCluster=subg(tmpG, $.tail.name);
print("// tail: ", tailCluster.name," ", BB[tailCluster.name]);
tNode=makeOverlay(tailCluster, tmpG);
}else{
tNode=node(tmpG, $.tail.name);
}
if (isNode(tmpG, $.head.name)==NULL){
headCluster=subg(tmpG, $.head.name);
hNode=makeOverlay(headCluster, tmpG);
}else{
hNode=node(tmpG, $.head.name);
}
newE=edge_sg(tmpG, tNode, hNode, "");
copyA($, newE);
newE.pos="";
}
END_G{
if (Gcnt==2){
write(tmpG);
}
}
/********************* Demo Input **********************
graph G {
e
subgraph clusterA {
a -- b;
subgraph clusterC {
C -- D;
}
}
subgraph clusterB {
d -- f
}
d -- D
}
graph cc{
e -- clusterB
clusterC -- clusterB
}
**********************************************/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment