Moved second half of gmxana tools to C++
[gromacs.git] / src / gromacs / gmxana / gmx_xpm2ps.cpp
blob06c2677a89503a4c5a3646b0ceb8fc554edca072
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "gmxpre.h"
39 #include <cmath>
40 #include <cstdio>
41 #include <cstdlib>
42 #include <cstring>
44 #include <algorithm>
46 #include "gromacs/commandline/pargs.h"
47 #include "gromacs/fileio/matio.h"
48 #include "gromacs/fileio/trxio.h"
49 #include "gromacs/fileio/writeps.h"
50 #include "gromacs/gmxana/gmx_ana.h"
51 #include "gromacs/legacyheaders/macros.h"
52 #include "gromacs/legacyheaders/typedefs.h"
53 #include "gromacs/legacyheaders/viewit.h"
54 #include "gromacs/utility/cstringutil.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/futil.h"
57 #include "gromacs/utility/gmxassert.h"
58 #include "gromacs/utility/smalloc.h"
60 #define FUDGE 1.2
61 #define DDD 2
63 typedef struct {
64 real major;
65 real minor;
66 real offset;
67 gmx_bool first;
68 int lineatzero;
69 real majorticklen;
70 real minorticklen;
71 char label[STRLEN];
72 real fontsize;
73 char font[STRLEN];
74 real tickfontsize;
75 char tickfont[STRLEN];
76 } t_axisdef;
78 typedef struct {
79 int bw;
80 real linewidth;
81 real xoffs, yoffs;
82 gmx_bool bTitle;
83 gmx_bool bTitleOnce;
84 gmx_bool bYonce;
85 real titfontsize;
86 char titfont[STRLEN];
87 gmx_bool legend;
88 real legfontsize;
89 char legfont[STRLEN];
90 char leglabel[STRLEN];
91 char leg2label[STRLEN];
92 real xboxsize;
93 real yboxsize;
94 real boxspacing;
95 real boxlinewidth;
96 real ticklinewidth;
97 real zerolinewidth;
98 t_axisdef X, Y;
99 } t_psrec;
101 /* MUST correspond to char *legend[] in main() */
102 enum {
103 elSel, elBoth, elFirst, elSecond, elNone, elNR
106 /* MUST correspond to char *combine[] in main() */
107 enum {
108 ecSel, ecHalves, ecAdd, ecSub, ecMult, ecDiv, ecNR
111 void get_params(const char *mpin, const char *mpout, t_psrec *psr)
113 static const char *gmx_bools[BOOL_NR+1] = { "no", "yes", NULL };
114 /* this must correspond to t_rgb *linecolors[] below */
115 static const char *colors[] = { "none", "black", "white", NULL };
116 warninp_t wi;
117 t_inpfile *inp;
118 const char *tmp;
119 int ninp = 0;
121 wi = init_warning(FALSE, 0);
123 if (mpin != NULL)
125 inp = read_inpfile(mpin, &ninp, wi);
127 else
129 inp = NULL;
131 ETYPE("black&white", psr->bw, gmx_bools);
132 RTYPE("linewidth", psr->linewidth, 1.0);
133 STYPE("titlefont", psr->titfont, "Helvetica");
134 RTYPE("titlefontsize", psr->titfontsize, 20.0);
135 ETYPE("legend", psr->legend, gmx_bools);
136 STYPE("legendfont", psr->legfont, psr->titfont);
137 STYPE("legendlabel", psr->leglabel, "");
138 STYPE("legend2label", psr->leg2label, psr->leglabel);
139 RTYPE("legendfontsize", psr->legfontsize, 14.0);
140 RTYPE("xbox", psr->xboxsize, 0.0);
141 RTYPE("ybox", psr->yboxsize, 0.0);
142 RTYPE("matrixspacing", psr->boxspacing, 20.0);
143 RTYPE("xoffset", psr->xoffs, 0.0);
144 RTYPE("yoffset", psr->yoffs, psr->xoffs);
145 RTYPE("boxlinewidth", psr->boxlinewidth, psr->linewidth);
146 RTYPE("ticklinewidth", psr->ticklinewidth, psr->linewidth);
147 RTYPE("zerolinewidth", psr->zerolinewidth, psr->ticklinewidth);
148 ETYPE("x-lineat0value", psr->X.lineatzero, colors);
149 RTYPE("x-major", psr->X.major, NOTSET);
150 RTYPE("x-minor", psr->X.minor, NOTSET);
151 RTYPE("x-firstmajor", psr->X.offset, 0.0);
152 ETYPE("x-majorat0", psr->X.first, gmx_bools);
153 RTYPE("x-majorticklen", psr->X.majorticklen, 8.0);
154 RTYPE("x-minorticklen", psr->X.minorticklen, 4.0);
155 STYPE("x-label", psr->X.label, "");
156 RTYPE("x-fontsize", psr->X.fontsize, 16.0);
157 STYPE("x-font", psr->X.font, psr->titfont);
158 RTYPE("x-tickfontsize", psr->X.tickfontsize, 10.0);
159 STYPE("x-tickfont", psr->X.tickfont, psr->X.font);
160 ETYPE("y-lineat0value", psr->Y.lineatzero, colors);
161 RTYPE("y-major", psr->Y.major, psr->X.major);
162 RTYPE("y-minor", psr->Y.minor, psr->X.minor);
163 RTYPE("y-firstmajor", psr->Y.offset, psr->X.offset);
164 ETYPE("y-majorat0", psr->Y.first, gmx_bools);
165 RTYPE("y-majorticklen", psr->Y.majorticklen, psr->X.majorticklen);
166 RTYPE("y-minorticklen", psr->Y.minorticklen, psr->X.minorticklen);
167 STYPE("y-label", psr->Y.label, psr->X.label);
168 RTYPE("y-fontsize", psr->Y.fontsize, psr->X.fontsize);
169 STYPE("y-font", psr->Y.font, psr->X.font);
170 RTYPE("y-tickfontsize", psr->Y.tickfontsize, psr->X.tickfontsize);
171 STYPE("y-tickfont", psr->Y.tickfont, psr->Y.font);
173 if (mpout != NULL)
175 write_inpfile(mpout, ninp, inp, TRUE, wi);
178 done_warning(wi, FARGS);
181 t_rgb black = { 0, 0, 0 };
182 t_rgb white = { 1, 1, 1 };
183 t_rgb red = { 1, 0, 0 };
184 t_rgb blue = { 0, 0, 1 };
185 #define BLACK (&black)
186 /* this must correspond to *colors[] in get_params */
187 t_rgb *linecolors[] = { NULL, &black, &white, NULL };
189 gmx_bool diff_maps(int nmap1, t_mapping *map1, int nmap2, t_mapping *map2)
191 int i;
192 gmx_bool bDiff, bColDiff = FALSE;
194 if (nmap1 != nmap2)
196 bDiff = TRUE;
198 else
200 bDiff = FALSE;
201 for (i = 0; i < nmap1; i++)
203 if (!matelmt_cmp(map1[i].code, map2[i].code))
205 bDiff = TRUE;
207 if (std::strcmp(map1[i].desc, map2[i].desc) != 0)
209 bDiff = TRUE;
211 if ((map1[i].rgb.r != map2[i].rgb.r) ||
212 (map1[i].rgb.g != map2[i].rgb.g) ||
213 (map1[i].rgb.b != map2[i].rgb.b))
215 bColDiff = TRUE;
218 if (!bDiff && bColDiff)
220 fprintf(stderr, "Warning: two colormaps differ only in RGB value, using one colormap.\n");
224 return bDiff;
227 void leg_discrete(t_psdata ps, real x0, real y0, char *label,
228 real fontsize, char *font, int nmap, t_mapping map[])
230 int i;
231 real yhh;
232 real boxhh;
234 boxhh = fontsize+DDD;
235 /* LANDSCAPE */
236 ps_rgb(ps, BLACK);
237 ps_strfont(ps, font, fontsize);
238 yhh = y0+fontsize+3*DDD;
239 if (std::strlen(label) > 0)
241 ps_ctext(ps, x0, yhh, label, eXLeft);
243 ps_moveto(ps, x0, y0);
244 for (i = 0; (i < nmap); i++)
246 ps_setorigin(ps);
247 ps_rgb(ps, &(map[i].rgb));
248 ps_fillbox(ps, DDD, DDD, DDD+fontsize, boxhh-DDD);
249 ps_rgb(ps, BLACK);
250 ps_box(ps, DDD, DDD, DDD+fontsize, boxhh-DDD);
251 ps_ctext(ps, boxhh+2*DDD, fontsize/3, map[i].desc, eXLeft);
252 ps_unsetorigin(ps);
253 ps_moverel(ps, DDD, -fontsize/3);
257 void leg_continuous(t_psdata ps, real x0, real x, real y0, char *label,
258 real fontsize, char *font,
259 int nmap, t_mapping map[],
260 int mapoffset)
262 int i;
263 real xx0;
264 real yhh, boxxh, boxyh;
266 boxyh = fontsize;
267 if (x < 8*fontsize)
269 x = 8*fontsize;
271 boxxh = x/(nmap-mapoffset);
272 if (boxxh > fontsize)
274 boxxh = fontsize;
277 GMX_RELEASE_ASSERT(map != NULL, "NULL map array provided to leg_continuous()");
279 /* LANDSCAPE */
280 xx0 = x0-((nmap-mapoffset)*boxxh)/2.0;
282 for (i = 0; (i < nmap-mapoffset); i++)
284 ps_rgb(ps, &(map[i+mapoffset].rgb));
285 ps_fillbox(ps, xx0+i*boxxh, y0, xx0+(i+1)*boxxh, y0+boxyh);
287 ps_strfont(ps, font, fontsize);
288 ps_rgb(ps, BLACK);
289 ps_box(ps, xx0, y0, xx0+(nmap-mapoffset)*boxxh, y0+boxyh);
291 yhh = y0+boxyh+3*DDD;
292 ps_ctext(ps, xx0+boxxh/2, yhh, map[0].desc, eXCenter);
293 if (std::strlen(label) > 0)
295 ps_ctext(ps, x0, yhh, label, eXCenter);
297 ps_ctext(ps, xx0+((nmap-mapoffset)*boxxh)
298 - boxxh/2, yhh, map[nmap-1].desc, eXCenter);
301 void leg_bicontinuous(t_psdata ps, real x0, real x, real y0, char *label1,
302 char *label2, real fontsize, char *font,
303 int nmap1, t_mapping map1[], int nmap2, t_mapping map2[])
305 real xx1, xx2, x1, x2;
307 x1 = x/(nmap1+nmap2)*nmap1; /* width of legend 1 */
308 x2 = x/(nmap1+nmap2)*nmap2; /* width of legend 2 */
309 xx1 = x0-(x2/2.0)-fontsize; /* center of legend 1 */
310 xx2 = x0+(x1/2.0)+fontsize; /* center of legend 2 */
311 x1 -= fontsize/2; /* adjust width */
312 x2 -= fontsize/2; /* adjust width */
313 leg_continuous(ps, xx1, x1, y0, label1, fontsize, font, nmap1, map1, 0);
314 leg_continuous(ps, xx2, x2, y0, label2, fontsize, font, nmap2, map2, 0);
317 static real box_height(t_matrix *mat, t_psrec *psr)
319 return mat->ny*psr->yboxsize;
322 static real box_dh(t_psrec *psr)
324 return psr->boxspacing;
327 #define IS_ONCE (i == nmat-1)
328 static real box_dh_top(gmx_bool bOnce, t_psrec *psr)
330 real dh;
332 if (psr->bTitle || (psr->bTitleOnce && bOnce) )
334 dh = 2*psr->titfontsize;
336 else
338 dh = 0;
341 return dh;
344 static gmx_bool box_do_all_x_maj_ticks(t_psrec *psr)
346 return (psr->boxspacing > (1.5*psr->X.majorticklen));
349 static gmx_bool box_do_all_x_min_ticks(t_psrec *psr)
351 return (psr->boxspacing > (1.5*psr->X.minorticklen));
354 static void draw_boxes(t_psdata ps, real x0, real y0, real w,
355 int nmat, t_matrix mat[], t_psrec *psr)
357 char buf[128];
358 char *mylab;
359 real xxx;
360 char **xtick, **ytick;
361 real xx, yy, dy, xx00, yy00, offset_x, offset_y;
362 int i, j, x, y, ntx, nty;
363 size_t strlength;
365 /* Only necessary when there will be no y-labels */
366 strlength = 0;
368 /* Draw the box */
369 ps_rgb(ps, BLACK);
370 ps_linewidth(ps, static_cast<int>(psr->boxlinewidth));
371 yy00 = y0;
372 for (i = 0; (i < nmat); i++)
374 dy = box_height(&(mat[i]), psr);
375 ps_box(ps, x0-1, yy00-1, x0+w+1, yy00+dy+1);
376 yy00 += dy+box_dh(psr)+box_dh_top(IS_ONCE, psr);
379 /* Draw the ticks on the axes */
380 ps_linewidth(ps, static_cast<int>(psr->ticklinewidth));
381 xx00 = x0-1;
382 yy00 = y0-1;
383 for (i = 0; (i < nmat); i++)
385 if (mat[i].flags & MAT_SPATIAL_X)
387 ntx = mat[i].nx + 1;
388 offset_x = 0.1;
390 else
392 ntx = mat[i].nx;
393 offset_x = 0.6;
395 if (mat[i].flags & MAT_SPATIAL_Y)
397 nty = mat[i].ny + 1;
398 offset_y = 0.1;
400 else
402 nty = mat[i].ny;
403 offset_y = 0.6;
405 snew(xtick, ntx);
406 for (j = 0; (j < ntx); j++)
408 sprintf(buf, "%g", mat[i].axis_x[j]);
409 xtick[j] = gmx_strdup(buf);
411 ps_strfont(ps, psr->X.tickfont, psr->X.tickfontsize);
412 for (x = 0; (x < ntx); x++)
414 xx = xx00 + (x + offset_x)*psr->xboxsize;
415 if ( ( bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.major) ||
416 (psr->X.first && (x == 0))) &&
417 ( (i == 0) || box_do_all_x_maj_ticks(psr) ) )
419 /* Longer tick marks */
420 ps_line (ps, xx, yy00, xx, yy00-psr->X.majorticklen);
421 /* Plot label on lowest graph only */
422 if (i == 0)
424 ps_ctext(ps, xx,
425 yy00-DDD-psr->X.majorticklen-psr->X.tickfontsize*0.8,
426 xtick[x], eXCenter);
429 else if (bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.minor) &&
430 ( (i == 0) || box_do_all_x_min_ticks(psr) ) )
432 /* Shorter tick marks */
433 ps_line(ps, xx, yy00, xx, yy00-psr->X.minorticklen);
435 else if (bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.major) )
437 /* Even shorter marks, only each X.major */
438 ps_line(ps, xx, yy00, xx, yy00-(psr->boxspacing/2));
441 ps_strfont(ps, psr->Y.tickfont, psr->Y.tickfontsize);
442 snew(ytick, nty);
443 for (j = 0; (j < nty); j++)
445 sprintf(buf, "%g", mat[i].axis_y[j]);
446 ytick[j] = gmx_strdup(buf);
449 for (y = 0; (y < nty); y++)
451 yy = yy00 + (y + offset_y)*psr->yboxsize;
452 if (bRmod(mat[i].axis_y[y], psr->Y.offset, psr->Y.major) ||
453 (psr->Y.first && (y == 0)))
455 /* Major ticks */
456 strlength = std::max(strlength, std::strlen(ytick[y]));
457 ps_line (ps, xx00, yy, xx00-psr->Y.majorticklen, yy);
458 ps_ctext(ps, xx00-psr->Y.majorticklen-DDD,
459 yy-psr->Y.tickfontsize/3.0, ytick[y], eXRight);
461 else if (bRmod(mat[i].axis_y[y], psr->Y.offset, psr->Y.minor) )
463 /* Minor ticks */
464 ps_line(ps, xx00, yy, xx00-psr->Y.minorticklen, yy);
467 sfree(xtick);
468 sfree(ytick);
470 /* Label on Y-axis */
471 if (!psr->bYonce || i == nmat/2)
473 if (strlen(psr->Y.label) > 0)
475 mylab = psr->Y.label;
477 else
479 mylab = mat[i].label_y;
481 if (strlen(mylab) > 0)
483 ps_strfont(ps, psr->Y.font, psr->Y.fontsize);
484 ps_flip(ps, TRUE);
485 xxx = x0-psr->X.majorticklen-psr->X.tickfontsize*strlength-DDD;
486 ps_ctext(ps, yy00+box_height(&mat[i], psr)/2.0, 612.5-xxx,
487 mylab, eXCenter);
488 ps_flip(ps, FALSE);
492 yy00 += box_height(&(mat[i]), psr)+box_dh(psr)+box_dh_top(IS_ONCE, psr);
494 /* Label on X-axis */
495 if (strlen(psr->X.label) > 0)
497 mylab = psr->X.label;
499 else
501 mylab = mat[0].label_x;
503 if (strlen(mylab) > 0)
505 ps_strfont(ps, psr->X.font, psr->X.fontsize);
506 ps_ctext(ps, x0+w/2, y0-DDD-psr->X.majorticklen-psr->X.tickfontsize*FUDGE-
507 psr->X.fontsize, mylab, eXCenter);
511 static void draw_zerolines(t_psdata out, real x0, real y0, real w,
512 int nmat, t_matrix mat[], t_psrec *psr)
514 real xx, yy, dy, xx00, yy00;
515 int i, x, y;
517 xx00 = x0-1.5;
518 yy00 = y0-1.5;
519 ps_linewidth(out, static_cast<int>(psr->zerolinewidth));
520 for (i = 0; (i < nmat); i++)
522 dy = box_height(&(mat[i]), psr);
523 /* mat[i].axis_x and _y were already set by draw_boxes */
524 if (psr->X.lineatzero)
526 ps_rgb(out, linecolors[psr->X.lineatzero]);
527 for (x = 0; (x < mat[i].nx); x++)
529 xx = xx00+(x+0.7)*psr->xboxsize;
530 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
531 if (x != 0 && x < mat[i].nx-1 &&
532 std::abs(mat[i].axis_x[x]) <
533 0.1*std::abs(mat[i].axis_x[x+1]-mat[i].axis_x[x]) )
535 ps_line (out, xx, yy00, xx, yy00+dy+2);
539 if (psr->Y.lineatzero)
541 ps_rgb(out, linecolors[psr->Y.lineatzero]);
542 for (y = 0; (y < mat[i].ny); y++)
544 yy = yy00+(y+0.7)*psr->yboxsize;
545 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
546 if (y != 0 && y < mat[i].ny-1 &&
547 std::abs(mat[i].axis_y[y]) <
548 0.1*std::abs(mat[i].axis_y[y+1]-mat[i].axis_y[y]) )
550 ps_line (out, xx00, yy, xx00+w+2, yy);
554 yy00 += box_height(&(mat[i]), psr)+box_dh(psr)+box_dh_top(IS_ONCE, psr);
558 static void box_dim(int nmat, t_matrix mat[], t_matrix *mat2, t_psrec *psr,
559 int elegend, gmx_bool bFrame,
560 real *w, real *h, real *dw, real *dh)
562 int i, maxytick;
563 real ww, hh, dww, dhh;
565 hh = dww = dhh = 0;
566 maxytick = 0;
568 ww = 0;
569 for (i = 0; (i < nmat); i++)
571 ww = std::max(ww, mat[i].nx*psr->xboxsize);
572 hh += box_height(&(mat[i]), psr);
573 maxytick = std::max(maxytick, mat[i].nx);
575 if (bFrame)
577 if (mat[0].label_y[0])
579 dww += 2.0*(psr->Y.fontsize+DDD);
581 if (psr->Y.major > 0)
583 dww += psr->Y.majorticklen + DDD +
584 psr->Y.tickfontsize*(std::log(static_cast<real>(maxytick))/std::log(10.0));
586 else if (psr->Y.minor > 0)
588 dww += psr->Y.minorticklen;
591 if (mat[0].label_x[0])
593 dhh += psr->X.fontsize+2*DDD;
595 if ( /* fool emacs auto-indent */
596 (elegend == elBoth && (mat[0].legend[0] || mat2[0].legend[0])) ||
597 (elegend == elFirst && mat[0].legend[0]) ||
598 (elegend == elSecond && mat2[0].legend[0]) )
600 dhh += 2*(psr->legfontsize*FUDGE+2*DDD);
602 else
604 dhh += psr->legfontsize*FUDGE+2*DDD;
606 if (psr->X.major > 0)
608 dhh += psr->X.tickfontsize*FUDGE+2*DDD+psr->X.majorticklen;
610 else if (psr->X.minor > 0)
612 dhh += psr->X.minorticklen;
615 hh += (nmat-1)*box_dh(psr);
616 hh += box_dh_top(TRUE, psr);
617 if (nmat > 1)
619 hh += (nmat-1)*box_dh_top(FALSE, psr);
622 *w = ww;
623 *h = hh;
624 *dw = dww;
625 *dh = dhh;
628 int add_maps(t_mapping **newmap,
629 int nmap1, t_mapping map1[], int nmap2, t_mapping map2[])
631 static char mapper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+{}|;:',<.>/?";
632 int nsymbols;
633 int nmap, j, k;
634 t_mapping *map;
636 nsymbols = std::strlen(mapper);
637 nmap = nmap1+nmap2;
638 if (nmap > nsymbols*nsymbols)
640 gmx_fatal(FARGS, "Not enough symbols to merge the two colormaps\n");
642 printf("Combining colormaps of %d and %d elements into one of %d elements\n",
643 nmap1, nmap2, nmap);
644 snew(map, nmap);
645 for (j = 0; j < nmap1; j++)
647 map[j].code.c1 = mapper[j % nsymbols];
648 if (nmap > nsymbols)
650 map[j].code.c2 = mapper[j/nsymbols];
652 map[j].rgb.r = map1[j].rgb.r;
653 map[j].rgb.g = map1[j].rgb.g;
654 map[j].rgb.b = map1[j].rgb.b;
655 map[j].desc = map1[j].desc;
657 for (j = 0; j < nmap2; j++)
659 k = j+nmap1;
660 map[k].code.c1 = mapper[k % nsymbols];
661 if (nmap > nsymbols)
663 map[k].code.c2 = mapper[k/nsymbols];
665 map[k].rgb.r = map2[j].rgb.r;
666 map[k].rgb.g = map2[j].rgb.g;
667 map[k].rgb.b = map2[j].rgb.b;
668 map[k].desc = map2[j].desc;
671 *newmap = map;
672 return nmap;
675 void xpm_mat(const char *outf, int nmat, t_matrix *mat, t_matrix *mat2,
676 gmx_bool bDiag, gmx_bool bFirstDiag)
678 FILE *out;
679 int i, x, y, col;
680 int nmap;
681 t_mapping *map = NULL;
683 out = gmx_ffopen(outf, "w");
685 for (i = 0; i < nmat; i++)
687 if (!mat2 || !diff_maps(mat[i].nmap, mat[i].map, mat2[i].nmap, mat2[i].map))
689 write_xpm_m(out, mat[0]);
691 else
693 nmap = add_maps(&map, mat[i].nmap, mat[i].map, mat2[i].nmap, mat2[i].map);
694 for (x = 0; (x < mat[i].nx); x++)
696 for (y = 0; (y < mat[i].nx); y++)
698 if ((x < y) || ((x == y) && bFirstDiag)) /* upper left -> map1 */
700 col = mat[i].matrix[x][y];
702 else /* lower right -> map2 */
704 col = mat[i].nmap+mat[i].matrix[x][y];
706 if ((bDiag) || (x != y))
708 mat[i].matrix[x][y] = col;
710 else
712 mat[i].matrix[x][y] = 0;
716 sfree(mat[i].map);
717 mat[i].nmap = nmap;
718 mat[i].map = map;
719 if (std::strcmp(mat[i].title, mat2[i].title) != 0)
721 sprintf(mat[i].title+strlen(mat[i].title), " / %s", mat2[i].title);
723 if (std::strcmp(mat[i].legend, mat2[i].legend) != 0)
725 sprintf(mat[i].legend+strlen(mat[i].legend), " / %s", mat2[i].legend);
727 write_xpm_m(out, mat[i]);
730 gmx_ffclose(out);
733 static void tick_spacing(int n, real axis[], real offset, char axisnm,
734 real *major, real *minor)
736 real space;
737 gmx_bool bTryAgain;
738 int i, j, t, f = 0, ten;
739 #define NFACT 4
740 real major_fact[NFACT] = {5, 4, 2, 1};
741 real minor_fact[NFACT] = {5, 4, 4, 5};
743 /* start with interval between 10 matrix points: */
744 space = std::max(10*axis[1]-axis[0], axis[std::min(10, n-1)]-axis[0]);
745 /* get power of 10 */
746 ten = static_cast<int>(std::ceil(std::log(space)/std::log(10.0))-1);
747 bTryAgain = TRUE;
748 for (t = ten+2; t > ten-3 && bTryAgain; t--)
750 for (f = 0; f < NFACT && bTryAgain; f++)
752 space = std::pow(static_cast<real>(10.0), static_cast<real>(t)) * major_fact[f];
753 /* count how many ticks we would get: */
754 i = 0;
755 for (j = 0; j < n; j++)
757 if (bRmod(axis[j], offset, space) )
759 i++;
762 /* do we have a reasonable number of ticks ? */
763 bTryAgain = (i > std::min(10, n-1)) || (i < 5);
766 if (bTryAgain)
768 space = std::max(10*axis[1]-axis[0], axis[std::min(10, n-1)]-axis[0]);
769 fprintf(stderr, "Auto tick spacing failed for %c-axis, guessing %g\n",
770 axisnm, space);
772 *major = space;
773 *minor = space / minor_fact[(f > 0) ? f-1 : 0];
774 fprintf(stderr, "Auto tick spacing for %c-axis: major %g, minor %g\n",
775 axisnm, *major, *minor);
778 void ps_mat(const char *outf, int nmat, t_matrix mat[], t_matrix mat2[],
779 gmx_bool bFrame, gmx_bool bDiag, gmx_bool bFirstDiag,
780 gmx_bool bTitle, gmx_bool bTitleOnce, gmx_bool bYonce, int elegend,
781 real size, real boxx, real boxy, const char *m2p, const char *m2pout,
782 int mapoffset)
784 const char *libm2p;
785 char buf[256], *legend;
786 t_psdata out;
787 t_psrec psrec, *psr;
788 int W, H;
789 int i, x, y, col, leg = 0;
790 real x0, y0, xx;
791 real w, h, dw, dh;
792 int nmap1 = 0, nmap2 = 0, leg_nmap;
793 t_mapping *map1 = NULL, *map2 = NULL, *leg_map;
794 gmx_bool bMap1, bNextMap1, bDiscrete;
796 /* memory leak: */
797 libm2p = m2p ? gmxlibfn(m2p) : m2p;
798 get_params(libm2p, m2pout, &psrec);
800 psr = &psrec;
802 if (psr->X.major <= 0)
804 tick_spacing((mat[0].flags & MAT_SPATIAL_X) ? mat[0].nx + 1 : mat[0].nx,
805 mat[0].axis_x, psr->X.offset, 'X',
806 &(psr->X.major), &(psr->X.minor) );
808 if (psr->X.minor <= 0)
810 psr->X.minor = psr->X.major / 2;
812 if (psr->Y.major <= 0)
814 tick_spacing((mat[0].flags & MAT_SPATIAL_Y) ? mat[0].ny + 1 : mat[0].ny,
815 mat[0].axis_y, psr->Y.offset, 'Y',
816 &(psr->Y.major), &(psr->Y.minor) );
818 if (psr->Y.minor <= 0)
820 psr->Y.minor = psr->Y.major / 2;
823 if (boxx > 0)
825 psr->xboxsize = boxx;
826 psr->yboxsize = boxx;
828 if (boxy > 0)
830 psr->yboxsize = boxy;
833 if (psr->xboxsize == 0)
835 psr->xboxsize = size/mat[0].nx;
836 printf("Set the x-size of the box to %.3f\n", psr->xboxsize);
838 if (psr->yboxsize == 0)
840 psr->yboxsize = size/mat[0].nx;
841 printf("Set the y-size of the box to %.3f\n", psr->yboxsize);
844 nmap1 = 0;
845 for (i = 0; (i < nmat); i++)
847 if (mat[i].nmap > nmap1)
849 nmap1 = mat[i].nmap;
850 map1 = mat[i].map;
851 leg = i+1;
854 if (leg != 1)
856 printf("Selected legend of matrix # %d for display\n", leg);
858 if (mat2)
860 nmap2 = 0;
861 for (i = 0; (i < nmat); i++)
863 if (mat2[i].nmap > nmap2)
865 nmap2 = mat2[i].nmap;
866 map2 = mat2[i].map;
867 leg = i+1;
870 if (leg != 1)
872 printf("Selected legend of matrix # %d for second display\n", leg);
875 if ( (mat[0].legend[0] == 0) && psr->legend)
877 std::strcpy(mat[0].legend, psr->leglabel);
880 bTitle = bTitle && mat[nmat-1].title[0];
881 bTitleOnce = bTitleOnce && mat[nmat-1].title[0];
882 psr->bTitle = bTitle;
883 psr->bTitleOnce = bTitleOnce;
884 psr->bYonce = bYonce;
886 /* Set up size of box for nice colors */
887 box_dim(nmat, mat, mat2, psr, elegend, bFrame, &w, &h, &dw, &dh);
889 /* Set up bounding box */
890 W = static_cast<int>(w+dw);
891 H = static_cast<int>(h+dh);
893 /* Start box at */
894 x0 = dw;
895 y0 = dh;
896 x = static_cast<int>(W+psr->xoffs);
897 y = static_cast<int>(H+psr->yoffs);
898 if (bFrame)
900 x += 5*DDD;
901 y += 4*DDD;
903 out = ps_open(outf, 0, 0, x, y);
904 ps_linewidth(out, static_cast<int>(psr->linewidth));
905 ps_init_rgb_box(out, psr->xboxsize, psr->yboxsize);
906 ps_init_rgb_nbox(out, psr->xboxsize, psr->yboxsize);
907 ps_translate(out, psr->xoffs, psr->yoffs);
909 if (bFrame)
911 ps_comment(out, "Here starts the BOX drawing");
912 draw_boxes(out, x0, y0, w, nmat, mat, psr);
915 for (i = 0; (i < nmat); i++)
917 if (bTitle || (bTitleOnce && i == nmat-1) )
919 /* Print title, if any */
920 ps_rgb(out, BLACK);
921 ps_strfont(out, psr->titfont, psr->titfontsize);
922 if (!mat2 || (std::strcmp(mat[i].title, mat2[i].title) == 0))
924 std::strcpy(buf, mat[i].title);
926 else
928 sprintf(buf, "%s / %s", mat[i].title, mat2[i].title);
930 ps_ctext(out, x0+w/2, y0+box_height(&(mat[i]), psr)+psr->titfontsize,
931 buf, eXCenter);
933 sprintf(buf, "Here starts the filling of box #%d", i);
934 ps_comment(out, buf);
935 for (x = 0; (x < mat[i].nx); x++)
937 int nexty;
938 int nextcol;
940 xx = x0+x*psr->xboxsize;
941 ps_moveto(out, xx, y0);
942 y = 0;
943 bMap1 = (!mat2 || (x < y || (x == y && bFirstDiag)));
944 if ((bDiag) || (x != y))
946 col = mat[i].matrix[x][y];
948 else
950 col = -1;
952 for (nexty = 1; (nexty <= mat[i].ny); nexty++)
954 bNextMap1 = (!mat2 || (x < nexty || (x == nexty && bFirstDiag)));
955 /* TRUE: upper left -> map1 */
956 /* FALSE: lower right -> map2 */
957 if ((nexty == mat[i].ny) || (!bDiag && (x == nexty)))
959 nextcol = -1;
961 else
963 nextcol = mat[i].matrix[x][nexty];
965 if ( (nexty == mat[i].ny) || (col != nextcol) || (bMap1 != bNextMap1) )
967 if (col >= 0)
969 if (bMap1)
971 ps_rgb_nbox(out, &(mat[i].map[col].rgb), nexty-y);
973 else
975 ps_rgb_nbox(out, &(mat2[i].map[col].rgb), nexty-y);
978 else
980 ps_moverel(out, 0, psr->yboxsize);
982 y = nexty;
983 bMap1 = bNextMap1;
984 col = nextcol;
988 y0 += box_height(&(mat[i]), psr)+box_dh(psr)+box_dh_top(IS_ONCE, psr);
991 if (psr->X.lineatzero || psr->Y.lineatzero)
993 /* reset y0 for first box */
994 y0 = dh;
995 ps_comment(out, "Here starts the zero lines drawing");
996 draw_zerolines(out, x0, y0, w, nmat, mat, psr);
999 if (elegend != elNone)
1001 ps_comment(out, "Now it's legend time!");
1002 ps_linewidth(out, static_cast<int>(psr->linewidth));
1003 if (mat2 == NULL || elegend != elSecond)
1005 bDiscrete = mat[0].bDiscrete;
1006 legend = mat[0].legend;
1007 leg_nmap = nmap1;
1008 leg_map = map1;
1010 else
1012 bDiscrete = mat2[0].bDiscrete;
1013 legend = mat2[0].legend;
1014 leg_nmap = nmap2;
1015 leg_map = map2;
1017 if (bDiscrete)
1019 leg_discrete(out, psr->legfontsize, DDD, legend,
1020 psr->legfontsize, psr->legfont, leg_nmap, leg_map);
1022 else
1024 if (elegend != elBoth)
1026 leg_continuous(out, x0+w/2, w/2, DDD, legend,
1027 psr->legfontsize, psr->legfont, leg_nmap, leg_map,
1028 mapoffset);
1030 else
1032 leg_bicontinuous(out, x0+w/2, w, DDD, mat[0].legend, mat2[0].legend,
1033 psr->legfontsize, psr->legfont, nmap1, map1, nmap2, map2);
1036 ps_comment(out, "Were there, dude");
1039 ps_close(out);
1042 void make_axis_labels(int nmat, t_matrix *mat)
1044 int i, j;
1046 for (i = 0; (i < nmat); i++)
1048 /* Make labels for x axis */
1049 if (mat[i].axis_x == NULL)
1051 snew(mat[i].axis_x, mat[i].nx);
1052 for (j = 0; (j < mat[i].nx); j++)
1054 mat[i].axis_x[j] = j;
1057 /* Make labels for y axis */
1058 if (mat[i].axis_y == NULL)
1060 snew(mat[i].axis_y, mat[i].ny);
1061 for (j = 0; (j < mat[i].ny); j++)
1063 mat[i].axis_y[j] = j;
1069 void prune_mat(int nmat, t_matrix *mat, t_matrix *mat2, int skip)
1071 int i, x, y, xs, ys;
1073 for (i = 0; i < nmat; i++)
1075 fprintf(stderr, "converting %dx%d matrix to %dx%d\n",
1076 mat[i].nx, mat[i].ny,
1077 (mat[i].nx+skip-1)/skip, (mat[i].ny+skip-1)/skip);
1078 /* walk through matrix */
1079 xs = 0;
1080 for (x = 0; (x < mat[i].nx); x++)
1082 if (x % skip == 0)
1084 mat[i].axis_x[xs] = mat[i].axis_x[x];
1085 if (mat2)
1087 mat2[i].axis_x[xs] = mat2[i].axis_x[x];
1089 ys = 0;
1090 for (y = 0; (y < mat[i].ny); y++)
1092 if (x == 0)
1094 mat[i].axis_y[ys] = mat[i].axis_y[y];
1095 if (mat2)
1097 mat2[i].axis_y[ys] = mat2[i].axis_y[y];
1100 if (y % skip == 0)
1102 mat[i].matrix[xs][ys] = mat[i].matrix[x][y];
1103 if (mat2)
1105 mat2[i].matrix[xs][ys] = mat2[i].matrix[x][y];
1107 ys++;
1110 xs++;
1113 /* adjust parameters */
1114 mat[i].nx = (mat[i].nx+skip-1)/skip;
1115 mat[i].ny = (mat[i].ny+skip-1)/skip;
1116 if (mat2)
1118 mat2[i].nx = (mat2[i].nx+skip-1)/skip;
1119 mat2[i].ny = (mat2[i].ny+skip-1)/skip;
1124 void zero_lines(int nmat, t_matrix *mat, t_matrix *mat2)
1126 int i, x, y, m;
1127 t_matrix *mats;
1129 for (i = 0; i < nmat; i++)
1131 for (m = 0; m < (mat2 ? 2 : 1); m++)
1133 if (m == 0)
1135 mats = mat;
1137 else
1139 mats = mat2;
1141 for (x = 0; x < mats[i].nx-1; x++)
1143 if (std::abs(mats[i].axis_x[x+1]) < 1e-5)
1145 for (y = 0; y < mats[i].ny; y++)
1147 mats[i].matrix[x][y] = 0;
1151 for (y = 0; y < mats[i].ny-1; y++)
1153 if (std::abs(mats[i].axis_y[y+1]) < 1e-5)
1155 for (x = 0; x < mats[i].nx; x++)
1157 mats[i].matrix[x][y] = 0;
1165 void write_combined_matrix(int ecombine, const char *fn,
1166 int nmat, t_matrix *mat1, t_matrix *mat2,
1167 real *cmin, real *cmax)
1169 int i, j, k, nlevels;
1170 FILE *out;
1171 real **rmat1, **rmat2;
1172 real rhi, rlo;
1174 out = gmx_ffopen(fn, "w");
1175 for (k = 0; k < nmat; k++)
1177 if (mat2[k].nx != mat1[k].nx || mat2[k].ny != mat1[k].ny)
1179 gmx_fatal(FARGS, "Size of frame %d in 1st (%dx%d) and 2nd matrix (%dx%d) do"
1180 " not match.\n", k, mat1[k].nx, mat1[k].ny, mat2[k].nx, mat2[k].ny);
1182 printf("Combining two %dx%d matrices\n", mat1[k].nx, mat1[k].ny);
1183 rmat1 = matrix2real(&mat1[k], NULL);
1184 rmat2 = matrix2real(&mat2[k], NULL);
1185 if (NULL == rmat1 || NULL == rmat2)
1187 gmx_fatal(FARGS, "Could not extract real data from %s xpm matrices. Note that, e.g.,\n"
1188 "g_rms and g_mdmat provide such data, but not do_dssp.\n",
1189 (NULL == rmat1 && NULL == rmat2) ? "both" : "one of the" );
1191 rlo = 1e38;
1192 rhi = -1e38;
1193 for (j = 0; j < mat1[k].ny; j++)
1195 for (i = 0; i < mat1[k].nx; i++)
1197 switch (ecombine)
1199 case ecAdd: rmat1[i][j] += rmat2[i][j]; break;
1200 case ecSub: rmat1[i][j] -= rmat2[i][j]; break;
1201 case ecMult: rmat1[i][j] *= rmat2[i][j]; break;
1202 case ecDiv: rmat1[i][j] /= rmat2[i][j]; break;
1203 default:
1204 gmx_fatal(FARGS, "No such combination rule %d for matrices", ecombine);
1206 rlo = std::min(rlo, rmat1[i][j]);
1207 rhi = std::max(rhi, rmat1[i][j]);
1210 if (cmin)
1212 rlo = *cmin;
1214 if (cmax)
1216 rhi = *cmax;
1218 nlevels = std::max(mat1[k].nmap, mat2[k].nmap);
1219 if (rhi == rlo)
1221 fprintf(stderr,
1222 "combination results in uniform matrix (%g), no output\n", rhi);
1225 else if (rlo>=0 || rhi<=0)
1226 write_xpm(out, mat1[k].flags, mat1[k].title, mat1[k].legend,
1227 mat1[k].label_x, mat1[k].label_y,
1228 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1229 rmat1, rlo, rhi, rhi<=0?red:white, rhi<=0?white:blue,
1230 &nlevels);
1231 else
1232 write_xpm3(out, mat2[k].flags, mat1[k].title, mat1[k].legend,
1233 mat1[k].label_x, mat1[k].label_y,
1234 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1235 rmat1, rlo, 0, rhi, red, white, blue, &nlevels);
1237 else
1239 write_xpm(out, mat1[k].flags, mat1[k].title, mat1[k].legend,
1240 mat1[k].label_x, mat1[k].label_y,
1241 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1242 rmat1, rlo, rhi, white, black, &nlevels);
1245 gmx_ffclose(out);
1248 void do_mat(int nmat, t_matrix *mat, t_matrix *mat2,
1249 gmx_bool bFrame, gmx_bool bZeroLine, gmx_bool bDiag, gmx_bool bFirstDiag, gmx_bool bTitle,
1250 gmx_bool bTitleOnce, gmx_bool bYonce, int elegend,
1251 real size, real boxx, real boxy,
1252 const char *epsfile, const char *xpmfile, const char *m2p,
1253 const char *m2pout, int skip, int mapoffset)
1255 int i, j, k;
1257 if (mat2)
1259 for (k = 0; (k < nmat); k++)
1261 if ((mat2[k].nx != mat[k].nx) || (mat2[k].ny != mat[k].ny))
1263 gmx_fatal(FARGS, "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",
1264 k, mat2[k].nx, mat2[k].ny, mat[k].nx, mat[k].ny);
1266 for (j = 0; (j < mat[k].ny); j++)
1268 for (i = bFirstDiag ? j+1 : j; (i < mat[k].nx); i++)
1270 mat[k].matrix[i][j] = mat2[k].matrix[i][j];
1275 for (i = 0; (i < nmat); i++)
1277 fprintf(stderr, "Matrix %d is %d x %d\n", i, mat[i].nx, mat[i].ny);
1280 make_axis_labels(nmat, mat);
1282 if (skip > 1)
1284 prune_mat(nmat, mat, mat2, skip);
1287 if (bZeroLine)
1289 zero_lines(nmat, mat, mat);
1292 if (epsfile != NULL)
1294 ps_mat(epsfile, nmat, mat, mat2, bFrame, bDiag, bFirstDiag,
1295 bTitle, bTitleOnce, bYonce, elegend,
1296 size, boxx, boxy, m2p, m2pout, mapoffset);
1298 if (xpmfile != NULL)
1300 xpm_mat(xpmfile, nmat, mat, mat2, bDiag, bFirstDiag);
1304 void gradient_map(rvec grad, int nmap, t_mapping map[])
1306 int i;
1307 real c;
1309 for (i = 0; i < nmap; i++)
1311 c = i/(nmap-1.0);
1312 map[i].rgb.r = 1-c*(1-grad[XX]);
1313 map[i].rgb.g = 1-c*(1-grad[YY]);
1314 map[i].rgb.b = 1-c*(1-grad[ZZ]);
1318 void gradient_mat(rvec grad, int nmat, t_matrix mat[])
1320 int m;
1322 for (m = 0; m < nmat; m++)
1324 gradient_map(grad, mat[m].nmap, mat[m].map);
1328 void rainbow_map(gmx_bool bBlue, int nmap, t_mapping map[])
1330 int i;
1331 real c, r, g, b;
1333 for (i = 0; i < nmap; i++)
1335 c = (map[i].rgb.r + map[i].rgb.g + map[i].rgb.b)/3;
1336 if (c > 1)
1338 c = 1;
1340 if (bBlue)
1342 c = 1 - c;
1344 if (c <= 0.25) /* 0-0.25 */
1346 r = 0;
1347 g = std::pow(4.0*c, 2.0/3.0);
1348 b = 1;
1350 else if (c <= 0.5) /* 0.25-0.5 */
1352 r = 0;
1353 g = 1;
1354 b = std::pow(2.0-4.0*c, 2.0/3.0);
1356 else if (c <= 0.75) /* 0.5-0.75 */
1358 r = std::pow(4.0*c-2.0, 2.0/3.0);
1359 g = 1;
1360 b = 0;
1362 else /* 0.75-1 */
1364 r = 1;
1365 g = std::pow(4.0-4.0*c, 2.0/3.0);
1366 b = 0;
1368 map[i].rgb.r = r;
1369 map[i].rgb.g = g;
1370 map[i].rgb.b = b;
1374 void rainbow_mat(gmx_bool bBlue, int nmat, t_matrix mat[])
1376 int m;
1378 for (m = 0; m < nmat; m++)
1380 rainbow_map(bBlue, mat[m].nmap, mat[m].map);
1384 int gmx_xpm2ps(int argc, char *argv[])
1386 const char *desc[] = {
1387 "[THISMODULE] makes a beautiful color plot of an XPixelMap file.",
1388 "Labels and axis can be displayed, when they are supplied",
1389 "in the correct matrix format.",
1390 "Matrix data may be generated by programs such as [gmx-do_dssp], [gmx-rms] or",
1391 "[gmx-mdmat].[PAR]",
1392 "Parameters are set in the [TT].m2p[tt] file optionally supplied with",
1393 "[TT]-di[tt]. Reasonable defaults are provided. Settings for the [IT]y[it]-axis",
1394 "default to those for the [IT]x[it]-axis. Font names have a defaulting hierarchy:",
1395 "titlefont -> legendfont; titlefont -> (xfont -> yfont -> ytickfont)",
1396 "-> xtickfont, e.g. setting titlefont sets all fonts, setting xfont",
1397 "sets yfont, ytickfont and xtickfont.[PAR]",
1398 "When no [TT].m2p[tt] file is supplied, many settings are taken from",
1399 "command line options. The most important option is [TT]-size[tt],",
1400 "which sets the size of the whole matrix in postscript units.",
1401 "This option can be overridden with the [TT]-bx[tt] and [TT]-by[tt]",
1402 "options (and the corresponding parameters in the [TT].m2p[tt] file),",
1403 "which set the size of a single matrix element.[PAR]",
1404 "With [TT]-f2[tt] a second matrix file can be supplied. Both matrix",
1405 "files will be read simultaneously and the upper left half of the",
1406 "first one ([TT]-f[tt]) is plotted together with the lower right",
1407 "half of the second one ([TT]-f2[tt]). The diagonal will contain",
1408 "values from the matrix file selected with [TT]-diag[tt].",
1409 "Plotting of the diagonal values can be suppressed altogether by",
1410 "setting [TT]-diag[tt] to [TT]none[tt].",
1411 "In this case, a new color map will be generated with",
1412 "a red gradient for negative numbers and a blue for positive.",
1413 "If the color coding and legend labels of both matrices are identical,",
1414 "only one legend will be displayed, else two separate legends are",
1415 "displayed.",
1416 "With [TT]-combine[tt], an alternative operation can be selected",
1417 "to combine the matrices. The output range is automatically set",
1418 "to the actual range of the combined matrix. This can be overridden",
1419 "with [TT]-cmin[tt] and [TT]-cmax[tt].[PAR]",
1420 "[TT]-title[tt] can be set to [TT]none[tt] to suppress the title, or to",
1421 "[TT]ylabel[tt] to show the title in the Y-label position (alongside",
1422 "the [IT]y[it]-axis).[PAR]",
1423 "With the [TT]-rainbow[tt] option, dull grayscale matrices can be turned",
1424 "into attractive color pictures.[PAR]",
1425 "Merged or rainbowed matrices can be written to an XPixelMap file with",
1426 "the [TT]-xpm[tt] option."
1429 output_env_t oenv;
1430 const char *fn, *epsfile = NULL, *xpmfile = NULL;
1431 int i, nmat, nmat2, etitle, elegend, ediag, erainbow, ecombine;
1432 t_matrix *mat = NULL, *mat2 = NULL;
1433 gmx_bool bTitle, bTitleOnce, bDiag, bFirstDiag, bGrad;
1434 static gmx_bool bFrame = TRUE, bZeroLine = FALSE, bYonce = FALSE;
1435 static real size = 400, boxx = 0, boxy = 0, cmin = 0, cmax = 0;
1436 static rvec grad = {0, 0, 0};
1437 enum {
1438 etSel, etTop, etOnce, etYlabel, etNone, etNR
1440 const char *title[] = { NULL, "top", "once", "ylabel", "none", NULL };
1441 /* MUST correspond to enum elXxx as defined at top of file */
1442 const char *legend[] = { NULL, "both", "first", "second", "none", NULL };
1443 enum {
1444 edSel, edFirst, edSecond, edNone, edNR
1446 const char *diag[] = { NULL, "first", "second", "none", NULL };
1447 enum {
1448 erSel, erNo, erBlue, erRed, erNR
1450 const char *rainbow[] = { NULL, "no", "blue", "red", NULL };
1451 /* MUST correspond to enum ecXxx as defined at top of file */
1452 const char *combine[] = {
1453 NULL, "halves", "add", "sub", "mult", "div", NULL
1455 static int skip = 1, mapoffset = 0;
1456 t_pargs pa[] = {
1457 { "-frame", FALSE, etBOOL, {&bFrame},
1458 "Display frame, ticks, labels, title and legend" },
1459 { "-title", FALSE, etENUM, {title}, "Show title at" },
1460 { "-yonce", FALSE, etBOOL, {&bYonce}, "Show y-label only once" },
1461 { "-legend", FALSE, etENUM, {legend}, "Show legend" },
1462 { "-diag", FALSE, etENUM, {diag}, "Diagonal" },
1463 { "-size", FALSE, etREAL, {&size},
1464 "Horizontal size of the matrix in ps units" },
1465 { "-bx", FALSE, etREAL, {&boxx},
1466 "Element x-size, overrides [TT]-size[tt] (also y-size when [TT]-by[tt] is not set)" },
1467 { "-by", FALSE, etREAL, {&boxy}, "Element y-size" },
1468 { "-rainbow", FALSE, etENUM, {rainbow},
1469 "Rainbow colors, convert white to" },
1470 { "-gradient", FALSE, etRVEC, {grad},
1471 "Re-scale colormap to a smooth gradient from white {1,1,1} to {r,g,b}" },
1472 { "-skip", FALSE, etINT, {&skip},
1473 "only write out every nr-th row and column" },
1474 { "-zeroline", FALSE, etBOOL, {&bZeroLine},
1475 "insert line in [REF].xpm[ref] matrix where axis label is zero"},
1476 { "-legoffset", FALSE, etINT, {&mapoffset},
1477 "Skip first N colors from [REF].xpm[ref] file for the legend" },
1478 { "-combine", FALSE, etENUM, {combine}, "Combine two matrices" },
1479 { "-cmin", FALSE, etREAL, {&cmin}, "Minimum for combination output" },
1480 { "-cmax", FALSE, etREAL, {&cmax}, "Maximum for combination output" }
1482 #define NPA asize(pa)
1483 t_filenm fnm[] = {
1484 { efXPM, "-f", NULL, ffREAD },
1485 { efXPM, "-f2", "root2", ffOPTRD },
1486 { efM2P, "-di", NULL, ffLIBOPTRD },
1487 { efM2P, "-do", "out", ffOPTWR },
1488 { efEPS, "-o", NULL, ffOPTWR },
1489 { efXPM, "-xpm", NULL, ffOPTWR }
1491 #define NFILE asize(fnm)
1493 if (!parse_common_args(&argc, argv, PCA_CAN_VIEW,
1494 NFILE, fnm, NPA, pa,
1495 asize(desc), desc, 0, NULL, &oenv))
1497 return 0;
1500 etitle = nenum(title);
1501 elegend = nenum(legend);
1502 ediag = nenum(diag);
1503 erainbow = nenum(rainbow);
1504 ecombine = nenum(combine);
1505 bGrad = opt2parg_bSet("-gradient", NPA, pa);
1506 for (i = 0; i < DIM; i++)
1508 if (grad[i] < 0 || grad[i] > 1)
1510 gmx_fatal(FARGS, "RGB value %g out of range (0.0-1.0)", grad[i]);
1513 if (!bFrame)
1515 etitle = etNone;
1516 elegend = elNone;
1519 epsfile = ftp2fn_null(efEPS, NFILE, fnm);
1520 xpmfile = opt2fn_null("-xpm", NFILE, fnm);
1521 if (epsfile == NULL && xpmfile == NULL)
1523 if (ecombine != ecHalves)
1525 xpmfile = opt2fn("-xpm", NFILE, fnm);
1527 else
1529 epsfile = ftp2fn(efEPS, NFILE, fnm);
1532 if (ecombine != ecHalves && epsfile)
1534 fprintf(stderr,
1535 "WARNING: can only write result of arithmetic combination "
1536 "of two matrices to .xpm file\n"
1537 " file %s will not be written\n", epsfile);
1538 epsfile = NULL;
1541 bDiag = ediag != edNone;
1542 bFirstDiag = ediag != edSecond;
1544 fn = opt2fn("-f", NFILE, fnm);
1545 nmat = read_xpm_matrix(fn, &mat);
1546 fprintf(stderr, "There %s %d matri%s in %s\n", (nmat > 1) ? "are" : "is", nmat, (nmat > 1) ? "ces" : "x", fn);
1547 fn = opt2fn_null("-f2", NFILE, fnm);
1548 if (fn)
1550 nmat2 = read_xpm_matrix(fn, &mat2);
1551 fprintf(stderr, "There %s %d matri%s in %s\n", (nmat2 > 1) ? "are" : "is", nmat2, (nmat2 > 1) ? "ces" : "x", fn);
1552 if (nmat != nmat2)
1554 fprintf(stderr, "Different number of matrices, using the smallest number.\n");
1555 nmat = nmat2 = std::min(nmat, nmat2);
1558 else
1560 if (ecombine != ecHalves)
1562 fprintf(stderr,
1563 "WARNING: arithmetic matrix combination selected (-combine), "
1564 "but no second matrix (-f2) supplied\n"
1565 " no matrix combination will be performed\n");
1567 ecombine = 0;
1568 nmat2 = 0;
1570 bTitle = etitle == etTop;
1571 bTitleOnce = etitle == etOnce;
1572 if (etitle == etYlabel)
1574 for (i = 0; (i < nmat); i++)
1576 std::strcpy(mat[i].label_y, mat[i].title);
1577 if (mat2)
1579 std::strcpy(mat2[i].label_y, mat2[i].title);
1583 if (bGrad)
1585 gradient_mat(grad, nmat, mat);
1586 if (mat2)
1588 gradient_mat(grad, nmat2, mat2);
1591 if (erainbow != erNo)
1593 rainbow_mat(erainbow == erBlue, nmat, mat);
1594 if (mat2)
1596 rainbow_mat(erainbow == erBlue, nmat2, mat2);
1600 if ((mat2 == NULL) && (elegend != elNone))
1602 elegend = elFirst;
1605 if (ecombine && ecombine != ecHalves)
1607 write_combined_matrix(ecombine, xpmfile, nmat, mat, mat2,
1608 opt2parg_bSet("-cmin", NPA, pa) ? &cmin : NULL,
1609 opt2parg_bSet("-cmax", NPA, pa) ? &cmax : NULL);
1611 else
1613 do_mat(nmat, mat, mat2, bFrame, bZeroLine, bDiag, bFirstDiag,
1614 bTitle, bTitleOnce, bYonce,
1615 elegend, size, boxx, boxy, epsfile, xpmfile,
1616 opt2fn_null("-di", NFILE, fnm), opt2fn_null("-do", NFILE, fnm), skip,
1617 mapoffset);
1620 view_all(oenv, NFILE, fnm);
1622 return 0;