mirror of http://192.168.1.51:8099/lmh188/twain3.0
958 lines
29 KiB
C
958 lines
29 KiB
C
|
/*====================================================================*
|
||
|
- 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
|
||
|
* <pre>
|
||
|
*
|
||
|
* Basic plotting functions
|
||
|
* GPLOT *gplotCreate()
|
||
|
* void gplotDestroy()
|
||
|
* l_int32 gplotAddPlot()
|
||
|
* l_int32 gplotSetScaling()
|
||
|
* l_int32 gplotMakeOutput()
|
||
|
* l_int32 gplotGenCommandFile()
|
||
|
* l_int32 gplotGenDataFiles()
|
||
|
*
|
||
|
* Quick and dirty plots
|
||
|
* l_int32 gplotSimple1()
|
||
|
* l_int32 gplotSimple2()
|
||
|
* l_int32 gplotSimpleN()
|
||
|
* l_int32 gplotSimpleXY1()
|
||
|
* l_int32 gplotSimpleXY2()
|
||
|
* l_int32 gplotSimpleXYN()
|
||
|
*
|
||
|
* 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 graph
|
||
|
* ~ optional x and y axis labels
|
||
|
* ~ multiple plots on one frame
|
||
|
* ~ optional title for each plot on the frame
|
||
|
* ~ optional log scaling on either or both axes
|
||
|
* ~ choice of 5 plot styles for each plot
|
||
|
* ~ choice of 2 plot modes, either using one input array
|
||
|
* (Y vs index) or two input arrays (Y vs X). This
|
||
|
* choice is made implicitly depending on the number of
|
||
|
* input arrays.
|
||
|
*
|
||
|
* 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);
|
||
|
*
|
||
|
* Note for output to GPLOT_LATEX:
|
||
|
* This creates latex output of the plot, named <rootname>.tex.
|
||
|
* It needs to be placed in a latex file <latexname>.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 <latexname>.dvi using
|
||
|
* latex <latexname>.tex
|
||
|
* and a PostScript file <psname>.ps from that using
|
||
|
* dvips -o <psname>.ps <latexname>.dvi
|
||
|
*
|
||
|
* N.B. To generate plots, it is necessary to have gnuplot installed on
|
||
|
* your Unix system, or wgnuplot on Windows.
|
||
|
* </pre>
|
||
|
*/
|
||
|
|
||
|
#include <string.h>
|
||
|
#include "allheaders.h"
|
||
|
|
||
|
//static const l_int32 Bufsize = 512; /* hardcoded below in fscanf */
|
||
|
#define Bufsize 512
|
||
|
|
||
|
const char *gplotstylenames[] = { "with lines",
|
||
|
"with points",
|
||
|
"with impulses",
|
||
|
"with linespoints",
|
||
|
"with dots" };
|
||
|
const char *gplotfileoutputs[] = { "",
|
||
|
"PNG",
|
||
|
"PS",
|
||
|
"EPS",
|
||
|
"LATEX" };
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------*
|
||
|
* Basic Plotting Functions *
|
||
|
*-----------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief gplotCreate()
|
||
|
*
|
||
|
* \param[in] rootname root for all output files
|
||
|
* \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, GPLOT_LATEX
|
||
|
* \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
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This initializes the plot.
|
||
|
* (2) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
|
||
|
* double quotes and backquotes, but not single quotes.
|
||
|
* </pre>
|
||
|
*/
|
||
|
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)
|
||
|
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);
|
||
|
|
||
|
gplot = (GPLOT *)LEPT_CALLOC(1, sizeof(GPLOT));
|
||
|
gplot->cmddata = sarrayCreate(0);
|
||
|
gplot->datanames = sarrayCreate(0);
|
||
|
gplot->plotdata = sarrayCreate(0);
|
||
|
gplot->plottitles = 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);
|
||
|
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->plottitles);
|
||
|
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;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \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] plottitle [optional] title for individual plot
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* 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 'plottitle' string can have spaces, double
|
||
|
* quotes and backquotes, but not single quotes.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
gplotAddPlot(GPLOT *gplot,
|
||
|
NUMA *nax,
|
||
|
NUMA *nay,
|
||
|
l_int32 plotstyle,
|
||
|
const char *plottitle)
|
||
|
{
|
||
|
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 plottitle */
|
||
|
numaGetParameters(nay, &startx, &delx);
|
||
|
numaAddNumber(gplot->plotstyles, plotstyle);
|
||
|
if (plottitle) {
|
||
|
title = stringNew(plottitle);
|
||
|
sarrayAddString(gplot->plottitles, title, L_INSERT);
|
||
|
}
|
||
|
else {
|
||
|
sarrayAddString(gplot->plottitles, 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
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) By default, the x and y axis scaling is linear.
|
||
|
* (2) Call this function to set semi-log or log-log scaling.
|
||
|
* </pre>
|
||
|
*/
|
||
|
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 gplotMakeOutput()
|
||
|
*
|
||
|
* \param[in] gplot
|
||
|
* \return 0 if OK; 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* 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) This is the only function 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
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, *plottitle, *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);
|
||
|
}
|
||
|
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++) {
|
||
|
plottitle = sarrayGetString(gplot->plottitles, 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, plottitle, gplotstylenames[plotstyle]);
|
||
|
}
|
||
|
else {
|
||
|
if (i == 0)
|
||
|
snprintf(buf, Bufsize, "plot '%s' title '%s' %s, \\",
|
||
|
dataname, plottitle, gplotstylenames[plotstyle]);
|
||
|
else if (i < nplots - 1)
|
||
|
snprintf(buf, Bufsize, " '%s' title '%s' %s, \\",
|
||
|
dataname, plottitle, gplotstylenames[plotstyle]);
|
||
|
else
|
||
|
snprintf(buf, Bufsize, " '%s' title '%s' %s",
|
||
|
dataname, plottitle, 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
|
||
|
*
|
||
|
* <pre>
|
||
|
* 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().
|
||
|
* </pre>
|
||
|
*/
|
||
|
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 and Dirty Plots *
|
||
|
*-----------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief gplotSimple1()
|
||
|
*
|
||
|
* \param[in] na numa; plot Y_VS_I
|
||
|
* \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, GPLOT_LATEX
|
||
|
* \param[in] outroot root of output files
|
||
|
* \param[in] title [optional], can be NULL
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This gives 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
gplotSimple1(NUMA *na,
|
||
|
l_int32 outformat,
|
||
|
const char *outroot,
|
||
|
const char *title)
|
||
|
{
|
||
|
return gplotSimpleXY1(NULL, na, GPLOT_LINES, outformat, outroot, title);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \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
|
||
|
* \param[in] outroot root of output files
|
||
|
* \param[in] title [optional]
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This gives 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
gplotSimple2(NUMA *na1,
|
||
|
NUMA *na2,
|
||
|
l_int32 outformat,
|
||
|
const char *outroot,
|
||
|
const char *title)
|
||
|
{
|
||
|
return gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES,
|
||
|
outformat, outroot, title);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief gplotSimpleN()
|
||
|
*
|
||
|
* \param[in] naa numaa; we plotted with Y_VS_I for each numa
|
||
|
* \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS, GPLOT_LATEX
|
||
|
* \param[in] outroot root of output files
|
||
|
* \param[in] title [optional]
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This gives 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
gplotSimpleN(NUMAA *naa,
|
||
|
l_int32 outformat,
|
||
|
const char *outroot,
|
||
|
const char *title)
|
||
|
{
|
||
|
return gplotSimpleXYN(NULL, naa, GPLOT_LINES, outformat, outroot, title);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \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
|
||
|
* \param[in] outroot root of output files
|
||
|
* \param[in] title [optional], can be NULL
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This gives 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
gplotSimpleXY1(NUMA *nax,
|
||
|
NUMA *nay,
|
||
|
l_int32 plotstyle,
|
||
|
l_int32 outformat,
|
||
|
const char *outroot,
|
||
|
const char *title)
|
||
|
{
|
||
|
GPLOT *gplot;
|
||
|
|
||
|
PROCNAME("gplotSimpleXY1");
|
||
|
|
||
|
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 (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
|
||
|
outformat != GPLOT_EPS && outformat != GPLOT_LATEX)
|
||
|
return ERROR_INT("invalid outformat", procName, 1);
|
||
|
if (!outroot)
|
||
|
return ERROR_INT("outroot not specified", procName, 1);
|
||
|
|
||
|
if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
|
||
|
return ERROR_INT("gplot not made", procName, 1);
|
||
|
gplotAddPlot(gplot, nax, nay, plotstyle, NULL);
|
||
|
gplotMakeOutput(gplot);
|
||
|
gplotDestroy(&gplot);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \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
|
||
|
* \param[in] outroot root of output files
|
||
|
* \param[in] title [optional]
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This gives 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
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 ERROR_INT("nay1 and nay2 not both defined", procName, 1);
|
||
|
if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
|
||
|
return ERROR_INT("invalid plotstyle", procName, 1);
|
||
|
if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
|
||
|
outformat != GPLOT_EPS && outformat != GPLOT_LATEX)
|
||
|
return ERROR_INT("invalid outformat", procName, 1);
|
||
|
if (!outroot)
|
||
|
return ERROR_INT("outroot not specified", procName, 1);
|
||
|
|
||
|
if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
|
||
|
return ERROR_INT("gplot not made", procName, 1);
|
||
|
gplotAddPlot(gplot, nax, nay1, plotstyle, NULL);
|
||
|
gplotAddPlot(gplot, nax, nay2, plotstyle, NULL);
|
||
|
gplotMakeOutput(gplot);
|
||
|
gplotDestroy(&gplot);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \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
|
||
|
* \param[in] outroot root of output files
|
||
|
* \param[in] title [optional]
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This gives 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
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 ERROR_INT("naay not defined", procName, 1);
|
||
|
if ((n = numaaGetCount(naay)) == 0)
|
||
|
return ERROR_INT("no numa in array", procName, 1);
|
||
|
if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
|
||
|
return ERROR_INT("invalid plotstyle", procName, 1);
|
||
|
if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
|
||
|
outformat != GPLOT_EPS && outformat != GPLOT_LATEX)
|
||
|
return ERROR_INT("invalid outformat", procName, 1);
|
||
|
if (!outroot)
|
||
|
return ERROR_INT("outroot not specified", procName, 1);
|
||
|
|
||
|
if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
|
||
|
return ERROR_INT("gplot not made", procName, 1);
|
||
|
for (i = 0; i < n; i++) {
|
||
|
nay = numaaGetNuma(naay, i, L_CLONE);
|
||
|
gplotAddPlot(gplot, nax, nay, plotstyle, NULL);
|
||
|
numaDestroy(&nay);
|
||
|
}
|
||
|
gplotMakeOutput(gplot);
|
||
|
gplotDestroy(&gplot);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------*
|
||
|
* 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->plottitles);
|
||
|
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->plottitles = 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->plottitles);
|
||
|
fprintf(fp, "\nPlot styles:");
|
||
|
numaWriteStream(fp, 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;
|
||
|
}
|