/*====================================================================* - Copyright (C) 2001 Leptonica. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *====================================================================*/ /*! * \file gplot.c *
 *
 *     Basic plotting functions
 *          GPLOT      *gplotCreate()
 *          void        gplotDestroy()
 *          l_int32     gplotAddPlot()
 *          l_int32     gplotSetScaling()
 *          PIX        *gplotMakeOutputPix()
 *          l_int32     gplotMakeOutput()
 *          l_int32     gplotGenCommandFile()
 *          l_int32     gplotGenDataFiles()
 *
 *     Quick, one-line plots
 *          l_int32     gplotSimple1()
 *          l_int32     gplotSimple2()
 *          l_int32     gplotSimpleN()
 *          PIX        *gplotSimplePix1()
 *          PIX        *gplotSimplePix2()
 *          PIX        *gplotSimplePixN()
 *          GPLOT      *gplotSimpleXY1()
 *          GPLOT      *gplotSimpleXY2()
 *          GPLOT      *gplotSimpleXYN()
 *          PIX        *gplotGeneralPix1()
 *          PIX        *gplotGeneralPix2()
 *          PIX        *gplotGeneralPixN()
 *
 *     Serialize for I/O
 *          GPLOT      *gplotRead()
 *          l_int32     gplotWrite()
 *
 *
 *     Utility for programmatic plotting using gnuplot 4.6 or later
 *     Enabled:
 *         ~ output to png (color), ps and eps (mono), latex (mono)
 *         ~ optional title for plot
 *         ~ optional x and y axis labels
 *         ~ multiple plots on one frame
 *         ~ optional label for each plot on the frame
 *         ~ optional log scaling on either or both axes
 *         ~ choice of 5 plot styles for each array of input data
 *         ~ choice of 2 plot modes, either using one input array
 *           (Y vs index) or two input arrays (Y vs X).  For functions
 *           that take two arrays, the first mode (Y vs index) is
 *           employed if the first array is NULL.
 *
 *     General usage:
 *         gplotCreate() initializes for plotting
 *         gplotAddPlot() for each plot on the frame
 *         gplotMakeOutput() to generate all output files and run gnuplot
 *         gplotDestroy() to clean up
 *
 *     Example of use:
 *         gplot = gplotCreate("tempskew", GPLOT_PNG, "Skew score vs angle",
 *                    "angle (deg)", "score");
 *         gplotAddPlot(gplot, natheta, nascore1, GPLOT_LINES, "plot 1");
 *         gplotAddPlot(gplot, natheta, nascore2, GPLOT_POINTS, "plot 2");
 *         gplotSetScaling(gplot, GPLOT_LOG_SCALE_Y);
 *         gplotMakeOutput(gplot);
 *         gplotDestroy(&gplot);
 *
 *     Example usage of one-line plot generators:
 *
 *         -- Simple plots --
 *         Specify the root of output files, the output format,
 *         and the title (optional), but not the x and y coordinate labels
 *         or the plot labels.  The plotstyle defaults to GPLOT_LINES.
 *            gplotSimple2(na1, na2, GPLOT_PNG, "/tmp/lept/histo/gray",
 *                         "gray histogram");
 *         Multiple plots can be generated using gplotSimpleN().
 *
 *         -- Simple plots with more options --
 *         Specify the root of output files, the plotstyle, the output format,
 *         and optionally the title, but not the x and y coordinate labels
 *         or the plot labels.
 *            gplotSimpleXY1(na1, na2, GPLOT_LINES, GPLOT_PNG,
 *                           "/tmp/lept/histo/gray", "gray histogram");
 *         Multiple plots can be generated using gplotSimpleXYN().
 *
 *         -- Simple plots returning a pix --
 *         Specify only the title (optional).  The plotstyle defaults
 *         GPLOT_LINES and the output format is GPLOT_PNG..
 *         You can't specify the x and y coordinate lables or the plot label.
 *         The rootname of the generated files is determined internally.
 *            Pix *pix = gplotSimplePix2(na1, na2, "gray histogram");
 *         Multiple plots can be generated using gplotSimplePixN().
 *
 *         -- General plots returning a pix --
 *         Specify the root of the output files, the plotstyle, and optionally
 *         the title and axis labels.  This does not allow the individual
 *         plots to have plot labels, or to use different plotstyles
 *         for each plot.
 *            Pix *pix = gplotGeneralPix2(na1, na2, "/tmp/lept/histo/gray",
 *                                   GPLOT_LINES, "gray histogram",
 *                                   "pix value", "num pixels");
 *         Multiple plots can be generated using gplotGeneralPixN().
 *
 *     Note for output to GPLOT_LATEX:
 *         This creates latex output of the plot, named .tex.
 *         It needs to be placed in a latex file .tex
 *         that precedes the plot output with, at a minimum:
 *           \documentclass{article}
 *           \begin{document}
 *         and ends with
 *           \end{document}
 *         You can then generate a dvi file .dvi using
 *           latex .tex
 *         and a PostScript file .ps from that using
 *           dvips -o .ps .dvi
 *
 *     N.B. To generate plots, it is necessary to have gnuplot installed on
 *          your Unix system, or wgnuplot on Windows.
 * 
*/ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include "allheaders.h" #define Bufsize 512 /* hardcoded below in fscanf */ const char *gplotstylenames[] = {"with lines", "with points", "with impulses", "with linespoints", "with dots"}; const char *gplotfileoutputs[] = {"", "PNG", "PS", "EPS", "LATEX", "PNM"}; /*-----------------------------------------------------------------* * Basic Plotting Functions * *-----------------------------------------------------------------*/ /*! * \brief gplotCreate() * * \param[in] rootname root for all output files * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, * GPLOT_LATEX, GPLOT_PNM * \param[in] title [optional] overall title * \param[in] xlabel [optional] x axis label * \param[in] ylabel [optional] y axis label * \return gplot, or NULL on error * *
 * Notes:
 *      (1) This initializes the plot.
 *      (2) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
 *          double quotes and backquotes, but not single quotes.
 * 
