Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I reverse the direction of every edge in a Graphviz (dot language) graph?

Tags:

graphviz

dot

I have a directed graph specified in Graphviz's dot language, e.g.

digraph G { A -> B [label="foo"]; A -> B [label="bar"]; B -> A; C; }

I want to automatically process this into a graph with its edges reversed, i.e.

digraph G { B -> A [label="foo"]; B -> A [label="bar"]; A -> B; C; }

I would like to use a robust solution (i.e. one that understands the graph and therefore probably doesn't use sed) that preserves any existing edge labels and other attributes. Note that I am not merely talking about getting dot to render my graph with the arrows pointing backward; I really need a graph whose edges are reversed. (In this case, I intend to reverse the edges, apply prune, then reverse the edges again.)

How can I reverse the direction of every edge in a Graphviz (dot-language) graph?

like image 676
Woody Zenfell III Avatar asked Feb 02 '23 06:02

Woody Zenfell III


2 Answers

Easiest way is to include a graph-level dir statement where you reverse the direction of the arrows. By default, the direction is forward. If you reverse it at the top of your graph, then without changing a single other line, the graph will show up the way you want.

What you have now is this:

digraph G
{
    edge [dir="forward"]; /* implied */
    A -> B [label="foo"];
    A -> B [label="bar"];
    B -> A;
    C;
}

What you want is this:

digraph G
{
    edge [dir="back"]; /* note the change to this line */
    A -> B [label="foo"];
    A -> B [label="bar"];
    B -> A;
    C;
}
like image 53
Stéphane Avatar answered May 11 '23 01:05

Stéphane


The best I've come up with so far is

BEG_G {
    graph_t g = graph($.name + " reversed", "D");
    int edge_id = 0;
}

N {
    clone(g, $);
}

E {
    node_t newHead = clone(g, $.head);
    node_t newTail = clone(g, $.tail);
    edge_t newEdge = edge_sg(g, newHead, newTail, edge_id);
    copyA($, newEdge);
    edge_id++;
}

END_G {
    $O = g;
}

which I then invoke with gvpr.

This does add a "key" attribute to all resultant edges, but I'm not sure how to avoid that and still preserve multiple edges between the same pair of nodes.

When I do echo 'digraph G { A -> B [label="foo"]; A -> B [label="bar"]; B -> A; C; }' | gvpr -f reverseAllEdges.gvpr, I get:

digraph "G reversed" {
    A -> B [key=2];
    B -> A [key=0, label=foo];
    B -> A [key=1, label=bar];
    C;
}

I don't know how robust this will prove to be, but it looks promising.

like image 27
Woody Zenfell III Avatar answered May 11 '23 01:05

Woody Zenfell III