]> granicus.if.org Git - graphviz/commitdiff
Add new gvpr scripts
authorerg <devnull@localhost>
Wed, 20 Apr 2011 19:26:31 +0000 (19:26 +0000)
committererg <devnull@localhost>
Wed, 20 Apr 2011 19:26:31 +0000 (19:26 +0000)
15 files changed:
cmd/gvpr/lib/addrings.g [new file with mode: 0644]
cmd/gvpr/lib/anon.g [new file with mode: 0644]
cmd/gvpr/lib/attr.g [new file with mode: 0644]
cmd/gvpr/lib/bb.g [new file with mode: 0644]
cmd/gvpr/lib/cliptree.g [new file with mode: 0644]
cmd/gvpr/lib/col.g [new file with mode: 0644]
cmd/gvpr/lib/color.g [new file with mode: 0644]
cmd/gvpr/lib/deledges.g [new file with mode: 0644]
cmd/gvpr/lib/delnodes.g [new file with mode: 0644]
cmd/gvpr/lib/dijkstra.g [new file with mode: 0644]
cmd/gvpr/lib/path.g [new file with mode: 0644]
cmd/gvpr/lib/scale.g [new file with mode: 0644]
cmd/gvpr/lib/scalexy.g [new file with mode: 0644]
cmd/gvpr/lib/topon.g [new file with mode: 0644]
cmd/gvpr/lib/treetoclust.g [new file with mode: 0644]

