source: trunk/lib/gnuplot_i.cc @ 27

Last change on this file since 27 was 27, checked in by Jari Häkkinen, 16 years ago

Moved current gnuplot interface out from theplu::svnstat namespace.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.4 KB
Line 
1// $Id: gnuplot_i.cc 27 2006-01-07 08:43:32Z jari $
2
3////////////////////////////////////////////
4//
5// A C++ interface to gnuplot.
6//
7// This is a direct translation from the C interface
8// written by N. Devillard (which is available from
9// http://ndevilla.free.fr/gnuplot/).
10//
11// As in the C interface this uses pipes and so wont
12// run on a system that does'nt have POSIX pipe
13// support
14//
15// Rajarshi Guha
16// <rajarshi@presidency.com>
17//
18// 07/03/03
19//
20////////////////////////////////////////////
21
22
23
24#include "gnuplot_i.h"
25
26namespace theplu {
27
28#define PATH_MAXNAMESZ       4096
29
30using namespace std;
31
32/////////////////////////////
33//
34// A string tokenizer taken from
35// http://www.sunsite.ualberta.ca/Documentation/Gnu/libstdc++-2.90.8/html/21_strings/stringtok_std_h.txt
36//
37/////////////////////////////
38template <typename Container>
39void
40stringtok (Container &container, string const &in,
41           const char * const delimiters = " \t\n")
42{
43    const string::size_type len = in.length();
44          string::size_type i = 0;
45
46    while ( i < len )
47    {
48        // eat leading whitespace
49        i = in.find_first_not_of (delimiters, i);
50        if (i == string::npos)
51            return;   // nothing left but white space
52
53        // find the end of the token
54        string::size_type j = in.find_first_of (delimiters, i);
55
56        // push token
57        if (j == string::npos) {
58            container.push_back (in.substr(i));
59            return;
60        } else
61            container.push_back (in.substr(i, j-i));
62
63        // set up for next loop
64        i = j + 1;
65    }
66}
67
68//
69// Constructors
70//
71Gnuplot::Gnuplot(void)
72{
73    if (getenv("DISPLAY") == NULL)
74      {
75        this->valid = false;
76        throw GnuplotException("cannot find DISPLAY variable");
77      }
78    if (!this->get_program_path("gnuplot"))
79      {
80        this->valid = false;
81        throw GnuplotException("Can't find gnuplot in your PATH");
82      }
83   
84    this->gnucmd = popen("gnuplot","w");
85    if (!this->gnucmd)
86      {
87        this->valid = false;
88        throw GnuplotException("Could'nt open connection to gnuplot");
89      }
90
91    this->set_style("points");
92    this->nplots = 0;
93    this->valid = true;
94}
95
96Gnuplot::Gnuplot(const string &style)
97{
98    if (getenv("DISPLAY") == NULL)
99      {
100        this->valid = false;
101        throw GnuplotException("cannot find DISPLAY variable");
102      }
103    if (!this->get_program_path("gnuplot"))
104      {
105        this->valid = false;
106        throw GnuplotException("Can't find gnuplot in your PATH");
107      }
108
109    this->gnucmd = popen("gnuplot","w");
110    if (!this->gnucmd)
111      {
112        this->valid = false;
113        throw GnuplotException("Could'nt open connection to gnuplot");
114      }
115    this->set_style(style);
116    this->nplots = 0;
117    this->valid = true;
118}
119
120Gnuplot::Gnuplot(
121         const string &title,
122         const string &style,
123         const string &labelx,  const string &labely,
124         vector<double> x, vector<double> y)
125{
126    if (getenv("DISPLAY") == NULL)
127      {
128        this->valid = false;
129        throw GnuplotException("cannot find DISPLAY variable");
130      }
131    if (!this->get_program_path("gnuplot"))
132      {
133        this->valid = false;
134        throw GnuplotException("Can't find gnuplot in your PATH");
135      }
136
137
138    this->gnucmd = popen("gnuplot","w");
139    if (!this->gnucmd)
140      {
141        this->valid = false;
142        throw GnuplotException("Could'nt open connection to gnuplot");
143      }
144    this->nplots = 0;
145    this->valid = true;
146
147
148    if (x.size() == 0 || y.size() == 0)
149        throw GnuplotException("vectors too small");
150
151    if (style == "")
152        this->set_style("lines");
153    else
154        this->set_style(style);
155
156    if (labelx == "")
157        this->set_xlabel("X");
158    else
159        this->set_xlabel(labelx);
160    if (labely == "")
161        this->set_ylabel("Y");
162    else
163        this->set_ylabel(labely);
164   
165    this->plot_xy(x,y,title);
166
167    cout << "Press enter to continue" << endl;
168    while (getchar() != '\n'){}
169}
170
171Gnuplot::Gnuplot(
172         const string &title,
173         const string &style,
174         const string &labelx,  const string &labely,
175         vector<double> x)
176{
177    if (getenv("DISPLAY") == NULL)
178      {
179        this->valid = false;
180        throw GnuplotException("cannot find DISPLAY variable");
181      }
182    if (!this->get_program_path("gnuplot"))
183      {
184        this->valid = false;
185        throw GnuplotException("Can't find gnuplot in your PATH");
186      }
187
188
189    this->gnucmd = popen("gnuplot","w");
190    if (!this->gnucmd)
191      {
192        this->valid = false;
193        throw GnuplotException("Could'nt open connection to gnuplot");
194      }
195    this->nplots = 0;
196    this->valid = true;
197   
198    this->nplots = 0;
199    this->valid = true;
200
201
202    if (x.size() == 0)
203        throw GnuplotException("vector too small");
204    if (!this->gnucmd)
205        throw GnuplotException("Could'nt open connection to gnuplot");
206
207    if (style == "")
208        this->set_style("lines");
209    else
210        this->set_style(style);
211
212    if (labelx == "")
213        this->set_xlabel("X");
214    else
215        this->set_xlabel(labelx);
216    if (labely == "")
217        this->set_ylabel("Y");
218    else
219        this->set_ylabel(labely);
220   
221    this->plot_x(x,title);
222
223    cout << "Press enter to continue" << endl;
224    while (getchar() != '\n'){}
225}
226
227//
228// Destructor
229//
230Gnuplot::~Gnuplot()
231{
232    if (pclose(this->gnucmd) == -1)
233        cerr << "Problem closing communication to gnuplot" << endl;
234    if ((this->to_delete).size() > 0)
235      {
236        for (vector<string>::size_type i = 0; i < this->to_delete.size(); i++)
237            remove(this->to_delete[i].c_str());
238        to_delete.clear();
239      }
240    return;
241}
242
243bool Gnuplot::is_valid(void)
244{
245    return(this->valid);
246}
247
248bool Gnuplot::get_program_path(const string pname)
249{
250    list<string> ls;
251    char *path;
252
253    path = getenv("PATH");
254    if (!path)
255      {
256        cerr << "Path is not set" << endl;
257        return false;
258      }
259    else
260      {
261        stringtok(ls,path,":");
262        for (list<string>::const_iterator i = ls.begin();
263                i != ls.end(); ++i)
264          {
265            string tmp = (*i) + "/" + pname;
266            if (access(tmp.c_str(),X_OK) == 0)
267                return true;
268          }
269      }
270    return false;
271}
272
273void Gnuplot::reset_plot(void)
274{       
275    if (this->to_delete.size() > 0)
276      {
277        for (vector<string>::size_type i = 0; i < this->to_delete.size(); i++)
278            remove(this->to_delete[i].c_str());
279        to_delete.clear();
280      }
281    this->nplots = 0;
282    return;
283}
284
285void Gnuplot::set_style(const string &stylestr)
286{
287    if (stylestr != "lines" &&
288            stylestr != "points" &&
289            stylestr != "linespoints" &&
290            stylestr != "impulses" &&
291            stylestr != "dots" &&
292            stylestr != "steps" &&
293            stylestr != "errorbars" &&
294            stylestr != "boxes" &&
295            stylestr != "boxerrorbars")
296        this->pstyle = string("points");
297    else
298        this->pstyle = stylestr;
299}
300
301void Gnuplot::cmd(const char *cmdstr, ...)
302{
303    va_list ap;
304    char local_cmd[GP_CMD_SIZE];
305
306    va_start(ap, cmdstr);
307    vsprintf(local_cmd, cmdstr, ap);
308    va_end(ap);
309    strcat(local_cmd,"\n");
310    fputs(local_cmd,this->gnucmd);
311    fflush(this->gnucmd);
312    return;
313}
314
315void Gnuplot::set_ylabel(const string &label)
316{
317    ostringstream cmdstr;
318
319    cmdstr << "set xlabel \"" << label << "\"";
320    this->cmd(cmdstr.str().c_str());
321
322    return;
323}
324
325void Gnuplot::set_xlabel(const string &label)
326{
327    ostringstream cmdstr;
328
329    cmdstr << "set xlabel \"" << label << "\"";
330    this->cmd(cmdstr.str().c_str());
331
332    return;
333}
334
335//
336// Plots a linear equation (where you supply the
337// slope and intercept)
338//
339void Gnuplot::plot_slope(double a, double b, const string &title)
340{
341    ostringstream stitle;
342    ostringstream cmdstr;
343
344    if (title == "")
345        stitle << "no title";
346    else
347        stitle << title;
348
349    if (this->nplots > 0)
350        cmdstr << "replot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle;
351    else
352        cmdstr << "plot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle;
353    this->cmd(cmdstr.str().c_str());
354    this->nplots++;
355    return;
356}
357
358//
359// Plot an equation which is supplied as a string
360//
361void Gnuplot::plot_equation(const string &equation, const string &title)
362{
363    string titlestr, plotstr;
364    ostringstream cmdstr;
365
366    if (title == "")
367        titlestr = "no title";
368    else
369        titlestr = title;
370
371    if (this->nplots > 0)
372        plotstr = "replot";
373    else
374        plotstr = "plot";
375
376    cmdstr << plotstr << " " << equation << " " << "title \"" << titlestr << "\" with " << this->pstyle;
377    this->cmd(cmdstr.str().c_str());
378    this->nplots++;
379
380    return;
381}
382
383void Gnuplot::plot_x(vector<double> d, const string &title)
384{
385    ofstream tmp;
386    ostringstream cmdstr;
387    char name[] = "/tmp/gnuplotiXXXXXX";
388
389    if (this->to_delete.size() == GP_MAX_TMP_FILES - 1)
390      {
391        cerr << "Maximum number of temporary files reached (" << GP_MAX_TMP_FILES << "): cannot open more files" << endl;
392        return;
393      }
394
395    //
396    //open temporary files for output
397    if (mkstemp(name) == -1)
398      {
399        cerr << "Cannot create temporary file: exiting plot" << endl;
400        return;
401      }
402    tmp.open(name);
403    if (tmp.bad())
404      {
405        cerr << "Cannot create temorary file: exiting plot" << endl;
406        return;
407      }
408
409    //
410    // Save the temporary filename
411    //
412    this->to_delete.push_back(name);
413
414    //
415    // write the data to file
416    //
417    for (vector<double>::size_type i = 0; i < d.size(); i++)
418        tmp << d[i] << endl;
419    tmp.flush();   
420    tmp.close();
421
422    //
423    // command to be sent to gnuplot
424    //
425    if (this->nplots > 0)
426        cmdstr << "replot ";
427    else cmdstr << "plot ";
428    if (title == "")
429        cmdstr << "\"" << name << "\" with " << this->pstyle;
430    else
431        cmdstr << "\"" << name << "\" title \"" << title << "\" with " << this->pstyle;
432
433    //
434    // Do the actual plot
435    //
436    this->cmd(cmdstr.str().c_str());
437    this->nplots++;
438
439    return;
440}
441   
442void Gnuplot::plot_xy(vector<double> x, vector<double> y, const string &title)
443{
444    ofstream tmp;
445    ostringstream cmdstr;
446    char name[] = "/tmp/gnuplotiXXXXXX";
447   
448    // should raise an exception
449    if (x.size() != y.size())
450        return;
451
452    if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1)
453      {
454        cerr << "Maximum number of temporary files reached (" << GP_MAX_TMP_FILES << "): cannot open more files" << endl;
455        return;
456      }
457
458    //
459    //open temporary files for output
460    //
461    if (mkstemp(name) == -1)
462      {
463        cerr << "Cannot create temporary file: exiting plot" << endl;
464        return;
465      }
466    tmp.open(name);
467    if (tmp.bad())
468      {
469        cerr << "Cannot create temorary file: exiting plot" << endl;
470        return;
471      }
472
473    //
474    // Save the temporary filename
475    //
476    this->to_delete.push_back(name);
477
478    //
479    // write the data to file
480    //
481    for (vector<double>::size_type i = 0; i < x.size(); i++)
482        tmp << x[i] << " " << y[i] << endl;
483    tmp.flush();   
484    tmp.close();
485
486    //
487    // command to be sent to gnuplot
488    //
489    if (this->nplots > 0)
490        cmdstr << "replot ";
491    else cmdstr << "plot ";
492    if (title == "")
493        cmdstr << "\"" << name << "\" with " << this->pstyle;
494    else
495        cmdstr << "\"" << name << "\" title \"" << title << "\" with " << this->pstyle;
496
497    //
498    // Do the actual plot
499    //
500    this->cmd(cmdstr.str().c_str());
501    this->nplots++;
502
503    return;
504}
505
506
507} // end of namespace theplu
Note: See TracBrowser for help on using the repository browser.