source: trunk/lib/Gnuplot.h @ 70

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

Fixed too many files open problem.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.7 KB
Line 
1// $Id: Gnuplot.h 70 2006-02-22 07:40:36Z jari $
2
3#ifndef _theplu_svnstat_gnuplot_
4#define _theplu_svnstat_gnuplot_
5
6#include <cassert>
7#include <cstdio>
8#include <fstream>
9#include <list>
10#include <stdexcept>
11#include <string>
12#include <vector>
13
14
15namespace theplu {
16namespace svnstat {
17
18  ///
19  /// If something goes wrong in the use of the Gnuplot class, a
20  /// GnuplotException is thrown.
21  ///
22  struct GnuplotException : public std::runtime_error
23  { inline GnuplotException(const std::string& msg) : runtime_error(msg) {} };
24
25  ///
26  /// The Gnuplot class creates a pipe to 'gnuplot' and facilitates
27  /// communication with the binary.
28  ///
29  /// Temporary files are created in directory /tmp. These temporary
30  /// files are removed on a normal program exit.
31  ///
32  class Gnuplot
33  {
34  public:
35    ///
36    /// This constructor sets up the pipe to the first gnuplot
37    /// executable found in the PATH environment variable. The PATH
38    /// variable must exist.
39    ///
40    /// @throw Throws a GnuplotException if a no PATH variable is
41    /// found, if the gnuplot binary cannot be found, or if a pipe
42    /// cannot to the gnuplot binary cannot be established.
43    ///
44    Gnuplot(void);
45
46    ///
47    /// The destructor deletes all temporary files created in the
48    /// calls to plot_xy and plot_x. If the program execution fails to
49    /// reach this destructor the temporary files will not be removed
50    /// from the storage area.
51    ///
52    ~Gnuplot(void);
53
54    ///
55    /// Send arbitrary commands to Gnuplot.
56    ///
57    void command(std::string);
58
59    ///
60    /// @return input format for date
61    ///
62    // Peter, obsolete ?
63    const std::string& date_input_format(void) { return date_input_format_; }
64
65    ///
66    ///
67    ///
68    void date_plot(const std::vector<double>& y, 
69                   const std::string& format="%y-%b-%d");
70    ///
71    ///
72    ///
73    void date_replot(const std::vector<double>& y,
74                     const std::string& format="%y-%b-%d");
75
76    ///
77    /// Set the \a style of the line in the subsequent plot or
78    /// replot calls. The setting applies until this function is
79    /// called again.
80    ///
81    /// @note The \a style is not checked to be valid.
82    ///
83    inline void linestyle(const std::string& style) { linestyle_=style; }
84
85    ///
86    /// Set the \a title of the line in the subsequent plot or
87    /// replot calls. The setting applies until this function is
88    /// called again.
89    ///
90    inline void linetitle(const std::string& title) { linetitle_=title; }
91
92    ///
93    /// Plot the data \a y as a function of \a x using the Gnuplot
94    /// 'plot' command. The \a x vector can be omitted as in normal
95    /// Gnuplot usage.
96    ///
97    // Peter, do we have to set xdata for replot
98    inline void
99    plot(const std::vector<double>& y,
100         const std::vector<double>& x=std::vector<double>())
101    { command("set xdata"); plot(y,x,"plot"); }
102
103    ///
104    /// Plot the data \a y as a function of \a x using the Gnuplot
105    /// 'replot' command. The \a x vector can be omitted as in normal
106    /// Gnuplot usage.
107    ///
108    inline void
109    replot(const std::vector<double>& y,
110           const std::vector<double>& x=std::vector<double>())
111    { command("set xdata"); plot(y,x,"replot"); }
112
113    ///
114    /// sets format of date output
115    ///
116    inline void set_date_format(const std::string& format) 
117    { date_output_format_ = format;}
118
119    ///
120    /// Function setting the dates. \a format must comply with strings
121    /// in date
122    ///
123    inline void set_dates(const std::vector<std::string>& date, 
124                          const std::string& format="%Y-%m-%d")
125    { date_=date; date_input_format_=format; }
126
127  private:
128    ///
129    /// Copy constructor, not implemented.
130    ///
131    Gnuplot(const Gnuplot&);
132
133    void acquire_program_path(const std::string&);
134
135    ///
136    /// @param \a plotcmd must be "plot" or "replot".
137    ///
138    template <class T1, class T2>
139    void plot(const std::vector<T1>& y, const std::vector<T2>& x,
140              const std::string& plotcmd)
141    {
142      assert(x.size()==y.size() || x.empty());
143      assert(plotcmd=="plot" || plotcmd=="replot");
144      char name[]="/tmp/svnstatXXXXXX";
145      int fd=mkstemp(name); // mkstemp return a file descriptor
146      if (fd == -1)
147        throw GnuplotException(std::string("Failed to get unique filename: ") +
148                               name);
149      // Jari would like to do something like 'std::ofstream tmp(fd);'
150      // but has to settle for (which is stupid since the file is
151      // already open for writing.
152      std::ofstream tmp(name);
153      for (size_t i = 0; i<y.size() && (i<x.size() || x.empty()); ++i )
154        if (x.empty())
155          tmp << y[i] << '\n';
156        else
157          tmp << x[i] << '\t' << y[i] << '\n';
158      // Jari, here the stupidity goes beyond everything - the
159      // ofstream must be closed as well as the file descriptor. If
160      // not the program will exhaust the availabe number of
161      // simultaneous open files.
162      tmp.close();
163      close(fd);
164
165      std::string cmdstring(plotcmd + " '" + name + "' u 1:2 title '" + 
166                              linetitle_ + "' with " + linestyle_ + "\n");
167      if (x.empty())
168        cmdstring = plotcmd + " '" + name + "' u 1 title '" + 
169          linetitle_ + "' with " + linestyle_ + "\n";
170       
171      command(cmdstring);
172      // need to keep track of created files since the gnuplot command
173      // is not executed until pclose on MacOSX, shouldn't the fflush
174      // fix this in the command() member function?
175      tempfiles_.push_back(name);
176    }
177
178    void tokenizer(const std::string& in, std::list<std::string>& tokens,
179                   const std::string& delimiters = ":");
180
181    // need to keep track of created files since the gnuplot command
182    // is not executed until pclose on MacOSX, shouldn't the fflush
183    // fix this in the command() member function?
184    std::list<std::string> tempfiles_;
185    std::vector<std::string> date_;
186    std::string date_input_format_; 
187    std::string date_output_format_; 
188    std::string gnuplot_binary_;
189    std::string linestyle_;
190    std::string linetitle_;
191    FILE* pipe_;
192};
193
194}} // end of namespace svnstat and namespace theplu
195
196#endif
Note: See TracBrowser for help on using the repository browser.