Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/gplot.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*====================================================================* | |
| 2 - Copyright (C) 2001 Leptonica. All rights reserved. | |
| 3 - | |
| 4 - Redistribution and use in source and binary forms, with or without | |
| 5 - modification, are permitted provided that the following conditions | |
| 6 - are met: | |
| 7 - 1. Redistributions of source code must retain the above copyright | |
| 8 - notice, this list of conditions and the following disclaimer. | |
| 9 - 2. Redistributions in binary form must reproduce the above | |
| 10 - copyright notice, this list of conditions and the following | |
| 11 - disclaimer in the documentation and/or other materials | |
| 12 - provided with the distribution. | |
| 13 - | |
| 14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY | |
| 18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 *====================================================================*/ | |
| 26 | |
| 27 /*! | |
| 28 * \file gplot.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * Basic plotting functions | |
| 32 * GPLOT *gplotCreate() | |
| 33 * void gplotDestroy() | |
| 34 * l_int32 gplotAddPlot() | |
| 35 * l_int32 gplotSetScaling() | |
| 36 * PIX *gplotMakeOutputPix() | |
| 37 * l_int32 gplotMakeOutput() | |
| 38 * l_int32 gplotGenCommandFile() | |
| 39 * l_int32 gplotGenDataFiles() | |
| 40 * | |
| 41 * Quick, one-line plots | |
| 42 * l_int32 gplotSimple1() | |
| 43 * l_int32 gplotSimple2() | |
| 44 * l_int32 gplotSimpleN() | |
| 45 * PIX *gplotSimplePix1() | |
| 46 * PIX *gplotSimplePix2() | |
| 47 * PIX *gplotSimplePixN() | |
| 48 * GPLOT *gplotSimpleXY1() | |
| 49 * GPLOT *gplotSimpleXY2() | |
| 50 * GPLOT *gplotSimpleXYN() | |
| 51 * PIX *gplotGeneralPix1() | |
| 52 * PIX *gplotGeneralPix2() | |
| 53 * PIX *gplotGeneralPixN() | |
| 54 * | |
| 55 * Serialize for I/O | |
| 56 * GPLOT *gplotRead() | |
| 57 * l_int32 gplotWrite() | |
| 58 * | |
| 59 * | |
| 60 * Utility for programmatic plotting using gnuplot 4.6 or later | |
| 61 * Enabled: | |
| 62 * ~ output to png (color), ps and eps (mono), latex (mono) | |
| 63 * ~ optional title for plot | |
| 64 * ~ optional x and y axis labels | |
| 65 * ~ multiple plots on one frame | |
| 66 * ~ optional label for each plot on the frame | |
| 67 * ~ optional log scaling on either or both axes | |
| 68 * ~ choice of 5 plot styles for each array of input data | |
| 69 * ~ choice of 2 plot modes, either using one input array | |
| 70 * (Y vs index) or two input arrays (Y vs X). For functions | |
| 71 * that take two arrays, the first mode (Y vs index) is | |
| 72 * employed if the first array is NULL. | |
| 73 * | |
| 74 * General usage: | |
| 75 * gplotCreate() initializes for plotting | |
| 76 * gplotAddPlot() for each plot on the frame | |
| 77 * gplotMakeOutput() to generate all output files and run gnuplot | |
| 78 * gplotDestroy() to clean up | |
| 79 * | |
| 80 * Example of use: | |
| 81 * gplot = gplotCreate("tempskew", GPLOT_PNG, "Skew score vs angle", | |
| 82 * "angle (deg)", "score"); | |
| 83 * gplotAddPlot(gplot, natheta, nascore1, GPLOT_LINES, "plot 1"); | |
| 84 * gplotAddPlot(gplot, natheta, nascore2, GPLOT_POINTS, "plot 2"); | |
| 85 * gplotSetScaling(gplot, GPLOT_LOG_SCALE_Y); | |
| 86 * gplotMakeOutput(gplot); | |
| 87 * gplotDestroy(&gplot); | |
| 88 * | |
| 89 * Example usage of one-line plot generators: | |
| 90 * | |
| 91 * -- Simple plots -- | |
| 92 * Specify the root of output files, the output format, | |
| 93 * and the title (optional), but not the x and y coordinate labels | |
| 94 * or the plot labels. The plotstyle defaults to GPLOT_LINES. | |
| 95 * gplotSimple2(na1, na2, GPLOT_PNG, "/tmp/lept/histo/gray", | |
| 96 * "gray histogram"); | |
| 97 * Multiple plots can be generated using gplotSimpleN(). | |
| 98 * | |
| 99 * -- Simple plots with more options -- | |
| 100 * Specify the root of output files, the plotstyle, the output format, | |
| 101 * and optionally the title, but not the x and y coordinate labels | |
| 102 * or the plot labels. | |
| 103 * gplotSimpleXY1(na1, na2, GPLOT_LINES, GPLOT_PNG, | |
| 104 * "/tmp/lept/histo/gray", "gray histogram"); | |
| 105 * Multiple plots can be generated using gplotSimpleXYN(). | |
| 106 * | |
| 107 * -- Simple plots returning a pix -- | |
| 108 * Specify only the title (optional). The plotstyle defaults | |
| 109 * GPLOT_LINES and the output format is GPLOT_PNG.. | |
| 110 * You can't specify the x and y coordinate labels or the plot label. | |
| 111 * The rootname of the generated files is determined internally. | |
| 112 * Pix *pix = gplotSimplePix2(na1, na2, "gray histogram"); | |
| 113 * Multiple plots can be generated using gplotSimplePixN(). | |
| 114 * | |
| 115 * -- General plots returning a pix -- | |
| 116 * Specify the root of the output files, the plotstyle, and optionally | |
| 117 * the title and axis labels. This does not allow the individual | |
| 118 * plots to have plot labels, or to use different plotstyles | |
| 119 * for each plot. | |
| 120 * Pix *pix = gplotGeneralPix2(na1, na2, "/tmp/lept/histo/gray", | |
| 121 * GPLOT_LINES, "gray histogram", | |
| 122 * "pix value", "num pixels"); | |
| 123 * Multiple plots can be generated using gplotGeneralPixN(). | |
| 124 * | |
| 125 * Note for output to GPLOT_LATEX: | |
| 126 * This creates latex output of the plot, named <rootname>.tex. | |
| 127 * It needs to be placed in a latex file <latexname>.tex | |
| 128 * that precedes the plot output with, at a minimum: | |
| 129 * \documentclass{article} | |
| 130 * \begin{document} | |
| 131 * and ends with | |
| 132 * \end{document} | |
| 133 * You can then generate a dvi file <latexname>.dvi using | |
| 134 * latex <latexname>.tex | |
| 135 * a PostScript file <psname>.ps from that using | |
| 136 * dvips -o <psname>.ps <latexname>.dvi | |
| 137 * and pdf file <psname>.pdf from that using Ghostscript's ps2pdf: | |
| 138 * ps2pdf <psname>.ps <pdfname>.pdf | |
| 139 * | |
| 140 * N.B. To generate plots: | |
| 141 * (1) It is necessary to have gnuplot installed on your Unix system, | |
| 142 * or wgnuplot on Windows. | |
| 143 * (2) You must enable debug operations: | |
| 144 * setLeptDebugOK(1); | |
| 145 * </pre> | |
| 146 */ | |
| 147 | |
| 148 #ifdef HAVE_CONFIG_H | |
| 149 #include <config_auto.h> | |
| 150 #endif /* HAVE_CONFIG_H */ | |
| 151 | |
| 152 #include <string.h> | |
| 153 #include "allheaders.h" | |
| 154 | |
| 155 #define Bufsize 512 /* hardcoded below in fscanf */ | |
| 156 | |
| 157 const char *gplotstylenames[] = {"with lines", | |
| 158 "with points", | |
| 159 "with impulses", | |
| 160 "with linespoints", | |
| 161 "with dots"}; | |
| 162 const char *gplotfileoutputs[] = {"", | |
| 163 "PNG", | |
| 164 "PS", | |
| 165 "EPS", | |
| 166 "LATEX", | |
| 167 "PNM"}; | |
| 168 | |
| 169 | |
| 170 /*-----------------------------------------------------------------* | |
| 171 * Basic Plotting Functions * | |
| 172 *-----------------------------------------------------------------*/ | |
| 173 /*! | |
| 174 * \brief gplotCreate() | |
| 175 * | |
| 176 * \param[in] rootname root for all output files | |
| 177 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, | |
| 178 * GPLOT_LATEX, GPLOT_PNM | |
| 179 * \param[in] title [optional] overall title | |
| 180 * \param[in] xlabel [optional] x axis label | |
| 181 * \param[in] ylabel [optional] y axis label | |
| 182 * \return gplot, or NULL on error | |
| 183 * | |
| 184 * <pre> | |
| 185 * Notes: | |
| 186 * (1) This initializes the plot. | |
| 187 * (2) The 'title', 'xlabel' and 'ylabel' strings can have spaces, | |
| 188 * double quotes and backquotes, but not single quotes. | |
| 189 * </pre> | |
| 190 */ | |
| 191 GPLOT * | |
| 192 gplotCreate(const char *rootname, | |
| 193 l_int32 outformat, | |
| 194 const char *title, | |
| 195 const char *xlabel, | |
| 196 const char *ylabel) | |
| 197 { | |
| 198 char *newroot; | |
| 199 char buf[Bufsize]; | |
| 200 l_int32 badchar; | |
| 201 GPLOT *gplot; | |
| 202 | |
| 203 if (!rootname) | |
| 204 return (GPLOT *)ERROR_PTR("rootname not defined", __func__, NULL); | |
| 205 if (outformat != GPLOT_PNG && outformat != GPLOT_PS && | |
| 206 outformat != GPLOT_EPS && outformat != GPLOT_LATEX && | |
| 207 outformat != GPLOT_PNM) | |
| 208 return (GPLOT *)ERROR_PTR("outformat invalid", __func__, NULL); | |
| 209 stringCheckForChars(rootname, "`;&|><\"?*$()", &badchar); | |
| 210 if (badchar) /* danger of command injection */ | |
| 211 return (GPLOT *)ERROR_PTR("invalid rootname", __func__, NULL); | |
| 212 | |
| 213 #if !defined(HAVE_LIBPNG) | |
| 214 if (outformat == GPLOT_PNG) { | |
| 215 L_WARNING("png library missing; output pnm format\n", __func__); | |
| 216 outformat = GPLOT_PNM; | |
| 217 } | |
| 218 #endif | |
| 219 | |
| 220 gplot = (GPLOT *)LEPT_CALLOC(1, sizeof(GPLOT)); | |
| 221 gplot->cmddata = sarrayCreate(0); | |
| 222 gplot->datanames = sarrayCreate(0); | |
| 223 gplot->plotdata = sarrayCreate(0); | |
| 224 gplot->plotlabels = sarrayCreate(0); | |
| 225 gplot->plotstyles = numaCreate(0); | |
| 226 | |
| 227 /* Save title, labels, rootname, outformat, cmdname, outname */ | |
| 228 newroot = genPathname(rootname, NULL); | |
| 229 gplot->rootname = newroot; | |
| 230 gplot->outformat = outformat; | |
| 231 snprintf(buf, Bufsize, "%s.cmd", rootname); | |
| 232 gplot->cmdname = stringNew(buf); | |
| 233 if (outformat == GPLOT_PNG) | |
| 234 snprintf(buf, Bufsize, "%s.png", newroot); | |
| 235 else if (outformat == GPLOT_PS) | |
| 236 snprintf(buf, Bufsize, "%s.ps", newroot); | |
| 237 else if (outformat == GPLOT_EPS) | |
| 238 snprintf(buf, Bufsize, "%s.eps", newroot); | |
| 239 else if (outformat == GPLOT_LATEX) | |
| 240 snprintf(buf, Bufsize, "%s.tex", newroot); | |
| 241 else if (outformat == GPLOT_PNM) | |
| 242 snprintf(buf, Bufsize, "%s.pnm", newroot); | |
| 243 gplot->outname = stringNew(buf); | |
| 244 if (title) gplot->title = stringNew(title); | |
| 245 if (xlabel) gplot->xlabel = stringNew(xlabel); | |
| 246 if (ylabel) gplot->ylabel = stringNew(ylabel); | |
| 247 | |
| 248 return gplot; | |
| 249 } | |
| 250 | |
| 251 | |
| 252 /*! | |
| 253 * \brief gplotDestroy() | |
| 254 * | |
| 255 * \param[in,out] pgplot will be set to null before returning | |
| 256 */ | |
| 257 void | |
| 258 gplotDestroy(GPLOT **pgplot) | |
| 259 { | |
| 260 GPLOT *gplot; | |
| 261 | |
| 262 if (pgplot == NULL) { | |
| 263 L_WARNING("ptr address is null!\n", __func__); | |
| 264 return; | |
| 265 } | |
| 266 | |
| 267 if ((gplot = *pgplot) == NULL) | |
| 268 return; | |
| 269 | |
| 270 LEPT_FREE(gplot->rootname); | |
| 271 LEPT_FREE(gplot->cmdname); | |
| 272 sarrayDestroy(&gplot->cmddata); | |
| 273 sarrayDestroy(&gplot->datanames); | |
| 274 sarrayDestroy(&gplot->plotdata); | |
| 275 sarrayDestroy(&gplot->plotlabels); | |
| 276 numaDestroy(&gplot->plotstyles); | |
| 277 LEPT_FREE(gplot->outname); | |
| 278 if (gplot->title) | |
| 279 LEPT_FREE(gplot->title); | |
| 280 if (gplot->xlabel) | |
| 281 LEPT_FREE(gplot->xlabel); | |
| 282 if (gplot->ylabel) | |
| 283 LEPT_FREE(gplot->ylabel); | |
| 284 | |
| 285 LEPT_FREE(gplot); | |
| 286 *pgplot = NULL; | |
| 287 } | |
| 288 | |
| 289 | |
| 290 /*! | |
| 291 * \brief gplotAddPlot() | |
| 292 * | |
| 293 * \param[in] gplot | |
| 294 * \param[in] nax [optional] numa: set to null for Y_VS_I; | |
| 295 * required for Y_VS_X | |
| 296 * \param[in] nay numa; required for both Y_VS_I and Y_VS_X | |
| 297 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, | |
| 298 * GPLOT_LINESPOINTS, GPLOT_DOTS | |
| 299 * \param[in] plotlabel [optional] label for individual plot | |
| 300 * \return 0 if OK, 1 on error | |
| 301 * | |
| 302 * <pre> | |
| 303 * Notes: | |
| 304 * (1) There are 2 options for (x,y) values: | |
| 305 * o To plot an array vs a linear function of the | |
| 306 * index, set %nax = NULL. | |
| 307 * o To plot one array vs another, use both %nax and %nay. | |
| 308 * (2) If %nax is NULL, the x value corresponding to the i-th | |
| 309 * value of %nay is found from the startx and delx fields | |
| 310 * in %nay: | |
| 311 * x = startx + i * delx | |
| 312 * These are set with numaSetParameters(). Their default | |
| 313 * values are startx = 0.0, delx = 1.0. | |
| 314 * (3) If %nax is defined, it must be the same size as %nay, and | |
| 315 * must have at least one number. | |
| 316 * (4) The 'plotlabel' string can have spaces, double | |
| 317 * quotes and backquotes, but not single quotes. | |
| 318 * </pre> | |
| 319 */ | |
| 320 l_ok | |
| 321 gplotAddPlot(GPLOT *gplot, | |
| 322 NUMA *nax, | |
| 323 NUMA *nay, | |
| 324 l_int32 plotstyle, | |
| 325 const char *plotlabel) | |
| 326 { | |
| 327 char buf[Bufsize]; | |
| 328 char emptystring[] = ""; | |
| 329 char *datastr, *title; | |
| 330 l_int32 n, i; | |
| 331 l_float32 valx, valy, startx, delx; | |
| 332 SARRAY *sa; | |
| 333 | |
| 334 if (!gplot) | |
| 335 return ERROR_INT("gplot not defined", __func__, 1); | |
| 336 if (!nay) | |
| 337 return ERROR_INT("nay not defined", __func__, 1); | |
| 338 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) | |
| 339 return ERROR_INT("invalid plotstyle", __func__, 1); | |
| 340 | |
| 341 if ((n = numaGetCount(nay)) == 0) | |
| 342 return ERROR_INT("no points to plot", __func__, 1); | |
| 343 if (nax && (n != numaGetCount(nax))) | |
| 344 return ERROR_INT("nax and nay sizes differ", __func__, 1); | |
| 345 if (n == 1 && plotstyle == GPLOT_LINES) { | |
| 346 L_INFO("only 1 pt; changing style to points\n", __func__); | |
| 347 plotstyle = GPLOT_POINTS; | |
| 348 } | |
| 349 | |
| 350 /* Save plotstyle and plotlabel */ | |
| 351 numaGetParameters(nay, &startx, &delx); | |
| 352 numaAddNumber(gplot->plotstyles, plotstyle); | |
| 353 if (plotlabel) { | |
| 354 title = stringNew(plotlabel); | |
| 355 sarrayAddString(gplot->plotlabels, title, L_INSERT); | |
| 356 } else { | |
| 357 sarrayAddString(gplot->plotlabels, emptystring, L_COPY); | |
| 358 } | |
| 359 | |
| 360 /* Generate and save data filename */ | |
| 361 gplot->nplots++; | |
| 362 snprintf(buf, Bufsize, "%s.data.%d", gplot->rootname, gplot->nplots); | |
| 363 sarrayAddString(gplot->datanames, buf, L_COPY); | |
| 364 | |
| 365 /* Generate data and save as a string */ | |
| 366 sa = sarrayCreate(n); | |
| 367 for (i = 0; i < n; i++) { | |
| 368 if (nax) | |
| 369 numaGetFValue(nax, i, &valx); | |
| 370 else | |
| 371 valx = startx + i * delx; | |
| 372 numaGetFValue(nay, i, &valy); | |
| 373 snprintf(buf, Bufsize, "%f %f\n", valx, valy); | |
| 374 sarrayAddString(sa, buf, L_COPY); | |
| 375 } | |
| 376 datastr = sarrayToString(sa, 0); | |
| 377 sarrayAddString(gplot->plotdata, datastr, L_INSERT); | |
| 378 sarrayDestroy(&sa); | |
| 379 | |
| 380 return 0; | |
| 381 } | |
| 382 | |
| 383 | |
| 384 /*! | |
| 385 * \brief gplotSetScaling() | |
| 386 * | |
| 387 * \param[in] gplot | |
| 388 * \param[in] scaling GPLOT_LINEAR_SCALE, GPLOT_LOG_SCALE_X, | |
| 389 * GPLOT_LOG_SCALE_Y, GPLOT_LOG_SCALE_X_Y | |
| 390 * \return 0 if OK; 1 on error | |
| 391 * | |
| 392 * <pre> | |
| 393 * Notes: | |
| 394 * (1) By default, the x and y axis scaling is linear. | |
| 395 * (2) Call this function to set semi-log or log-log scaling. | |
| 396 * </pre> | |
| 397 */ | |
| 398 l_ok | |
| 399 gplotSetScaling(GPLOT *gplot, | |
| 400 l_int32 scaling) | |
| 401 { | |
| 402 if (!gplot) | |
| 403 return ERROR_INT("gplot not defined", __func__, 1); | |
| 404 if (scaling != GPLOT_LINEAR_SCALE && | |
| 405 scaling != GPLOT_LOG_SCALE_X && | |
| 406 scaling != GPLOT_LOG_SCALE_Y && | |
| 407 scaling != GPLOT_LOG_SCALE_X_Y) | |
| 408 return ERROR_INT("invalid gplot scaling", __func__, 1); | |
| 409 gplot->scaling = scaling; | |
| 410 return 0; | |
| 411 } | |
| 412 | |
| 413 | |
| 414 /*! | |
| 415 * \brief gplotMakeOutputPix() | |
| 416 * | |
| 417 * \param[in] gplot | |
| 418 * \return 0 if OK; 1 on error | |
| 419 * | |
| 420 * <pre> | |
| 421 * Notes: | |
| 422 * (1) This wraps gplotMakeOutput(), and returns a pix. | |
| 423 * See gplotMakeOutput() for details. | |
| 424 * (2) The gplot output format must be an image (png or pnm). | |
| 425 * </pre> | |
| 426 */ | |
| 427 PIX * | |
| 428 gplotMakeOutputPix(GPLOT *gplot) | |
| 429 { | |
| 430 if (!gplot) | |
| 431 return (PIX *)ERROR_PTR("gplot not defined", __func__, NULL); | |
| 432 if (gplot->outformat != GPLOT_PNG && gplot->outformat != GPLOT_PNM) | |
| 433 return (PIX *)ERROR_PTR("output format not an image", __func__, NULL); | |
| 434 | |
| 435 if (gplotMakeOutput(gplot)) | |
| 436 return (PIX *)ERROR_PTR("plot output not made", __func__, NULL); | |
| 437 return pixRead(gplot->outname); | |
| 438 } | |
| 439 | |
| 440 | |
| 441 /*! | |
| 442 * \brief gplotMakeOutput() | |
| 443 * | |
| 444 * \param[in] gplot | |
| 445 * \return 0 if OK; 1 on error | |
| 446 * | |
| 447 * <pre> | |
| 448 * Notes: | |
| 449 * (1) This uses gplot and the new arrays to add a plot | |
| 450 * to the output, by writing a new data file and appending | |
| 451 * the appropriate plot commands to the command file. | |
| 452 * (2) Along with gplotMakeOutputPix(), these are the only functions | |
| 453 * in this file that requires the gnuplot executable to | |
| 454 * actually generate the plot. | |
| 455 * (3) The command file name for unix is canonical (i.e., directory /tmp) | |
| 456 * but the temp filename paths in the command file must be correct. | |
| 457 * (4) The gnuplot program for Windows is wgnuplot.exe. | |
| 458 * </pre> | |
| 459 */ | |
| 460 l_ok | |
| 461 gplotMakeOutput(GPLOT *gplot) | |
| 462 { | |
| 463 char buf[Bufsize]; | |
| 464 char *cmdname; | |
| 465 | |
| 466 if (!gplot) | |
| 467 return ERROR_INT("gplot not defined", __func__, 1); | |
| 468 | |
| 469 if (!LeptDebugOK) { | |
| 470 L_INFO("running gnuplot is disabled; " | |
| 471 "use setLeptDebugOK(1) to enable\n", __func__); | |
| 472 return 0; | |
| 473 } | |
| 474 | |
| 475 #ifdef OS_IOS /* iOS 11 does not support system() */ | |
| 476 return ERROR_INT("iOS 11 does not support system()", __func__, 0); | |
| 477 #endif /* OS_IOS */ | |
| 478 | |
| 479 gplotGenCommandFile(gplot); | |
| 480 gplotGenDataFiles(gplot); | |
| 481 cmdname = genPathname(gplot->cmdname, NULL); | |
| 482 | |
| 483 #ifndef _WIN32 | |
| 484 snprintf(buf, Bufsize, "gnuplot %s", cmdname); | |
| 485 #else | |
| 486 snprintf(buf, Bufsize, "wgnuplot %s", cmdname); | |
| 487 #endif /* _WIN32 */ | |
| 488 | |
| 489 callSystemDebug(buf); /* gnuplot || wgnuplot */ | |
| 490 LEPT_FREE(cmdname); | |
| 491 return 0; | |
| 492 } | |
| 493 | |
| 494 | |
| 495 /*! | |
| 496 * \brief gplotGenCommandFile() | |
| 497 * | |
| 498 * \param[in] gplot | |
| 499 * \return 0 if OK, 1 on error | |
| 500 */ | |
| 501 l_ok | |
| 502 gplotGenCommandFile(GPLOT *gplot) | |
| 503 { | |
| 504 char buf[Bufsize]; | |
| 505 char *cmdstr, *plotlabel, *dataname; | |
| 506 l_int32 i, plotstyle, nplots; | |
| 507 FILE *fp; | |
| 508 | |
| 509 if (!gplot) | |
| 510 return ERROR_INT("gplot not defined", __func__, 1); | |
| 511 | |
| 512 /* Remove any previous command data */ | |
| 513 sarrayClear(gplot->cmddata); | |
| 514 | |
| 515 /* Generate command data instructions */ | |
| 516 if (gplot->title) { /* set title */ | |
| 517 snprintf(buf, Bufsize, "set title '%s'", gplot->title); | |
| 518 sarrayAddString(gplot->cmddata, buf, L_COPY); | |
| 519 } | |
| 520 if (gplot->xlabel) { /* set xlabel */ | |
| 521 snprintf(buf, Bufsize, "set xlabel '%s'", gplot->xlabel); | |
| 522 sarrayAddString(gplot->cmddata, buf, L_COPY); | |
| 523 } | |
| 524 if (gplot->ylabel) { /* set ylabel */ | |
| 525 snprintf(buf, Bufsize, "set ylabel '%s'", gplot->ylabel); | |
| 526 sarrayAddString(gplot->cmddata, buf, L_COPY); | |
| 527 } | |
| 528 | |
| 529 /* Set terminal type and output */ | |
| 530 if (gplot->outformat == GPLOT_PNG) { | |
| 531 snprintf(buf, Bufsize, "set terminal png; set output '%s'", | |
| 532 gplot->outname); | |
| 533 } else if (gplot->outformat == GPLOT_PS) { | |
| 534 snprintf(buf, Bufsize, "set terminal postscript; set output '%s'", | |
| 535 gplot->outname); | |
| 536 } else if (gplot->outformat == GPLOT_EPS) { | |
| 537 snprintf(buf, Bufsize, "set terminal postscript eps; set output '%s'", | |
| 538 gplot->outname); | |
| 539 } else if (gplot->outformat == GPLOT_LATEX) { | |
| 540 snprintf(buf, Bufsize, "set terminal latex; set output '%s'", | |
| 541 gplot->outname); | |
| 542 } else if (gplot->outformat == GPLOT_PNM) { | |
| 543 snprintf(buf, Bufsize, "set terminal pbm color; set output '%s'", | |
| 544 gplot->outname); | |
| 545 } | |
| 546 sarrayAddString(gplot->cmddata, buf, L_COPY); | |
| 547 | |
| 548 if (gplot->scaling == GPLOT_LOG_SCALE_X || | |
| 549 gplot->scaling == GPLOT_LOG_SCALE_X_Y) { | |
| 550 snprintf(buf, Bufsize, "set logscale x"); | |
| 551 sarrayAddString(gplot->cmddata, buf, L_COPY); | |
| 552 } | |
| 553 if (gplot->scaling == GPLOT_LOG_SCALE_Y || | |
| 554 gplot->scaling == GPLOT_LOG_SCALE_X_Y) { | |
| 555 snprintf(buf, Bufsize, "set logscale y"); | |
| 556 sarrayAddString(gplot->cmddata, buf, L_COPY); | |
| 557 } | |
| 558 | |
| 559 nplots = sarrayGetCount(gplot->datanames); | |
| 560 for (i = 0; i < nplots; i++) { | |
| 561 plotlabel = sarrayGetString(gplot->plotlabels, i, L_NOCOPY); | |
| 562 dataname = sarrayGetString(gplot->datanames, i, L_NOCOPY); | |
| 563 numaGetIValue(gplot->plotstyles, i, &plotstyle); | |
| 564 if (nplots == 1) { | |
| 565 snprintf(buf, Bufsize, "plot '%s' title '%s' %s", | |
| 566 dataname, plotlabel, gplotstylenames[plotstyle]); | |
| 567 } else { | |
| 568 if (i == 0) | |
| 569 snprintf(buf, Bufsize, "plot '%s' title '%s' %s, \\", | |
| 570 dataname, plotlabel, gplotstylenames[plotstyle]); | |
| 571 else if (i < nplots - 1) | |
| 572 snprintf(buf, Bufsize, " '%s' title '%s' %s, \\", | |
| 573 dataname, plotlabel, gplotstylenames[plotstyle]); | |
| 574 else | |
| 575 snprintf(buf, Bufsize, " '%s' title '%s' %s", | |
| 576 dataname, plotlabel, gplotstylenames[plotstyle]); | |
| 577 } | |
| 578 sarrayAddString(gplot->cmddata, buf, L_COPY); | |
| 579 } | |
| 580 | |
| 581 /* Write command data to file */ | |
| 582 cmdstr = sarrayToString(gplot->cmddata, 1); | |
| 583 if ((fp = fopenWriteStream(gplot->cmdname, "w")) == NULL) { | |
| 584 L_ERROR("stream not opened for command: %s\n", __func__, cmdstr); | |
| 585 LEPT_FREE(cmdstr); | |
| 586 return 1; | |
| 587 } | |
| 588 fwrite(cmdstr, 1, strlen(cmdstr), fp); | |
| 589 fclose(fp); | |
| 590 LEPT_FREE(cmdstr); | |
| 591 return 0; | |
| 592 } | |
| 593 | |
| 594 | |
| 595 /*! | |
| 596 * \brief gplotGenDataFiles() | |
| 597 * | |
| 598 * \param[in] gplot | |
| 599 * \return 0 if OK, 1 on error | |
| 600 * | |
| 601 * <pre> | |
| 602 * Notes: | |
| 603 * (1) The pathnames in the gplot command file are actual pathnames, | |
| 604 * which can be in temp directories. Consequently, they must not be | |
| 605 * rewritten by calling fopenWriteStream(), and we use fopen(). | |
| 606 * </pre> | |
| 607 */ | |
| 608 l_ok | |
| 609 gplotGenDataFiles(GPLOT *gplot) | |
| 610 { | |
| 611 char *plotdata, *dataname; | |
| 612 l_int32 i, nplots; | |
| 613 FILE *fp; | |
| 614 | |
| 615 if (!gplot) | |
| 616 return ERROR_INT("gplot not defined", __func__, 1); | |
| 617 | |
| 618 nplots = sarrayGetCount(gplot->datanames); | |
| 619 for (i = 0; i < nplots; i++) { | |
| 620 plotdata = sarrayGetString(gplot->plotdata, i, L_NOCOPY); | |
| 621 dataname = sarrayGetString(gplot->datanames, i, L_NOCOPY); | |
| 622 if ((fp = fopen(dataname, "w")) == NULL) | |
| 623 return ERROR_INT_1("datafile stream not opened", | |
| 624 dataname, __func__, 1); | |
| 625 fwrite(plotdata, 1, strlen(plotdata), fp); | |
| 626 fclose(fp); | |
| 627 } | |
| 628 | |
| 629 return 0; | |
| 630 } | |
| 631 | |
| 632 | |
| 633 /*-----------------------------------------------------------------* | |
| 634 * Quick one-line plots * | |
| 635 *-----------------------------------------------------------------*/ | |
| 636 /*! | |
| 637 * \brief gplotSimple1() | |
| 638 * | |
| 639 * \param[in] na numa; plot Y_VS_I | |
| 640 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, | |
| 641 * GPLOT_LATEX, GPLOT_PNM | |
| 642 * \param[in] outroot root of output files | |
| 643 * \param[in] title [optional], can be NULL | |
| 644 * \return 0 if OK, 1 on error | |
| 645 * | |
| 646 * <pre> | |
| 647 * Notes: | |
| 648 * (1) This generates a line plot of a numa, where the array value | |
| 649 * is plotted vs the array index. The plot is generated | |
| 650 * in the specified output format; the title is optional. | |
| 651 * (2) When calling these simple plot functions more than once, use | |
| 652 * different %outroot to avoid overwriting the output files. | |
| 653 * </pre> | |
| 654 */ | |
| 655 l_ok | |
| 656 gplotSimple1(NUMA *na, | |
| 657 l_int32 outformat, | |
| 658 const char *outroot, | |
| 659 const char *title) | |
| 660 { | |
| 661 GPLOT *gplot; | |
| 662 | |
| 663 gplot = gplotSimpleXY1(NULL, na, GPLOT_LINES, outformat, outroot, title); | |
| 664 if (!gplot) | |
| 665 return ERROR_INT("failed to generate plot", __func__, 1); | |
| 666 gplotDestroy(&gplot); | |
| 667 return 0; | |
| 668 } | |
| 669 | |
| 670 | |
| 671 /*! | |
| 672 * \brief gplotSimple2() | |
| 673 * | |
| 674 * \param[in] na1 numa; plot with Y_VS_I | |
| 675 * \param[in] na2 ditto | |
| 676 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, | |
| 677 * GPLOT_LATEX, GPLOT_PNM | |
| 678 * \param[in] outroot root of output files | |
| 679 * \param[in] title [optional] | |
| 680 * \return 0 if OK, 1 on error | |
| 681 * | |
| 682 * <pre> | |
| 683 * Notes: | |
| 684 * (1) This generates a line plot of two numa, where the array values | |
| 685 * are each plotted vs the array index. The plot is generated | |
| 686 * in the specified output format; the title is optional. | |
| 687 * (2) When calling these simple plot functions more than once, use | |
| 688 * different %outroot to avoid overwriting the output files. | |
| 689 * </pre> | |
| 690 */ | |
| 691 l_ok | |
| 692 gplotSimple2(NUMA *na1, | |
| 693 NUMA *na2, | |
| 694 l_int32 outformat, | |
| 695 const char *outroot, | |
| 696 const char *title) | |
| 697 { | |
| 698 GPLOT *gplot; | |
| 699 | |
| 700 gplot = gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES, | |
| 701 outformat, outroot, title); | |
| 702 if (!gplot) | |
| 703 return ERROR_INT("failed to generate plot", __func__, 1); | |
| 704 gplotDestroy(&gplot); | |
| 705 return 0; | |
| 706 } | |
| 707 | |
| 708 | |
| 709 /*! | |
| 710 * \brief gplotSimpleN() | |
| 711 * | |
| 712 * \param[in] naa numaa; plot Y_VS_I for each numa | |
| 713 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, | |
| 714 * GPLOT_LATEX, GPLOT_PNM | |
| 715 * \param[in] outroot root of output files | |
| 716 * \param[in] title [optional] | |
| 717 * \return 0 if OK, 1 on error | |
| 718 * | |
| 719 * <pre> | |
| 720 * Notes: | |
| 721 * (1) This generates a line plot of all numas in a numaa (array of numa), | |
| 722 * where the array values are each plotted vs the array index. | |
| 723 * The plot is generated in the specified output format; | |
| 724 * the title is optional. | |
| 725 * (2) When calling these simple plot functions more than once, use | |
| 726 * different %outroot to avoid overwriting the output files. | |
| 727 * </pre> | |
| 728 */ | |
| 729 l_ok | |
| 730 gplotSimpleN(NUMAA *naa, | |
| 731 l_int32 outformat, | |
| 732 const char *outroot, | |
| 733 const char *title) | |
| 734 { | |
| 735 GPLOT *gplot; | |
| 736 | |
| 737 gplot = gplotSimpleXYN(NULL, naa, GPLOT_LINES, outformat, outroot, title); | |
| 738 if (!gplot) | |
| 739 return ERROR_INT("failed to generate plot", __func__, 1); | |
| 740 gplotDestroy(&gplot); | |
| 741 return 0; | |
| 742 } | |
| 743 | |
| 744 | |
| 745 /*! | |
| 746 * \brief gplotSimplePix1() | |
| 747 * | |
| 748 * \param[in] na numa; plot Y_VS_I | |
| 749 * \param[in] title [optional], can be NULL | |
| 750 * \return pix of plot, or null on error | |
| 751 * | |
| 752 * <pre> | |
| 753 * Notes: | |
| 754 * (1) This generates a line plot of a numa as a pix, where the array | |
| 755 * value is plotted vs the array index. The title is optional. | |
| 756 * (2) The temporary plot file is a png; its name is generated internally | |
| 757 * and stored in gplot. | |
| 758 * </pre> | |
| 759 */ | |
| 760 PIX * | |
| 761 gplotSimplePix1(NUMA *na, | |
| 762 const char *title) | |
| 763 { | |
| 764 char buf[64]; | |
| 765 static l_atomic index; | |
| 766 GPLOT *gplot; | |
| 767 PIX *pix; | |
| 768 | |
| 769 if (!na) | |
| 770 return (PIX *)ERROR_PTR("na not defined", __func__, NULL); | |
| 771 | |
| 772 lept_mkdir("lept/gplot/pix"); | |
| 773 snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pix1.%d", index++); | |
| 774 gplot = gplotSimpleXY1(NULL, na, GPLOT_LINES, GPLOT_PNG, buf, title); | |
| 775 if (!gplot) | |
| 776 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL); | |
| 777 pix = pixRead(gplot->outname); | |
| 778 gplotDestroy(&gplot); | |
| 779 if (!pix) | |
| 780 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL); | |
| 781 return pix; | |
| 782 } | |
| 783 | |
| 784 | |
| 785 /*! | |
| 786 * \brief gplotSimplePix2() | |
| 787 * | |
| 788 * \param[in] na1 numa; plot with Y_VS_I | |
| 789 * \param[in] na2 ditto | |
| 790 * \param[in] title [optional], can be NULL | |
| 791 * \return pix of plot, or null on error | |
| 792 * | |
| 793 * <pre> | |
| 794 * Notes: | |
| 795 * (1) This generates a pix with line plots of two numa, where each of | |
| 796 * two arrays is plotted vs the array index. the title is optional. | |
| 797 * (2) The temporary plot file is a png; its name is generated internally | |
| 798 * and stored in gplot. | |
| 799 * </pre> | |
| 800 */ | |
| 801 PIX * | |
| 802 gplotSimplePix2(NUMA *na1, | |
| 803 NUMA *na2, | |
| 804 const char *title) | |
| 805 { | |
| 806 char buf[64]; | |
| 807 static l_atomic index; | |
| 808 GPLOT *gplot; | |
| 809 PIX *pix; | |
| 810 | |
| 811 if (!na1 || !na2) | |
| 812 return (PIX *)ERROR_PTR("both na1, na2 not defined", __func__, NULL); | |
| 813 | |
| 814 lept_mkdir("lept/gplot/pix"); | |
| 815 snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pix2.%d", index++); | |
| 816 gplot = gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES, GPLOT_PNG, buf, title); | |
| 817 if (!gplot) | |
| 818 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL); | |
| 819 pix = pixRead(gplot->outname); | |
| 820 gplotDestroy(&gplot); | |
| 821 if (!pix) | |
| 822 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL); | |
| 823 return pix; | |
| 824 } | |
| 825 | |
| 826 | |
| 827 /*! | |
| 828 * \brief gplotSimplePixN() | |
| 829 * | |
| 830 * \param[in] naa numaa; plot Y_VS_I for each numa | |
| 831 * \param[in] title [optional], can be NULL | |
| 832 * \return pix of plot, or null on error | |
| 833 * | |
| 834 * <pre> | |
| 835 * Notes: | |
| 836 * (1) This generates a pix with an arbitrary number of line plots, | |
| 837 * each coming from a numa in %naa. Each array value is plotted | |
| 838 * vs the array index. The title is optional. | |
| 839 * (2) The temporary plot file is a png; its name is generated internally | |
| 840 * and stored in gplot. | |
| 841 * </pre> | |
| 842 */ | |
| 843 PIX * | |
| 844 gplotSimplePixN(NUMAA *naa, | |
| 845 const char *title) | |
| 846 { | |
| 847 char buf[64]; | |
| 848 static l_atomic index; | |
| 849 GPLOT *gplot; | |
| 850 PIX *pix; | |
| 851 | |
| 852 if (!naa) | |
| 853 return (PIX *)ERROR_PTR("naa not defined", __func__, NULL); | |
| 854 | |
| 855 lept_mkdir("lept/gplot/pix"); | |
| 856 snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pixN.%d", index++); | |
| 857 gplot = gplotSimpleXYN(NULL, naa, GPLOT_LINES, GPLOT_PNG, buf, title); | |
| 858 if (!gplot) | |
| 859 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL); | |
| 860 pix = pixRead(gplot->outname); | |
| 861 gplotDestroy(&gplot); | |
| 862 if (!pix) | |
| 863 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL); | |
| 864 return pix; | |
| 865 } | |
| 866 | |
| 867 | |
| 868 /*! | |
| 869 * \brief gplotSimpleXY1() | |
| 870 * | |
| 871 * \param[in] nax [optional] | |
| 872 * \param[in] nay [required] | |
| 873 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, | |
| 874 * GPLOT_LINESPOINTS, GPLOT_DOTS | |
| 875 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, | |
| 876 * GPLOT_LATEX, GPLOT_PNM | |
| 877 * \param[in] outroot root of output files | |
| 878 * \param[in] title [optional], can be NULL | |
| 879 * \return gplot or null on error | |
| 880 * | |
| 881 * <pre> | |
| 882 * Notes: | |
| 883 * (1) This generates a plot of a %nay vs %nax, generated in | |
| 884 * the specified output format. The title is optional. | |
| 885 * (2) Use 0 for default plotstyle (lines). | |
| 886 * (3) %nax is optional. If NULL, %nay is plotted against | |
| 887 * the array index. | |
| 888 * (4) When calling these simple plot functions more than once, use | |
| 889 * different %outroot to avoid overwriting the output files. | |
| 890 * (5) The returned gplot must be destroyed by the caller. | |
| 891 * </pre> | |
| 892 */ | |
| 893 GPLOT * | |
| 894 gplotSimpleXY1(NUMA *nax, | |
| 895 NUMA *nay, | |
| 896 l_int32 plotstyle, | |
| 897 l_int32 outformat, | |
| 898 const char *outroot, | |
| 899 const char *title) | |
| 900 { | |
| 901 GPLOT *gplot; | |
| 902 | |
| 903 if (!nay) | |
| 904 return (GPLOT *)ERROR_PTR("nay not defined", __func__, NULL); | |
| 905 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) | |
| 906 return (GPLOT *)ERROR_PTR("invalid plotstyle", __func__, NULL); | |
| 907 if (outformat != GPLOT_PNG && outformat != GPLOT_PS && | |
| 908 outformat != GPLOT_EPS && outformat != GPLOT_LATEX && | |
| 909 outformat != GPLOT_PNM) | |
| 910 return (GPLOT *)ERROR_PTR("invalid outformat", __func__, NULL); | |
| 911 if (!outroot) | |
| 912 return (GPLOT *)ERROR_PTR("outroot not specified", __func__, NULL); | |
| 913 | |
| 914 if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0) | |
| 915 return (GPLOT *)ERROR_PTR("gplot not made", __func__, NULL); | |
| 916 gplotAddPlot(gplot, nax, nay, plotstyle, NULL); | |
| 917 gplotMakeOutput(gplot); | |
| 918 return gplot; | |
| 919 } | |
| 920 | |
| 921 | |
| 922 /*! | |
| 923 * \brief gplotSimpleXY2() | |
| 924 * | |
| 925 * \param[in] nax [optional], can be NULL | |
| 926 * \param[in] nay1 | |
| 927 * \param[in] nay2 | |
| 928 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, | |
| 929 * GPLOT_LINESPOINTS, GPLOT_DOTS | |
| 930 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, | |
| 931 * GPLOT_LATEX, GPLOT_PNM | |
| 932 * \param[in] outroot root of output files | |
| 933 * \param[in] title [optional] | |
| 934 * \return gplot or null on error | |
| 935 * | |
| 936 * <pre> | |
| 937 * Notes: | |
| 938 * (1) This generates plots of %nay1 and %nay2 against %nax, generated | |
| 939 * in the specified output format. The title is optional. | |
| 940 * (2) Use 0 for default plotstyle (lines). | |
| 941 * (3) %nax is optional. If NULL, %nay1 and %nay2 are plotted | |
| 942 * against the array index. | |
| 943 * (4) When calling these simple plot functions more than once, use | |
| 944 * different %outroot to avoid overwriting the output files. | |
| 945 * (5) The returned gplot must be destroyed by the caller. | |
| 946 * </pre> | |
| 947 */ | |
| 948 GPLOT * | |
| 949 gplotSimpleXY2(NUMA *nax, | |
| 950 NUMA *nay1, | |
| 951 NUMA *nay2, | |
| 952 l_int32 plotstyle, | |
| 953 l_int32 outformat, | |
| 954 const char *outroot, | |
| 955 const char *title) | |
| 956 { | |
| 957 GPLOT *gplot; | |
| 958 | |
| 959 if (!nay1 || !nay2) | |
| 960 return (GPLOT *)ERROR_PTR("nay1 and nay2 not both defined", | |
| 961 __func__, NULL); | |
| 962 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) | |
| 963 return (GPLOT *)ERROR_PTR("invalid plotstyle", __func__, NULL); | |
| 964 if (outformat != GPLOT_PNG && outformat != GPLOT_PS && | |
| 965 outformat != GPLOT_EPS && outformat != GPLOT_LATEX && | |
| 966 outformat != GPLOT_PNM) | |
| 967 return (GPLOT *)ERROR_PTR("invalid outformat", __func__, NULL); | |
| 968 if (!outroot) | |
| 969 return (GPLOT *)ERROR_PTR("outroot not specified", __func__, NULL); | |
| 970 | |
| 971 if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0) | |
| 972 return (GPLOT *)ERROR_PTR("gplot not made", __func__, NULL); | |
| 973 gplotAddPlot(gplot, nax, nay1, plotstyle, NULL); | |
| 974 gplotAddPlot(gplot, nax, nay2, plotstyle, NULL); | |
| 975 gplotMakeOutput(gplot); | |
| 976 return gplot; | |
| 977 } | |
| 978 | |
| 979 | |
| 980 /*! | |
| 981 * \brief gplotSimpleXYN() | |
| 982 * | |
| 983 * \param[in] nax [optional]; can be NULL | |
| 984 * \param[in] naay numaa of arrays to plot against %nax | |
| 985 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, | |
| 986 * GPLOT_LINESPOINTS, GPLOT_DOTS | |
| 987 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, | |
| 988 * GPLOT_LATEX, GPLOT_PNM | |
| 989 * \param[in] outroot root of output files | |
| 990 * \param[in] title [optional] | |
| 991 * \return gplot or null on error | |
| 992 * | |
| 993 * <pre> | |
| 994 * Notes: | |
| 995 * (1) This generates plots of each Numa in %naa against %nax, | |
| 996 * generated in the specified output format. The title is optional. | |
| 997 * (2) Use 0 for default plotstyle (lines). | |
| 998 * (3) %nax is optional. If NULL, each Numa array is plotted against | |
| 999 * the array index. | |
| 1000 * (4) When calling these simple plot functions more than once, use | |
| 1001 * different %outroot to avoid overwriting the output files. | |
| 1002 * (5) The returned gplot must be destroyed by the caller. | |
| 1003 * </pre> | |
| 1004 */ | |
| 1005 GPLOT * | |
| 1006 gplotSimpleXYN(NUMA *nax, | |
| 1007 NUMAA *naay, | |
| 1008 l_int32 plotstyle, | |
| 1009 l_int32 outformat, | |
| 1010 const char *outroot, | |
| 1011 const char *title) | |
| 1012 { | |
| 1013 l_int32 i, n; | |
| 1014 GPLOT *gplot; | |
| 1015 NUMA *nay; | |
| 1016 | |
| 1017 if (!naay) | |
| 1018 return (GPLOT *)ERROR_PTR("naay not defined", __func__, NULL); | |
| 1019 if ((n = numaaGetCount(naay)) == 0) | |
| 1020 return (GPLOT *)ERROR_PTR("no numa in array", __func__, NULL); | |
| 1021 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) | |
| 1022 return (GPLOT *)ERROR_PTR("invalid plotstyle", __func__, NULL); | |
| 1023 if (outformat != GPLOT_PNG && outformat != GPLOT_PS && | |
| 1024 outformat != GPLOT_EPS && outformat != GPLOT_LATEX && | |
| 1025 outformat != GPLOT_PNM) | |
| 1026 return (GPLOT *)ERROR_PTR("invalid outformat", __func__, NULL); | |
| 1027 if (!outroot) | |
| 1028 return (GPLOT *)ERROR_PTR("outroot not specified", __func__, NULL); | |
| 1029 | |
| 1030 if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0) | |
| 1031 return (GPLOT *)ERROR_PTR("gplot not made", __func__, NULL); | |
| 1032 for (i = 0; i < n; i++) { | |
| 1033 nay = numaaGetNuma(naay, i, L_CLONE); | |
| 1034 gplotAddPlot(gplot, nax, nay, plotstyle, NULL); | |
| 1035 numaDestroy(&nay); | |
| 1036 } | |
| 1037 gplotMakeOutput(gplot); | |
| 1038 return gplot; | |
| 1039 } | |
| 1040 | |
| 1041 | |
| 1042 /*! | |
| 1043 * \brief gplotGeneralPix1() | |
| 1044 * | |
| 1045 * \param[in] na data array | |
| 1046 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, | |
| 1047 * GPLOT_LINESPOINTS, GPLOT_DOTS | |
| 1048 * \param[in] rootname root for all output files | |
| 1049 * \param[in] title [optional] overall title | |
| 1050 * \param[in] xlabel [optional] x axis label | |
| 1051 * \param[in] ylabel [optional] y axis label | |
| 1052 * \return pix of plot, or NULL on error | |
| 1053 * | |
| 1054 * <pre> | |
| 1055 * Notes: | |
| 1056 * (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces, | |
| 1057 * double quotes and backquotes, but not single quotes. | |
| 1058 * </pre> | |
| 1059 */ | |
| 1060 PIX * | |
| 1061 gplotGeneralPix1(NUMA *na, | |
| 1062 l_int32 plotstyle, | |
| 1063 const char *rootname, | |
| 1064 const char *title, | |
| 1065 const char *xlabel, | |
| 1066 const char *ylabel) | |
| 1067 { | |
| 1068 GPLOT *gplot; | |
| 1069 PIX *pix; | |
| 1070 | |
| 1071 if (!na) | |
| 1072 return (PIX *)ERROR_PTR("na not defined", __func__, NULL); | |
| 1073 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) | |
| 1074 return (PIX *)ERROR_PTR("invalid plotstyle", __func__, NULL); | |
| 1075 if (!rootname) | |
| 1076 return (PIX *)ERROR_PTR("rootname not defined", __func__, NULL); | |
| 1077 | |
| 1078 gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel); | |
| 1079 if (!gplot) | |
| 1080 return (PIX *)ERROR_PTR("gplot not made", __func__, NULL); | |
| 1081 gplotAddPlot(gplot, NULL, na, plotstyle, NULL); | |
| 1082 pix = gplotMakeOutputPix(gplot); | |
| 1083 gplotDestroy(&gplot); | |
| 1084 return pix; | |
| 1085 } | |
| 1086 | |
| 1087 | |
| 1088 /*! | |
| 1089 * \brief gplotGeneralPix2() | |
| 1090 * | |
| 1091 * \param[in] na1 x-axis data array | |
| 1092 * \param[in] na2 y-axis data array | |
| 1093 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, | |
| 1094 * GPLOT_LINESPOINTS, GPLOT_DOTS | |
| 1095 * \param[in] rootname root for all output files | |
| 1096 * \param[in] title [optional] overall title | |
| 1097 * \param[in] xlabel [optional] x axis label | |
| 1098 * \param[in] ylabel [optional] y axis label | |
| 1099 * \return pix of plot, or NULL on error | |
| 1100 * | |
| 1101 * <pre> | |
| 1102 * Notes: | |
| 1103 * (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces, | |
| 1104 * double quotes and backquotes, but not single quotes. | |
| 1105 * </pre> | |
| 1106 */ | |
| 1107 PIX * | |
| 1108 gplotGeneralPix2(NUMA *na1, | |
| 1109 NUMA *na2, | |
| 1110 l_int32 plotstyle, | |
| 1111 const char *rootname, | |
| 1112 const char *title, | |
| 1113 const char *xlabel, | |
| 1114 const char *ylabel) | |
| 1115 { | |
| 1116 GPLOT *gplot; | |
| 1117 PIX *pix; | |
| 1118 | |
| 1119 if (!na1) | |
| 1120 return (PIX *)ERROR_PTR("na1 not defined", __func__, NULL); | |
| 1121 if (!na2) | |
| 1122 return (PIX *)ERROR_PTR("na2 not defined", __func__, NULL); | |
| 1123 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) | |
| 1124 return (PIX *)ERROR_PTR("invalid plotstyle", __func__, NULL); | |
| 1125 if (!rootname) | |
| 1126 return (PIX *)ERROR_PTR("rootname not defined", __func__, NULL); | |
| 1127 | |
| 1128 gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel); | |
| 1129 if (!gplot) | |
| 1130 return (PIX *)ERROR_PTR("gplot not made", __func__, NULL); | |
| 1131 gplotAddPlot(gplot, na1, na2, plotstyle, NULL); | |
| 1132 pix = gplotMakeOutputPix(gplot); | |
| 1133 gplotDestroy(&gplot); | |
| 1134 return pix; | |
| 1135 } | |
| 1136 | |
| 1137 | |
| 1138 /*! | |
| 1139 * \brief gplotGeneralPixN() | |
| 1140 * | |
| 1141 * \param[in] nax x-axis data array | |
| 1142 * \param[in] naay array of y-axis data arrays | |
| 1143 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, | |
| 1144 * GPLOT_LINESPOINTS, GPLOT_DOTS | |
| 1145 * \param[in] rootname root for all output files | |
| 1146 * \param[in] title [optional] overall title | |
| 1147 * \param[in] xlabel [optional] x axis label | |
| 1148 * \param[in] ylabel [optional] y axis label | |
| 1149 * \return pix of plot, or NULL on error | |
| 1150 * | |
| 1151 * <pre> | |
| 1152 * Notes: | |
| 1153 * (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces, | |
| 1154 * double quotes and backquotes, but not single quotes. | |
| 1155 * </pre> | |
| 1156 */ | |
| 1157 PIX * | |
| 1158 gplotGeneralPixN(NUMA *nax, | |
| 1159 NUMAA *naay, | |
| 1160 l_int32 plotstyle, | |
| 1161 const char *rootname, | |
| 1162 const char *title, | |
| 1163 const char *xlabel, | |
| 1164 const char *ylabel) | |
| 1165 { | |
| 1166 l_int32 i, n; | |
| 1167 GPLOT *gplot; | |
| 1168 NUMA *nay; | |
| 1169 PIX *pix; | |
| 1170 | |
| 1171 if (!nax) | |
| 1172 return (PIX *)ERROR_PTR("nax not defined", __func__, NULL); | |
| 1173 if (!naay) | |
| 1174 return (PIX *)ERROR_PTR("naay not defined", __func__, NULL); | |
| 1175 if ((n = numaaGetCount(naay)) == 0) | |
| 1176 return (PIX *)ERROR_PTR("no numa in array", __func__, NULL); | |
| 1177 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) | |
| 1178 return (PIX *)ERROR_PTR("invalid plotstyle", __func__, NULL); | |
| 1179 if (!rootname) | |
| 1180 return (PIX *)ERROR_PTR("rootname not defined", __func__, NULL); | |
| 1181 | |
| 1182 gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel); | |
| 1183 if (!gplot) | |
| 1184 return (PIX *)ERROR_PTR("gplot not made", __func__, NULL); | |
| 1185 for (i = 0; i < n; i++) { | |
| 1186 nay = numaaGetNuma(naay, i, L_CLONE); | |
| 1187 gplotAddPlot(gplot, nax, nay, plotstyle, NULL); | |
| 1188 numaDestroy(&nay); | |
| 1189 } | |
| 1190 pix = gplotMakeOutputPix(gplot); | |
| 1191 gplotDestroy(&gplot); | |
| 1192 return pix; | |
| 1193 } | |
| 1194 | |
| 1195 | |
| 1196 /*-----------------------------------------------------------------* | |
| 1197 * Serialize for I/O * | |
| 1198 *-----------------------------------------------------------------*/ | |
| 1199 /*! | |
| 1200 * \brief gplotRead() | |
| 1201 * | |
| 1202 * \param[in] filename | |
| 1203 * \return gplot, or NULL on error | |
| 1204 */ | |
| 1205 GPLOT * | |
| 1206 gplotRead(const char *filename) | |
| 1207 { | |
| 1208 char buf[Bufsize]; | |
| 1209 char *rootname, *title, *xlabel, *ylabel, *ignores; | |
| 1210 l_int32 outformat, ret, version, ignore; | |
| 1211 FILE *fp; | |
| 1212 GPLOT *gplot; | |
| 1213 | |
| 1214 if (!filename) | |
| 1215 return (GPLOT *)ERROR_PTR("filename not defined", __func__, NULL); | |
| 1216 | |
| 1217 if ((fp = fopenReadStream(filename)) == NULL) | |
| 1218 return (GPLOT *)ERROR_PTR_1("stream not opened", | |
| 1219 filename, __func__, NULL); | |
| 1220 | |
| 1221 ret = fscanf(fp, "Gplot Version %d\n", &version); | |
| 1222 if (ret != 1) { | |
| 1223 fclose(fp); | |
| 1224 return (GPLOT *)ERROR_PTR_1("not a gplot file", | |
| 1225 filename, __func__, NULL); | |
| 1226 } | |
| 1227 if (version != GPLOT_VERSION_NUMBER) { | |
| 1228 fclose(fp); | |
| 1229 return (GPLOT *)ERROR_PTR_1("invalid gplot version", | |
| 1230 filename, __func__, NULL); | |
| 1231 } | |
| 1232 | |
| 1233 ignore = fscanf(fp, "Rootname: %511s\n", buf); /* Bufsize - 1 */ | |
| 1234 rootname = stringNew(buf); | |
| 1235 ignore = fscanf(fp, "Output format: %d\n", &outformat); | |
| 1236 ignores = fgets(buf, Bufsize, fp); /* Title: ... */ | |
| 1237 title = stringNew(buf + 7); | |
| 1238 title[strlen(title) - 1] = '\0'; | |
| 1239 ignores = fgets(buf, Bufsize, fp); /* X axis label: ... */ | |
| 1240 xlabel = stringNew(buf + 14); | |
| 1241 xlabel[strlen(xlabel) - 1] = '\0'; | |
| 1242 ignores = fgets(buf, Bufsize, fp); /* Y axis label: ... */ | |
| 1243 ylabel = stringNew(buf + 14); | |
| 1244 ylabel[strlen(ylabel) - 1] = '\0'; | |
| 1245 | |
| 1246 gplot = gplotCreate(rootname, outformat, title, xlabel, ylabel); | |
| 1247 LEPT_FREE(rootname); | |
| 1248 LEPT_FREE(title); | |
| 1249 LEPT_FREE(xlabel); | |
| 1250 LEPT_FREE(ylabel); | |
| 1251 if (!gplot) { | |
| 1252 fclose(fp); | |
| 1253 return (GPLOT *)ERROR_PTR_1("gplot not made", filename, __func__, NULL); | |
| 1254 } | |
| 1255 sarrayDestroy(&gplot->cmddata); | |
| 1256 sarrayDestroy(&gplot->datanames); | |
| 1257 sarrayDestroy(&gplot->plotdata); | |
| 1258 sarrayDestroy(&gplot->plotlabels); | |
| 1259 numaDestroy(&gplot->plotstyles); | |
| 1260 | |
| 1261 ignore = fscanf(fp, "Commandfile name: %s\n", buf); /* Bufsize - 1 */ | |
| 1262 stringReplace(&gplot->cmdname, buf); | |
| 1263 ignore = fscanf(fp, "\nCommandfile data:"); | |
| 1264 gplot->cmddata = sarrayReadStream(fp); | |
| 1265 ignore = fscanf(fp, "\nDatafile names:"); | |
| 1266 gplot->datanames = sarrayReadStream(fp); | |
| 1267 ignore = fscanf(fp, "\nPlot data:"); | |
| 1268 gplot->plotdata = sarrayReadStream(fp); | |
| 1269 ignore = fscanf(fp, "\nPlot titles:"); | |
| 1270 gplot->plotlabels = sarrayReadStream(fp); | |
| 1271 ignore = fscanf(fp, "\nPlot styles:"); | |
| 1272 gplot->plotstyles = numaReadStream(fp); | |
| 1273 | |
| 1274 ignore = fscanf(fp, "Number of plots: %d\n", &gplot->nplots); | |
| 1275 ignore = fscanf(fp, "Output file name: %s\n", buf); | |
| 1276 stringReplace(&gplot->outname, buf); | |
| 1277 ignore = fscanf(fp, "Axis scaling: %d\n", &gplot->scaling); | |
| 1278 | |
| 1279 fclose(fp); | |
| 1280 return gplot; | |
| 1281 } | |
| 1282 | |
| 1283 | |
| 1284 /*! | |
| 1285 * \brief gplotWrite() | |
| 1286 * | |
| 1287 * \param[in] filename | |
| 1288 * \param[in] gplot | |
| 1289 * \return 0 if OK; 1 on error | |
| 1290 */ | |
| 1291 l_ok | |
| 1292 gplotWrite(const char *filename, | |
| 1293 GPLOT *gplot) | |
| 1294 { | |
| 1295 FILE *fp; | |
| 1296 | |
| 1297 if (!filename) | |
| 1298 return ERROR_INT("filename not defined", __func__, 1); | |
| 1299 if (!gplot) | |
| 1300 return ERROR_INT("gplot not defined", __func__, 1); | |
| 1301 | |
| 1302 if ((fp = fopenWriteStream(filename, "wb")) == NULL) | |
| 1303 return ERROR_INT_1("stream not opened", filename, __func__, 1); | |
| 1304 | |
| 1305 fprintf(fp, "Gplot Version %d\n", GPLOT_VERSION_NUMBER); | |
| 1306 fprintf(fp, "Rootname: %s\n", gplot->rootname); | |
| 1307 fprintf(fp, "Output format: %d\n", gplot->outformat); | |
| 1308 fprintf(fp, "Title: %s\n", gplot->title); | |
| 1309 fprintf(fp, "X axis label: %s\n", gplot->xlabel); | |
| 1310 fprintf(fp, "Y axis label: %s\n", gplot->ylabel); | |
| 1311 | |
| 1312 fprintf(fp, "Commandfile name: %s\n", gplot->cmdname); | |
| 1313 fprintf(fp, "\nCommandfile data:"); | |
| 1314 sarrayWriteStream(fp, gplot->cmddata); | |
| 1315 fprintf(fp, "\nDatafile names:"); | |
| 1316 sarrayWriteStream(fp, gplot->datanames); | |
| 1317 fprintf(fp, "\nPlot data:"); | |
| 1318 sarrayWriteStream(fp, gplot->plotdata); | |
| 1319 fprintf(fp, "\nPlot titles:"); | |
| 1320 sarrayWriteStream(fp, gplot->plotlabels); | |
| 1321 fprintf(fp, "\nPlot styles:"); | |
| 1322 numaWriteStderr(gplot->plotstyles); | |
| 1323 | |
| 1324 fprintf(fp, "Number of plots: %d\n", gplot->nplots); | |
| 1325 fprintf(fp, "Output file name: %s\n", gplot->outname); | |
| 1326 fprintf(fp, "Axis scaling: %d\n", gplot->scaling); | |
| 1327 | |
| 1328 fclose(fp); | |
| 1329 return 0; | |
| 1330 } |
