Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Graphviz Sharing Attributes between Nodes or Edges

Tags:

graphviz

dot

I'm using Graphviz (namely Dot) to draw up a state machine for a Hypermedia API I'm planning on building. In my graph, nodes represent states, while edges represent links. What I'm trying to do is have edges (links) of the same "type" (ie, use the same verb or same rel) to share attributes like color.

I know you can define "global" attributes that apply to all nodes/edges, but I need something I can apply more generally to several different "types". The closest analogy I can come up with for what I want is HTML classes. I don't need multiple "classes" for my edges (although that would be nice) but repeating attributes like color=red, style=bold is cumbersome.

Is there a way in Dot to declare something like this? Or at least some way I don't have to repeat myself so often?

like image 364
Dominic Barnes Avatar asked Apr 14 '13 03:04

Dominic Barnes


1 Answers

I've done this in two different ways:

Option (A): Write the dot file from another script. This is particularly useful when I'm using a script (in, say, Python or Perl) to rework the input data into dot format for drawing. In that case, as well as having the Python script write the data into dot format I can also have it write the attributes for each node and edge into the dot file. An example is shown below (not runnable because I've extracted it from a larger script that interprets the input data but you can see how the Perl is writing the dot code).

print "graph G {\n graph [overlap = scale, size = \"10,10\"]; node [fontname = \"Helvetica\", fontsize = 9]\n";
for ($j = 0; $j <= $#sectionList; $j++) {
   print "n$j [label = \"$sectionList[$j]\", style = filled, fillcolor = $groupColour{$group{$sectionList[$j]}} ]\n";
   }
for ($j = 0; $j <= $#sectionList; $j++) {
   for ($i = $j+1; $i <= $#sectionList; $i++) {
      $wt = ($collab{$sectionList[$j]}{$sectionList[$i]}+0)/
         ($collab{$sectionList[$j]}{$sectionList[$j]}+0);
      if ($wt > 0.01) {
         print "n$j -- n$i [weight = $wt, ";
         if ($wt > 0.15) {
            print "style = bold]\n";
         }
         elsif ($wt > 0.04) {
            print "]\n";
         } else {
            print "style = dotted]\n";
         }
      }
   }
   print "\n";
}

print "}\n";

Option (B): If I'm writing the dot script by hand, I'll use a macro processor to define common elements. For example given the file polygon.dot.m4 containing the m4 macro define() as follows:

define(SHAPE1,square)
define(SHAPE2,triangle)

digraph G {
    a -> b -> c;
    b -> d;
    a [shape=SHAPE1];
    b [shape=SHAPE2];
    d [shape=SHAPE1];
    e [shape=SHAPE2];
    }

... the command m4 <polygon.dot.m4 | dot -Tjpg -opolygon.jpg produces: enter image description here

Changing the definitions of SHAPE1 and SHAPE2 at the top of the file will change the shapes drawn for each of the relevant nodes.

like image 106
Simon Avatar answered Oct 09 '22 09:10

Simon