WSTester updated to work plus hopefully all the other changes that need to go into...
[jabaws.git] / binaries / src / ViennaRNA / Cluster / treeplot.c
diff --git a/binaries/src/ViennaRNA/Cluster/treeplot.c b/binaries/src/ViennaRNA/Cluster/treeplot.c
new file mode 100644 (file)
index 0000000..7be12b4
--- /dev/null
@@ -0,0 +1,358 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "distance_matrix.h"
+#include "utils.h"
+
+#define PUBLIC
+#define PRIVATE  static
+
+#define MAXTAXA_FOR_LABELS  200
+
+typedef struct{
+        int   set1;
+        int   set2;
+        float distance;
+        float distance2;
+        } Union;
+
+typedef struct _Node_ {
+                 float  height;
+                 float  brr;
+                 float  brl;
+                 int    whoami;
+                 int    size;
+                 struct _Node_  *father;
+                 struct _Node_  *left;
+                 struct _Node_  *right;                
+               } Node;
+
+PUBLIC void  PSplot_phylogeny(Union *cluster, char *filename, char *type);
+
+PRIVATE Node *W2Phylo(Union *cluster);
+PRIVATE Node *Nj2Phylo(Union *cluster);
+PRIVATE void  free_phylo_tree(Node *root);
+PRIVATE void fill_height_into_tree(Node *root);
+PRIVATE void fill_br_from_height(Node *root);
+PRIVATE void plot_branch(Node *root, FILE *fp);
+PRIVATE void format_number(float x);
+
+PRIVATE char  str[10];
+PRIVATE float threshold;
+PRIVATE int   print_labels=1;
+
+/* --------------------------------------------------------------------------*/
+
+PUBLIC void  PSplot_phylogeny(Union *cluster, char *filename, char *type)
+{
+   int   n;
+   char  outfile[50];
+   char  *tmp, *tfont;
+   Node  *root;
+   Node  *tempnode;
+   FILE  *fp;
+   float xsize, ysize, tfontsize, lfontsize, lwidth;
+      
+   n = cluster[0].set1;
+   switch(type[0]) {
+      case 'W' :
+        root = W2Phylo(cluster);
+        break;
+      case 'N' : 
+        root = Nj2Phylo(cluster);
+        break;
+      default :
+        return;
+   }
+
+   outfile[0] = '\0';
+   tmp = get_taxon_label(-1);   /* retrieve data set identifier */
+   if(tmp) {strcat(outfile,tmp); strcat(outfile,"_"); free(tmp);}
+   strcat(outfile,filename);
+   
+   fp = fopen(outfile,"w");
+   if (fp==NULL) {
+      fprintf(stderr,"couldn't open %s -- not doing treeplot\n", outfile);
+      return;
+   }
+   xsize = root->size;
+   tempnode = root;
+   while(tempnode->right) 
+      tempnode = tempnode->right;   
+   ysize = tempnode->height;
+   threshold = ysize*0.06;
+
+   lwidth = MIN2(1.5, 8/sqrt((double)n));
+   tfontsize = MIN2(15,550./(10+n));
+   lfontsize = 2./3.*tfontsize;
+   if (n>30) tfont = "Helvetica";
+   else tfont = "Times-Roman";
+   if(n > MAXTAXA_FOR_LABELS) print_labels=0;
+   else print_labels=1;
+   fprintf(fp,"%%!PS-Adobe-2.0 EPSF-1.2\n");
+   fprintf(fp,"%%%%Title: TreePlot (%s)\n",type);
+   fprintf(fp,"%%%%Creator: AnalyseDists\n");
+   fprintf(fp,"%%%%CreationDate: %s", time_stamp());
+   /* BoundingBox is only approximate */
+   fprintf(fp,"%%%%BoundingBox: 35 45 535 640\n");
+   fprintf(fp,"%%%%Pages: 1\n");
+   fprintf(fp,"%%%%EndComments: No comment!\n");
+   fprintf(fp,"288.5 50 translate\n");
+   fprintf(fp,"%3.1f setlinewidth\n"
+             "/cmtx matrix currentmatrix def\n", lwidth);
+   fprintf(fp,"500 %g div 360 %g div scale\n", xsize, ysize); 
+   fprintf(fp,"/rotshow {gsave cmtx setmatrix\n"); 
+   fprintf(fp,"          90 rotate 5 %4.1f rmoveto show grestore} def\n",
+          -tfontsize/4);
+   fprintf(fp,"/cshow {gsave cmtx setmatrix\n"
+              "          /Helvetica findfont %4.1f scalefont setfont\n"
+              "          90 rotate 0 %3.1f rmoveto\n"
+              "          dup stringwidth pop 2 div neg 0 rmoveto show\n"
+              "        grestore} def\n", lfontsize, lfontsize/5);
+   fprintf(fp,"/%s findfont %4.1f scalefont setfont\n", tfont, tfontsize);
+
+   fprintf(fp,"0 0 moveto\n");
+   plot_branch(root,fp);
+   
+   fprintf(fp,"cmtx setmatrix stroke\nshowpage\n");
+   free_phylo_tree(root);
+   fclose(fp);
+
+}
+
+/* --------------------------------------------------------------------------*/
+
+PRIVATE Node *W2Phylo(Union *cluster)
+{
+   int i,n;
+   float b;
+   Node **taxa;
+   Node  *father;
+   
+   n=cluster[0].set1;
+   taxa = (Node **) space(sizeof(Node*)*(n+1));
+   
+   b = sqrt(MAX2(cluster[n-1].distance,0.));
+   for(i=1;i<=n;i++){
+      taxa[i] = (Node *) space(sizeof(Node));
+      taxa[i]->whoami = i;
+      taxa[i]->size   = 1;
+      taxa[i]->height = b;
+   }
+   
+   for(i=1;i<n;i++) {
+      father = (Node *) space(sizeof(Node));
+      father->whoami = 0;
+      father->left  = taxa[cluster[i].set1];
+      father->right = taxa[cluster[i].set2];
+      father->size  = father->left->size+father->right->size;
+      b = sqrt(MAX2(cluster[n-1].distance-cluster[i].distance,0.));
+      father->height   = b;
+      father->left->father   = father;
+      father->right->father  = father;
+      taxa[cluster[i].set1] = father;
+   }
+   free(taxa);
+   father->whoami = -1;
+   fill_br_from_height(father);
+   return father;
+}
+
+
+/* --------------------------------------------------------------------------*/
+
+PRIVATE void fill_br_from_height(Node *root)
+{
+   root->brr  = root->right->height - root->height;
+   root->brl  = root->left->height  - root->height;
+   if(!root->left->whoami)  fill_br_from_height(root->left);
+   if(!root->right->whoami)  fill_br_from_height(root->right);
+   return;
+}
+
+/* -------------------------------------------------------------------------- */
+#define ORDER(X) \
+if ((X)->brl>(X)->brr) { \
+   xnode=(X)->right; \
+   (X)->right=(X)->left; \
+   (X)->left=xnode; \
+   br = (X)->brr; \
+   (X)->brr=(X)->brl; \
+   (X)->brl=br; \
+}
+
+
+
+PRIVATE Node *Nj2Phylo(Union *cluster)
+{
+   int i,n, br;
+   float h1,h2,maxdist,dist;
+   Node **taxa;
+   Node  *father;
+   Node  *topnode;   /* of the longest path in the tree */
+   Node  *tempnode, *xnode;
+   Node  *root;
+
+   maxdist = 0.;
+   n=cluster[0].set1;
+   taxa = (Node **) space(sizeof(Node*)*(n+1));
+   
+   for(i=1;i<=n;i++){
+      taxa[i] = (Node *) space(sizeof(Node));
+      taxa[i]->whoami = i;
+      taxa[i]->size   = 1;
+   }
+   for(i=1;i<n;i++) {
+      father = (Node *) space(sizeof(Node));
+      father->whoami = 0;
+      h1 = cluster[i].distance +taxa[cluster[i].set1]->height;
+      h2 = cluster[i].distance2+taxa[cluster[i].set2]->height;  
+      dist = h1 + h2;
+      if(dist > maxdist) {
+         maxdist = dist;
+         topnode = father;
+      }
+      if(h1<=h2) {
+         father->brr   = cluster[i].distance2;
+         father->brl   = cluster[i].distance;
+         father->left  = taxa[cluster[i].set1];
+         father->right = taxa[cluster[i].set2];
+      }
+      else {
+         father->brr   = cluster[i].distance;
+         father->brl   = cluster[i].distance2;
+         father->left  = taxa[cluster[i].set2];
+         father->right = taxa[cluster[i].set1];
+      }
+      father->height        = MAX2(h1,h2);
+      father->size          = father->left->size + father->right->size;
+      father->left->father   = father;
+      father->right->father  = father;
+      taxa[cluster[i].set1] = father;
+   }
+
+   /* new root is inserted in the middle of the longest path */
+   dist = maxdist/2.;
+   tempnode = topnode;
+   while (tempnode->height > dist)
+      tempnode = tempnode->right;
+   
+   topnode  = tempnode->father;
+   /* new root must go between topnode and tempnode */
+   h1 = dist - tempnode->height;
+   h2 = topnode->height - dist ;
+
+   root = (Node *) space(sizeof(Node));
+   root->father = NULL;
+   root->whoami = -1;
+   root->right  = tempnode;
+   root->left   = topnode;
+   root->height = 0.0;
+   root->brr    = h1;
+   root->brl    = h2;
+   root->size   = n;
+
+   topnode->size = n - tempnode->size;
+
+   tempnode = root;
+   while(topnode->father) {
+      topnode->right  = topnode->father;
+      topnode->brr    = topnode->father->brr;
+      topnode->father = tempnode;
+      tempnode = topnode;
+      topnode  = topnode->right;
+      topnode->size   = tempnode->size - tempnode->left->size;
+      ORDER(tempnode);
+   }
+   /* topnode is now old root, remove it */
+   if (tempnode->right==topnode) {
+      tempnode->right = topnode->left;
+      tempnode->brr   = topnode->brr + topnode->brl;
+      tempnode->right->father = tempnode;
+   } else {
+      tempnode->left = topnode->left;
+      tempnode->brl  = topnode->brr + topnode->brl;
+      tempnode->left->father = tempnode;
+   }
+   free(topnode);
+   ORDER(root);
+   
+   fill_height_into_tree(root);
+   
+   return root;
+}
+
+/* -------------------------------------------------------------------------- */
+
+PRIVATE void fill_height_into_tree(Node *root)
+{
+   if(root->whoami>0) return;
+   root->left->height  = root->height + root->brl;
+   root->right->height = root->height + root->brr;
+   fill_height_into_tree(root->left);
+   fill_height_into_tree(root->right);
+   return;
+}
+   
+/* -------------------------------------------------------------------------- */
+
+PRIVATE void free_phylo_tree(Node *root) {
+   if(root->left)  free_phylo_tree(root->left);
+   if(root->right) free_phylo_tree(root->right);
+   free(root);
+}  
+
+
+/* -------------------------------------------------------------------------- */
+
+PRIVATE void plot_branch(Node *root, FILE *fp)
+{
+   char *label;
+
+   fprintf(fp,"currentpoint %g 0  rlineto 0 %g rlineto \n",
+                     -(float)(root->left->size)/2., root->brr);
+   if((print_labels)&&(root->brr > threshold)) {
+      format_number(root->brr);
+      fprintf(fp,"currentpoint 0 %g rlineto \n", -root->brr/2.);
+      fprintf(fp,"(%s) cshow moveto\n", str);
+   }
+   if(root->right->whoami==0) plot_branch(root->right,fp);
+   else if(print_labels) {
+      label = get_taxon_label(root->right->whoami);
+      fprintf(fp, "(%s) rotshow\n", label);
+      free(label);
+   }
+   fprintf(fp,"moveto\n");
+   fprintf(fp,"currentpoint %g 0  rlineto 0 %g rlineto \n",
+                     +(float)(root->right->size)/2., root->brl);
+   if((print_labels)&&(root->brl > threshold)) {
+      format_number(root->brl);
+      fprintf(fp,"currentpoint 0 %g rlineto \n", -root->brl/2.);
+      fprintf(fp,"(%s) cshow moveto\n",str);
+   }
+   if(root->left->whoami==0) plot_branch(root->left,fp);
+   else if(print_labels) {
+      label = get_taxon_label(root->left->whoami);
+      fprintf(fp, "(%s) rotshow\n", label);
+      free(label);
+   }
+   fprintf(fp,"moveto\n");  
+}
+
+/* -------------------------------------------------------------------------- */
+
+PRIVATE void format_number(float x)
+{
+   if(x >= 1.e5) { sprintf(str, "%4.1g",x ); return;}
+   if(x >=  100) { sprintf(str, "%.0f" ,x ); return;}
+   if(x >=   10) { sprintf(str, "%.1f", x ); return;}
+   if(x >=    1) { sprintf(str, "%.2f", x ); return;}
+   if(x >=  0.1) { sprintf(str, "%.2f", x ); return;}
+   if(x >= 0.01) { sprintf(str, "%.3f", x ); return;}
+   sprintf(str, "%4.1g",x ); 
+   return;
+}
+   
+/* -------------------------------------------------------------------------- */