*/ GPLOT * gplotCreate(const char *rootname, l_int32 outformat, const char *title, const char *xlabel, const char *ylabel) { char *newroot; char buf[Bufsize]; l_int32 badchar; GPLOT *gplot; PROCNAME("gplotCreate"); if (!rootname) return (GPLOT *)ERROR_PTR("rootname not defined", procName, NULL); if (outformat != GPLOT_PNG && outformat != GPLOT_PS && outformat != GPLOT_EPS && outformat != GPLOT_LATEX && outformat != GPLOT_PNM) return (GPLOT *)ERROR_PTR("outformat invalid", procName, NULL); stringCheckForChars(rootname, "`;&|><\"?*$()", &badchar); if (badchar) /* danger of command injection */ return (GPLOT *)ERROR_PTR("invalid rootname", procName, NULL); #if !defined(HAVE_LIBPNG) if (outformat == GPLOT_PNG) { L_WARNING("png library missing; output pnm format\n", procName); outformat = GPLOT_PNM; } #endif gplot = (GPLOT *)LEPT_CALLOC(1, sizeof(GPLOT)); gplot->cmddata = sarrayCreate(0); gplot->datanames = sarrayCreate(0); gplot->plotdata = sarrayCreate(0); gplot->plotlabels = sarrayCreate(0); gplot->plotstyles = numaCreate(0); /* Save title, labels, rootname, outformat, cmdname, outname */ newroot = genPathname(rootname, NULL); gplot->rootname = newroot; gplot->outformat = outformat; snprintf(buf, Bufsize, "%s.cmd", rootname); gplot->cmdname = stringNew(buf); if (outformat == GPLOT_PNG) snprintf(buf, Bufsize, "%s.png", newroot); else if (outformat == GPLOT_PS) snprintf(buf, Bufsize, "%s.ps", newroot); else if (outformat == GPLOT_EPS) snprintf(buf, Bufsize, "%s.eps", newroot); else if (outformat == GPLOT_LATEX) snprintf(buf, Bufsize, "%s.tex", newroot); else if (outformat == GPLOT_PNM) snprintf(buf, Bufsize, "%s.pnm", newroot); gplot->outname = stringNew(buf); if (title) gplot->title = stringNew(title); if (xlabel) gplot->xlabel = stringNew(xlabel); if (ylabel) gplot->ylabel = stringNew(ylabel); return gplot; } /*! * \brief gplotDestroy() * * \param[in,out] pgplot will be set to null before returning */ void gplotDestroy(GPLOT **pgplot) { GPLOT *gplot; PROCNAME("gplotDestroy"); if (pgplot == NULL) { L_WARNING("ptr address is null!\n", procName); return; } if ((gplot = *pgplot) == NULL) return; LEPT_FREE(gplot->rootname); LEPT_FREE(gplot->cmdname); sarrayDestroy(&gplot->cmddata); sarrayDestroy(&gplot->datanames); sarrayDestroy(&gplot->plotdata); sarrayDestroy(&gplot->plotlabels); numaDestroy(&gplot->plotstyles); LEPT_FREE(gplot->outname); if (gplot->title) LEPT_FREE(gplot->title); if (gplot->xlabel) LEPT_FREE(gplot->xlabel); if (gplot->ylabel) LEPT_FREE(gplot->ylabel); LEPT_FREE(gplot); *pgplot = NULL; } /*! * \brief gplotAddPlot() * * \param[in] gplot * \param[in] nax [optional] numa: set to null for Y_VS_I; * required for Y_VS_X * \param[in] nay numa; required for both Y_VS_I and Y_VS_X * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, * GPLOT_LINESPOINTS, GPLOT_DOTS * \param[in] plotlabel [optional] label for individual plot * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) There are 2 options for (x,y) values:
 *            o  To plot an array vs a linear function of the
 *               index, set %nax = NULL.
 *            o  To plot one array vs another, use both %nax and %nay.
 *      (2) If %nax is NULL, the x value corresponding to the i-th
 *          value of %nay is found from the startx and delx fields
 *          in %nay:
 *               x = startx + i * delx
 *          These are set with numaSetParameters().  Their default
 *          values are startx = 0.0, delx = 1.0.
 *      (3) If %nax is defined, it must be the same size as %nay, and
 *          must have at least one number.
 *      (4) The 'plotlabel' string can have spaces, double
 *          quotes and backquotes, but not single quotes.
 * 
*/ l_ok gplotAddPlot(GPLOT *gplot, NUMA *nax, NUMA *nay, l_int32 plotstyle, const char *plotlabel) { char buf[Bufsize]; char emptystring[] = ""; char *datastr, *title; l_int32 n, i; l_float32 valx, valy, startx, delx; SARRAY *sa; PROCNAME("gplotAddPlot"); if (!gplot) return ERROR_INT("gplot not defined", procName, 1); if (!nay) return ERROR_INT("nay not defined", procName, 1); if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) return ERROR_INT("invalid plotstyle", procName, 1); if ((n = numaGetCount(nay)) == 0) return ERROR_INT("no points to plot", procName, 1); if (nax && (n != numaGetCount(nax))) return ERROR_INT("nax and nay sizes differ", procName, 1); if (n == 1 && plotstyle == GPLOT_LINES) { L_INFO("only 1 pt; changing style to points\n", procName); plotstyle = GPLOT_POINTS; } /* Save plotstyle and plotlabel */ numaGetParameters(nay, &startx, &delx); numaAddNumber(gplot->plotstyles, plotstyle); if (plotlabel) { title = stringNew(plotlabel); sarrayAddString(gplot->plotlabels, title, L_INSERT); } else { sarrayAddString(gplot->plotlabels, emptystring, L_COPY); } /* Generate and save data filename */ gplot->nplots++; snprintf(buf, Bufsize, "%s.data.%d", gplot->rootname, gplot->nplots); sarrayAddString(gplot->datanames, buf, L_COPY); /* Generate data and save as a string */ sa = sarrayCreate(n); for (i = 0; i < n; i++) { if (nax) numaGetFValue(nax, i, &valx); else valx = startx + i * delx; numaGetFValue(nay, i, &valy); snprintf(buf, Bufsize, "%f %f\n", valx, valy); sarrayAddString(sa, buf, L_COPY); } datastr = sarrayToString(sa, 0); sarrayAddString(gplot->plotdata, datastr, L_INSERT); sarrayDestroy(&sa); return 0; } /*! * \brief gplotSetScaling() * * \param[in] gplot * \param[in] scaling GPLOT_LINEAR_SCALE, GPLOT_LOG_SCALE_X, * GPLOT_LOG_SCALE_Y, GPLOT_LOG_SCALE_X_Y * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) By default, the x and y axis scaling is linear.
 *      (2) Call this function to set semi-log or log-log scaling.
 * 
*/ l_ok gplotSetScaling(GPLOT *gplot, l_int32 scaling) { PROCNAME("gplotSetScaling"); if (!gplot) return ERROR_INT("gplot not defined", procName, 1); if (scaling != GPLOT_LINEAR_SCALE && scaling != GPLOT_LOG_SCALE_X && scaling != GPLOT_LOG_SCALE_Y && scaling != GPLOT_LOG_SCALE_X_Y) return ERROR_INT("invalid gplot scaling", procName, 1); gplot->scaling = scaling; return 0; } /*! * \brief gplotMakeOutputPix() * * \param[in] gplot * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) This wraps gplotMakeOutput(), and returns a pix.
 *          See gplotMakeOutput() for details.
 *      (2) The gplot output format must be an image (png or pnm).
 * 
*/ PIX * gplotMakeOutputPix(GPLOT *gplot) { PROCNAME("gplotMakeOutputPix"); if (!gplot) return (PIX *)ERROR_PTR("gplot not defined", procName, NULL); if (gplot->outformat != GPLOT_PNG && gplot->outformat != GPLOT_PNM) return (PIX *)ERROR_PTR("output format not an image", procName, NULL); if (gplotMakeOutput(gplot)) return (PIX *)ERROR_PTR("plot output not made", procName, NULL); return pixRead(gplot->outname); } /*! * \brief gplotMakeOutput() * * \param[in] gplot * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) This uses gplot and the new arrays to add a plot
 *          to the output, by writing a new data file and appending
 *          the appropriate plot commands to the command file.
 *      (2) Along with gplotMakeOutputPix(), these are the only functions
 *          in this file that requires the gnuplot executable to
 *          actually generate the plot.
 *      (3) The command file name for unix is canonical (i.e., directory /tmp)
 *          but the temp filename paths in the command file must be correct.
 *      (4) The gnuplot program for windows is wgnuplot.exe.
 * 
*/ l_ok gplotMakeOutput(GPLOT *gplot) { char buf[Bufsize]; char *cmdname; PROCNAME("gplotMakeOutput"); if (!gplot) return ERROR_INT("gplot not defined", procName, 1); if (!LeptDebugOK) { L_INFO("running gnuplot is disabled; " "use setLeptDebugOK(1) to enable\n", procName); return 0; } #ifdef OS_IOS /* iOS 11 does not support system() */ return ERROR_INT("iOS 11 does not support system()", procName, 0); #endif /* OS_IOS */ gplotGenCommandFile(gplot); gplotGenDataFiles(gplot); cmdname = genPathname(gplot->cmdname, NULL); #ifndef _WIN32 snprintf(buf, Bufsize, "gnuplot %s", cmdname); #else snprintf(buf, Bufsize, "wgnuplot %s", cmdname); #endif /* _WIN32 */ callSystemDebug(buf); /* gnuplot || wgnuplot */ LEPT_FREE(cmdname); return 0; } /*! * \brief gplotGenCommandFile() * * \param[in] gplot * \return 0 if OK, 1 on error */ l_ok gplotGenCommandFile(GPLOT *gplot) { char buf[Bufsize]; char *cmdstr, *plotlabel, *dataname; l_int32 i, plotstyle, nplots; FILE *fp; PROCNAME("gplotGenCommandFile"); if (!gplot) return ERROR_INT("gplot not defined", procName, 1); /* Remove any previous command data */ sarrayClear(gplot->cmddata); /* Generate command data instructions */ if (gplot->title) { /* set title */ snprintf(buf, Bufsize, "set title '%s'", gplot->title); sarrayAddString(gplot->cmddata, buf, L_COPY); } if (gplot->xlabel) { /* set xlabel */ snprintf(buf, Bufsize, "set xlabel '%s'", gplot->xlabel); sarrayAddString(gplot->cmddata, buf, L_COPY); } if (gplot->ylabel) { /* set ylabel */ snprintf(buf, Bufsize, "set ylabel '%s'", gplot->ylabel); sarrayAddString(gplot->cmddata, buf, L_COPY); } /* Set terminal type and output */ if (gplot->outformat == GPLOT_PNG) { snprintf(buf, Bufsize, "set terminal png; set output '%s'", gplot->outname); } else if (gplot->outformat == GPLOT_PS) { snprintf(buf, Bufsize, "set terminal postscript; set output '%s'", gplot->outname); } else if (gplot->outformat == GPLOT_EPS) { snprintf(buf, Bufsize, "set terminal postscript eps; set output '%s'", gplot->outname); } else if (gplot->outformat == GPLOT_LATEX) { snprintf(buf, Bufsize, "set terminal latex; set output '%s'", gplot->outname); } else if (gplot->outformat == GPLOT_PNM) { snprintf(buf, Bufsize, "set terminal pbm color; set output '%s'", gplot->outname); } sarrayAddString(gplot->cmddata, buf, L_COPY); if (gplot->scaling == GPLOT_LOG_SCALE_X || gplot->scaling == GPLOT_LOG_SCALE_X_Y) { snprintf(buf, Bufsize, "set logscale x"); sarrayAddString(gplot->cmddata, buf, L_COPY); } if (gplot->scaling == GPLOT_LOG_SCALE_Y || gplot->scaling == GPLOT_LOG_SCALE_X_Y) { snprintf(buf, Bufsize, "set logscale y"); sarrayAddString(gplot->cmddata, buf, L_COPY); } nplots = sarrayGetCount(gplot->datanames); for (i = 0; i < nplots; i++) { plotlabel = sarrayGetString(gplot->plotlabels, i, L_NOCOPY); dataname = sarrayGetString(gplot->datanames, i, L_NOCOPY); numaGetIValue(gplot->plotstyles, i, &plotstyle); if (nplots == 1) { snprintf(buf, Bufsize, "plot '%s' title '%s' %s", dataname, plotlabel, gplotstylenames[plotstyle]); } else { if (i == 0) snprintf(buf, Bufsize, "plot '%s' title '%s' %s, \\", dataname, plotlabel, gplotstylenames[plotstyle]); else if (i < nplots - 1) snprintf(buf, Bufsize, " '%s' title '%s' %s, \\", dataname, plotlabel, gplotstylenames[plotstyle]); else snprintf(buf, Bufsize, " '%s' title '%s' %s", dataname, plotlabel, gplotstylenames[plotstyle]); } sarrayAddString(gplot->cmddata, buf, L_COPY); } /* Write command data to file */ cmdstr = sarrayToString(gplot->cmddata, 1); if ((fp = fopenWriteStream(gplot->cmdname, "w")) == NULL) { LEPT_FREE(cmdstr); return ERROR_INT("cmd stream not opened", procName, 1); } fwrite(cmdstr, 1, strlen(cmdstr), fp); fclose(fp); LEPT_FREE(cmdstr); return 0; } /*! * \brief gplotGenDataFiles() * * \param[in] gplot * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) The pathnames in the gplot command file are actual pathnames,
 *          which can be in temp directories.  Consequently, they must not be
 *          rewritten by calling fopenWriteStream(), and we use fopen().
 * 
*/ l_ok gplotGenDataFiles(GPLOT *gplot) { char *plotdata, *dataname; l_int32 i, nplots; FILE *fp; PROCNAME("gplotGenDataFiles"); if (!gplot) return ERROR_INT("gplot not defined", procName, 1); nplots = sarrayGetCount(gplot->datanames); for (i = 0; i < nplots; i++) { plotdata = sarrayGetString(gplot->plotdata, i, L_NOCOPY); dataname = sarrayGetString(gplot->datanames, i, L_NOCOPY); if ((fp = fopen(dataname, "w")) == NULL) return ERROR_INT("datafile stream not opened", procName, 1); fwrite(plotdata, 1, strlen(plotdata), fp); fclose(fp); } return 0; } /*-----------------------------------------------------------------* * Quick one-line plots * *-----------------------------------------------------------------*/ /*! * \brief gplotSimple1() * * \param[in] na numa; plot Y_VS_I * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, * GPLOT_LATEX, GPLOT_PNM * \param[in] outroot root of output files * \param[in] title [optional], can be NULL * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) This generates a line plot of a numa, where the array value
 *          is plotted vs the array index.  The plot is generated
 *          in the specified output format; the title  is optional.
 *      (2) When calling these simple plot functions more than once, use
 *          different %outroot to avoid overwriting the output files.
 * 
*/ l_ok gplotSimple1(NUMA *na, l_int32 outformat, const char *outroot, const char *title) { GPLOT *gplot; PROCNAME("gplotSimple1"); gplot = gplotSimpleXY1(NULL, na, GPLOT_LINES, outformat, outroot, title); if (!gplot) return ERROR_INT("failed to generate plot", procName, 1); gplotDestroy(&gplot); return 0; } /*! * \brief gplotSimple2() * * \param[in] na1 numa; plot with Y_VS_I * \param[in] na2 ditto * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, * GPLOT_LATEX, GPLOT_PNM * \param[in] outroot root of output files * \param[in] title [optional] * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) This generates a line plot of two numa, where the array values
 *          are each plotted vs the array index.  The plot is generated
 *          in the specified output format; the title  is optional.
 *      (2) When calling these simple plot functions more than once, use
 *          different %outroot to avoid overwriting the output files.
 * 
*/ l_ok gplotSimple2(NUMA *na1, NUMA *na2, l_int32 outformat, const char *outroot, const char *title) { GPLOT *gplot; PROCNAME("gplotSimple2"); gplot = gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES, outformat, outroot, title); if (!gplot) return ERROR_INT("failed to generate plot", procName, 1); gplotDestroy(&gplot); return 0; } /*! * \brief gplotSimpleN() * * \param[in] naa numaa; plot Y_VS_I for each numa * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, * GPLOT_LATEX, GPLOT_PNM * \param[in] outroot root of output files * \param[in] title [optional] * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) This generates a line plot of all numas in a numaa (array of numa),
 *          where the array values are each plotted vs the array index.
 *          The plot is generated in the specified output format;
 *          the title  is optional.
 *      (2) When calling these simple plot functions more than once, use
 *          different %outroot to avoid overwriting the output files.
 * 
*/ l_ok gplotSimpleN(NUMAA *naa, l_int32 outformat, const char *outroot, const char *title) { GPLOT *gplot; PROCNAME("gplotSimpleN"); gplot = gplotSimpleXYN(NULL, naa, GPLOT_LINES, outformat, outroot, title); if (!gplot) return ERROR_INT("failed to generate plot", procName, 1); gplotDestroy(&gplot); return 0; } /*! * \brief gplotSimplePix1() * * \param[in] na numa; plot Y_VS_I * \param[in] title [optional], can be NULL * \return pix of plot, or null on error * *
 * Notes:
 *      (1) This generates a line plot of a numa as a pix, where the array
 *          value is plotted vs the array index.  The title is optional.
 *      (2) The temporary plot file is a png; its name is generated internally
 *          and stored in gplot.
 * 
*/ PIX * gplotSimplePix1(NUMA *na, const char *title) { char buf[64]; static l_int32 index; GPLOT *gplot; PIX *pix; PROCNAME("gplotSimplePix1"); if (!na) return (PIX *)ERROR_PTR("na not defined", procName, NULL); lept_mkdir("lept/gplot/pix"); snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pix1.%d", index++); gplot = gplotSimpleXY1(NULL, na, GPLOT_LINES, GPLOT_PNG, buf, title); if (!gplot) return (PIX *)ERROR_PTR("failed to generate plot", procName, NULL); pix = pixRead(gplot->outname); gplotDestroy(&gplot); if (!pix) return (PIX *)ERROR_PTR("failed to generate plot", procName, NULL); return pix; } /*! * \brief gplotSimplePix2() * * \param[in] na1 numa; plot with Y_VS_I * \param[in] na2 ditto * \param[in] title [optional], can be NULL * \return pix of plot, or null on error * *
 * Notes:
 *      (1) This generates a pix with line plots of two numa, where each of
 *          two arrays is plotted vs the array index.  the title is optional.
 *      (2) The temporary plot file is a png; its name is generated internally
 *          and stored in gplot.
 * 
*/ PIX * gplotSimplePix2(NUMA *na1, NUMA *na2, const char *title) { char buf[64]; static l_int32 index; GPLOT *gplot; PIX *pix; PROCNAME("gplotSimplePix2"); if (!na1 || !na2) return (PIX *)ERROR_PTR("both na1, na2 not defined", procName, NULL); lept_mkdir("lept/gplot/pix"); snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pix2.%d", index++); gplot = gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES, GPLOT_PNG, buf, title); if (!gplot) return (PIX *)ERROR_PTR("failed to generate plot", procName, NULL); pix = pixRead(gplot->outname); gplotDestroy(&gplot); if (!pix) return (PIX *)ERROR_PTR("failed to generate plot", procName, NULL); return pix; } /*! * \brief gplotSimplePixN() * * \param[in] naa numaa; plot Y_VS_I for each numa * \param[in] title [optional], can be NULL * \return pix of plot, or null on error * *
 * Notes:
 *      (1) This generates a pix with an arbitrary number of line plots,
 *          each coming from a numa in %naa.  Each array value is plotted
 *          vs the array index.  The title is optional.
 *      (2) The temporary plot file is a png; its name is generated internally
 *          and stored in gplot.
 * 
*/ PIX * gplotSimplePixN(NUMAA *naa, const char *title) { char buf[64]; static l_int32 index; GPLOT *gplot; PIX *pix; PROCNAME("gplotSimplePixN"); if (!naa) return (PIX *)ERROR_PTR("naa not defined", procName, NULL); lept_mkdir("lept/gplot/pix"); snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pixN.%d", index++); gplot = gplotSimpleXYN(NULL, naa, GPLOT_LINES, GPLOT_PNG, buf, title); if (!gplot) return (PIX *)ERROR_PTR("failed to generate plot", procName, NULL); pix = pixRead(gplot->outname); gplotDestroy(&gplot); if (!pix) return (PIX *)ERROR_PTR("failed to generate plot", procName, NULL); return pix; } /*! * \brief gplotSimpleXY1() * * \param[in] nax [optional] * \param[in] nay [required] * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, * GPLOT_LINESPOINTS, GPLOT_DOTS * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, * GPLOT_LATEX, GPLOT_PNM * \param[in] outroot root of output files * \param[in] title [optional], can be NULL * \return gplot or null on error * *
 * Notes:
 *      (1) This generates a plot of a %nay vs %nax, generated in
 *          the specified output format.  The title is optional.
 *      (2) Use 0 for default plotstyle (lines).
 *      (3) %nax is optional.  If NULL, %nay is plotted against
 *          the array index.
 *      (4) When calling these simple plot functions more than once, use
 *          different %outroot to avoid overwriting the output files.
 *      (5) The returned gplot must be destroyed by the caller.
 * 
*/ GPLOT * gplotSimpleXY1(NUMA *nax, NUMA *nay, l_int32 plotstyle, l_int32 outformat, const char *outroot, const char *title) { GPLOT *gplot; PROCNAME("gplotSimpleXY1"); if (!nay) return (GPLOT *)ERROR_PTR("nay not defined", procName, NULL); if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) return (GPLOT *)ERROR_PTR("invalid plotstyle", procName, NULL); if (outformat != GPLOT_PNG && outformat != GPLOT_PS && outformat != GPLOT_EPS && outformat != GPLOT_LATEX && outformat != GPLOT_PNM) return (GPLOT *)ERROR_PTR("invalid outformat", procName, NULL); if (!outroot) return (GPLOT *)ERROR_PTR("outroot not specified", procName, NULL); if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0) return (GPLOT *)ERROR_PTR("gplot not made", procName, NULL); gplotAddPlot(gplot, nax, nay, plotstyle, NULL); gplotMakeOutput(gplot); return gplot; } /*! * \brief gplotSimpleXY2() * * \param[in] nax [optional], can be NULL * \param[in] nay1 * \param[in] nay2 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, * GPLOT_LINESPOINTS, GPLOT_DOTS * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, * GPLOT_LATEX, GPLOT_PNM * \param[in] outroot root of output files * \param[in] title [optional] * \return gplot or null on error * *
 * Notes:
 *      (1) This generates plots of %nay1 and %nay2 against %nax, generated
 *          in the specified output format.  The title is optional.
 *      (2) Use 0 for default plotstyle (lines).
 *      (3) %nax is optional.  If NULL, %nay1 and %nay2 are plotted
 *          against the array index.
 *      (4) When calling these simple plot functions more than once, use
 *          different %outroot to avoid overwriting the output files.
 *      (5) The returned gplot must be destroyed by the caller.
 * 
*/ GPLOT * gplotSimpleXY2(NUMA *nax, NUMA *nay1, NUMA *nay2, l_int32 plotstyle, l_int32 outformat, const char *outroot, const char *title) { GPLOT *gplot; PROCNAME("gplotSimpleXY2"); if (!nay1 || !nay2) return (GPLOT *)ERROR_PTR("nay1 and nay2 not both defined", procName, NULL); if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) return (GPLOT *)ERROR_PTR("invalid plotstyle", procName, NULL); if (outformat != GPLOT_PNG && outformat != GPLOT_PS && outformat != GPLOT_EPS && outformat != GPLOT_LATEX && outformat != GPLOT_PNM) return (GPLOT *)ERROR_PTR("invalid outformat", procName, NULL); if (!outroot) return (GPLOT *)ERROR_PTR("outroot not specified", procName, NULL); if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0) return (GPLOT *)ERROR_PTR("gplot not made", procName, NULL); gplotAddPlot(gplot, nax, nay1, plotstyle, NULL); gplotAddPlot(gplot, nax, nay2, plotstyle, NULL); gplotMakeOutput(gplot); return gplot; } /*! * \brief gplotSimpleXYN() * * \param[in] nax [optional]; can be NULL * \param[in] naay numaa of arrays to plot against %nax * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, * GPLOT_LINESPOINTS, GPLOT_DOTS * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, * GPLOT_LATEX, GPLOT_PNM * \param[in] outroot root of output files * \param[in] title [optional] * \return gplot or null on error * *
 * Notes:
 *      (1) This generates plots of each Numa in %naa against %nax,
 *          generated in the specified output format.  The title is optional.
 *      (2) Use 0 for default plotstyle (lines).
 *      (3) %nax is optional.  If NULL, each Numa array is plotted against
 *          the array index.
 *      (4) When calling these simple plot functions more than once, use
 *          different %outroot to avoid overwriting the output files.
 *      (5) The returned gplot must be destroyed by the caller.
 * 
*/ GPLOT * gplotSimpleXYN(NUMA *nax, NUMAA *naay, l_int32 plotstyle, l_int32 outformat, const char *outroot, const char *title) { l_int32 i, n; GPLOT *gplot; NUMA *nay; PROCNAME("gplotSimpleXYN"); if (!naay) return (GPLOT *)ERROR_PTR("naay not defined", procName, NULL); if ((n = numaaGetCount(naay)) == 0) return (GPLOT *)ERROR_PTR("no numa in array", procName, NULL); if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) return (GPLOT *)ERROR_PTR("invalid plotstyle", procName, NULL); if (outformat != GPLOT_PNG && outformat != GPLOT_PS && outformat != GPLOT_EPS && outformat != GPLOT_LATEX && outformat != GPLOT_PNM) return (GPLOT *)ERROR_PTR("invalid outformat", procName, NULL); if (!outroot) return (GPLOT *)ERROR_PTR("outroot not specified", procName, NULL); if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0) return (GPLOT *)ERROR_PTR("gplot not made", procName, NULL); for (i = 0; i < n; i++) { nay = numaaGetNuma(naay, i, L_CLONE); gplotAddPlot(gplot, nax, nay, plotstyle, NULL); numaDestroy(&nay); } gplotMakeOutput(gplot); return gplot; } /*! * \brief gplotGeneralPix1() * * \param[in] na data array * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, * GPLOT_LINESPOINTS, GPLOT_DOTS * \param[in] rootname root for all output files * \param[in] title [optional] overall title * \param[in] xlabel [optional] x axis label * \param[in] ylabel [optional] y axis label * \return pix of plot, or NULL on error * *
 * Notes:
 *      (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
 *          double quotes and backquotes, but not single quotes.
 * 
*/ PIX * gplotGeneralPix1(NUMA *na, l_int32 plotstyle, const char *rootname, const char *title, const char *xlabel, const char *ylabel) { GPLOT *gplot; PIX *pix; PROCNAME("gplotGeneralPix1"); if (!na) return (PIX *)ERROR_PTR("na not defined", procName, NULL); if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) return (PIX *)ERROR_PTR("invalid plotstyle", procName, NULL); if (!rootname) return (PIX *)ERROR_PTR("rootname not defined", procName, NULL); gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel); if (!gplot) return (PIX *)ERROR_PTR("gplot not made", procName, NULL); gplotAddPlot(gplot, NULL, na, plotstyle, NULL); pix = gplotMakeOutputPix(gplot); gplotDestroy(&gplot); return pix; } /*! * \brief gplotGeneralPix2() * * \param[in] na1 x-axis data array * \param[in] na2 y-axis data array * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, * GPLOT_LINESPOINTS, GPLOT_DOTS * \param[in] rootname root for all output files * \param[in] title [optional] overall title * \param[in] xlabel [optional] x axis label * \param[in] ylabel [optional] y axis label * \return pix of plot, or NULL on error * *
 * Notes:
 *      (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
 *          double quotes and backquotes, but not single quotes.
 * 
*/ PIX * gplotGeneralPix2(NUMA *na1, NUMA *na2, l_int32 plotstyle, const char *rootname, const char *title, const char *xlabel, const char *ylabel) { GPLOT *gplot; PIX *pix; PROCNAME("gplotGeneralPix2"); if (!na1) return (PIX *)ERROR_PTR("na1 not defined", procName, NULL); if (!na2) return (PIX *)ERROR_PTR("na2 not defined", procName, NULL); if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) return (PIX *)ERROR_PTR("invalid plotstyle", procName, NULL); if (!rootname) return (PIX *)ERROR_PTR("rootname not defined", procName, NULL); gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel); if (!gplot) return (PIX *)ERROR_PTR("gplot not made", procName, NULL); gplotAddPlot(gplot, na1, na2, plotstyle, NULL); pix = gplotMakeOutputPix(gplot); gplotDestroy(&gplot); return pix; } /*! * \brief gplotGeneralPixN() * * \param[in] nax x-axis data array * \param[in] naay array of y-axis data arrays * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES, * GPLOT_LINESPOINTS, GPLOT_DOTS * \param[in] rootname root for all output files * \param[in] title [optional] overall title * \param[in] xlabel [optional] x axis label * \param[in] ylabel [optional] y axis label * \return pix of plot, or NULL on error * *
 * Notes:
 *      (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
 *          double quotes and backquotes, but not single quotes.
 * 
*/ PIX * gplotGeneralPixN(NUMA *nax, NUMAA *naay, l_int32 plotstyle, const char *rootname, const char *title, const char *xlabel, const char *ylabel) { l_int32 i, n; GPLOT *gplot; NUMA *nay; PIX *pix; PROCNAME("gplotGeneralPixN"); if (!nax) return (PIX *)ERROR_PTR("nax not defined", procName, NULL); if (!naay) return (PIX *)ERROR_PTR("naay not defined", procName, NULL); if ((n = numaaGetCount(naay)) == 0) return (PIX *)ERROR_PTR("no numa in array", procName, NULL); if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES) return (PIX *)ERROR_PTR("invalid plotstyle", procName, NULL); if (!rootname) return (PIX *)ERROR_PTR("rootname not defined", procName, NULL); gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel); if (!gplot) return (PIX *)ERROR_PTR("gplot not made", procName, NULL); for (i = 0; i < n; i++) { nay = numaaGetNuma(naay, i, L_CLONE); gplotAddPlot(gplot, nax, nay, plotstyle, NULL); numaDestroy(&nay); } pix = gplotMakeOutputPix(gplot); gplotDestroy(&gplot); return pix; } /*-----------------------------------------------------------------* * Serialize for I/O * *-----------------------------------------------------------------*/ /*! * \brief gplotRead() * * \param[in] filename * \return gplot, or NULL on error */ GPLOT * gplotRead(const char *filename) { char buf[Bufsize]; char *rootname, *title, *xlabel, *ylabel, *ignores; l_int32 outformat, ret, version, ignore; FILE *fp; GPLOT *gplot; PROCNAME("gplotRead"); if (!filename) return (GPLOT *)ERROR_PTR("filename not defined", procName, NULL); if ((fp = fopenReadStream(filename)) == NULL) return (GPLOT *)ERROR_PTR("stream not opened", procName, NULL); ret = fscanf(fp, "Gplot Version %d\n", &version); if (ret != 1) { fclose(fp); return (GPLOT *)ERROR_PTR("not a gplot file", procName, NULL); } if (version != GPLOT_VERSION_NUMBER) { fclose(fp); return (GPLOT *)ERROR_PTR("invalid gplot version", procName, NULL); } ignore = fscanf(fp, "Rootname: %511s\n", buf); /* Bufsize - 1 */ rootname = stringNew(buf); ignore = fscanf(fp, "Output format: %d\n", &outformat); ignores = fgets(buf, Bufsize, fp); /* Title: ... */ title = stringNew(buf + 7); title[strlen(title) - 1] = '\0'; ignores = fgets(buf, Bufsize, fp); /* X axis label: ... */ xlabel = stringNew(buf + 14); xlabel[strlen(xlabel) - 1] = '\0'; ignores = fgets(buf, Bufsize, fp); /* Y axis label: ... */ ylabel = stringNew(buf + 14); ylabel[strlen(ylabel) - 1] = '\0'; gplot = gplotCreate(rootname, outformat, title, xlabel, ylabel); LEPT_FREE(rootname); LEPT_FREE(title); LEPT_FREE(xlabel); LEPT_FREE(ylabel); if (!gplot) { fclose(fp); return (GPLOT *)ERROR_PTR("gplot not made", procName, NULL); } sarrayDestroy(&gplot->cmddata); sarrayDestroy(&gplot->datanames); sarrayDestroy(&gplot->plotdata); sarrayDestroy(&gplot->plotlabels); numaDestroy(&gplot->plotstyles); ignore = fscanf(fp, "Commandfile name: %511s\n", buf); /* Bufsize - 1 */ stringReplace(&gplot->cmdname, buf); ignore = fscanf(fp, "\nCommandfile data:"); gplot->cmddata = sarrayReadStream(fp); ignore = fscanf(fp, "\nDatafile names:"); gplot->datanames = sarrayReadStream(fp); ignore = fscanf(fp, "\nPlot data:"); gplot->plotdata = sarrayReadStream(fp); ignore = fscanf(fp, "\nPlot titles:"); gplot->plotlabels = sarrayReadStream(fp); ignore = fscanf(fp, "\nPlot styles:"); gplot->plotstyles = numaReadStream(fp); ignore = fscanf(fp, "Number of plots: %d\n", &gplot->nplots); ignore = fscanf(fp, "Output file name: %511s\n", buf); stringReplace(&gplot->outname, buf); ignore = fscanf(fp, "Axis scaling: %d\n", &gplot->scaling); fclose(fp); return gplot; } /*! * \brief gplotWrite() * * \param[in] filename * \param[in] gplot * \return 0 if OK; 1 on error */ l_ok gplotWrite(const char *filename, GPLOT *gplot) { FILE *fp; PROCNAME("gplotWrite"); if (!filename) return ERROR_INT("filename not defined", procName, 1); if (!gplot) return ERROR_INT("gplot not defined", procName, 1); if ((fp = fopenWriteStream(filename, "wb")) == NULL) return ERROR_INT("stream not opened", procName, 1); fprintf(fp, "Gplot Version %d\n", GPLOT_VERSION_NUMBER); fprintf(fp, "Rootname: %s\n", gplot->rootname); fprintf(fp, "Output format: %d\n", gplot->outformat); fprintf(fp, "Title: %s\n", gplot->title); fprintf(fp, "X axis label: %s\n", gplot->xlabel); fprintf(fp, "Y axis label: %s\n", gplot->ylabel); fprintf(fp, "Commandfile name: %s\n", gplot->cmdname); fprintf(fp, "\nCommandfile data:"); sarrayWriteStream(fp, gplot->cmddata); fprintf(fp, "\nDatafile names:"); sarrayWriteStream(fp, gplot->datanames); fprintf(fp, "\nPlot data:"); sarrayWriteStream(fp, gplot->plotdata); fprintf(fp, "\nPlot titles:"); sarrayWriteStream(fp, gplot->plotlabels); fprintf(fp, "\nPlot styles:"); numaWriteStderr(gplot->plotstyles); fprintf(fp, "Number of plots: %d\n", gplot->nplots); fprintf(fp, "Output file name: %s\n", gplot->outname); fprintf(fp, "Axis scaling: %d\n", gplot->scaling); fclose(fp); return 0; }