5 #include "distance_matrix.h"
11 #define MAXTAXA_FOR_LABELS 200
20 typedef struct _Node_ {
26 struct _Node_ *father;
31 PUBLIC void PSplot_phylogeny(Union *cluster, char *filename, char *type);
33 PRIVATE Node *W2Phylo(Union *cluster);
34 PRIVATE Node *Nj2Phylo(Union *cluster);
35 PRIVATE void free_phylo_tree(Node *root);
36 PRIVATE void fill_height_into_tree(Node *root);
37 PRIVATE void fill_br_from_height(Node *root);
38 PRIVATE void plot_branch(Node *root, FILE *fp);
39 PRIVATE void format_number(float x);
42 PRIVATE float threshold;
43 PRIVATE int print_labels=1;
45 /* --------------------------------------------------------------------------*/
47 PUBLIC void PSplot_phylogeny(Union *cluster, char *filename, char *type)
55 float xsize, ysize, tfontsize, lfontsize, lwidth;
60 root = W2Phylo(cluster);
63 root = Nj2Phylo(cluster);
70 tmp = get_taxon_label(-1); /* retrieve data set identifier */
71 if(tmp) {strcat(outfile,tmp); strcat(outfile,"_"); free(tmp);}
72 strcat(outfile,filename);
74 fp = fopen(outfile,"w");
76 fprintf(stderr,"couldn't open %s -- not doing treeplot\n", outfile);
81 while(tempnode->right)
82 tempnode = tempnode->right;
83 ysize = tempnode->height;
84 threshold = ysize*0.06;
86 lwidth = MIN2(1.5, 8/sqrt((double)n));
87 tfontsize = MIN2(15,550./(10+n));
88 lfontsize = 2./3.*tfontsize;
89 if (n>30) tfont = "Helvetica";
90 else tfont = "Times-Roman";
91 if(n > MAXTAXA_FOR_LABELS) print_labels=0;
93 fprintf(fp,"%%!PS-Adobe-2.0 EPSF-1.2\n");
94 fprintf(fp,"%%%%Title: TreePlot (%s)\n",type);
95 fprintf(fp,"%%%%Creator: AnalyseDists\n");
96 fprintf(fp,"%%%%CreationDate: %s", time_stamp());
97 /* BoundingBox is only approximate */
98 fprintf(fp,"%%%%BoundingBox: 35 45 535 640\n");
99 fprintf(fp,"%%%%Pages: 1\n");
100 fprintf(fp,"%%%%EndComments: No comment!\n");
101 fprintf(fp,"288.5 50 translate\n");
102 fprintf(fp,"%3.1f setlinewidth\n"
103 "/cmtx matrix currentmatrix def\n", lwidth);
104 fprintf(fp,"500 %g div 360 %g div scale\n", xsize, ysize);
105 fprintf(fp,"/rotshow {gsave cmtx setmatrix\n");
106 fprintf(fp," 90 rotate 5 %4.1f rmoveto show grestore} def\n",
108 fprintf(fp,"/cshow {gsave cmtx setmatrix\n"
109 " /Helvetica findfont %4.1f scalefont setfont\n"
110 " 90 rotate 0 %3.1f rmoveto\n"
111 " dup stringwidth pop 2 div neg 0 rmoveto show\n"
112 " grestore} def\n", lfontsize, lfontsize/5);
113 fprintf(fp,"/%s findfont %4.1f scalefont setfont\n", tfont, tfontsize);
115 fprintf(fp,"0 0 moveto\n");
116 plot_branch(root,fp);
118 fprintf(fp,"cmtx setmatrix stroke\nshowpage\n");
119 free_phylo_tree(root);
124 /* --------------------------------------------------------------------------*/
126 PRIVATE Node *W2Phylo(Union *cluster)
134 taxa = (Node **) space(sizeof(Node*)*(n+1));
136 b = sqrt(MAX2(cluster[n-1].distance,0.));
138 taxa[i] = (Node *) space(sizeof(Node));
145 father = (Node *) space(sizeof(Node));
147 father->left = taxa[cluster[i].set1];
148 father->right = taxa[cluster[i].set2];
149 father->size = father->left->size+father->right->size;
150 b = sqrt(MAX2(cluster[n-1].distance-cluster[i].distance,0.));
152 father->left->father = father;
153 father->right->father = father;
154 taxa[cluster[i].set1] = father;
158 fill_br_from_height(father);
163 /* --------------------------------------------------------------------------*/
165 PRIVATE void fill_br_from_height(Node *root)
167 root->brr = root->right->height - root->height;
168 root->brl = root->left->height - root->height;
169 if(!root->left->whoami) fill_br_from_height(root->left);
170 if(!root->right->whoami) fill_br_from_height(root->right);
174 /* -------------------------------------------------------------------------- */
176 if ((X)->brl>(X)->brr) { \
178 (X)->right=(X)->left; \
187 PRIVATE Node *Nj2Phylo(Union *cluster)
190 float h1,h2,maxdist,dist;
193 Node *topnode; /* of the longest path in the tree */
194 Node *tempnode, *xnode;
199 taxa = (Node **) space(sizeof(Node*)*(n+1));
202 taxa[i] = (Node *) space(sizeof(Node));
208 father = (Node *) space(sizeof(Node));
210 h1 = cluster[i].distance +taxa[cluster[i].set1]->height;
211 h2 = cluster[i].distance2+taxa[cluster[i].set2]->height;
218 father->brr = cluster[i].distance2;
219 father->brl = cluster[i].distance;
220 father->left = taxa[cluster[i].set1];
221 father->right = taxa[cluster[i].set2];
224 father->brr = cluster[i].distance;
225 father->brl = cluster[i].distance2;
226 father->left = taxa[cluster[i].set2];
227 father->right = taxa[cluster[i].set1];
229 father->height = MAX2(h1,h2);
230 father->size = father->left->size + father->right->size;
231 father->left->father = father;
232 father->right->father = father;
233 taxa[cluster[i].set1] = father;
236 /* new root is inserted in the middle of the longest path */
239 while (tempnode->height > dist)
240 tempnode = tempnode->right;
242 topnode = tempnode->father;
243 /* new root must go between topnode and tempnode */
244 h1 = dist - tempnode->height;
245 h2 = topnode->height - dist ;
247 root = (Node *) space(sizeof(Node));
250 root->right = tempnode;
251 root->left = topnode;
257 topnode->size = n - tempnode->size;
260 while(topnode->father) {
261 topnode->right = topnode->father;
262 topnode->brr = topnode->father->brr;
263 topnode->father = tempnode;
265 topnode = topnode->right;
266 topnode->size = tempnode->size - tempnode->left->size;
269 /* topnode is now old root, remove it */
270 if (tempnode->right==topnode) {
271 tempnode->right = topnode->left;
272 tempnode->brr = topnode->brr + topnode->brl;
273 tempnode->right->father = tempnode;
275 tempnode->left = topnode->left;
276 tempnode->brl = topnode->brr + topnode->brl;
277 tempnode->left->father = tempnode;
282 fill_height_into_tree(root);
287 /* -------------------------------------------------------------------------- */
289 PRIVATE void fill_height_into_tree(Node *root)
291 if(root->whoami>0) return;
292 root->left->height = root->height + root->brl;
293 root->right->height = root->height + root->brr;
294 fill_height_into_tree(root->left);
295 fill_height_into_tree(root->right);
299 /* -------------------------------------------------------------------------- */
301 PRIVATE void free_phylo_tree(Node *root) {
302 if(root->left) free_phylo_tree(root->left);
303 if(root->right) free_phylo_tree(root->right);
308 /* -------------------------------------------------------------------------- */
310 PRIVATE void plot_branch(Node *root, FILE *fp)
314 fprintf(fp,"currentpoint %g 0 rlineto 0 %g rlineto \n",
315 -(float)(root->left->size)/2., root->brr);
316 if((print_labels)&&(root->brr > threshold)) {
317 format_number(root->brr);
318 fprintf(fp,"currentpoint 0 %g rlineto \n", -root->brr/2.);
319 fprintf(fp,"(%s) cshow moveto\n", str);
321 if(root->right->whoami==0) plot_branch(root->right,fp);
322 else if(print_labels) {
323 label = get_taxon_label(root->right->whoami);
324 fprintf(fp, "(%s) rotshow\n", label);
327 fprintf(fp,"moveto\n");
328 fprintf(fp,"currentpoint %g 0 rlineto 0 %g rlineto \n",
329 +(float)(root->right->size)/2., root->brl);
330 if((print_labels)&&(root->brl > threshold)) {
331 format_number(root->brl);
332 fprintf(fp,"currentpoint 0 %g rlineto \n", -root->brl/2.);
333 fprintf(fp,"(%s) cshow moveto\n",str);
335 if(root->left->whoami==0) plot_branch(root->left,fp);
336 else if(print_labels) {
337 label = get_taxon_label(root->left->whoami);
338 fprintf(fp, "(%s) rotshow\n", label);
341 fprintf(fp,"moveto\n");
344 /* -------------------------------------------------------------------------- */
346 PRIVATE void format_number(float x)
348 if(x >= 1.e5) { sprintf(str, "%4.1g",x ); return;}
349 if(x >= 100) { sprintf(str, "%.0f" ,x ); return;}
350 if(x >= 10) { sprintf(str, "%.1f", x ); return;}
351 if(x >= 1) { sprintf(str, "%.2f", x ); return;}
352 if(x >= 0.1) { sprintf(str, "%.2f", x ); return;}
353 if(x >= 0.01) { sprintf(str, "%.3f", x ); return;}
354 sprintf(str, "%4.1g",x );
358 /* -------------------------------------------------------------------------- */