diff --git a/cmd/gvpr/lib/addrings.g b/cmd/gvpr/lib/addrings.g
new file mode 100644 (file)
index 0000000..024deb1
--- /dev/null
@@ -0,0 +1,56 @@
+/* Takes a graph laid out by twopi and adds rings.
+ * Assumes ARGV[] = "root" "=" <rootname>, as output by twopi -v.
+ * Usage:
+ *   twopi -v foo.dot > out 2> log
+ *   gvpr -f addrings.g -a"`grep root log`" out | neato -n2 ...
+ */
+BEG_G {
+  graph_t og;
+  edge_t e;
+  node_t ctr = node($, ARGV[0]);
+  double rs = 1.0; /* min. slack between the squares of two consecutive radii */
+  int cx, cy;
+  int x, y;
+  node_t n;
+  int i, n_r;
+  int d;
+  int rads[int];
+  char* ctr_s = ctr.pos;
+  sscanf (ctr_s, "%d,%d", &cx, &cy);
+  if (hasAttr($, "ranksep")) {
+    sscanf ($.ranksep, "%f", &rs);
+    if (rs == 0.0) rs = 1.0;
+  }
+  rs *= 72;
+  rs = 1.5*rs*rs;
+}
+N [$ != ctr] {
+  sscanf ($.pos, "%d,%d", &x, &y);
+  d = (x-cx)*(x-cx) + (y-cy)*(y-cy);
+  for (rads[i]) {
+    if ((rads[i]-rs <= d) && (d <= rads[i]+rs)) return;
+  }
+  n_r++;
+  rads[n_r] = d;
+}
+END_G {
+  og = copy (NULL, $);
+  og.outputorder = "nodesfirst";
+  setDflt (og, "N", "label", "\\N");
+  for (rads[i]) {
+    n = node(og, "ring_"+((string)i));
+    n.shape = "circle";
+    n.pos = ctr_s;
+    n.style = "";
+    n.label = "";
+    d = rads[i];
+    n.width = sprintf("%f", sqrt(d)/36.0);
+  }
+  for (n=fstnode($);n;n = nxtnode(n))
+    clone (og, n);
+  for (n=fstnode($);n;n = nxtnode(n))
+    for (e=fstedge(n);e;e = nxtedge(e,n))
+      clone (og, e);
+  write(og);
+  
+}
diff --git a/cmd/gvpr/lib/anon.g b/cmd/gvpr/lib/anon.g
new file mode 100644 (file)
index 0000000..4faa339
--- /dev/null
@@ -0,0 +1,32 @@
+/* anonymize the graph */
+BEG_G {
+  node_t map[node_t];
+  graph_t dup;
+  int id = 0;
+  char* gtype;
+  node_t n;
+  edge_t e;
+  char* l;
+
+  if ($.directed) gtype = "D";
+  else gtype = "U";
+  if ($.strict) gtype = gtype + "S";
+  dup = graph ($.name, gtype);
+  $tvtype = TV_ne;
+}
+
+N {
+  n = node(dup, (char*)id);
+  n.label=$.name;
+  map[$] = n; 
+  id++;
+}
+
+E {
+  edge (map[$.tail],map[$.head],"");
+}
+
+END_G {
+  write (dup);
+  delete (dup,dup);
+}
diff --git a/cmd/gvpr/lib/attr.g b/cmd/gvpr/lib/attr.g
new file mode 100644 (file)
index 0000000..f7a373a
--- /dev/null
@@ -0,0 +1,7 @@
+/* List known node attributes */
+BEG_G {
+  char* attr;
+  for (attr = fstAttr($,"N"); attr != ""; attr = nxtAttr($,"N",attr)) {
+    print (attr);
+  }
+}
diff --git a/cmd/gvpr/lib/bb.g b/cmd/gvpr/lib/bb.g
new file mode 100644 (file)
index 0000000..e1dcd02
--- /dev/null
@@ -0,0 +1,39 @@
+/* computes the bounding box of a graph based on its nodes 
+   taking into account clusters and node sizes.
+ */
+BEGIN {
+  double x, y, w2, h2;
+  double llx, lly, urx, ury;
+  double llx0, lly0, urx0, ury0;
+
+  graph_t clustBB (graph_t G) {
+    graph_t sg;
+    for (sg = fstsubg(G); sg; sg = nxtsubg(sg)) {
+         sg = clustBB(sg);
+    }
+       if (G.name == "cluster*") {
+      sscanf (G.bb, "%lf,%lf,%lf,%lf", &llx0, &lly0, &urx0, &ury0);
+      if (llx0 < llx) llx = llx0;
+      if (lly0 < lly) lly = lly0;
+      if (urx0 > urx) urx = urx0;
+      if (ury0 > ury) ury = ury0;
+    }
+    return G;
+  }
+}
+BEG_G {
+  llx = 1000000; lly = 1000000; urx = -1000000; ury = -1000000;
+}
+N {
+  sscanf ($.pos, "%lf,%lf", &x, &y);
+  w2 = (36.0*(double)$.width);
+  h2 = (36.0*(double)$.height);
+  if ((x - w2) < llx) llx = x - w2;
+  if ((x + w2) > urx) urx = x + w2;
+  if ((y - h2) < lly) lly = y - h2;
+  if ((y + h2) > ury) ury = y + h2;
+}
+END_G {
+  clustBB ($);
+  $.bb = sprintf ("%lf,%lf,%lf,%lf", llx, lly, urx, ury);
+}
diff --git a/cmd/gvpr/lib/cliptree.g b/cmd/gvpr/lib/cliptree.g
new file mode 100644 (file)
index 0000000..998443f
--- /dev/null
@@ -0,0 +1,8 @@
+/* Construct subgraph reachable from node ARGV[0] by forward edges */
+BEG_G {
+  node_t r = node($,ARGV[0]);
+
+  $tvroot = r;
+  $tvtype = TV_fwd;
+}
+N{$tvroot=NULL; subnode($T,$);}
diff --git a/cmd/gvpr/lib/col.g b/cmd/gvpr/lib/col.g
new file mode 100644 (file)
index 0000000..00a2848
--- /dev/null
@@ -0,0 +1,24 @@
+# test
+/* color nodes using output of dijkstra */
+BEG_G {
+    double h, hn, hf, d, sat, md = maxdist; 
+    if (hue_near =="") hue_near = 0.8;
+    if (hue_far =="") hue_far = 1.2;
+    hn = hue_near;
+    hf = hue_far;
+}
+# test
+N {
+    d = dist;
+    sat = (md - d + 1.0) /( md + 1.0);
+    h = hn + ((hf - hn) * d)/md;
+    while (h < 0.0) h = h + 1.0;
+    while (h > 1.0) h = h - 1.0;
+    color = sprintf("%lf %lf %lf",hue,sat,1.0);
+      /* make sure the shape is filled */
+    if (!match(style,"filled")>=0) {
+      if (style != "") style=sprintf("%s,filled",style);
+      else style="filled";
+    }
+}
+
diff --git a/cmd/gvpr/lib/color.g b/cmd/gvpr/lib/color.g
new file mode 100644 (file)
index 0000000..5688118
--- /dev/null
@@ -0,0 +1,59 @@
+/* color edges based on normalized length alpha.
+ * If we have lim[i-1] <= alpha <= lim[i], the color
+ * is linearly interpolated between color[i-1] and color[i].
+ * Edges already having a color attribute are left unchanged.
+ */
+BEGIN {
+  double lens [edge_t];
+  double maxlen, len, minlen=1.7976931348623157e+308;
+  double alpha, x0, y0, x1, y1;
+  double h0, s0, v0;
+  int i;
+  int ncolors;     /* number of colors: ncolors >= 2 */
+  /* start of color i.
+   * lim[0]=0 < lim[1] < ... < lim[ncolors-1]=1
+   */
+  double lim[int]; 
+  /* HSV values for color i */
+  double h[int];
+  double s[int];
+  double v[int];
+
+  /* simple default */
+  ncolors = 2;
+  lim[0] = 0;
+  lim[1] = 1;
+  h[0] = 0;
+  h[1] = 0.67;
+  s[0] = 1;
+  s[1] = 1;
+  v[0] = 1;
+  v[1] = 1;
+}
+E{
+    sscanf ($.tail.pos, "%f,%f", &x0, &y0);
+    sscanf ($.head.pos, "%f,%f", &x1, &y1);
+
+    len = sqrt ((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1));
+
+    lens[$] = len;
+    if (len > maxlen) maxlen = len;
+    if (len < minlen) minlen = len;
+}
+BEG_G {
+  if (!isAttr($,"E","color"))
+    setDflt($,"E","color","");
+}
+E{
+  if ($.color != "") return; 
+  alpha = (lens[$]-minlen)/(maxlen-minlen);
+  for (i = 1; i < ncolors; i++) {
+    if (alpha < lim[i]) break;
+  }
+  alpha = (alpha - lim[i-1])/(lim[i] - lim[i-1]);
+  h0 = (1-alpha)*h[i-1] + alpha*h[i];  
+  s0 = (1-alpha)*s[i-1] + alpha*s[i];  
+  v0 = (1-alpha)*v[i-1] + alpha*v[i];  
+  $.color = sprintf ("%.02f %.02f %.02f", h0, s0, v0);
+}
diff --git a/cmd/gvpr/lib/deledges.g b/cmd/gvpr/lib/deledges.g
new file mode 100644 (file)
index 0000000..c1efa8f
--- /dev/null
@@ -0,0 +1,9 @@
+/* delete all edges */
+BEGIN {
+  int map[edge_t];
+  edge_t e;
+}
+E {map[$]=1}
+END_G {
+  for (map[e]) delete ($,e);
+}
diff --git a/cmd/gvpr/lib/delnodes.g b/cmd/gvpr/lib/delnodes.g
new file mode 100644 (file)
index 0000000..57d1cc7
--- /dev/null
@@ -0,0 +1,15 @@
+/* Delete nodes whose names are given in ARGV */
+BEG_G {
+  int names[char*];
+  int nodes[node_t];
+  node_t n;
+  int i;
+
+  for (i = 0; i < ARGC; i++)
+    names[ARGV[i]] = 1;
+}
+N[names[name]]{nodes[$] = 1}
+END_G {
+  for (nodes[n])
+    delete ($,n);
+}
diff --git a/cmd/gvpr/lib/dijkstra.g b/cmd/gvpr/lib/dijkstra.g
new file mode 100644 (file)
index 0000000..08c7fce
--- /dev/null
@@ -0,0 +1,28 @@
+/* Given graph processed by dijkstra, and node,
+ * color shortest path
+ * Assumes path has been computed by dijkstra
+ */
+BEG_G {
+  node_t n = isNode($,ARGV[0]);
+  node_t nxt;
+  edge_t e;
+  double d, totd = 0;
+
+  if (n == NULL) {
+    printf(2, "no node named \"%s\"\n", ARGV[0]);
+    exit(1);
+  }
+  while (n.prev != "") {
+       nxt = isNode($,n.prev);
+    /* printf(2, "nxt \"%s\"\n", nxt.name); */
+       e = isEdge (n, nxt, "");
+    if (e == NULL) {
+      printf(2, "no edge between %s and %s\n", n.name, nxt.name);
+    }
+    e.color = "blue";
+    /* printf(2, "len %s\n", e.len); */
+    /* sscanf (e.len, "%f", &d); */
+       /* totd += d; */
+    n = nxt;
+  }
+}
diff --git a/cmd/gvpr/lib/path.g b/cmd/gvpr/lib/path.g
new file mode 100644 (file)
index 0000000..931a0cd
--- /dev/null
@@ -0,0 +1,24 @@
+/* Report the distance from src = ARGV[0] to dst = ARGV[1]
+ */
+BEG_G {
+  int dist[node_t];
+  node_t n, curn;
+  node_t src = node($G, ARGV[0]);
+  node_t dst = node($G, ARGV[1]);
+  $tvroot = src;
+  $tvtype = TV_bfs;
+}
+
+N {
+  curn = $;
+  if ($ == dst) {
+    printf ("dist from %s to %s is %d\n", src.name, dst.name, dist[dst]);
+    exit(0);
+  }
+}
+
+E {
+  if ($.head == curn) n = $.tail; 
+  else n = $.head;
+  if (dist[n] == 0) dist[n] = dist[curn]+1;
+}
diff --git a/cmd/gvpr/lib/scale.g b/cmd/gvpr/lib/scale.g
new file mode 100644 (file)
index 0000000..c56afd2
--- /dev/null
@@ -0,0 +1,46 @@
+/* finds node n with root attribute 
+ * finds distance minr of closest node
+ * the layout is then scaled out from n so that 
+ * a node is put on the smallest circle of radius x*minr
+ * containing n
+ */
+BEG_G {
+  node_t ctr;
+  int cx, cy;
+  int x, y;
+  double delx, dely;
+  int newx, newy;
+  node_t n;
+  edge_t e;
+  int i, sc, d, mind = -1;
+  double fact, newr, ang, minr;
+  
+  ctr = node($,aget($,"root"));
+  sscanf (ctr.pos, "%d,%d", &cx, &cy);
+  for (e = fstedge(ctr); e; e = nxtedge(e, ctr)) {
+    if (e.head == ctr) n = e.tail;
+    else n = e.head;
+    sscanf (n.pos, "%d,%d", &x, &y);
+    d = (x-cx)*(x-cx) + (y-cy)*(y-cy);
+    if ((mind == -1) || (d < mind)) mind = d;
+  } 
+  minr = (int)sqrt((double)mind);
+}
+
+N [$ != ctr] {
+  
+    sscanf ($.pos, "%d,%d", &x, &y);
+    dely = y - cy;
+    delx = x - cx;
+    d = delx*delx + dely*dely;
+    sc = (int)sqrt((double)(d/mind));
+    if (sc > 1) {
+      fact = 2.0;
+      for (i=1; i<sc-1;i++) fact *= 2.0;
+      newr = minr*(2.0 - (1.0/fact));
+      ang = atan2 (dely, delx);
+      newx = newr*cos(ang) + cx; 
+      newy = newr*sin(ang) + cy; 
+      $.pos = sprintf ("%d,%d", newx, newy);
+    }
+}
diff --git a/cmd/gvpr/lib/scalexy.g b/cmd/gvpr/lib/scalexy.g
new file mode 100644 (file)
index 0000000..1a9bc0e
--- /dev/null
@@ -0,0 +1,54 @@
+/* finds root node of graph.
+ * scales the x and y position of all other nodes using, first,
+ * ARGV[0], or $G.scale.
+ * 
+ * The expected syntax is "x,y" where at least one of x or y must
+ * be given. If only one is given, the other is taken as 1.
+ */
+BEGIN {
+  double scalex, scaley;
+  int r, done;
+
+  int setScale (char* s) 
+  {
+    if ((sscanf (s, ",%f",&scaley))) {
+        scalex = 1;
+        return 1;
+    }
+    else {
+      r = sscanf (s, "%f,%f",&scalex,&scaley);
+      if (r) {
+        if (r == 1) scaley = 1;
+        return 1;
+      }
+    }
+    return 0;
+  }
+
+}
+
+BEG_G {
+  node_t ctr = node($,aget($,"root"));
+  double cx, cy, x, y, delx;
+  
+  /* get scale argument */
+  done = 0;
+  if (ARGC == 1)
+    done = setScale (ARGV[0]);
+  if (!done && isAttr($,"G","scale"))
+    done = setScale ($.scale);
+  if (!done)
+    scalex = scaley = 1.0;
+
+  if ((scalex == 1.0) && (scaley == 1.0))
+    exit (0);
+
+  $.bb = "";
+  sscanf (ctr.pos, "%f,%f", &cx, &cy);
+}
+N [$ != ctr] {
+    sscanf ($.pos, "%f,%f", &x, &y);
+    delx = scalex*(x - cx) + cx;
+    dely = scaley*(y - cy) + cy;
+    $.pos = sprintf ("%f,%f", delx, dely);
+}
diff --git a/cmd/gvpr/lib/topon.g b/cmd/gvpr/lib/topon.g
new file mode 100644 (file)
index 0000000..c247696
--- /dev/null
@@ -0,0 +1,27 @@
+/* Generate copy of topology of input graph
+ * Replace names with numbers
+ */
+BEGIN {
+int id = 0;
+char* names[char*];
+
+char* mapn (char* inname)
+{
+   char* s = names[inname];
+   if (s == "") {
+     s = id++;
+     names[inname] = s;
+   }
+   return s;
+}
+
+}
+
+BEG_G {
+  graph_t g = graph ($.name, "U");
+}
+N { node (g, mapn($.name)); }
+E { edge (node (g, mapn($.tail.name)), node (g, mapn($.head.name)), ""); }
+END_G {
+  write (g);
+}
diff --git a/cmd/gvpr/lib/treetoclust.g b/cmd/gvpr/lib/treetoclust.g
new file mode 100644 (file)
index 0000000..df8ffb7
--- /dev/null
@@ -0,0 +1,54 @@
+/* Convert a rooted tree to a hierarchy of clusters for patchwork.
+ * ARGV[0] is desired root
+ */
+BEG_G {
+  node_t rt;
+  node_t n;
+  graph_t cg;
+  graph_t sg;
+  int depth;
+  int mark[node_t];
+  graph_t stk[int];
+
+  if (! $.directed) {
+    printf(2,"Input graph is not directed\n");
+    exit (1);
+  }
+  rt = isNode($,ARGV[0]);
+  if (rt == NULL) {
+    printf(2,"Root node \"%s\" not found\n", ARGV[0]);
+    exit (1);
+  }
+  $tvroot = rt;
+  $tvtype = TV_prepostfwd;
+  cg = graph(rt.name,"U");
+}
+
+N {
+  if (mark[$]) {
+    depth--;
+  }
+  else {
+    mark[$] = 1;
+    if (depth > 0) {
+      if (fstout($)) {
+        sg = subg(stk[depth-1], "cluster_" + $.name); 
+        if (($.style == "filled") && ($.fillcolor != ""))
+          sg.bgcolor = $.fillcolor;
+      }
+      else {
+        sg = NULL;
+        n = node(stk[depth-1], $.name);
+        n.style = "filled";
+        n.fillcolor = $.fillcolor;
+      }
+    }
+    else sg = cg;
+    stk[depth] = sg;
+    depth++;
+  }
+}
+END_G {
+  write(cg);
+}
+