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.
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"
75 char tickfont
[STRLEN
];
90 char leglabel
[STRLEN
];
91 char leg2label
[STRLEN
];
101 /* MUST correspond to char *legend[] in main() */
103 elSel
, elBoth
, elFirst
, elSecond
, elNone
, elNR
106 /* MUST correspond to char *combine[] in main() */
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
};
121 wi
= init_warning(FALSE
, 0);
125 inp
= read_inpfile(mpin
, &ninp
, wi
);
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
);
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
)
192 gmx_bool bDiff
, bColDiff
= FALSE
;
201 for (i
= 0; i
< nmap1
; i
++)
203 if (!matelmt_cmp(map1
[i
].code
, map2
[i
].code
))
207 if (std::strcmp(map1
[i
].desc
, map2
[i
].desc
) != 0)
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
))
218 if (!bDiff
&& bColDiff
)
220 fprintf(stderr
, "Warning: two colormaps differ only in RGB value, using one colormap.\n");
227 void leg_discrete(t_psdata ps
, real x0
, real y0
, char *label
,
228 real fontsize
, char *font
, int nmap
, t_mapping map
[])
234 boxhh
= fontsize
+DDD
;
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
++)
247 ps_rgb(ps
, &(map
[i
].rgb
));
248 ps_fillbox(ps
, DDD
, DDD
, DDD
+fontsize
, boxhh
-DDD
);
250 ps_box(ps
, DDD
, DDD
, DDD
+fontsize
, boxhh
-DDD
);
251 ps_ctext(ps
, boxhh
+2*DDD
, fontsize
/3, map
[i
].desc
, eXLeft
);
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
[],
264 real yhh
, boxxh
, boxyh
;
271 boxxh
= x
/(nmap
-mapoffset
);
272 if (boxxh
> fontsize
)
277 GMX_RELEASE_ASSERT(map
!= NULL
, "NULL map array provided to leg_continuous()");
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
);
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
)
332 if (psr
->bTitle
|| (psr
->bTitleOnce
&& bOnce
) )
334 dh
= 2*psr
->titfontsize
;
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
)
360 char **xtick
, **ytick
;
361 real xx
, yy
, dy
, xx00
, yy00
, offset_x
, offset_y
;
362 int i
, j
, x
, y
, ntx
, nty
;
365 /* Only necessary when there will be no y-labels */
370 ps_linewidth(ps
, static_cast<int>(psr
->boxlinewidth
));
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
));
383 for (i
= 0; (i
< nmat
); i
++)
385 if (mat
[i
].flags
& MAT_SPATIAL_X
)
395 if (mat
[i
].flags
& MAT_SPATIAL_Y
)
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 */
425 yy00
-DDD
-psr
->X
.majorticklen
-psr
->X
.tickfontsize
*0.8,
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
);
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)))
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
) )
464 ps_line(ps
, xx00
, yy
, xx00
-psr
->Y
.minorticklen
, yy
);
470 /* Label on Y-axis */
471 if (!psr
->bYonce
|| i
== nmat
/2)
473 if (strlen(psr
->Y
.label
) > 0)
475 mylab
= psr
->Y
.label
;
479 mylab
= mat
[i
].label_y
;
481 if (strlen(mylab
) > 0)
483 ps_strfont(ps
, psr
->Y
.font
, psr
->Y
.fontsize
);
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
,
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
;
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
;
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
)
563 real ww
, hh
, dww
, dhh
;
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
);
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
);
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
);
619 hh
+= (nmat
-1)*box_dh_top(FALSE
, psr
);
628 int add_maps(t_mapping
**newmap
,
629 int nmap1
, t_mapping map1
[], int nmap2
, t_mapping map2
[])
631 static char mapper
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+{}|;:',<.>/?";
636 nsymbols
= std::strlen(mapper
);
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",
645 for (j
= 0; j
< nmap1
; j
++)
647 map
[j
].code
.c1
= mapper
[j
% 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
++)
660 map
[k
].code
.c1
= mapper
[k
% 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
;
675 void xpm_mat(const char *outf
, int nmat
, t_matrix
*mat
, t_matrix
*mat2
,
676 gmx_bool bDiag
, gmx_bool bFirstDiag
)
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]);
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
;
712 mat
[i
].matrix
[x
][y
] = 0;
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
]);
733 static void tick_spacing(int n
, real axis
[], real offset
, char axisnm
,
734 real
*major
, real
*minor
)
738 int i
, j
, t
, f
= 0, ten
;
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);
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: */
755 for (j
= 0; j
< n
; j
++)
757 if (bRmod(axis
[j
], offset
, space
) )
762 /* do we have a reasonable number of ticks ? */
763 bTryAgain
= (i
> std::min(10, n
-1)) || (i
< 5);
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",
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
,
785 char buf
[256], *legend
;
789 int i
, x
, y
, col
, leg
= 0;
792 int nmap1
= 0, nmap2
= 0, leg_nmap
;
793 t_mapping
*map1
= NULL
, *map2
= NULL
, *leg_map
;
794 gmx_bool bMap1
, bNextMap1
, bDiscrete
;
797 libm2p
= m2p
? gmxlibfn(m2p
) : m2p
;
798 get_params(libm2p
, m2pout
, &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;
825 psr
->xboxsize
= boxx
;
826 psr
->yboxsize
= boxx
;
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
);
845 for (i
= 0; (i
< nmat
); i
++)
847 if (mat
[i
].nmap
> nmap1
)
856 printf("Selected legend of matrix # %d for display\n", leg
);
861 for (i
= 0; (i
< nmat
); i
++)
863 if (mat2
[i
].nmap
> nmap2
)
865 nmap2
= mat2
[i
].nmap
;
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
);
896 x
= static_cast<int>(W
+psr
->xoffs
);
897 y
= static_cast<int>(H
+psr
->yoffs
);
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
);
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 */
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
);
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
,
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
++)
940 xx
= x0
+x
*psr
->xboxsize
;
941 ps_moveto(out
, xx
, y0
);
943 bMap1
= (!mat2
|| (x
< y
|| (x
== y
&& bFirstDiag
)));
944 if ((bDiag
) || (x
!= y
))
946 col
= mat
[i
].matrix
[x
][y
];
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
)))
963 nextcol
= mat
[i
].matrix
[x
][nexty
];
965 if ( (nexty
== mat
[i
].ny
) || (col
!= nextcol
) || (bMap1
!= bNextMap1
) )
971 ps_rgb_nbox(out
, &(mat
[i
].map
[col
].rgb
), nexty
-y
);
975 ps_rgb_nbox(out
, &(mat2
[i
].map
[col
].rgb
), nexty
-y
);
980 ps_moverel(out
, 0, psr
->yboxsize
);
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 */
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
;
1012 bDiscrete
= mat2
[0].bDiscrete
;
1013 legend
= mat2
[0].legend
;
1019 leg_discrete(out
, psr
->legfontsize
, DDD
, legend
,
1020 psr
->legfontsize
, psr
->legfont
, leg_nmap
, leg_map
);
1024 if (elegend
!= elBoth
)
1026 leg_continuous(out
, x0
+w
/2, w
/2, DDD
, legend
,
1027 psr
->legfontsize
, psr
->legfont
, leg_nmap
, leg_map
,
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");
1042 void make_axis_labels(int nmat
, t_matrix
*mat
)
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 */
1080 for (x
= 0; (x
< mat
[i
].nx
); x
++)
1084 mat
[i
].axis_x
[xs
] = mat
[i
].axis_x
[x
];
1087 mat2
[i
].axis_x
[xs
] = mat2
[i
].axis_x
[x
];
1090 for (y
= 0; (y
< mat
[i
].ny
); y
++)
1094 mat
[i
].axis_y
[ys
] = mat
[i
].axis_y
[y
];
1097 mat2
[i
].axis_y
[ys
] = mat2
[i
].axis_y
[y
];
1102 mat
[i
].matrix
[xs
][ys
] = mat
[i
].matrix
[x
][y
];
1105 mat2
[i
].matrix
[xs
][ys
] = mat2
[i
].matrix
[x
][y
];
1113 /* adjust parameters */
1114 mat
[i
].nx
= (mat
[i
].nx
+skip
-1)/skip
;
1115 mat
[i
].ny
= (mat
[i
].ny
+skip
-1)/skip
;
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
)
1129 for (i
= 0; i
< nmat
; i
++)
1131 for (m
= 0; m
< (mat2
? 2 : 1); m
++)
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
;
1171 real
**rmat1
, **rmat2
;
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" );
1193 for (j
= 0; j
< mat1
[k
].ny
; j
++)
1195 for (i
= 0; i
< mat1
[k
].nx
; i
++)
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;
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
]);
1218 nlevels
= std::max(mat1
[k
].nmap
, mat2
[k
].nmap
);
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,
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);
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
);
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
)
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
);
1284 prune_mat(nmat
, mat
, mat2
, skip
);
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
[])
1309 for (i
= 0; i
< nmap
; i
++)
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
[])
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
[])
1333 for (i
= 0; i
< nmap
; i
++)
1335 c
= (map
[i
].rgb
.r
+ map
[i
].rgb
.g
+ map
[i
].rgb
.b
)/3;
1344 if (c
<= 0.25) /* 0-0.25 */
1347 g
= std::pow(4.0*c
, 2.0/3.0);
1350 else if (c
<= 0.5) /* 0.25-0.5 */
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);
1365 g
= std::pow(4.0-4.0*c
, 2.0/3.0);
1374 void rainbow_mat(gmx_bool bBlue
, int nmat
, t_matrix mat
[])
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",
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."
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};
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
};
1444 edSel
, edFirst
, edSecond
, edNone
, edNR
1446 const char *diag
[] = { NULL
, "first", "second", "none", NULL
};
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;
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)
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
))
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
]);
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
);
1529 epsfile
= ftp2fn(efEPS
, NFILE
, fnm
);
1532 if (ecombine
!= ecHalves
&& epsfile
)
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
);
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
);
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
);
1554 fprintf(stderr
, "Different number of matrices, using the smallest number.\n");
1555 nmat
= nmat2
= std::min(nmat
, nmat2
);
1560 if (ecombine
!= ecHalves
)
1563 "WARNING: arithmetic matrix combination selected (-combine), "
1564 "but no second matrix (-f2) supplied\n"
1565 " no matrix combination will be performed\n");
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
);
1579 std::strcpy(mat2
[i
].label_y
, mat2
[i
].title
);
1585 gradient_mat(grad
, nmat
, mat
);
1588 gradient_mat(grad
, nmat2
, mat2
);
1591 if (erainbow
!= erNo
)
1593 rainbow_mat(erainbow
== erBlue
, nmat
, mat
);
1596 rainbow_mat(erainbow
== erBlue
, nmat2
, mat2
);
1600 if ((mat2
== NULL
) && (elegend
!= elNone
))
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
);
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
,
1620 view_all(oenv
, NFILE
, fnm
);