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,2016,2017,2018,2019, 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.
48 #include "gromacs/commandline/pargs.h"
49 #include "gromacs/commandline/viewit.h"
50 #include "gromacs/fileio/matio.h"
51 #include "gromacs/fileio/readinp.h"
52 #include "gromacs/fileio/trxio.h"
53 #include "gromacs/fileio/warninp.h"
54 #include "gromacs/fileio/writeps.h"
55 #include "gromacs/gmxana/gmx_ana.h"
56 #include "gromacs/utility/arraysize.h"
57 #include "gromacs/utility/cstringutil.h"
58 #include "gromacs/utility/exceptions.h"
59 #include "gromacs/utility/fatalerror.h"
60 #include "gromacs/utility/filestream.h"
61 #include "gromacs/utility/futil.h"
62 #include "gromacs/utility/gmxassert.h"
63 #include "gromacs/utility/smalloc.h"
64 #include "gromacs/utility/stringutil.h"
81 char tickfont
[STRLEN
];
96 char leglabel
[STRLEN
];
97 char leg2label
[STRLEN
];
107 /* MUST correspond to char *legend[] in main() */
109 elSel
, elBoth
, elFirst
, elSecond
, elNone
, elNR
112 /* MUST correspond to char *combine[] in main() */
114 ecSel
, ecHalves
, ecAdd
, ecSub
, ecMult
, ecDiv
, ecNR
117 static void get_params(const char *mpin
, const char *mpout
, t_psrec
*psr
)
119 static const char *gmx_bools
[BOOL_NR
+1] = { "no", "yes", nullptr };
120 /* this must correspond to t_rgb *linecolors[] below */
121 static const char *colors
[] = { "none", "black", "white", nullptr };
123 std::vector
<t_inpfile
> inp
;
125 wi
= init_warning(FALSE
, 0);
129 std::string libmpin
= gmx::findLibraryFile(mpin
);
130 gmx::TextInputFile
stream(libmpin
);
131 inp
= read_inpfile(&stream
, libmpin
.c_str(), wi
);
138 psr
->bw
= get_eenum(&inp
, "black&white", gmx_bools
);
139 psr
->linewidth
= get_ereal(&inp
, "linewidth", 1.0, wi
);
140 setStringEntry(&inp
, "titlefont", psr
->titfont
, "Helvetica");
141 psr
->titfontsize
= get_ereal(&inp
, "titlefontsize", 20.0, wi
);
142 psr
->legend
= (get_eenum(&inp
, "legend", gmx_bools
) != 0);
143 setStringEntry(&inp
, "legendfont", psr
->legfont
, psr
->titfont
);
144 setStringEntry(&inp
, "legendlabel", psr
->leglabel
, "");
145 setStringEntry(&inp
, "legend2label", psr
->leg2label
, psr
->leglabel
);
146 psr
->legfontsize
= get_ereal(&inp
, "legendfontsize", 14.0, wi
);
147 psr
->xboxsize
= get_ereal(&inp
, "xbox", 0.0, wi
);
148 psr
->yboxsize
= get_ereal(&inp
, "ybox", 0.0, wi
);
149 psr
->boxspacing
= get_ereal(&inp
, "matrixspacing", 20.0, wi
);
150 psr
->xoffs
= get_ereal(&inp
, "xoffset", 0.0, wi
);
151 psr
->yoffs
= get_ereal(&inp
, "yoffset", psr
->xoffs
, wi
);
152 psr
->boxlinewidth
= get_ereal(&inp
, "boxlinewidth", psr
->linewidth
, wi
);
153 psr
->ticklinewidth
= get_ereal(&inp
, "ticklinewidth", psr
->linewidth
, wi
);
154 psr
->zerolinewidth
= get_ereal(&inp
, "zerolinewidth", psr
->ticklinewidth
, wi
);
155 psr
->X
.lineatzero
= get_eenum(&inp
, "x-lineat0value", colors
);
156 psr
->X
.major
= get_ereal(&inp
, "x-major", 1, wi
);
157 psr
->X
.minor
= get_ereal(&inp
, "x-minor", 1, wi
);
158 psr
->X
.offset
= get_ereal(&inp
, "x-firstmajor", 0.0, wi
);
159 psr
->X
.first
= (get_eenum(&inp
, "x-majorat0", gmx_bools
) != 0);
160 psr
->X
.majorticklen
= get_ereal(&inp
, "x-majorticklen", 8.0, wi
);
161 psr
->X
.minorticklen
= get_ereal(&inp
, "x-minorticklen", 4.0, wi
);
162 setStringEntry(&inp
, "x-label", psr
->X
.label
, "");
163 psr
->X
.fontsize
= get_ereal(&inp
, "x-fontsize", 16.0, wi
);
164 setStringEntry(&inp
, "x-font", psr
->X
.font
, psr
->titfont
);
165 psr
->X
.tickfontsize
= get_ereal(&inp
, "x-tickfontsize", 10.0, wi
);
166 setStringEntry(&inp
, "x-tickfont", psr
->X
.tickfont
, psr
->X
.font
);
167 psr
->Y
.lineatzero
= get_eenum(&inp
, "y-lineat0value", colors
);
168 psr
->Y
.major
= get_ereal(&inp
, "y-major", psr
->X
.major
, wi
);
169 psr
->Y
.minor
= get_ereal(&inp
, "y-minor", psr
->X
.minor
, wi
);
170 psr
->Y
.offset
= get_ereal(&inp
, "y-firstmajor", psr
->X
.offset
, wi
);
171 psr
->Y
.first
= (get_eenum(&inp
, "y-majorat0", gmx_bools
) != 0);
172 psr
->Y
.majorticklen
= get_ereal(&inp
, "y-majorticklen", psr
->X
.majorticklen
, wi
);
173 psr
->Y
.minorticklen
= get_ereal(&inp
, "y-minorticklen", psr
->X
.minorticklen
, wi
);
174 setStringEntry(&inp
, "y-label", psr
->Y
.label
, psr
->X
.label
);
175 psr
->Y
.fontsize
= get_ereal(&inp
, "y-fontsize", psr
->X
.fontsize
, wi
);
176 setStringEntry(&inp
, "y-font", psr
->Y
.font
, psr
->X
.font
);
177 psr
->Y
.tickfontsize
= get_ereal(&inp
, "y-tickfontsize", psr
->X
.tickfontsize
, wi
);
178 setStringEntry(&inp
, "y-tickfont", psr
->Y
.tickfont
, psr
->Y
.font
);
180 check_warning_error(wi
, FARGS
);
182 if (mpout
!= nullptr)
184 gmx::TextOutputFile
stream(mpout
);
185 write_inpfile(&stream
, mpout
, &inp
, TRUE
, WriteMdpHeader::yes
, wi
);
189 done_warning(wi
, FARGS
);
192 static t_rgb black
= { 0, 0, 0 };
193 static t_rgb white
= { 1, 1, 1 };
194 #define BLACK (&black)
195 /* this must correspond to *colors[] in get_params */
196 static t_rgb
*linecolors
[] = { nullptr, &black
, &white
, nullptr };
198 static gmx_bool
diff_maps(int nmap1
, t_mapping
*map1
, int nmap2
, t_mapping
*map2
)
201 gmx_bool bDiff
, bColDiff
= FALSE
;
210 for (i
= 0; i
< nmap1
; i
++)
212 if (!matelmt_cmp(map1
[i
].code
, map2
[i
].code
))
216 if (std::strcmp(map1
[i
].desc
, map2
[i
].desc
) != 0)
220 if ((map1
[i
].rgb
.r
!= map2
[i
].rgb
.r
) ||
221 (map1
[i
].rgb
.g
!= map2
[i
].rgb
.g
) ||
222 (map1
[i
].rgb
.b
!= map2
[i
].rgb
.b
))
227 if (!bDiff
&& bColDiff
)
229 fprintf(stderr
, "Warning: two colormaps differ only in RGB value, using one colormap.\n");
236 static void leg_discrete(t_psdata ps
, real x0
, real y0
, char *label
,
237 real fontsize
, char *font
, int nmap
, t_mapping map
[])
243 boxhh
= fontsize
+DDD
;
246 ps_strfont(ps
, font
, fontsize
);
247 yhh
= y0
+fontsize
+3*DDD
;
248 if (std::strlen(label
) > 0)
250 ps_ctext(ps
, x0
, yhh
, label
, eXLeft
);
252 ps_moveto(ps
, x0
, y0
);
253 for (i
= 0; (i
< nmap
); i
++)
256 ps_rgb(ps
, &(map
[i
].rgb
));
257 ps_fillbox(ps
, DDD
, DDD
, DDD
+fontsize
, boxhh
-DDD
);
259 ps_box(ps
, DDD
, DDD
, DDD
+fontsize
, boxhh
-DDD
);
260 ps_ctext(ps
, boxhh
+2*DDD
, fontsize
/3, map
[i
].desc
, eXLeft
);
262 ps_moverel(ps
, DDD
, -fontsize
/3);
266 static void leg_continuous(t_psdata ps
, real x0
, real x
, real y0
, char *label
,
267 real fontsize
, char *font
,
268 int nmap
, t_mapping map
[],
273 real yhh
, boxxh
, boxyh
;
280 boxxh
= x
/(nmap
-mapoffset
);
281 if (boxxh
> fontsize
)
286 GMX_RELEASE_ASSERT(map
!= nullptr, "NULL map array provided to leg_continuous()");
289 xx0
= x0
-((nmap
-mapoffset
)*boxxh
)/2.0;
291 for (i
= 0; (i
< nmap
-mapoffset
); i
++)
293 ps_rgb(ps
, &(map
[i
+mapoffset
].rgb
));
294 ps_fillbox(ps
, xx0
+i
*boxxh
, y0
, xx0
+(i
+1)*boxxh
, y0
+boxyh
);
296 ps_strfont(ps
, font
, fontsize
);
298 ps_box(ps
, xx0
, y0
, xx0
+(nmap
-mapoffset
)*boxxh
, y0
+boxyh
);
300 yhh
= y0
+boxyh
+3*DDD
;
301 ps_ctext(ps
, xx0
+boxxh
/2, yhh
, map
[0].desc
, eXCenter
);
302 if (std::strlen(label
) > 0)
304 ps_ctext(ps
, x0
, yhh
, label
, eXCenter
);
306 ps_ctext(ps
, xx0
+((nmap
-mapoffset
)*boxxh
)
307 - boxxh
/2, yhh
, map
[nmap
-1].desc
, eXCenter
);
310 static void leg_bicontinuous(t_psdata ps
, real x0
, real x
, real y0
, char *label1
,
311 char *label2
, real fontsize
, char *font
,
312 int nmap1
, t_mapping map1
[], int nmap2
, t_mapping map2
[])
314 real xx1
, xx2
, x1
, x2
;
316 x1
= x
/(nmap1
+nmap2
)*nmap1
; /* width of legend 1 */
317 x2
= x
/(nmap1
+nmap2
)*nmap2
; /* width of legend 2 */
318 xx1
= x0
-(x2
/2.0)-fontsize
; /* center of legend 1 */
319 xx2
= x0
+(x1
/2.0)+fontsize
; /* center of legend 2 */
320 x1
-= fontsize
/2; /* adjust width */
321 x2
-= fontsize
/2; /* adjust width */
322 leg_continuous(ps
, xx1
, x1
, y0
, label1
, fontsize
, font
, nmap1
, map1
, 0);
323 leg_continuous(ps
, xx2
, x2
, y0
, label2
, fontsize
, font
, nmap2
, map2
, 0);
326 static real
box_height(t_matrix
*mat
, t_psrec
*psr
)
328 return mat
->ny
*psr
->yboxsize
;
331 static real
box_dh(t_psrec
*psr
)
333 return psr
->boxspacing
;
336 #define IS_ONCE (i == nmat-1)
337 static real
box_dh_top(gmx_bool bOnce
, t_psrec
*psr
)
341 if (psr
->bTitle
|| (psr
->bTitleOnce
&& bOnce
) )
343 dh
= 2*psr
->titfontsize
;
353 static gmx_bool
box_do_all_x_maj_ticks(t_psrec
*psr
)
355 return (psr
->boxspacing
> (1.5*psr
->X
.majorticklen
));
358 static gmx_bool
box_do_all_x_min_ticks(t_psrec
*psr
)
360 return (psr
->boxspacing
> (1.5*psr
->X
.minorticklen
));
363 static void draw_boxes(t_psdata ps
, real x0
, real y0
, real w
,
364 int nmat
, t_matrix mat
[], t_psrec
*psr
)
369 char **xtick
, **ytick
;
370 real xx
, yy
, dy
, xx00
, yy00
, offset_x
, offset_y
;
371 int i
, j
, x
, y
, ntx
, nty
;
374 /* Only necessary when there will be no y-labels */
379 ps_linewidth(ps
, static_cast<int>(psr
->boxlinewidth
));
381 for (i
= 0; (i
< nmat
); i
++)
383 dy
= box_height(&(mat
[i
]), psr
);
384 ps_box(ps
, x0
-1, yy00
-1, x0
+w
+1, yy00
+dy
+1);
385 yy00
+= dy
+box_dh(psr
)+box_dh_top(IS_ONCE
, psr
);
388 /* Draw the ticks on the axes */
389 ps_linewidth(ps
, static_cast<int>(psr
->ticklinewidth
));
392 for (i
= 0; (i
< nmat
); i
++)
394 if (mat
[i
].flags
& MAT_SPATIAL_X
)
404 if (mat
[i
].flags
& MAT_SPATIAL_Y
)
415 for (j
= 0; (j
< ntx
); j
++)
417 sprintf(buf
, "%g", mat
[i
].axis_x
[j
]);
418 xtick
[j
] = gmx_strdup(buf
);
420 ps_strfont(ps
, psr
->X
.tickfont
, psr
->X
.tickfontsize
);
421 for (x
= 0; (x
< ntx
); x
++)
423 xx
= xx00
+ (x
+ offset_x
)*psr
->xboxsize
;
424 if ( ( bRmod(mat
[i
].axis_x
[x
], psr
->X
.offset
, psr
->X
.major
) ||
425 (psr
->X
.first
&& (x
== 0))) &&
426 ( (i
== 0) || box_do_all_x_maj_ticks(psr
) ) )
428 /* Longer tick marks */
429 ps_line (ps
, xx
, yy00
, xx
, yy00
-psr
->X
.majorticklen
);
430 /* Plot label on lowest graph only */
434 yy00
-DDD
-psr
->X
.majorticklen
-psr
->X
.tickfontsize
*0.8,
438 else if (bRmod(mat
[i
].axis_x
[x
], psr
->X
.offset
, psr
->X
.minor
) &&
439 ( (i
== 0) || box_do_all_x_min_ticks(psr
) ) )
441 /* Shorter tick marks */
442 ps_line(ps
, xx
, yy00
, xx
, yy00
-psr
->X
.minorticklen
);
444 else if (bRmod(mat
[i
].axis_x
[x
], psr
->X
.offset
, psr
->X
.major
) )
446 /* Even shorter marks, only each X.major */
447 ps_line(ps
, xx
, yy00
, xx
, yy00
-(psr
->boxspacing
/2));
450 ps_strfont(ps
, psr
->Y
.tickfont
, psr
->Y
.tickfontsize
);
452 for (j
= 0; (j
< nty
); j
++)
454 sprintf(buf
, "%g", mat
[i
].axis_y
[j
]);
455 ytick
[j
] = gmx_strdup(buf
);
458 for (y
= 0; (y
< nty
); y
++)
460 yy
= yy00
+ (y
+ offset_y
)*psr
->yboxsize
;
461 if (bRmod(mat
[i
].axis_y
[y
], psr
->Y
.offset
, psr
->Y
.major
) ||
462 (psr
->Y
.first
&& (y
== 0)))
465 strlength
= std::max(strlength
, std::strlen(ytick
[y
]));
466 ps_line (ps
, xx00
, yy
, xx00
-psr
->Y
.majorticklen
, yy
);
467 ps_ctext(ps
, xx00
-psr
->Y
.majorticklen
-DDD
,
468 yy
-psr
->Y
.tickfontsize
/3.0, ytick
[y
], eXRight
);
470 else if (bRmod(mat
[i
].axis_y
[y
], psr
->Y
.offset
, psr
->Y
.minor
) )
473 ps_line(ps
, xx00
, yy
, xx00
-psr
->Y
.minorticklen
, yy
);
479 /* Label on Y-axis */
480 if (!psr
->bYonce
|| i
== nmat
/2)
482 if (strlen(psr
->Y
.label
) > 0)
484 mylab
= psr
->Y
.label
;
488 mylab
= mat
[i
].label_y
;
490 if (strlen(mylab
) > 0)
492 ps_strfont(ps
, psr
->Y
.font
, psr
->Y
.fontsize
);
494 xxx
= x0
-psr
->X
.majorticklen
-psr
->X
.tickfontsize
*strlength
-DDD
;
495 ps_ctext(ps
, yy00
+box_height(&mat
[i
], psr
)/2.0, 612.5-xxx
,
501 yy00
+= box_height(&(mat
[i
]), psr
)+box_dh(psr
)+box_dh_top(IS_ONCE
, psr
);
503 /* Label on X-axis */
504 if (strlen(psr
->X
.label
) > 0)
506 mylab
= psr
->X
.label
;
510 mylab
= mat
[0].label_x
;
512 if (strlen(mylab
) > 0)
514 ps_strfont(ps
, psr
->X
.font
, psr
->X
.fontsize
);
515 ps_ctext(ps
, x0
+w
/2, y0
-DDD
-psr
->X
.majorticklen
-psr
->X
.tickfontsize
*FUDGE
-
516 psr
->X
.fontsize
, mylab
, eXCenter
);
520 static void draw_zerolines(t_psdata out
, real x0
, real y0
, real w
,
521 int nmat
, t_matrix mat
[], t_psrec
*psr
)
523 real xx
, yy
, dy
, xx00
, yy00
;
528 ps_linewidth(out
, static_cast<int>(psr
->zerolinewidth
));
529 for (i
= 0; (i
< nmat
); i
++)
531 dy
= box_height(&(mat
[i
]), psr
);
532 /* mat[i].axis_x and _y were already set by draw_boxes */
533 if (psr
->X
.lineatzero
)
535 ps_rgb(out
, linecolors
[psr
->X
.lineatzero
]);
536 for (x
= 0; (x
< mat
[i
].nx
); x
++)
538 xx
= xx00
+(x
+0.7)*psr
->xboxsize
;
539 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
540 if (x
!= 0 && x
< mat
[i
].nx
-1 &&
541 std::abs(mat
[i
].axis_x
[x
]) <
542 0.1*std::abs(mat
[i
].axis_x
[x
+1]-mat
[i
].axis_x
[x
]) )
544 ps_line (out
, xx
, yy00
, xx
, yy00
+dy
+2);
548 if (psr
->Y
.lineatzero
)
550 ps_rgb(out
, linecolors
[psr
->Y
.lineatzero
]);
551 for (y
= 0; (y
< mat
[i
].ny
); y
++)
553 yy
= yy00
+(y
+0.7)*psr
->yboxsize
;
554 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
555 if (y
!= 0 && y
< mat
[i
].ny
-1 &&
556 std::abs(mat
[i
].axis_y
[y
]) <
557 0.1*std::abs(mat
[i
].axis_y
[y
+1]-mat
[i
].axis_y
[y
]) )
559 ps_line (out
, xx00
, yy
, xx00
+w
+2, yy
);
563 yy00
+= box_height(&(mat
[i
]), psr
)+box_dh(psr
)+box_dh_top(IS_ONCE
, psr
);
567 static void box_dim(int nmat
, t_matrix mat
[], t_matrix
*mat2
, t_psrec
*psr
,
568 int elegend
, gmx_bool bFrame
,
569 real
*w
, real
*h
, real
*dw
, real
*dh
)
572 real ww
, hh
, dww
, dhh
;
578 for (i
= 0; (i
< nmat
); i
++)
580 ww
= std::max(ww
, mat
[i
].nx
*psr
->xboxsize
);
581 hh
+= box_height(&(mat
[i
]), psr
);
582 maxytick
= std::max(maxytick
, mat
[i
].nx
);
586 if (mat
[0].label_y
[0])
588 dww
+= 2.0*(psr
->Y
.fontsize
+DDD
);
590 if (psr
->Y
.major
> 0)
592 dww
+= psr
->Y
.majorticklen
+ DDD
+
593 psr
->Y
.tickfontsize
*(std::log(static_cast<real
>(maxytick
))/std::log(10.0));
595 else if (psr
->Y
.minor
> 0)
597 dww
+= psr
->Y
.minorticklen
;
600 if (mat
[0].label_x
[0])
602 dhh
+= psr
->X
.fontsize
+2*DDD
;
604 if ( /* fool emacs auto-indent */
605 (elegend
== elBoth
&& (mat
[0].legend
[0] || (mat2
&& mat2
[0].legend
[0]))) ||
606 (elegend
== elFirst
&& mat
[0].legend
[0]) ||
607 (elegend
== elSecond
&& (mat2
&& mat2
[0].legend
[0])) )
609 dhh
+= 2*(psr
->legfontsize
*FUDGE
+2*DDD
);
613 dhh
+= psr
->legfontsize
*FUDGE
+2*DDD
;
615 if (psr
->X
.major
> 0)
617 dhh
+= psr
->X
.tickfontsize
*FUDGE
+2*DDD
+psr
->X
.majorticklen
;
619 else if (psr
->X
.minor
> 0)
621 dhh
+= psr
->X
.minorticklen
;
624 hh
+= (nmat
-1)*box_dh(psr
);
625 hh
+= box_dh_top(TRUE
, psr
);
628 hh
+= (nmat
-1)*box_dh_top(FALSE
, psr
);
637 static int add_maps(t_mapping
**newmap
,
638 int nmap1
, t_mapping map1
[], int nmap2
, t_mapping map2
[])
640 static char mapper
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+{}|;:',<.>/?";
645 nsymbols
= std::strlen(mapper
);
647 if (nmap
> nsymbols
*nsymbols
)
649 gmx_fatal(FARGS
, "Not enough symbols to merge the two colormaps\n");
651 printf("Combining colormaps of %d and %d elements into one of %d elements\n",
654 for (j
= 0; j
< nmap1
; j
++)
656 map
[j
].code
.c1
= mapper
[j
% nsymbols
];
659 map
[j
].code
.c2
= mapper
[j
/nsymbols
];
661 map
[j
].rgb
.r
= map1
[j
].rgb
.r
;
662 map
[j
].rgb
.g
= map1
[j
].rgb
.g
;
663 map
[j
].rgb
.b
= map1
[j
].rgb
.b
;
664 map
[j
].desc
= map1
[j
].desc
;
666 for (j
= 0; j
< nmap2
; j
++)
669 map
[k
].code
.c1
= mapper
[k
% nsymbols
];
672 map
[k
].code
.c2
= mapper
[k
/nsymbols
];
674 map
[k
].rgb
.r
= map2
[j
].rgb
.r
;
675 map
[k
].rgb
.g
= map2
[j
].rgb
.g
;
676 map
[k
].rgb
.b
= map2
[j
].rgb
.b
;
677 map
[k
].desc
= map2
[j
].desc
;
684 static void xpm_mat(const char *outf
, int nmat
, t_matrix
*mat
, t_matrix
*mat2
,
685 gmx_bool bDiag
, gmx_bool bFirstDiag
)
690 t_mapping
*map
= nullptr;
692 out
= gmx_ffopen(outf
, "w");
694 for (i
= 0; i
< nmat
; i
++)
696 if (!mat2
|| !diff_maps(mat
[i
].nmap
, mat
[i
].map
, mat2
[i
].nmap
, mat2
[i
].map
))
698 write_xpm_m(out
, mat
[0]);
702 nmap
= add_maps(&map
, mat
[i
].nmap
, mat
[i
].map
, mat2
[i
].nmap
, mat2
[i
].map
);
703 for (x
= 0; (x
< mat
[i
].nx
); x
++)
705 for (y
= 0; (y
< mat
[i
].nx
); y
++)
707 if ((x
< y
) || ((x
== y
) && bFirstDiag
)) /* upper left -> map1 */
709 col
= mat
[i
].matrix
[x
][y
];
711 else /* lower right -> map2 */
713 col
= mat
[i
].nmap
+mat
[i
].matrix
[x
][y
];
715 if ((bDiag
) || (x
!= y
))
717 mat
[i
].matrix
[x
][y
] = col
;
721 mat
[i
].matrix
[x
][y
] = 0;
728 if (std::strcmp(mat
[i
].title
, mat2
[i
].title
) != 0)
730 sprintf(mat
[i
].title
+strlen(mat
[i
].title
), " / %s", mat2
[i
].title
);
732 if (std::strcmp(mat
[i
].legend
, mat2
[i
].legend
) != 0)
734 sprintf(mat
[i
].legend
+strlen(mat
[i
].legend
), " / %s", mat2
[i
].legend
);
736 write_xpm_m(out
, mat
[i
]);
742 static void tick_spacing(int n
, real axis
[], real offset
, char axisnm
,
743 real
*major
, real
*minor
)
747 int i
, j
, t
, f
= 0, ten
;
749 real major_fact
[NFACT
] = {5, 4, 2, 1};
750 real minor_fact
[NFACT
] = {5, 4, 4, 5};
752 /* start with interval between 10 matrix points: */
753 space
= std::max(10*axis
[1]-axis
[0], axis
[std::min(10, n
-1)]-axis
[0]);
754 /* get power of 10 */
755 ten
= static_cast<int>(std::ceil(std::log(space
)/std::log(10.0))-1);
757 for (t
= ten
+2; t
> ten
-3 && bTryAgain
; t
--)
759 for (f
= 0; f
< NFACT
&& bTryAgain
; f
++)
761 space
= std::pow(10.0_real
, static_cast<real
>(t
)) * major_fact
[f
];
762 /* count how many ticks we would get: */
764 for (j
= 0; j
< n
; j
++)
766 if (bRmod(axis
[j
], offset
, space
) )
771 /* do we have a reasonable number of ticks ? */
772 bTryAgain
= (i
> std::min(10, n
-1)) || (i
< 5);
777 space
= std::max(10*axis
[1]-axis
[0], axis
[std::min(10, n
-1)]-axis
[0]);
778 fprintf(stderr
, "Auto tick spacing failed for %c-axis, guessing %g\n",
782 *minor
= space
/ minor_fact
[(f
> 0) ? f
-1 : 0];
783 fprintf(stderr
, "Auto tick spacing for %c-axis: major %g, minor %g\n",
784 axisnm
, *major
, *minor
);
787 static void ps_mat(const char *outf
, int nmat
, t_matrix mat
[], t_matrix mat2
[],
788 gmx_bool bFrame
, gmx_bool bDiag
, gmx_bool bFirstDiag
,
789 gmx_bool bTitle
, gmx_bool bTitleOnce
, gmx_bool bYonce
, int elegend
,
790 real size
, real boxx
, real boxy
, const char *m2p
, const char *m2pout
,
797 int i
, x
, y
, col
, leg
= 0;
800 int nmap1
= 0, nmap2
= 0, leg_nmap
;
801 t_mapping
*map1
= nullptr, *map2
= nullptr, *leg_map
;
802 gmx_bool bMap1
, bNextMap1
, bDiscrete
;
806 get_params(m2p
, m2pout
, &psrec
);
808 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
812 if (psr
->X
.major
<= 0)
814 tick_spacing((mat
[0].flags
& MAT_SPATIAL_X
) ? mat
[0].nx
+ 1 : mat
[0].nx
,
815 mat
[0].axis_x
, psr
->X
.offset
, 'X',
816 &(psr
->X
.major
), &(psr
->X
.minor
) );
818 if (psr
->X
.minor
<= 0)
820 psr
->X
.minor
= psr
->X
.major
/ 2;
822 if (psr
->Y
.major
<= 0)
824 tick_spacing((mat
[0].flags
& MAT_SPATIAL_Y
) ? mat
[0].ny
+ 1 : mat
[0].ny
,
825 mat
[0].axis_y
, psr
->Y
.offset
, 'Y',
826 &(psr
->Y
.major
), &(psr
->Y
.minor
) );
828 if (psr
->Y
.minor
<= 0)
830 psr
->Y
.minor
= psr
->Y
.major
/ 2;
835 psr
->xboxsize
= boxx
;
836 psr
->yboxsize
= boxx
;
840 psr
->yboxsize
= boxy
;
843 if (psr
->xboxsize
== 0)
845 psr
->xboxsize
= size
/mat
[0].nx
;
846 printf("Set the x-size of the box to %.3f\n", psr
->xboxsize
);
848 if (psr
->yboxsize
== 0)
850 psr
->yboxsize
= size
/mat
[0].nx
;
851 printf("Set the y-size of the box to %.3f\n", psr
->yboxsize
);
855 for (i
= 0; (i
< nmat
); i
++)
857 if (mat
[i
].nmap
> nmap1
)
866 printf("Selected legend of matrix # %d for display\n", leg
);
871 for (i
= 0; (i
< nmat
); i
++)
873 if (mat2
[i
].nmap
> nmap2
)
875 nmap2
= mat2
[i
].nmap
;
882 printf("Selected legend of matrix # %d for second display\n", leg
);
885 if ( (mat
[0].legend
[0] == 0) && psr
->legend
)
887 std::strcpy(mat
[0].legend
, psr
->leglabel
);
890 bTitle
= bTitle
&& (mat
[nmat
-1].title
[0] != 0);
891 bTitleOnce
= bTitleOnce
&& (mat
[nmat
-1].title
[0] != 0);
892 psr
->bTitle
= bTitle
;
893 psr
->bTitleOnce
= bTitleOnce
;
894 psr
->bYonce
= bYonce
;
896 /* Set up size of box for nice colors */
897 box_dim(nmat
, mat
, mat2
, psr
, elegend
, bFrame
, &w
, &h
, &dw
, &dh
);
899 /* Set up bounding box */
900 W
= static_cast<int>(w
+dw
);
901 H
= static_cast<int>(h
+dh
);
906 x
= static_cast<int>(W
+psr
->xoffs
);
907 y
= static_cast<int>(H
+psr
->yoffs
);
913 out
= ps_open(outf
, 0, 0, x
, y
);
914 ps_linewidth(out
, static_cast<int>(psr
->linewidth
));
915 ps_init_rgb_box(out
, psr
->xboxsize
, psr
->yboxsize
);
916 ps_init_rgb_nbox(out
, psr
->xboxsize
, psr
->yboxsize
);
917 ps_translate(out
, psr
->xoffs
, psr
->yoffs
);
921 ps_comment(out
, "Here starts the BOX drawing");
922 draw_boxes(out
, x0
, y0
, w
, nmat
, mat
, psr
);
925 for (i
= 0; (i
< nmat
); i
++)
927 if (bTitle
|| (bTitleOnce
&& i
== nmat
-1) )
929 /* Print title, if any */
931 ps_strfont(out
, psr
->titfont
, psr
->titfontsize
);
933 if (!mat2
|| (std::strcmp(mat
[i
].title
, mat2
[i
].title
) == 0))
939 buf
= gmx::formatString("%s / %s", mat
[i
].title
, mat2
[i
].title
);
941 ps_ctext(out
, x0
+w
/2, y0
+box_height(&(mat
[i
]), psr
)+psr
->titfontsize
,
942 buf
.c_str(), eXCenter
);
944 ps_comment(out
, gmx::formatString("Here starts the filling of box #%d", i
).c_str());
945 for (x
= 0; (x
< mat
[i
].nx
); x
++)
950 xx
= x0
+x
*psr
->xboxsize
;
951 ps_moveto(out
, xx
, y0
);
953 bMap1
= ((mat2
== nullptr) || (x
< y
|| (x
== y
&& bFirstDiag
)));
954 if ((bDiag
) || (x
!= y
))
956 col
= mat
[i
].matrix
[x
][y
];
962 for (nexty
= 1; (nexty
<= mat
[i
].ny
); nexty
++)
964 bNextMap1
= ((mat2
== nullptr) || (x
< nexty
|| (x
== nexty
&& bFirstDiag
)));
965 /* TRUE: upper left -> map1 */
966 /* FALSE: lower right -> map2 */
967 if ((nexty
== mat
[i
].ny
) || (!bDiag
&& (x
== nexty
)))
973 nextcol
= mat
[i
].matrix
[x
][nexty
];
975 if ( (nexty
== mat
[i
].ny
) || (col
!= nextcol
) || (bMap1
!= bNextMap1
) )
981 ps_rgb_nbox(out
, &(mat
[i
].map
[col
].rgb
), nexty
-y
);
986 ps_rgb_nbox(out
, &(mat2
[i
].map
[col
].rgb
), nexty
-y
);
991 ps_moverel(out
, 0, psr
->yboxsize
);
999 y0
+= box_height(&(mat
[i
]), psr
)+box_dh(psr
)+box_dh_top(IS_ONCE
, psr
);
1002 if (psr
->X
.lineatzero
|| psr
->Y
.lineatzero
)
1004 /* reset y0 for first box */
1006 ps_comment(out
, "Here starts the zero lines drawing");
1007 draw_zerolines(out
, x0
, y0
, w
, nmat
, mat
, psr
);
1010 if (elegend
!= elNone
)
1012 ps_comment(out
, "Now it's legend time!");
1013 ps_linewidth(out
, static_cast<int>(psr
->linewidth
));
1014 if (mat2
== nullptr || elegend
!= elSecond
)
1016 bDiscrete
= mat
[0].bDiscrete
;
1017 legend
= mat
[0].legend
;
1023 bDiscrete
= mat2
[0].bDiscrete
;
1024 legend
= mat2
[0].legend
;
1030 leg_discrete(out
, psr
->legfontsize
, DDD
, legend
,
1031 psr
->legfontsize
, psr
->legfont
, leg_nmap
, leg_map
);
1035 if (elegend
!= elBoth
)
1037 leg_continuous(out
, x0
+w
/2, w
/2, DDD
, legend
,
1038 psr
->legfontsize
, psr
->legfont
, leg_nmap
, leg_map
,
1044 leg_bicontinuous(out
, x0
+w
/2, w
, DDD
, mat
[0].legend
, mat2
[0].legend
,
1045 psr
->legfontsize
, psr
->legfont
, nmap1
, map1
, nmap2
, map2
);
1048 ps_comment(out
, "Were there, dude");
1054 static void make_axis_labels(int nmat
, t_matrix
*mat
)
1058 for (i
= 0; (i
< nmat
); i
++)
1060 /* Make labels for x axis */
1061 if (mat
[i
].axis_x
== nullptr)
1063 snew(mat
[i
].axis_x
, mat
[i
].nx
);
1064 for (j
= 0; (j
< mat
[i
].nx
); j
++)
1066 mat
[i
].axis_x
[j
] = j
;
1069 /* Make labels for y axis */
1070 if (mat
[i
].axis_y
== nullptr)
1072 snew(mat
[i
].axis_y
, mat
[i
].ny
);
1073 for (j
= 0; (j
< mat
[i
].ny
); j
++)
1075 mat
[i
].axis_y
[j
] = j
;
1081 static void prune_mat(int nmat
, t_matrix
*mat
, t_matrix
*mat2
, int skip
)
1083 int i
, x
, y
, xs
, ys
;
1085 for (i
= 0; i
< nmat
; i
++)
1087 fprintf(stderr
, "converting %dx%d matrix to %dx%d\n",
1088 mat
[i
].nx
, mat
[i
].ny
,
1089 (mat
[i
].nx
+skip
-1)/skip
, (mat
[i
].ny
+skip
-1)/skip
);
1090 /* walk through matrix */
1092 for (x
= 0; (x
< mat
[i
].nx
); x
++)
1096 mat
[i
].axis_x
[xs
] = mat
[i
].axis_x
[x
];
1099 mat2
[i
].axis_x
[xs
] = mat2
[i
].axis_x
[x
];
1102 for (y
= 0; (y
< mat
[i
].ny
); y
++)
1106 mat
[i
].axis_y
[ys
] = mat
[i
].axis_y
[y
];
1109 mat2
[i
].axis_y
[ys
] = mat2
[i
].axis_y
[y
];
1114 mat
[i
].matrix
[xs
][ys
] = mat
[i
].matrix
[x
][y
];
1117 mat2
[i
].matrix
[xs
][ys
] = mat2
[i
].matrix
[x
][y
];
1125 /* adjust parameters */
1126 mat
[i
].nx
= (mat
[i
].nx
+skip
-1)/skip
;
1127 mat
[i
].ny
= (mat
[i
].ny
+skip
-1)/skip
;
1130 mat2
[i
].nx
= (mat2
[i
].nx
+skip
-1)/skip
;
1131 mat2
[i
].ny
= (mat2
[i
].ny
+skip
-1)/skip
;
1136 static void zero_lines(int nmat
, t_matrix
*mat
, t_matrix
*mat2
)
1141 for (i
= 0; i
< nmat
; i
++)
1143 for (m
= 0; m
< (mat2
? 2 : 1); m
++)
1153 for (x
= 0; x
< mats
[i
].nx
-1; x
++)
1155 if (std::abs(mats
[i
].axis_x
[x
+1]) < 1e-5)
1157 for (y
= 0; y
< mats
[i
].ny
; y
++)
1159 mats
[i
].matrix
[x
][y
] = 0;
1163 for (y
= 0; y
< mats
[i
].ny
-1; y
++)
1165 if (std::abs(mats
[i
].axis_y
[y
+1]) < 1e-5)
1167 for (x
= 0; x
< mats
[i
].nx
; x
++)
1169 mats
[i
].matrix
[x
][y
] = 0;
1177 static void write_combined_matrix(int ecombine
, const char *fn
,
1178 int nmat
, t_matrix
*mat1
, t_matrix
*mat2
,
1179 const real
*cmin
, const real
*cmax
)
1181 int i
, j
, k
, nlevels
;
1183 real
**rmat1
, **rmat2
;
1186 out
= gmx_ffopen(fn
, "w");
1187 for (k
= 0; k
< nmat
; k
++)
1189 if (mat2
[k
].nx
!= mat1
[k
].nx
|| mat2
[k
].ny
!= mat1
[k
].ny
)
1191 gmx_fatal(FARGS
, "Size of frame %d in 1st (%dx%d) and 2nd matrix (%dx%d) do"
1192 " not match.\n", k
, mat1
[k
].nx
, mat1
[k
].ny
, mat2
[k
].nx
, mat2
[k
].ny
);
1194 printf("Combining two %dx%d matrices\n", mat1
[k
].nx
, mat1
[k
].ny
);
1195 rmat1
= matrix2real(&mat1
[k
], nullptr);
1196 rmat2
= matrix2real(&mat2
[k
], nullptr);
1197 if (nullptr == rmat1
|| nullptr == rmat2
)
1199 gmx_fatal(FARGS
, "Could not extract real data from %s xpm matrices. Note that, e.g.,\n"
1200 "g_rms and g_mdmat provide such data, but not do_dssp.\n",
1201 (nullptr == rmat1
&& nullptr == rmat2
) ? "both" : "one of the" );
1205 for (j
= 0; j
< mat1
[k
].ny
; j
++)
1207 for (i
= 0; i
< mat1
[k
].nx
; i
++)
1211 case ecAdd
: rmat1
[i
][j
] += rmat2
[i
][j
]; break;
1212 case ecSub
: rmat1
[i
][j
] -= rmat2
[i
][j
]; break;
1213 case ecMult
: rmat1
[i
][j
] *= rmat2
[i
][j
]; break;
1214 case ecDiv
: rmat1
[i
][j
] /= rmat2
[i
][j
]; break;
1216 gmx_fatal(FARGS
, "No such combination rule %d for matrices", ecombine
);
1218 rlo
= std::min(rlo
, rmat1
[i
][j
]);
1219 rhi
= std::max(rhi
, rmat1
[i
][j
]);
1230 nlevels
= std::max(mat1
[k
].nmap
, mat2
[k
].nmap
);
1234 "combination results in uniform matrix (%g), no output\n", rhi
);
1237 else if (rlo>=0 || rhi<=0)
1238 write_xpm(out, mat1[k].flags, mat1[k].title, mat1[k].legend,
1239 mat1[k].label_x, mat1[k].label_y,
1240 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1241 rmat1, rlo, rhi, rhi<=0?red:white, rhi<=0?white:blue,
1244 write_xpm3(out, mat2[k].flags, mat1[k].title, mat1[k].legend,
1245 mat1[k].label_x, mat1[k].label_y,
1246 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1247 rmat1, rlo, 0, rhi, red, white, blue, &nlevels);
1251 write_xpm(out
, mat1
[k
].flags
, mat1
[k
].title
, mat1
[k
].legend
,
1252 mat1
[k
].label_x
, mat1
[k
].label_y
,
1253 mat1
[k
].nx
, mat1
[k
].ny
, mat1
[k
].axis_x
, mat1
[k
].axis_y
,
1254 rmat1
, rlo
, rhi
, white
, black
, &nlevels
);
1260 static void do_mat(int nmat
, t_matrix
*mat
, t_matrix
*mat2
,
1261 gmx_bool bFrame
, gmx_bool bZeroLine
, gmx_bool bDiag
, gmx_bool bFirstDiag
, gmx_bool bTitle
,
1262 gmx_bool bTitleOnce
, gmx_bool bYonce
, int elegend
,
1263 real size
, real boxx
, real boxy
,
1264 const char *epsfile
, const char *xpmfile
, const char *m2p
,
1265 const char *m2pout
, int skip
, int mapoffset
)
1271 for (k
= 0; (k
< nmat
); k
++)
1273 if ((mat2
[k
].nx
!= mat
[k
].nx
) || (mat2
[k
].ny
!= mat
[k
].ny
))
1275 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",
1276 k
, mat2
[k
].nx
, mat2
[k
].ny
, mat
[k
].nx
, mat
[k
].ny
);
1278 for (j
= 0; (j
< mat
[k
].ny
); j
++)
1280 for (i
= bFirstDiag
? j
+1 : j
; (i
< mat
[k
].nx
); i
++)
1282 mat
[k
].matrix
[i
][j
] = mat2
[k
].matrix
[i
][j
];
1287 for (i
= 0; (i
< nmat
); i
++)
1289 fprintf(stderr
, "Matrix %d is %d x %d\n", i
, mat
[i
].nx
, mat
[i
].ny
);
1292 make_axis_labels(nmat
, mat
);
1296 prune_mat(nmat
, mat
, mat2
, skip
);
1301 zero_lines(nmat
, mat
, mat
);
1304 if (epsfile
!= nullptr)
1306 ps_mat(epsfile
, nmat
, mat
, mat2
, bFrame
, bDiag
, bFirstDiag
,
1307 bTitle
, bTitleOnce
, bYonce
, elegend
,
1308 size
, boxx
, boxy
, m2p
, m2pout
, mapoffset
);
1310 if (xpmfile
!= nullptr)
1312 xpm_mat(xpmfile
, nmat
, mat
, mat2
, bDiag
, bFirstDiag
);
1316 static void gradient_map(const rvec grad
, int nmap
, t_mapping map
[])
1321 for (i
= 0; i
< nmap
; i
++)
1324 map
[i
].rgb
.r
= 1-c
*(1-grad
[XX
]);
1325 map
[i
].rgb
.g
= 1-c
*(1-grad
[YY
]);
1326 map
[i
].rgb
.b
= 1-c
*(1-grad
[ZZ
]);
1330 static void gradient_mat(rvec grad
, int nmat
, t_matrix mat
[])
1334 for (m
= 0; m
< nmat
; m
++)
1336 gradient_map(grad
, mat
[m
].nmap
, mat
[m
].map
);
1340 static void rainbow_map(gmx_bool bBlue
, int nmap
, t_mapping map
[])
1345 for (i
= 0; i
< nmap
; i
++)
1347 c
= (map
[i
].rgb
.r
+ map
[i
].rgb
.g
+ map
[i
].rgb
.b
)/3;
1356 if (c
<= 0.25) /* 0-0.25 */
1359 g
= std::pow(4.0*c
, 2.0/3.0);
1362 else if (c
<= 0.5) /* 0.25-0.5 */
1366 b
= std::pow(2.0-4.0*c
, 2.0/3.0);
1368 else if (c
<= 0.75) /* 0.5-0.75 */
1370 r
= std::pow(4.0*c
-2.0, 2.0/3.0);
1377 g
= std::pow(4.0-4.0*c
, 2.0/3.0);
1386 static void rainbow_mat(gmx_bool bBlue
, int nmat
, t_matrix mat
[])
1390 for (m
= 0; m
< nmat
; m
++)
1392 rainbow_map(bBlue
, mat
[m
].nmap
, mat
[m
].map
);
1396 int gmx_xpm2ps(int argc
, char *argv
[])
1398 const char *desc
[] = {
1399 "[THISMODULE] makes a beautiful color plot of an XPixelMap file.",
1400 "Labels and axis can be displayed, when they are supplied",
1401 "in the correct matrix format.",
1402 "Matrix data may be generated by programs such as [gmx-do_dssp], [gmx-rms] or",
1403 "[gmx-mdmat].[PAR]",
1404 "Parameters are set in the [TT].m2p[tt] file optionally supplied with",
1405 "[TT]-di[tt]. Reasonable defaults are provided. Settings for the [IT]y[it]-axis",
1406 "default to those for the [IT]x[it]-axis. Font names have a defaulting hierarchy:",
1407 "titlefont -> legendfont; titlefont -> (xfont -> yfont -> ytickfont)",
1408 "-> xtickfont, e.g. setting titlefont sets all fonts, setting xfont",
1409 "sets yfont, ytickfont and xtickfont.[PAR]",
1410 "When no [TT].m2p[tt] file is supplied, many settings are taken from",
1411 "command line options. The most important option is [TT]-size[tt],",
1412 "which sets the size of the whole matrix in postscript units.",
1413 "This option can be overridden with the [TT]-bx[tt] and [TT]-by[tt]",
1414 "options (and the corresponding parameters in the [TT].m2p[tt] file),",
1415 "which set the size of a single matrix element.[PAR]",
1416 "With [TT]-f2[tt] a second matrix file can be supplied. Both matrix",
1417 "files will be read simultaneously and the upper left half of the",
1418 "first one ([TT]-f[tt]) is plotted together with the lower right",
1419 "half of the second one ([TT]-f2[tt]). The diagonal will contain",
1420 "values from the matrix file selected with [TT]-diag[tt].",
1421 "Plotting of the diagonal values can be suppressed altogether by",
1422 "setting [TT]-diag[tt] to [TT]none[tt].",
1423 "In this case, a new color map will be generated with",
1424 "a red gradient for negative numbers and a blue for positive.",
1425 "If the color coding and legend labels of both matrices are identical,",
1426 "only one legend will be displayed, else two separate legends are",
1428 "With [TT]-combine[tt], an alternative operation can be selected",
1429 "to combine the matrices. The output range is automatically set",
1430 "to the actual range of the combined matrix. This can be overridden",
1431 "with [TT]-cmin[tt] and [TT]-cmax[tt].[PAR]",
1432 "[TT]-title[tt] can be set to [TT]none[tt] to suppress the title, or to",
1433 "[TT]ylabel[tt] to show the title in the Y-label position (alongside",
1434 "the [IT]y[it]-axis).[PAR]",
1435 "With the [TT]-rainbow[tt] option, dull grayscale matrices can be turned",
1436 "into attractive color pictures.[PAR]",
1437 "Merged or rainbowed matrices can be written to an XPixelMap file with",
1438 "the [TT]-xpm[tt] option."
1441 gmx_output_env_t
*oenv
;
1442 const char *fn
, *epsfile
= nullptr, *xpmfile
= nullptr;
1443 int i
, nmat
, nmat2
, etitle
, elegend
, ediag
, erainbow
, ecombine
;
1444 t_matrix
*mat
= nullptr, *mat2
= nullptr;
1445 gmx_bool bTitle
, bTitleOnce
, bDiag
, bFirstDiag
, bGrad
;
1446 static gmx_bool bFrame
= TRUE
, bZeroLine
= FALSE
, bYonce
= FALSE
;
1447 static real size
= 400, boxx
= 0, boxy
= 0, cmin
= 0, cmax
= 0;
1448 static rvec grad
= {0, 0, 0};
1450 etSel
, etTop
, etOnce
, etYlabel
, etNone
, etNR
1452 const char *title
[] = { nullptr, "top", "once", "ylabel", "none", nullptr };
1453 /* MUST correspond to enum elXxx as defined at top of file */
1454 const char *legend
[] = { nullptr, "both", "first", "second", "none", nullptr };
1456 edSel
, edFirst
, edSecond
, edNone
, edNR
1458 const char *diag
[] = { nullptr, "first", "second", "none", nullptr };
1460 erSel
, erNo
, erBlue
, erRed
, erNR
1462 const char *rainbow
[] = { nullptr, "no", "blue", "red", nullptr };
1463 /* MUST correspond to enum ecXxx as defined at top of file */
1464 const char *combine
[] = {
1465 nullptr, "halves", "add", "sub", "mult", "div", nullptr
1467 static int skip
= 1, mapoffset
= 0;
1469 { "-frame", FALSE
, etBOOL
, {&bFrame
},
1470 "Display frame, ticks, labels, title and legend" },
1471 { "-title", FALSE
, etENUM
, {title
}, "Show title at" },
1472 { "-yonce", FALSE
, etBOOL
, {&bYonce
}, "Show y-label only once" },
1473 { "-legend", FALSE
, etENUM
, {legend
}, "Show legend" },
1474 { "-diag", FALSE
, etENUM
, {diag
}, "Diagonal" },
1475 { "-size", FALSE
, etREAL
, {&size
},
1476 "Horizontal size of the matrix in ps units" },
1477 { "-bx", FALSE
, etREAL
, {&boxx
},
1478 "Element x-size, overrides [TT]-size[tt] (also y-size when [TT]-by[tt] is not set)" },
1479 { "-by", FALSE
, etREAL
, {&boxy
}, "Element y-size" },
1480 { "-rainbow", FALSE
, etENUM
, {rainbow
},
1481 "Rainbow colors, convert white to" },
1482 { "-gradient", FALSE
, etRVEC
, {grad
},
1483 "Re-scale colormap to a smooth gradient from white {1,1,1} to {r,g,b}" },
1484 { "-skip", FALSE
, etINT
, {&skip
},
1485 "only write out every nr-th row and column" },
1486 { "-zeroline", FALSE
, etBOOL
, {&bZeroLine
},
1487 "insert line in [REF].xpm[ref] matrix where axis label is zero"},
1488 { "-legoffset", FALSE
, etINT
, {&mapoffset
},
1489 "Skip first N colors from [REF].xpm[ref] file for the legend" },
1490 { "-combine", FALSE
, etENUM
, {combine
}, "Combine two matrices" },
1491 { "-cmin", FALSE
, etREAL
, {&cmin
}, "Minimum for combination output" },
1492 { "-cmax", FALSE
, etREAL
, {&cmax
}, "Maximum for combination output" }
1494 #define NPA asize(pa)
1496 { efXPM
, "-f", nullptr, ffREAD
},
1497 { efXPM
, "-f2", "root2", ffOPTRD
},
1498 { efM2P
, "-di", nullptr, ffLIBOPTRD
},
1499 { efM2P
, "-do", "out", ffOPTWR
},
1500 { efEPS
, "-o", nullptr, ffOPTWR
},
1501 { efXPM
, "-xpm", nullptr, ffOPTWR
}
1503 #define NFILE asize(fnm)
1505 if (!parse_common_args(&argc
, argv
, PCA_CAN_VIEW
,
1506 NFILE
, fnm
, NPA
, pa
,
1507 asize(desc
), desc
, 0, nullptr, &oenv
))
1512 etitle
= nenum(title
);
1513 elegend
= nenum(legend
);
1514 ediag
= nenum(diag
);
1515 erainbow
= nenum(rainbow
);
1516 ecombine
= nenum(combine
);
1517 bGrad
= opt2parg_bSet("-gradient", NPA
, pa
);
1518 for (i
= 0; i
< DIM
; i
++)
1520 if (grad
[i
] < 0 || grad
[i
] > 1)
1522 gmx_fatal(FARGS
, "RGB value %g out of range (0.0-1.0)", grad
[i
]);
1531 epsfile
= ftp2fn_null(efEPS
, NFILE
, fnm
);
1532 xpmfile
= opt2fn_null("-xpm", NFILE
, fnm
);
1533 if (epsfile
== nullptr && xpmfile
== nullptr)
1535 if (ecombine
!= ecHalves
)
1537 xpmfile
= opt2fn("-xpm", NFILE
, fnm
);
1541 epsfile
= ftp2fn(efEPS
, NFILE
, fnm
);
1544 if (ecombine
!= ecHalves
&& epsfile
)
1547 "WARNING: can only write result of arithmetic combination "
1548 "of two matrices to .xpm file\n"
1549 " file %s will not be written\n", epsfile
);
1553 bDiag
= ediag
!= edNone
;
1554 bFirstDiag
= ediag
!= edSecond
;
1556 fn
= opt2fn("-f", NFILE
, fnm
);
1557 nmat
= read_xpm_matrix(fn
, &mat
);
1558 fprintf(stderr
, "There %s %d matri%s in %s\n", (nmat
> 1) ? "are" : "is", nmat
, (nmat
> 1) ? "ces" : "x", fn
);
1559 fn
= opt2fn_null("-f2", NFILE
, fnm
);
1562 nmat2
= read_xpm_matrix(fn
, &mat2
);
1563 fprintf(stderr
, "There %s %d matri%s in %s\n", (nmat2
> 1) ? "are" : "is", nmat2
, (nmat2
> 1) ? "ces" : "x", fn
);
1566 fprintf(stderr
, "Different number of matrices, using the smallest number.\n");
1567 nmat
= nmat2
= std::min(nmat
, nmat2
);
1572 if (ecombine
!= ecHalves
)
1575 "WARNING: arithmetic matrix combination selected (-combine), "
1576 "but no second matrix (-f2) supplied\n"
1577 " no matrix combination will be performed\n");
1582 bTitle
= etitle
== etTop
;
1583 bTitleOnce
= etitle
== etOnce
;
1584 if (etitle
== etYlabel
)
1586 for (i
= 0; (i
< nmat
); i
++)
1588 std::strcpy(mat
[i
].label_y
, mat
[i
].title
);
1591 std::strcpy(mat2
[i
].label_y
, mat2
[i
].title
);
1597 gradient_mat(grad
, nmat
, mat
);
1600 gradient_mat(grad
, nmat2
, mat2
);
1603 if (erainbow
!= erNo
)
1605 rainbow_mat(erainbow
== erBlue
, nmat
, mat
);
1608 rainbow_mat(erainbow
== erBlue
, nmat2
, mat2
);
1612 if ((mat2
== nullptr) && (elegend
!= elNone
))
1617 if (ecombine
&& ecombine
!= ecHalves
)
1619 write_combined_matrix(ecombine
, xpmfile
, nmat
, mat
, mat2
,
1620 opt2parg_bSet("-cmin", NPA
, pa
) ? &cmin
: nullptr,
1621 opt2parg_bSet("-cmax", NPA
, pa
) ? &cmax
: nullptr);
1625 do_mat(nmat
, mat
, mat2
, bFrame
, bZeroLine
, bDiag
, bFirstDiag
,
1626 bTitle
, bTitleOnce
, bYonce
,
1627 elegend
, size
, boxx
, boxy
, epsfile
, xpmfile
,
1628 opt2fn_null("-di", NFILE
, fnm
), opt2fn_null("-do", NFILE
, fnm
), skip
,
1632 view_all(oenv
, NFILE
, fnm
);