4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
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
34 * Green Red Orange Magenta Azure Cyan Skyblue
69 char tickfont
[STRLEN
];
84 char leglabel
[STRLEN
];
85 char leg2label
[STRLEN
];
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
};
111 inp
= read_inpfile(mpin
,&ninp
);
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
);
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
)
170 bool bDiff
,bColDiff
=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
))
184 if (!bDiff
&& bColDiff
)
185 fprintf(stderr
,"Warning: two colormaps differ only in RGB value, using one colormap.\n");
191 void leg_discrete(t_psdata ps
,real x0
,real y0
,char *label
,
192 real fontsize
,char *font
,int nmap
,t_mapping map
[])
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
);
206 for(i
=0; (i
<nmap
); i
++) {
208 ps_rgb(ps
,&(map
[i
].rgb
));
209 ps_fillbox(ps
,DDD
,DDD
,DDD
+fontsize
,boxhh
-DDD
);
211 ps_box(ps
,DDD
,DDD
,DDD
+fontsize
,boxhh
-DDD
);
212 ps_ctext(ps
,boxhh
+2*DDD
,fontsize
/3,map
[i
].desc
,eXLeft
);
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
[],
225 real yhh
,boxxh
,boxyh
;
230 boxxh
=(real
)x
/(real
)(nmap
-mapoffset
);
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
);
243 ps_box(ps
,xx0
,y0
,xx0
+(nmap
-mapoffset
)*boxxh
,y0
+boxyh
);
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
[])
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
)
284 if (psr
->bTitle
|| (psr
->bTitleOnce
&& bOnce
) )
285 dh
=2*psr
->titfontsize
;
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
)
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 */
317 ps_linewidth(ps
,psr
->boxlinewidth
);
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
);
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 */
346 yy00
-DDD
-psr
->X
.majorticklen
-psr
->X
.tickfontsize
*0.8,
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))) {
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
) ) {
376 ps_line(ps
,xx00
,yy
,xx00
-psr
->Y
.minorticklen
,yy
);
382 /* Label on Y-axis */
383 if (!psr
->bYonce
|| i
==nmat
/2) {
384 if (strlen(psr
->Y
.label
) > 0)
385 mylab
= psr
->Y
.label
;
387 mylab
= mat
[i
].label_y
;
388 if (strlen(mylab
) > 0) {
389 ps_strfont(ps
,psr
->Y
.font
,psr
->Y
.fontsize
);
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
,
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
;
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
;
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
)
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
);
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
);
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
);
494 hh
+=(nmat
-1)*box_dh_top(FALSE
,psr
);
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)
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",
516 for(j
=0; j
<nmap1
; j
++) {
517 map
[j
].code
.c1
=mapper
[j
% 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
++) {
527 map
[k
].code
.c1
=mapper
[k
% 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
;
540 void xpm_mat(char *outf
,
541 int nmat
,t_matrix
*mat
,t_matrix
*mat2
,bool bDiag
,bool bFirstDiag
)
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]);
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
;
565 mat
[i
].matrix
[x
][y
]=0;
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
]);
581 static void tick_spacing(int n
, real axis
[], real offset
, char axisnm
,
582 real
*major
, real
*minor
)
585 bool bTryAgain
,bFive
;
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;
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: */
602 if ( bRmod(axis
[j
], offset
, space
) )
604 /* do we have a reasonable number of ticks ? */
605 bTryAgain
= i
> min(10, n
-1) || i
< 5;
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",
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
,
626 char buf
[256],*legend
;
630 int i
,j
,x
,y
,col
,leg
=0;
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
);
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;
661 for (i
=0; (i
<nmat
); i
++)
662 if (mat
[i
].nmap
>nmap1
) {
668 printf("Selected legend of matrix # %d for display\n",leg
);
671 for (i
=0; (i
<nmat
); i
++)
672 if (mat2
[i
].nmap
>nmap2
) {
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 */
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
);
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 */
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
);
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
,
728 sprintf(buf
,"Here starts the filling of box #%d",i
);
730 for(x
=0; (x
<mat
[i
].nx
); x
++) {
734 xx
=x0
+x
*psr
->xboxsize
;
735 ps_moveto(out
,xx
,y0
);
737 bMap1
= (!mat2
|| (x
<y
|| (x
==y
&& bFirstDiag
)));
738 if ((bDiag
) || (x
!=y
))
739 col
= mat
[i
].matrix
[x
][y
];
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
)))
749 nextcol
=mat
[i
].matrix
[x
][nexty
];
750 if ( (nexty
==mat
[i
].ny
) || (col
!=nextcol
) || (bMap1
!=bNextMap1
) ) {
753 ps_rgb_nbox(out
,&(mat
[i
].map
[col
].rgb
),nexty
-y
);
755 ps_rgb_nbox(out
,&(mat2
[i
].map
[col
].rgb
),nexty
-y
);
757 ps_moverel(out
,0,psr
->yboxsize
);
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 */
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
;
783 bDiscrete
= mat2
[0].bDiscrete
;
784 legend
= mat2
[0].legend
;
789 leg_discrete(out
,psr
->legfontsize
,DDD
,legend
,
790 psr
->legfontsize
,psr
->legfont
,leg_nmap
,leg_map
);
792 if ( elegend
!=elBoth
)
793 leg_continuous(out
,x0
+w
/2,w
/2,DDD
,legend
,
794 psr
->legfontsize
,psr
->legfont
,leg_nmap
,leg_map
,
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");
806 void make_axis_labels(int nmat
, t_matrix
*mat
)
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
++)
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
++)
826 void prune_mat(int nmat
, t_matrix
*mat
,t_matrix
*mat2
, int skip
)
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 */
836 for(x
=0; (x
<mat
[i
].nx
); x
++)
838 mat
[i
].axis_x
[xs
] = mat
[i
].axis_x
[x
];
840 mat2
[i
].axis_x
[xs
] = mat2
[i
].axis_x
[x
];
842 for(y
=0; (y
<mat
[i
].ny
); y
++) {
844 mat
[i
].axis_y
[ys
] = mat
[i
].axis_y
[y
];
846 mat2
[i
].axis_y
[ys
] = mat2
[i
].axis_y
[y
];
849 mat
[i
].matrix
[xs
][ys
] = mat
[i
].matrix
[x
][y
];
851 mat2
[i
].matrix
[xs
][ys
] = mat2
[i
].matrix
[x
][y
];
857 /* adjust parameters */
858 mat
[i
].nx
= (mat
[i
].nx
+skip
-1)/skip
;
859 mat
[i
].ny
= (mat
[i
].ny
+skip
-1)/skip
;
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
)
872 for(i
=0; i
<nmat
; i
++)
873 for(m
=0; m
< (mat2
? 2 : 1) ; m
++) {
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
;
895 real
**rmat1
, **rmat2
;
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
);
908 for(j
=0; j
<mat1
[k
].ny
; j
++)
909 for(i
=0; i
<mat1
[k
].nx
; i
++) {
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;
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
;
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
,
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
);
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
,
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
);
964 prune_mat(nmat
,mat
,mat2
,skip
);
967 zero_lines(nmat
,mat
,mat
);
970 ps_mat(epsfile
,nmat
,mat
,mat2
,bFrame
,bDiag
,bFirstDiag
,
971 bTitle
,bTitleOnce
,bYonce
,elegend
,boxx
,boxy
,m2p
,m2pout
,mapoffset
);
973 xpm_mat(xpmfile
,nmat
,mat
,mat2
,bDiag
,bFirstDiag
);
976 void gradient_map(rvec grad
, int nmap
, t_mapping map
[])
981 for(i
=0; i
<nmap
; i
++) {
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
[])
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
[])
1002 for(i
=0; i
<nmap
; i
++) {
1003 c
= (map
[i
].rgb
.r
+ map
[i
].rgb
.g
+ map
[i
].rgb
.b
)/3;
1008 if (c
<= 0.25) { /* 0-0.25 */
1012 } else if (c
<= 0.5) { /* 0.25-0.5 */
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);
1020 } else { /* 0.75-1 */
1022 g
= pow(4-4*c
,0.666);
1031 void rainbow_mat(bool bBlue
, int nmat
, t_matrix mat
[])
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",
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",
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;
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" }
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
]);
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
);
1151 epsfile
=ftp2fn(efEPS
,NFILE
,fnm
);
1153 if (ecombine
!=ecHalves
&& epsfile
) {
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
);
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
);
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
);
1176 if (ecombine
!=ecHalves
)
1178 "WARNING: arithmetic matrix combination selected (-combine), "
1179 "but no second matrix (-f2) supplied\n"
1180 " no matrix combination will be performed\n");
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
);
1190 strcpy(mat2
[i
].label_y
, mat2
[i
].title
);
1193 gradient_mat(grad
,nmat
,mat
);
1195 gradient_mat(grad
,nmat2
,mat2
);
1197 if (erainbow
!=erNo
) {
1198 rainbow_mat(erainbow
==erBlue
,nmat
,mat
);
1200 rainbow_mat(erainbow
==erBlue
,nmat2
,mat2
);
1203 if ((mat2
== NULL
) && (elegend
!=elNone
))
1206 if (ecombine
&& ecombine
!=ecHalves
)
1207 write_combined_matrix(ecombine
, xpmfile
, nmat
, mat
, mat2
);
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
,
1215 view_all(NFILE
, fnm
);