Fixed inclusion of config.h
[gromacs.git] / src / tools / xpm2ps.c
blob4e11f47c0d24d19770a9f4410becee76825d058c
1 /*
2 * $Id$
3 *
4 * This source code is part of
5 *
6 * G R O M A C S
7 *
8 * GROningen MAchine for Chemical Simulations
9 *
10 * VERSION 3.2.0
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
33 * And Hey:
34 * Green Red Orange Magenta Azure Cyan Skyblue
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
40 #include <math.h>
41 #include "string2.h"
42 #include "copyrite.h"
43 #include "typedefs.h"
44 #include "macros.h"
45 #include "statutil.h"
46 #include "writeps.h"
47 #include "futil.h"
48 #include "fatal.h"
49 #include "smalloc.h"
50 #include "string2.h"
51 #include "matio.h"
52 #include "viewit.h"
54 #define FUDGE 1.2
55 #define DDD 2
57 typedef struct {
58 real major;
59 real minor;
60 real offset;
61 bool first;
62 int lineatzero;
63 real majorticklen;
64 real minorticklen;
65 char label[STRLEN];
66 real fontsize;
67 char font[STRLEN];
68 real tickfontsize;
69 char tickfont[STRLEN];
70 } t_axisdef;
72 typedef struct {
73 int bw;
74 real linewidth;
75 real xoffs,yoffs;
76 bool bTitle;
77 bool bTitleOnce;
78 bool bYonce;
79 real titfontsize;
80 char titfont[STRLEN];
81 bool legend;
82 real legfontsize;
83 char legfont[STRLEN];
84 char leglabel[STRLEN];
85 char leg2label[STRLEN];
86 real xboxsize;
87 real yboxsize;
88 real boxspacing;
89 real boxlinewidth;
90 real ticklinewidth;
91 real zerolinewidth;
92 t_axisdef X,Y;
93 } t_psrec;
95 /* MUST correspond to char *legend[] in main() */
96 enum { elSel, elBoth, elFirst, elSecond, elNone, elNR };
98 /* MUST correspond to char *combine[] in main() */
99 enum { ecSel, ecHalves, ecAdd, ecSub, ecMult, ecDiv, ecNR };
101 void get_params(char *mpin,char *mpout,t_psrec *psr)
103 static const char *bools[BOOL_NR+1] = { "no", "yes", NULL };
104 /* this must correspond to t_rgb *linecolors[] below */
105 static const char *colors[] = { "none", "black", "white", NULL };
106 t_inpfile *inp;
107 char *tmp;
108 int ninp;
110 if (mpin)
111 inp = read_inpfile(mpin,&ninp);
112 else
113 inp = NULL;
114 ETYPE("black&white", psr->bw, bools);
115 RTYPE("linewidth", psr->linewidth, 1.0);
116 STYPE("titlefont", psr->titfont, "Helvetica");
117 RTYPE("titlefontsize", psr->titfontsize, 20.0);
118 ETYPE("legend", psr->legend, bools);
119 STYPE("legendfont", psr->legfont, psr->titfont);
120 STYPE("legendlabel", psr->leglabel, "");
121 STYPE("legend2label", psr->leg2label, psr->leglabel);
122 RTYPE("legendfontsize", psr->legfontsize, 14.0);
123 RTYPE("xbox", psr->xboxsize, 2.0);
124 RTYPE("ybox", psr->yboxsize, psr->xboxsize);
125 RTYPE("matrixspacing", psr->boxspacing, 20.0);
126 RTYPE("xoffset", psr->xoffs, 0.0);
127 RTYPE("yoffset", psr->yoffs, psr->xoffs);
128 RTYPE("boxlinewidth", psr->boxlinewidth, psr->linewidth);
129 RTYPE("ticklinewidth", psr->ticklinewidth, psr->linewidth);
130 RTYPE("zerolinewidth", psr->zerolinewidth, psr->ticklinewidth);
131 ETYPE("x-lineat0value", psr->X.lineatzero, colors);
132 RTYPE("x-major", psr->X.major, NOTSET);
133 RTYPE("x-minor", psr->X.minor, NOTSET);
134 RTYPE("x-firstmajor", psr->X.offset, 0.0);
135 ETYPE("x-majorat0", psr->X.first, bools);
136 RTYPE("x-majorticklen", psr->X.majorticklen, 8.0);
137 RTYPE("x-minorticklen", psr->X.minorticklen, 4.0);
138 STYPE("x-label", psr->X.label, "");
139 RTYPE("x-fontsize", psr->X.fontsize, 16.0);
140 STYPE("x-font", psr->X.font, psr->titfont);
141 RTYPE("x-tickfontsize", psr->X.tickfontsize, 10.0);
142 STYPE("x-tickfont", psr->X.tickfont, psr->X.font);
143 ETYPE("y-lineat0value", psr->Y.lineatzero, colors);
144 RTYPE("y-major", psr->Y.major, psr->X.major);
145 RTYPE("y-minor", psr->Y.minor, psr->X.minor);
146 RTYPE("y-firstmajor", psr->Y.offset, psr->X.offset);
147 ETYPE("y-majorat0", psr->Y.first, bools);
148 RTYPE("y-majorticklen", psr->Y.majorticklen, psr->X.majorticklen);
149 RTYPE("y-minorticklen", psr->Y.minorticklen, psr->X.minorticklen);
150 STYPE("y-label", psr->Y.label, psr->X.label);
151 RTYPE("y-fontsize", psr->Y.fontsize, psr->X.fontsize);
152 STYPE("y-font", psr->Y.font, psr->X.font);
153 RTYPE("y-tickfontsize", psr->Y.tickfontsize, psr->X.tickfontsize);
154 STYPE("y-tickfont", psr->Y.tickfont, psr->Y.font);
155 if (mpout)
156 write_inpfile(mpout,ninp,inp);
159 t_rgb black = { 0, 0, 0 };
160 t_rgb white = { 1, 1, 1 };
161 t_rgb red = { 1, 0, 0 };
162 t_rgb blue = { 0, 0, 1 };
163 #define BLACK (&black)
164 /* this must correspond to *colors[] in get_params */
165 t_rgb *linecolors[] = { NULL, &black, &white, NULL };
167 bool diff_maps(int nmap1,t_mapping *map1,int nmap2,t_mapping *map2)
169 int i;
170 bool bDiff,bColDiff=FALSE;
172 if (nmap1 != nmap2)
173 bDiff=TRUE;
174 else {
175 bDiff=FALSE;
176 for(i=0; i<nmap1; i++) {
177 if (!matelmt_cmp(map1[i].code, map2[i].code)) bDiff=TRUE;
178 if (strcmp(map1[i].desc,map2[i].desc) != 0) bDiff=TRUE;
179 if ((map1[i].rgb.r!=map2[i].rgb.r) ||
180 (map1[i].rgb.g!=map2[i].rgb.g) ||
181 (map1[i].rgb.b!=map2[i].rgb.b))
182 bColDiff=TRUE;
184 if (!bDiff && bColDiff)
185 fprintf(stderr,"Warning: two colormaps differ only in RGB value, using one colormap.\n");
188 return bDiff;
191 void leg_discrete(t_psdata ps,real x0,real y0,char *label,
192 real fontsize,char *font,int nmap,t_mapping map[])
194 int i;
195 real yhh;
196 real boxhh;
198 boxhh=fontsize+DDD;
199 /* LANDSCAPE */
200 ps_rgb(ps,BLACK);
201 ps_strfont(ps,font,fontsize);
202 yhh=y0+fontsize+3*DDD;
203 if ((int)strlen(label) > 0)
204 ps_ctext(ps,x0,yhh,label,eXLeft);
205 ps_moveto(ps,x0,y0);
206 for(i=0; (i<nmap); i++) {
207 ps_setorigin(ps);
208 ps_rgb(ps,&(map[i].rgb));
209 ps_fillbox(ps,DDD,DDD,DDD+fontsize,boxhh-DDD);
210 ps_rgb(ps,BLACK);
211 ps_box(ps,DDD,DDD,DDD+fontsize,boxhh-DDD);
212 ps_ctext(ps,boxhh+2*DDD,fontsize/3,map[i].desc,eXLeft);
213 ps_unsetorigin(ps);
214 ps_moverel(ps,DDD,-fontsize/3);
218 void leg_continuous(t_psdata ps,real x0,real x,real y0,char *label,
219 real fontsize,char *font,
220 int nmap,t_mapping map[],
221 int mapoffset)
223 int i;
224 real xx0;
225 real yhh,boxxh,boxyh;
227 boxyh=fontsize;
228 if (x<8*fontsize)
229 x=8*fontsize;
230 boxxh=(real)x/(real)(nmap-mapoffset);
231 if (boxxh>fontsize)
232 boxxh=fontsize;
234 /* LANDSCAPE */
235 xx0=x0-((nmap-mapoffset)*boxxh)/2.0;
237 for(i=0; (i<nmap-mapoffset); i++) {
238 ps_rgb(ps,&(map[i+mapoffset].rgb));
239 ps_fillbox(ps,xx0+i*boxxh,y0,xx0+(i+1)*boxxh,y0+boxyh);
241 ps_strfont(ps,font,fontsize);
242 ps_rgb(ps,BLACK);
243 ps_box(ps,xx0,y0,xx0+(nmap-mapoffset)*boxxh,y0+boxyh);
245 yhh=y0+boxyh+3*DDD;
246 ps_ctext(ps,xx0+boxxh/2,yhh,map[0].desc,eXCenter);
247 if ((int)strlen(label) > 0)
248 ps_ctext(ps,x0,yhh,label,eXCenter);
249 ps_ctext(ps,xx0+((nmap-mapoffset)*boxxh)
250 - boxxh/2,yhh,map[nmap-1].desc,eXCenter);
253 void leg_bicontinuous(t_psdata ps,real x0,real x,real y0,char *label1,char *label2,
254 real fontsize,char *font,
255 int nmap1,t_mapping map1[],int nmap2,t_mapping map2[])
257 real xx1,xx2,x1,x2;
259 x1=x/(nmap1+nmap2)*nmap1;/* width of legend 1 */
260 x2=x/(nmap1+nmap2)*nmap2;/* width of legend 2 */
261 xx1=x0-(x2/2.0)-fontsize;/* center of legend 1 */
262 xx2=x0+(x1/2.0)+fontsize;/* center of legend 2 */
263 x1-=fontsize/2;/* adjust width */
264 x2-=fontsize/2;/* adjust width */
265 leg_continuous(ps,xx1,x1,y0,label1,fontsize,font,nmap1,map1,0);
266 leg_continuous(ps,xx2,x2,y0,label2,fontsize,font,nmap2,map2,0);
269 static real box_height(t_matrix *mat,t_psrec *psr)
271 return mat->ny*psr->yboxsize;
274 static real box_dh(t_psrec *psr)
276 return psr->boxspacing;
279 #define IS_ONCE (i==nmat-1)
280 static real box_dh_top(bool bOnce, t_psrec *psr)
282 real dh;
284 if (psr->bTitle || (psr->bTitleOnce && bOnce) )
285 dh=2*psr->titfontsize;
286 else
287 dh=0;
289 return dh;
292 static bool box_do_all_x_maj_ticks(t_psrec *psr)
294 return (psr->boxspacing>(1.5*psr->X.majorticklen));
297 static bool box_do_all_x_min_ticks(t_psrec *psr)
299 return (psr->boxspacing>(1.5*psr->X.minorticklen));
302 static void draw_boxes(t_psdata ps,real x0,real y0,real w,
303 int nmat,t_matrix mat[],t_psrec *psr)
305 char buf[12];
306 char *mylab;
307 real xxx;
308 char **xtick,**ytick;
309 real xx,yy,dy,xx00,yy00;
310 int i,j,x,y,strlength;
312 /* Only necessary when there will be no y-labels */
313 strlength = 0;
315 /* Draw the box */
316 ps_rgb(ps,BLACK);
317 ps_linewidth(ps,psr->boxlinewidth);
318 yy00=y0;
319 for(i=0; (i<nmat); i++) {
320 dy=box_height(&(mat[i]),psr);
321 ps_box(ps,x0-1,yy00-1,x0+w+1,yy00+dy+1);
322 yy00+=dy+box_dh(psr)+box_dh_top(IS_ONCE,psr);
325 /* Draw the ticks on the axes */
326 ps_linewidth(ps,psr->ticklinewidth);
327 xx00=x0-1;
328 yy00=y0-1;
329 for (i=0; (i<nmat); i++) {
330 snew(xtick,mat[i].nx);
331 for(j=0; (j<mat[i].nx); j++) {
332 sprintf(buf,"%g",mat[i].axis_x[j]);
333 xtick[j]=strdup(buf);
335 ps_strfont(ps,psr->X.tickfont,psr->X.tickfontsize);
336 for(x=0; (x<mat[i].nx); x++) {
337 xx=xx00+(x+0.7)*psr->xboxsize;
338 if ( ( bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.major) ||
339 (psr->X.first && (x==0))) &&
340 ( (i == 0) || box_do_all_x_maj_ticks(psr) ) ) {
341 /* Longer tick marks */
342 ps_line (ps,xx,yy00,xx,yy00-psr->X.majorticklen);
343 /* Plot label on lowest graph only */
344 if (i == 0)
345 ps_ctext(ps,xx,
346 yy00-DDD-psr->X.majorticklen-psr->X.tickfontsize*0.8,
347 xtick[x],eXCenter);
348 } else if ( bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.minor) &&
349 ( (i == 0) || box_do_all_x_min_ticks(psr) ) ){
350 /* Shorter tick marks */
351 ps_line(ps,xx,yy00,xx,yy00-psr->X.minorticklen);
352 } else if ( bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.major) ) {
353 /* Even shorter marks, only each X.major */
354 ps_line(ps,xx,yy00,xx,yy00-(psr->boxspacing/2));
357 ps_strfont(ps,psr->Y.tickfont,psr->Y.tickfontsize);
358 snew(ytick,mat[i].ny);
359 for(j=0; (j<mat[i].ny); j++) {
360 sprintf(buf,"%g",mat[i].axis_y[j]);
361 ytick[j]=strdup(buf);
364 for(y=0; (y<mat[i].ny); y++) {
365 yy=yy00+(y+0.7)*psr->yboxsize;
366 if ( bRmod(mat[i].axis_y[y], psr->Y.offset, psr->Y.major) ||
367 (psr->Y.first && (y==0))) {
368 /* Major ticks */
369 strlength=max(strlength,(int)strlen(ytick[y]));
370 ps_line (ps,xx00,yy,xx00-psr->Y.majorticklen,yy);
371 ps_ctext(ps,xx00-psr->Y.majorticklen-DDD,
372 yy-psr->Y.tickfontsize/3.0,ytick[y],eXRight);
374 else if ( bRmod(mat[i].axis_y[y], psr->Y.offset, psr->Y.minor) ) {
375 /* Minor ticks */
376 ps_line(ps,xx00,yy,xx00-psr->Y.minorticklen,yy);
379 sfree(xtick);
380 sfree(ytick);
382 /* Label on Y-axis */
383 if (!psr->bYonce || i==nmat/2) {
384 if (strlen(psr->Y.label) > 0)
385 mylab = psr->Y.label;
386 else
387 mylab = mat[i].label_y;
388 if (strlen(mylab) > 0) {
389 ps_strfont(ps,psr->Y.font,psr->Y.fontsize);
390 ps_flip(ps,TRUE);
391 xxx=x0-psr->X.majorticklen-psr->X.tickfontsize*strlength-DDD;
392 ps_ctext(ps,yy00+box_height(&mat[i],psr)/2.0,612.5-xxx,
393 mylab,eXCenter);
394 ps_flip(ps,FALSE);
398 yy00+=box_height(&(mat[i]),psr)+box_dh(psr)+box_dh_top(IS_ONCE,psr);
400 /* Label on X-axis */
401 if (strlen(psr->X.label) > 0)
402 mylab = psr->X.label;
403 else
404 mylab = mat[0].label_x;
405 if (strlen(mylab) > 0) {
406 ps_strfont(ps,psr->X.font,psr->X.fontsize);
407 ps_ctext(ps,x0+w/2,y0-DDD-psr->X.majorticklen-psr->X.tickfontsize*FUDGE-
408 psr->X.fontsize,mylab,eXCenter);
412 static void draw_zerolines(t_psdata out,real x0,real y0,real w,
413 int nmat,t_matrix mat[],t_psrec *psr)
415 real xx,yy,dy,xx00,yy00;
416 int i,x,y;
418 xx00=x0-1.5;
419 yy00=y0-1.5;
420 ps_linewidth(out,psr->zerolinewidth);
421 for (i=0; (i<nmat); i++) {
422 dy=box_height(&(mat[i]),psr);
423 /* mat[i].axis_x and _y were already set by draw_boxes */
424 if (psr->X.lineatzero) {
425 ps_rgb(out,linecolors[psr->X.lineatzero]);
426 for(x=0; (x<mat[i].nx); x++) {
427 xx=xx00+(x+0.7)*psr->xboxsize;
428 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
429 if ( x!=0 && x<mat[i].nx-1 &&
430 abs(mat[i].axis_x[x]) <
431 0.1*abs(mat[i].axis_x[x+1]-mat[i].axis_x[x]) ) {
432 ps_line (out,xx,yy00,xx,yy00+dy+2);
436 if (psr->Y.lineatzero) {
437 ps_rgb(out,linecolors[psr->Y.lineatzero]);
438 for(y=0; (y<mat[i].ny); y++) {
439 yy=yy00+(y+0.7)*psr->yboxsize;
440 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
441 if ( y!=0 && y<mat[i].ny-1 &&
442 abs(mat[i].axis_y[y]) <
443 0.1*abs(mat[i].axis_y[y+1]-mat[i].axis_y[y]) ) {
444 ps_line (out,xx00,yy,xx00+w+2,yy);
448 yy00+=box_height(&(mat[i]),psr)+box_dh(psr)+box_dh_top(IS_ONCE,psr);
452 static void box_dim(int nmat,t_matrix mat[],t_matrix *mat2,t_psrec *psr,
453 int elegend,bool bFrame,
454 real *w,real *h,real *dw,real *dh)
456 int i,maxytick;
457 real ww,hh,dww,dhh;
459 hh=dww=dhh=0;
460 maxytick=0;
462 ww=0;
463 for(i=0; (i<nmat); i++) {
464 ww=max(ww,mat[i].nx*psr->xboxsize);
465 hh+=box_height(&(mat[i]),psr);
466 maxytick=max(maxytick,mat[i].nx);
468 if (bFrame) {
469 if (mat[0].label_y[0])
470 dww+=2.0*(psr->Y.fontsize+DDD);
471 if (psr->Y.major > 0)
472 dww += psr->Y.majorticklen + DDD +
473 psr->Y.tickfontsize*(log(maxytick)/log(10.0));
474 else if (psr->Y.minor > 0)
475 dww+=psr->Y.minorticklen;
477 if (mat[0].label_x[0])
478 dhh+=psr->X.fontsize+2*DDD;
479 if (/* fool emacs auto-indent */
480 (elegend==elBoth && (mat[0].legend[0] || mat2[0].legend[0])) ||
481 (elegend==elFirst && mat[0].legend[0]) ||
482 (elegend==elSecond && mat2[0].legend[0]) )
483 dhh+=2*(psr->legfontsize*FUDGE+2*DDD);
484 else
485 dhh+=psr->legfontsize*FUDGE+2*DDD;
486 if (psr->X.major > 0)
487 dhh+=psr->X.tickfontsize*FUDGE+2*DDD+psr->X.majorticklen;
488 else if (psr->X.minor > 0)
489 dhh+=psr->X.minorticklen;
491 hh+=(nmat-1)*box_dh(psr);
492 hh+=box_dh_top(TRUE,psr);
493 if (nmat>1)
494 hh+=(nmat-1)*box_dh_top(FALSE,psr);
496 *w=ww;
497 *h=hh;
498 *dw=dww;
499 *dh=dhh;
502 int add_maps(t_mapping **newmap,
503 int nmap1, t_mapping map1[], int nmap2, t_mapping map2[])
505 static char mapper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+{}|;:',<.>/?";
506 #define NMAP strlen(mapper)
507 int nmap,j,k;
508 t_mapping *map;
510 nmap=nmap1+nmap2;
511 if (nmap > NMAP*NMAP)
512 fatal_error(0,"Not enough symbols to merge the two colormaps\n");
513 printf("Combining colormaps of %d and %d elements into one of %d elements\n",
514 nmap1, nmap2, nmap);
515 snew(map,nmap);
516 for(j=0; j<nmap1; j++) {
517 map[j].code.c1=mapper[j % NMAP];
518 if (nmap > NMAP)
519 map[j].code.c2=mapper[j/NMAP];
520 map[j].rgb.r = map1[j].rgb.r;
521 map[j].rgb.g = map1[j].rgb.g;
522 map[j].rgb.b = map1[j].rgb.b;
523 map[j].desc = map1[j].desc;
525 for(j=0; j<nmap2; j++) {
526 k=j+nmap1;
527 map[k].code.c1=mapper[k % NMAP];
528 if (nmap > NMAP)
529 map[k].code.c2=mapper[k/NMAP];
530 map[k].rgb.r = map2[j].rgb.r;
531 map[k].rgb.g = map2[j].rgb.g;
532 map[k].rgb.b = map2[j].rgb.b;
533 map[k].desc = map2[j].desc;
536 *newmap = map;
537 return nmap;
540 void xpm_mat(char *outf,
541 int nmat,t_matrix *mat,t_matrix *mat2,bool bDiag,bool bFirstDiag)
543 FILE *out;
544 char buf[100];
545 int i,j,k,x,y,col;
546 int nmap;
547 t_mapping *map=NULL;
549 out=ffopen(outf,"w");
551 for(i=0; i<nmat; i++) {
552 if (!mat2 || !diff_maps(mat[i].nmap,mat[i].map,mat2[i].nmap,mat2[i].map))
553 write_xpm_m(out,mat[0]);
554 else {
555 nmap = add_maps(&map, mat[i].nmap,mat[i].map, mat2[i].nmap,mat2[i].map);
556 for(x=0; (x<mat[i].nx); x++) {
557 for(y=0; (y<mat[i].nx); y++) {
558 if ((x<y) || ((x==y) && bFirstDiag)) /* upper left -> map1 */
559 col=mat[i].matrix[x][y];
560 else /* lower right -> map2 */
561 col=mat[i].nmap+mat[i].matrix[x][y];
562 if ((bDiag) || (x!=y))
563 mat[i].matrix[x][y]=col;
564 else
565 mat[i].matrix[x][y]=0;
568 sfree(mat[i].map);
569 mat[i].nmap=nmap;
570 mat[i].map=map;
571 if (mat2 && (strcmp(mat[i].title,mat2[i].title) != 0))
572 sprintf(mat[i].title,"%s / %s",mat[i].title,mat2[i].title);
573 if (mat2 && (strcmp(mat[i].legend,mat2[i].legend) != 0))
574 sprintf(mat[i].legend,"%s / %s",mat[i].legend,mat2[i].legend);
575 write_xpm_m(out,mat[i]);
578 fclose(out);
581 static void tick_spacing(int n, real axis[], real offset, char axisnm,
582 real *major, real *minor)
584 real space;
585 bool bTryAgain,bFive;
586 int i,j,t,f=0,ten;
587 #define NFACT 6
588 int major_fact[NFACT] = {1, 2, 2.5, 4, 5, 7.5};
589 int minor_fact[NFACT] = {5, 4, 5, 4, 5, 2.5};
591 /* start with interval between 10 matrix points: */
592 space = max(10*axis[1]-axis[0], axis[min(10,n-1)]-axis[0]);
593 /* get power of 10 */
594 ten = (int)ceil(log(space)/log(10))-1;
595 bTryAgain = TRUE;
596 for(t=ten-2; t<ten+3 && bTryAgain; t++) {
597 for(f=0; f<NFACT && bTryAgain; f++) {
598 space = pow(10,t) * major_fact[f];
599 /* count how many ticks we would get: */
600 i = 0;
601 for(j=0; j<n; j++)
602 if ( bRmod(axis[j], offset, space) )
603 i++;
604 /* do we have a reasonable number of ticks ? */
605 bTryAgain = i > min(10, n-1) || i < 5;
608 if (bTryAgain) {
609 space = max(10*axis[1]-axis[0], axis[min(10,n-1)]-axis[0]);
610 fprintf(stderr,"Auto tick spacing failed for %c-axis, guessing %g\n",
611 axisnm,space);
613 *major = space;
614 *minor = space / minor_fact[f-1];
615 fprintf(stderr,"Auto tick spacing for %c-axis: major %g, minor %g\n",
616 axisnm, *major, *minor);
619 void ps_mat(char *outf,int nmat,t_matrix mat[],t_matrix mat2[],
620 bool bFrame,bool bDiag,bool bFirstDiag,
621 bool bTitle,bool bTitleOnce,bool bYonce,
622 int elegend,real boxx,real boxy,char *m2p,char *m2pout,
623 int mapoffset)
625 char *libm2p;
626 char buf[256],*legend;
627 t_psdata out;
628 t_psrec psrec,*psr;
629 int W,H;
630 int i,j,x,y,col,leg=0;
631 real x0,y0,xx;
632 real w,h,dw,dh;
633 int nmap1=0,nmap2=0,leg_nmap;
634 t_mapping *map1=NULL,*map2=NULL,*leg_map;
635 bool bMap1,bNextMap1,bDiscrete;
637 libm2p = m2p ? strdup(libfn(m2p)) : m2p;
638 get_params(libm2p,m2pout,&psrec);
640 psr=&psrec;
642 if (psr->X.major <= 0 )
643 tick_spacing(mat[0].nx, mat[0].axis_x, psr->X.offset, 'X',
644 &(psr->X.major), &(psr->X.minor) );
645 if (psr->X.minor <= 0 )
646 psr->X.minor = psr->X.major / 2;
647 if (psr->Y.major <= 0)
648 tick_spacing(mat[0].ny, mat[0].axis_y, psr->Y.offset, 'Y',
649 &(psr->Y.major), &(psr->Y.minor) );
650 if (psr->Y.minor <= 0)
651 psr->Y.minor = psr->Y.major / 2;
653 if (boxx>0) {
654 psr->xboxsize=boxx;
655 psr->yboxsize=boxx;
657 if (boxy>0)
658 psr->yboxsize=boxy;
660 nmap1=0;
661 for (i=0; (i<nmat); i++)
662 if (mat[i].nmap>nmap1) {
663 nmap1=mat[i].nmap;
664 map1=mat[i].map;
665 leg=i+1;
667 if (leg!=1)
668 printf("Selected legend of matrix # %d for display\n",leg);
669 if (mat2) {
670 nmap2=0;
671 for (i=0; (i<nmat); i++)
672 if (mat2[i].nmap>nmap2) {
673 nmap2=mat2[i].nmap;
674 map2=mat2[i].map;
675 leg=i+1;
677 if (leg!=1)
678 printf("Selected legend of matrix # %d for second display\n",leg);
680 if ( (mat[0].legend[0]==0) && psr->legend )
681 strcpy(mat[0].legend, psr->leglabel);
683 bTitle = bTitle && mat[nmat-1].title[0];
684 bTitleOnce = bTitleOnce && mat[nmat-1].title[0];
685 psr->bTitle = bTitle;
686 psr->bTitleOnce = bTitleOnce;
687 psr->bYonce = bYonce;
689 /* Set up size of box for nice colors */
690 box_dim(nmat,mat,mat2,psr,elegend,bFrame,&w,&h,&dw,&dh);
692 /* Set up bounding box */
693 W=w+dw;
694 H=h+dh;
696 /* Start box at */
697 x0=dw;
698 y0=dh;
699 x = W+psr->xoffs;
700 y = H+psr->yoffs;
701 if (bFrame) {
702 x += 5*DDD;
703 y += 4*DDD;
705 out=ps_open(outf,0,0,x,y);
706 ps_linewidth(out,psr->linewidth);
707 ps_init_rgb_box(out,psr->xboxsize,psr->yboxsize);
708 ps_init_rgb_nbox(out,psr->xboxsize,psr->yboxsize);
709 ps_translate(out,psr->xoffs,psr->yoffs);
711 if (bFrame) {
712 ps_comment(out,"Here starts the BOX drawing");
713 draw_boxes(out,x0,y0,w,nmat,mat,psr);
716 for(i=0; (i<nmat); i++) {
717 if (bTitle || (bTitleOnce && i==nmat-1) ) {
718 /* Print title, if any */
719 ps_rgb(out,BLACK);
720 ps_strfont(out,psr->titfont,psr->titfontsize);
721 if (!mat2 || (strcmp(mat[i].title,mat2[i].title) == 0))
722 strcpy(buf,mat[i].title);
723 else
724 sprintf(buf,"%s / %s",mat[i].title,mat2[i].title);
725 ps_ctext(out,x0+w/2,y0+box_height(&(mat[i]),psr)+psr->titfontsize,
726 buf,eXCenter);
728 sprintf(buf,"Here starts the filling of box #%d",i);
729 ps_comment(out,buf);
730 for(x=0; (x<mat[i].nx); x++) {
731 int nexty;
732 int nextcol;
734 xx=x0+x*psr->xboxsize;
735 ps_moveto(out,xx,y0);
736 y=0;
737 bMap1 = (!mat2 || (x<y || (x==y && bFirstDiag)));
738 if ((bDiag) || (x!=y))
739 col = mat[i].matrix[x][y];
740 else
741 col = -1;
742 for(nexty=1; (nexty<=mat[i].ny); nexty++) {
743 bNextMap1 = (!mat2 || (x<nexty || (x==nexty && bFirstDiag)));
744 /* TRUE: upper left -> map1 */
745 /* FALSE: lower right -> map2 */
746 if ((nexty==mat[i].ny) || (!bDiag && (x==nexty)))
747 nextcol = -1;
748 else
749 nextcol=mat[i].matrix[x][nexty];
750 if ( (nexty==mat[i].ny) || (col!=nextcol) || (bMap1!=bNextMap1) ) {
751 if (col >= 0)
752 if (bMap1)
753 ps_rgb_nbox(out,&(mat[i].map[col].rgb),nexty-y);
754 else
755 ps_rgb_nbox(out,&(mat2[i].map[col].rgb),nexty-y);
756 else
757 ps_moverel(out,0,psr->yboxsize);
758 y=nexty;
759 bMap1=bNextMap1;
760 col=nextcol;
764 y0+=box_height(&(mat[i]),psr)+box_dh(psr)+box_dh_top(IS_ONCE,psr);
767 if (psr->X.lineatzero || psr->Y.lineatzero) {
768 /* reset y0 for first box */
769 y0=dh;
770 ps_comment(out,"Here starts the zero lines drawing");
771 draw_zerolines(out,x0,y0,w,nmat,mat,psr);
774 if (elegend!=elNone) {
775 ps_comment(out,"Now it's legend time!");
776 ps_linewidth(out,psr->linewidth);
777 if ( mat2==NULL || elegend!=elSecond ) {
778 bDiscrete = mat[0].bDiscrete;
779 legend = mat[0].legend;
780 leg_nmap = nmap1;
781 leg_map = map1;
782 } else {
783 bDiscrete = mat2[0].bDiscrete;
784 legend = mat2[0].legend;
785 leg_nmap = nmap2;
786 leg_map = map2;
788 if (bDiscrete)
789 leg_discrete(out,psr->legfontsize,DDD,legend,
790 psr->legfontsize,psr->legfont,leg_nmap,leg_map);
791 else {
792 if ( elegend!=elBoth )
793 leg_continuous(out,x0+w/2,w/2,DDD,legend,
794 psr->legfontsize,psr->legfont,leg_nmap,leg_map,
795 mapoffset);
796 else
797 leg_bicontinuous(out,x0+w/2,w,DDD,mat[0].legend,mat2[0].legend,
798 psr->legfontsize,psr->legfont,nmap1,map1,nmap2,map2);
800 ps_comment(out,"Were there, dude");
803 ps_close(out);
806 void make_axis_labels(int nmat, t_matrix *mat)
808 int i,j;
810 for (i=0; (i<nmat); i++) {
811 /* Make labels for x axis */
812 if (mat[i].axis_x==NULL) {
813 snew(mat[i].axis_x,mat[i].nx);
814 for(j=0; (j<mat[i].nx); j++)
815 mat[i].axis_x[j]=j;
817 /* Make labels for y axis */
818 if (mat[i].axis_y==NULL) {
819 snew(mat[i].axis_y,mat[i].ny);
820 for(j=0; (j<mat[i].ny); j++)
821 mat[i].axis_y[j]=j;
826 void prune_mat(int nmat, t_matrix *mat,t_matrix *mat2, int skip)
828 int i,x,y,xs,ys;
830 for(i=0; i<nmat; i++) {
831 fprintf(stderr,"converting %dx%d matrix to %dx%d\n",
832 mat[i].nx, mat[i].ny,
833 (mat[i].nx+skip-1)/skip, (mat[i].ny+skip-1)/skip);
834 /* walk through matrix */
835 xs=0;
836 for(x=0; (x<mat[i].nx); x++)
837 if (x % skip == 0) {
838 mat[i].axis_x[xs] = mat[i].axis_x[x];
839 if (mat2)
840 mat2[i].axis_x[xs] = mat2[i].axis_x[x];
841 ys=0;
842 for(y=0; (y<mat[i].ny); y++) {
843 if(x==0) {
844 mat[i].axis_y[ys] = mat[i].axis_y[y];
845 if (mat2)
846 mat2[i].axis_y[ys] = mat2[i].axis_y[y];
848 if (y % skip == 0) {
849 mat[i].matrix[xs][ys] = mat[i].matrix[x][y];
850 if (mat2)
851 mat2[i].matrix[xs][ys] = mat2[i].matrix[x][y];
852 ys++;
855 xs++;
857 /* adjust parameters */
858 mat[i].nx = (mat[i].nx+skip-1)/skip;
859 mat[i].ny = (mat[i].ny+skip-1)/skip;
860 if (mat2) {
861 mat2[i].nx = (mat2[i].nx+skip-1)/skip;
862 mat2[i].ny = (mat2[i].ny+skip-1)/skip;
867 void zero_lines(int nmat, t_matrix *mat, t_matrix *mat2)
869 int i, x, y, m;
870 t_matrix *mats;
872 for(i=0; i<nmat; i++)
873 for(m=0; m < (mat2 ? 2 : 1) ; m++) {
874 if (m==0)
875 mats=mat;
876 else
877 mats=mat2;
878 for(x=0; x<mats[i].nx-1; x++)
879 if (abs(mats[i].axis_x[x+1]) < 1e-5)
880 for(y=0; y<mats[i].ny; y++)
881 mats[i].matrix[x][y]=0;
882 for(y=0; y<mats[i].ny-1; y++)
883 if (abs(mats[i].axis_y[y+1]) < 1e-5)
884 for(x=0; x<mats[i].nx; x++)
885 mats[i].matrix[x][y]=0;
889 void write_combined_matrix(int ecombine, char *fn,
890 int nmat, t_matrix *mat1, t_matrix *mat2)
892 int i, j, k, nlevels;
893 t_mapping *map=NULL;
894 FILE *out;
895 real **rmat1, **rmat2;
896 real rhi, rlo;
898 out = ffopen(fn, "w");
899 for(k=0; k<nmat; k++) {
900 if ( mat2[k].nx!=mat1[k].nx || mat2[k].ny!=mat1[k].ny )
901 fatal_error(0,"Size of frame %d in 1st (%dx%d) and 2nd matrix (%dx%d) do"
902 " not match.\n",k,mat1[k].nx,mat1[k].ny,mat2[k].nx,mat2[k].ny);
903 printf("Combining two %dx%d matrices\n",mat1[k].nx,mat1[k].ny);
904 rmat1 = matrix2real(&mat1[k], NULL);
905 rmat2 = matrix2real(&mat2[k], NULL);
906 rlo=1e38;
907 rhi=-1e38;
908 for(j=0; j<mat1[k].ny; j++)
909 for(i=0; i<mat1[k].nx; i++) {
910 switch (ecombine) {
911 case ecAdd: rmat1[i][j] += rmat2[i][j]; break;
912 case ecSub: rmat1[i][j] -= rmat2[i][j]; break;
913 case ecMult: rmat1[i][j] *= rmat2[i][j]; break;
914 case ecDiv: rmat1[i][j] /= rmat2[i][j]; break;
915 default:
916 fatal_error(0,"No such combination rule %d for matrices",ecombine);
918 rlo = min(rlo, rmat1[i][j]);
919 rhi = max(rhi, rmat1[i][j]);
921 nlevels = mat1[k].nmap+mat2[k].nmap;
922 if (rhi==rlo)
923 fprintf(stderr,
924 "combination results in uniform matrix (%g), no output\n",rhi);
925 else if (rlo>=0 || rhi<=0)
926 write_xpm(out, mat1[k].title, mat1[k].legend,
927 mat1[k].label_x, mat1[k].label_y,
928 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
929 rmat1, rlo, rhi, rhi<=0?red:white, rhi<=0?white:blue,
930 &nlevels);
931 else
932 write_xpm3(out, mat1[k].title, mat1[k].legend,
933 mat1[k].label_x, mat1[k].label_y,
934 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
935 rmat1, rlo, 0, rhi, red, white, blue, &nlevels);
937 fclose(out);
940 void do_mat(int nmat,t_matrix *mat,t_matrix *mat2,
941 bool bFrame,bool bZeroLine,bool bDiag,bool bFirstDiag,bool bTitle,
942 bool bTitleOnce,bool bYonce,int elegend,real boxx,real boxy,
943 char *epsfile,char *xpmfile,char *m2p,char *m2pout,int skip,
944 int mapoffset)
946 int i,j,k;
948 if (mat2) {
949 for (k=0; (k<nmat); k++) {
950 if ((mat2[k].nx!=mat[k].nx) || (mat2[k].ny!=mat[k].ny))
951 fatal_error(0,"WAKE UP!! Size of frame %d in 2nd matrix file (%dx%d) does not match size of 1st matrix (%dx%d) or the other way around.\n",
952 k,mat2[k].nx,mat2[k].ny,mat[k].nx,mat[k].ny);
953 for (j=0; (j<mat[k].ny); j++)
954 for (i=bFirstDiag?j+1:j; (i<mat[k].nx); i++)
955 mat[k].matrix[i][j]=mat2[k].matrix[i][j];
958 for(i=0; (i<nmat); i++)
959 fprintf(stderr,"Matrix %d is %d x %d\n",i,mat[i].nx,mat[i].ny);
961 make_axis_labels(nmat, mat);
963 if (skip > 1)
964 prune_mat(nmat,mat,mat2,skip);
966 if (bZeroLine)
967 zero_lines(nmat,mat,mat);
969 if (epsfile!=NULL)
970 ps_mat(epsfile,nmat,mat,mat2,bFrame,bDiag,bFirstDiag,
971 bTitle,bTitleOnce,bYonce,elegend,boxx,boxy,m2p,m2pout,mapoffset);
972 if (xpmfile!=NULL)
973 xpm_mat(xpmfile,nmat,mat,mat2,bDiag,bFirstDiag);
976 void gradient_map(rvec grad, int nmap, t_mapping map[])
978 int i;
979 real c;
981 for(i=0; i<nmap; i++) {
982 c = i/(nmap-1.0);
983 map[i].rgb.r = 1-c*(1-grad[XX]);
984 map[i].rgb.g = 1-c*(1-grad[YY]);
985 map[i].rgb.b = 1-c*(1-grad[ZZ]);
989 void gradient_mat(rvec grad, int nmat, t_matrix mat[])
991 int m;
993 for(m=0; m<nmat; m++)
994 gradient_map(grad, mat[m].nmap, mat[m].map);
997 void rainbow_map(bool bBlue, int nmap, t_mapping map[])
999 int i;
1000 real c,r,g,b;
1002 for(i=0; i<nmap; i++) {
1003 c = (map[i].rgb.r + map[i].rgb.g + map[i].rgb.b)/3;
1004 if (c > 1)
1005 c = 1;
1006 if (bBlue)
1007 c = 1 - c;
1008 if (c <= 0.25) { /* 0-0.25 */
1009 r = 0;
1010 g = pow(4*c,0.666);
1011 b = 1;
1012 } else if (c <= 0.5) { /* 0.25-0.5 */
1013 r = 0;
1014 g = 1;
1015 b = pow(2-4*c,0.666);
1016 } else if (c <= 0.75) { /* 0.5-0.75 */
1017 r = pow(4*c-2,0.666);
1018 g = 1;
1019 b = 0;
1020 } else { /* 0.75-1 */
1021 r = 1;
1022 g = pow(4-4*c,0.666);
1023 b = 0;
1025 map[i].rgb.r = r;
1026 map[i].rgb.g = g;
1027 map[i].rgb.b = b;
1031 void rainbow_mat(bool bBlue, int nmat, t_matrix mat[])
1033 int m;
1035 for(m=0; m<nmat; m++)
1036 rainbow_map(bBlue, mat[m].nmap, mat[m].map);
1039 int main(int argc,char *argv[])
1041 static char *desc[] = {
1042 "xpm2ps makes a beautiful color plot of an XPixelMap file.",
1043 "Labels and axis can be displayed, when they are supplied",
1044 "in the correct matrix format.",
1045 "Matrix data may be generated by programs such as do_dssp, g_rms or",
1046 "g_mdmat.[PAR]",
1047 "Parameters are set in the [TT]m2p[tt] file optionally supplied with",
1048 "[TT]-di[tt]. Reasonable defaults are provided. Settings for the y-axis",
1049 "default to those for the x-axis. Font names have a defaulting hierarchy:",
1050 "titlefont -> legendfont; titlefont -> (xfont -> yfont -> ytickfont)",
1051 "-> xtickfont, e.g. setting titlefont sets all fonts, setting xfont",
1052 "sets yfont, ytickfont and xtickfont.[PAR]",
1053 "With [TT]-f2[tt] a 2nd matrix file can be supplied, both matrix",
1054 "files will be read simultaneously and the upper left half of the",
1055 "first one ([TT]-f[tt]) is plotted together with the lower right",
1056 "half of the second one ([TT]-f2[tt]). The diagonal will contain",
1057 "values from the matrix file selected with [TT]-diag[tt].",
1058 "Plotting of the diagonal values can be suppressed altogether by",
1059 "setting [TT]-diag[tt] to [TT]none[tt]. With ",
1060 "[TT]-combine[tt] an alternative operation can be selected to combine",
1061 "the matrices. In this case, a new color map will be generated with",
1062 "a red gradient for negative numbers and a blue for positive.[PAR]",
1063 "If the color coding and legend labels of both matrices are identical,",
1064 "only one legend will be displayed, else two separate legends are",
1065 "displayed.[PAR]",
1066 "[TT]-title[tt] can be set to [TT]none[tt] to suppress the title, or to",
1067 "[TT]ylabel[tt] to show the title in the Y-label position (alongside",
1068 "the Y-axis).[PAR]",
1069 "With the [TT]-rainbow[tt] option dull grey-scale matrices can be turned",
1070 "into attractive color pictures.[PAR]",
1071 "Merged or rainbowed matrices can be written to an XPixelMap file with",
1072 "the [TT]-xpm[tt] option."
1075 char *fn,*epsfile=NULL,*xpmfile=NULL;
1076 int i,nmat,nmat2,etitle,elegend,ediag,erainbow,ecombine;
1077 t_matrix *mat=NULL,*mat2=NULL;
1078 bool bTitle,bTitleOnce,bDiag,bFirstDiag,bGrad;
1079 static bool bFrame=TRUE,bZeroLine=FALSE,bYonce=FALSE,bAdd=FALSE;
1080 static real boxx=0,boxy=0;
1081 static rvec grad={0,0,0};
1082 enum { etSel, etTop, etOnce, etYlabel, etNone, etNR };
1083 static char *title[] = { NULL, "top", "once", "ylabel", "none", NULL };
1084 /* MUST correspond to enum elXxx as defined at top of file */
1085 static char *legend[] = { NULL, "both", "first", "second", "none", NULL };
1086 enum { edSel, edFirst, edSecond, edNone, edNR };
1087 static char *diag[] = { NULL, "first", "second", "none", NULL };
1088 enum { erSel, erNo, erBlue, erRed, erNR };
1089 static char *rainbow[] = { NULL, "no", "blue", "red", NULL };
1090 /* MUST correspond to enum ecXxx as defined at top of file */
1091 static char *combine[] = {
1092 NULL, "halves", "add", "sub", "mult", "div", NULL };
1093 static int skip=1,mapoffset=0;
1094 t_pargs pa[] = {
1095 { "-frame", FALSE, etBOOL, {&bFrame},
1096 "Display frame, ticks, labels, title and legend" },
1097 { "-title", FALSE, etENUM, {title}, "Show title at" },
1098 { "-yonce", FALSE, etBOOL, {&bYonce}, "Show y-label only once" },
1099 { "-legend", FALSE, etENUM, {legend}, "Show legend" },
1100 { "-diag", FALSE, etENUM, {diag}, "Diagonal" },
1101 { "-combine", FALSE, etENUM, {combine}, "Combine two matrices" },
1102 { "-bx", FALSE, etREAL, {&boxx},
1103 "Box x-size (also y-size when -by is not set)" },
1104 { "-by", FALSE, etREAL, {&boxy}, "Box y-size" },
1105 { "-rainbow", FALSE, etENUM, {rainbow},
1106 "Rainbow colors, convert white to" },
1107 { "-gradient",FALSE, etRVEC, {grad},
1108 "Re-scale colormap to a smooth gradient from white {1,1,1} to {r,g,b}" },
1109 { "-skip", FALSE, etINT, {&skip},
1110 "only write out every nr-th row and column" },
1111 { "-zeroline",FALSE, etBOOL, {&bZeroLine},
1112 "insert line in xpm matrix where axis label is zero"},
1113 { "-legoffset", FALSE, etINT, {&mapoffset},
1114 "Skip first N colors from xpm file for the legend" }
1116 t_filenm fnm[] = {
1117 { efXPM, "-f", NULL, ffREAD },
1118 { efXPM, "-f2", "root2", ffOPTRD },
1119 { efM2P, "-di", NULL, ffLIBOPTRD },
1120 { efM2P, "-do", "out", ffOPTWR },
1121 { efEPS, "-o", NULL, ffOPTWR },
1122 { efXPM, "-xpm",NULL, ffOPTWR }
1124 #define NFILE asize(fnm)
1126 CopyRight(stderr,argv[0]);
1127 parse_common_args(&argc,argv,PCA_CAN_VIEW,
1128 NFILE,fnm,asize(pa),pa,
1129 asize(desc),desc,0,NULL);
1131 etitle = nenum(title);
1132 elegend = nenum(legend);
1133 ediag = nenum(diag);
1134 erainbow = nenum(rainbow);
1135 ecombine = nenum(combine);
1136 bGrad = opt2parg_bSet("-gradient",asize(pa),pa);
1137 for(i=0; i<DIM; i++)
1138 if (grad[i] < 0 || grad[i] > 1)
1139 fatal_error(0, "RGB value %g out of range (0.0-1.0)", grad[i]);
1140 if (!bFrame) {
1141 etitle = etNone;
1142 elegend = elNone;
1145 epsfile=ftp2fn_null(efEPS,NFILE,fnm);
1146 xpmfile=opt2fn_null("-xpm",NFILE,fnm);
1147 if ( epsfile==NULL && xpmfile==NULL ) {
1148 if (ecombine!=ecHalves)
1149 xpmfile=opt2fn("-xpm",NFILE,fnm);
1150 else
1151 epsfile=ftp2fn(efEPS,NFILE,fnm);
1153 if (ecombine!=ecHalves && epsfile) {
1154 fprintf(stderr,
1155 "WARNING: can only write result of arithmetic combination "
1156 "of two matrices to .xpm file\n"
1157 " file %s will not be written\n", epsfile);
1158 epsfile = NULL;
1161 bDiag = ediag!=edNone;
1162 bFirstDiag = ediag!=edSecond;
1164 fn=opt2fn("-f",NFILE,fnm);
1165 nmat=read_xpm_matrix(fn,&mat);
1166 fprintf(stderr,"There are %d matrices in %s\n",nmat,fn);
1167 fn=opt2fn_null("-f2",NFILE,fnm);
1168 if (fn) {
1169 nmat2=read_xpm_matrix(fn,&mat2);
1170 fprintf(stderr,"There are %d matrices in %s\n",nmat2,fn);
1171 if (nmat != nmat2) {
1172 fprintf(stderr,"Different number of matrices, using the smallest number.\n");
1173 nmat=nmat2=min(nmat,nmat2);
1175 } else {
1176 if (ecombine!=ecHalves)
1177 fprintf(stderr,
1178 "WARNING: arithmetic matrix combination selected (-combine), "
1179 "but no second matrix (-f2) supplied\n"
1180 " no matrix combination will be performed\n");
1181 ecombine=0;
1182 nmat2=0;
1184 bTitle = etitle==etTop;
1185 bTitleOnce = etitle==etOnce;
1186 if ( etitle==etYlabel )
1187 for (i=0; (i<nmat); i++) {
1188 strcpy(mat[i].label_y, mat[i].title);
1189 if (mat2)
1190 strcpy(mat2[i].label_y, mat2[i].title);
1192 if (bGrad) {
1193 gradient_mat(grad,nmat,mat);
1194 if (mat2)
1195 gradient_mat(grad,nmat2,mat2);
1197 if (erainbow!=erNo) {
1198 rainbow_mat(erainbow==erBlue,nmat,mat);
1199 if (mat2)
1200 rainbow_mat(erainbow==erBlue,nmat2,mat2);
1203 if ((mat2 == NULL) && (elegend!=elNone))
1204 elegend = elFirst;
1206 if (ecombine && ecombine!=ecHalves)
1207 write_combined_matrix(ecombine, xpmfile, nmat, mat, mat2);
1208 else
1209 do_mat(nmat,mat,mat2,bFrame,bZeroLine,bDiag,bFirstDiag,
1210 bTitle,bTitleOnce,bYonce,
1211 elegend, boxx,boxy,epsfile,xpmfile,
1212 opt2fn_null("-di",NFILE,fnm),opt2fn_null("-do",NFILE,fnm), skip,
1213 mapoffset);
1215 view_all(NFILE, fnm);
1217 thanx(stderr);
1219 return 0;