[graphviz-interest] GVPR script to merge graphs
"Schmitt, David A" <[email protected]> Fri, 17 Jan 2014 11:41:00 -0500
| Newsgroups | gmane.comp.video.graphviz |
|---|---|
| Message-ID | <B60145F537086E4EB84C96AB617CCEF72C3E18A791@FHDP1LUMXC7V21.us.one.verizon.com> |
Not sure if anyone else has already done this, but I recently had the need to merge elements from multiple source graphs.
In an attempt to give back to the Graphviz community in some small way, I'm including my script here.
Example ways to use the script:
# Add extra edges after initial layout is complete
dot -Txdot basic.dot | gvpr -f gvmerge -a edges.dot | neato -Tpng -n2 -o full.png
# Merge several graphs at once
gvpr -f gvmerge -a "extra1.dot extra2.dot" basic.dot | dot -Tpng -o extra.png
Not sure if the mailing list accepts attachments, so here it is inline:
====================gvmerge==============================
#!/bin/gvpr -f
// Author: David Schmitt
BEGIN {
// Since gvpr has no local scope, we must simulate a stack
graph_t source_subgraphs[];
graph_t target_subgraphs[];
int depth = 0;
string attribute;
string value;
graph_t current_subgraph;
graph_t new_subgraph;
node_t current_node;
node_t new_node;
// Must be called _after_ source_push
void target_set(graph_t new_target) {
target_subgraphs[depth - 1] = new_target;
}
graph_t target_get(int offset) {
return target_subgraphs[depth - 1 - offset];
}
void source_push(graph_t new_source) {
source_subgraphs[depth] = new_source;
depth = depth + 1;
}
graph_t source_pop() {
depth = depth - 1;
return source_subgraphs[depth];
}
graph_t source_peek(int offset) {
return source_subgraphs[depth - 1 - offset];
}
void copy_subgraphs() {
current_subgraph = source_peek(0);
if (depth > 1) {
new_subgraph = subg(target_get(1), current_subgraph.name);
target_set(new_subgraph);
attribute = fstAttr(current_subgraph, "G");
while (attribute) {
if (hasAttr(current_subgraph, attribute)) {
value = aget(current_subgraph, attribute);
aset(new_subgraph, attribute, value);
} else if (isAttr(current_subgraph, "G", attribute)) {
value = getDflt(current_subgraph, "G", attribute);
aset(new_subgraph, attribute, value);
}
attribute = nxtAttr(current_subgraph, "G", attribute);
}
}
source_push(fstsubg(current_subgraph));
while (source_peek(0)) {
copy_subgraphs();
current_subgraph = source_pop();
source_push(nxtsubg(current_subgraph));
}
source_pop();
current_subgraph = source_peek(0);
current_node = fstnode(current_subgraph);
while (current_node) {
if (!isNode(target_get(0), current_node.name)) {
new_node = node(target_get(0), current_node.name);
attribute = fstAttr(current_subgraph, "N");
while (attribute) {
if (hasAttr(current_node, attribute)) {
// Copy node attributes
value = aget(current_node, attribute);
aset(new_node, attribute, value);
} else if (isAttr(current_subgraph, "N", attribute)) {
// Copy node defaults
value = getDflt(current_subgraph, "N", attribute);
aset(new_node, attribute, value);
}
attribute = nxtAttr(current_subgraph, "N", attribute);
}
}
current_node = nxtnode(current_node);
}
}
}
END_G {
graph_t current_graph;
node_t tail_node;
node_t head_node;
edge_t current_edge;
edge_t new_edge;
// Sequence for generating unique edge names
int sequence = 0;
// Counter for extra edge file arguments
int i;
// Array to keep track of edges already inserted
string previous_edges[];
// Array to keep track of nodes already inserted
string pn[];
for(i = 0; i < ARGC; ++i) {
string path = ARGV[i];
current_graph = readG(path);
source_push(current_graph);
target_set($);
copy_subgraphs();
// Force the name trackers to be cleared
unset(previous_edges);
unset(pn);
current_node = fstnode(current_graph);
while (current_node) {
current_edge = fstedge(current_node);
while (current_edge) {
// Make sure you only add the edge once
if (!previous_edges[current_edge.name]) {
previous_edges[current_edge.name] = 1;
sequence = sequence + 1;
// Unique edge names
string new_edge_name = sprintf("gvmerge_%d", sequence);
tail_node = node($, current_edge.tail.name);
head_node = node($, current_edge.head.name);
new_edge = edge(tail_node, head_node, new_edge_name);
attribute = fstAttr(current_graph, "E");
while (attribute) {
if (hasAttr(current_edge, attribute)) {
// Copy edge attributes
value = aget(current_edge, attribute);
aset(new_edge, attribute, value);
} else if (isAttr(current_graph, "E", attribute)) {
// Copy edge defaults
value = getDflt(current_graph, "E", attribute);
aset(new_edge, attribute, value);
}
attribute = nxtAttr(current_graph, "E", attribute);
}
}
current_edge = nxtedge(current_edge, current_node);
}
current_node = nxtnode(current_node);
}
}
write($);
}
END {
// Without this here nothing gets generated!
printf("\n");
}
_______________________________________________
[email protected]
http://lists.research.att.com/mailman/listinfo/graphviz-interest