📄 gnuplot.cc
字号:
//////////////////////////////////////////////// A C++ interface to gnuplot. //// This is a direct translation from the C interface// written by N. Devillard (which is available from// http://ndevilla.free.fr/gnuplot/).//// As in the C interface this uses pipes and so wont// run on a system that does'nt have POSIX pipe // support//// Rajarshi Guha// <rajarshi@presidency.com>//// 07/03/03//////////////////////////////////////////////#include "Gnuplot.hh"#include <stdarg.h>#ifdef WIN32# include <io.h>#else# include <fcntl.h> // X_OK# include <unistd.h> // access# define PATH_MAXNAMESZ 4096#endif#include <iostream>#include <fstream>#include <sstream>#include <list>#if defined(WIN32)# define pclose _pclose# define popen _popen# define access _access# define ACCESS_OK 0# define PATH_SEP ";"# define MKTEMP_AND_CHECK_FAILED(name) (_mktemp(name) == NULL)#else# define ACCESS_OK X_OK# define PATH_SEP ":"# define MKTEMP_AND_CHECK_FAILED(name) (mkstemp(name) == -1)#endifusing namespace std;///////////////////////////////// A string tokenizer taken from// http://www.sunsite.ualberta.ca/// Documentation/Gnu/libstdc++-2.90.8/html/21_strings/stringtok_std_h.txt///////////////////////////////template <typename Container>voidstringtok (Container &container, string const &in, const char * const delimiters = " \t\n"){ const string::size_type len = in.length(); string::size_type i = 0; while ( i < len ) { // eat leading whitespace i = in.find_first_not_of (delimiters, i); if (i == string::npos) return; // nothing left but white space // find the end of the token string::size_type j = in.find_first_of (delimiters, i); // push token if (j == string::npos) { container.push_back (in.substr(i)); return; } else container.push_back (in.substr(i, j-i)); // set up for next loop i = j + 1; }}// ----------------------------------------------------------------------------#ifdef WIN32 std::string Gnuplot::gnuplot_executable_ = "pgnuplot.exe";#else std::string Gnuplot::gnuplot_executable_ = "gnuplot";#endif// ----------------------------------------------------------------------------Gnuplot::Gnuplot(void){ init(); set_style("points");}// ----------------------------------------------------------------------------Gnuplot::Gnuplot(const string &style){ init(); set_style(style);}// ----------------------------------------------------------------------------Gnuplot::Gnuplot(const string &title, const string &style, const string &labelx, const string &labely, vector<double> x, vector<double> y){ init(); if (x.size() == 0 || y.size() == 0) throw GnuplotException("vectors too small"); if (style == "") this->set_style("lines"); else this->set_style(style); if (labelx == "") this->set_xlabel("X"); else this->set_xlabel(labelx); if (labely == "") this->set_ylabel("Y"); else this->set_ylabel(labely); this->plot_xy(x,y,title); cout << "Press enter to continue" << endl; while (getchar() != '\n'){}}// ----------------------------------------------------------------------------Gnuplot::Gnuplot(const string &title, const string &style, const string &labelx, const string &labely, vector<double> x){ init(); if (x.size() == 0) throw GnuplotException("vector too small"); if (!this->gnucmd) throw GnuplotException("Could'nt open connection to gnuplot"); if (style == "") this->set_style("lines"); else this->set_style(style); if (labelx == "") this->set_xlabel("X"); else this->set_xlabel(labelx); if (labely == "") this->set_ylabel("Y"); else this->set_ylabel(labely); this->plot_x(x,title); cout << "Press enter to continue" << endl; while (getchar() != '\n'){}}// ----------------------------------------------------------------------------Gnuplot::~Gnuplot(){ if ((this->to_delete).size() > 0) { for (size_t i = 0; i < this->to_delete.size(); i++) remove(this->to_delete[i].c_str()); } if (pclose(this->gnucmd) == -1) cerr << "Problem closing communication to gnuplot" << endl; return;}// ----------------------------------------------------------------------------bool Gnuplot::get_program_path(const string pname){ list<string> ls; char *path; path = getenv("PATH"); if (!path) return false; stringtok(ls, path, PATH_SEP); for (list<string>::const_iterator i = ls.begin(); i != ls.end(); ++i) { string tmp = (*i) + "/" + pname; if ( access(tmp.c_str(), ACCESS_OK) == 0 ) return true; } return false;}// ----------------------------------------------------------------------------void Gnuplot::reset_plot(void){ if (this->to_delete.size() > 0) { for (size_t i = 0; i < this->to_delete.size(); i++) remove(this->to_delete[i].c_str()); } this->nplots = 0; return;}// ----------------------------------------------------------------------------void Gnuplot::set_style(const string &stylestr){ if (stylestr != "lines" && stylestr != "points" && stylestr != "linespoints" && stylestr != "impulses" && stylestr != "dots" && stylestr != "steps" && stylestr != "errorbars" && stylestr != "boxes" && stylestr != "boxerrorbars") this->pstyle = string("points"); else this->pstyle = stylestr;}// ----------------------------------------------------------------------------void Gnuplot::cmd(const char *_cmd, ...){ va_list ap; char local_cmd[GP_CMD_SIZE]; va_start(ap, _cmd); vsprintf(local_cmd, _cmd, ap); va_end(ap); strcat(local_cmd,"\n"); fputs(local_cmd,this->gnucmd); fflush(this->gnucmd); return;}// ----------------------------------------------------------------------------void Gnuplot::set_ylabel(const string &label){ ostringstream cmdstr; cmdstr << "set xlabel \"" << label << "\""; this->cmd(cmdstr.str().c_str()); return;}// ----------------------------------------------------------------------------void Gnuplot::set_xlabel(const string &label){ ostringstream cmdstr; cmdstr << "set xlabel \"" << label << "\""; this->cmd(cmdstr.str().c_str()); return;}// ----------------------------------------------------------------------------// Plots a linear equation (where you supply the// slope and intercept)//void Gnuplot::plot_slope(double a, double b, const string &title){ ostringstream stitle; ostringstream cmdstr; if (title == "") stitle << "no title"; else stitle << title; if (this->nplots > 0) cmdstr << "replot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle; else cmdstr << "plot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle; this->cmd(cmdstr.str().c_str()); this->nplots++; return;}// ----------------------------------------------------------------------------// Plot an equation which is supplied as a string// void Gnuplot::plot_equation(const string &equation, const string &title){ string titlestr, plotstr; ostringstream cmdstr; if (title == "") titlestr = "no title"; else titlestr = title; if (this->nplots > 0) plotstr = "replot"; else plotstr = "plot"; cmdstr << plotstr << " " << equation << " " << "title \"" << titlestr << "\" with " << this->pstyle; this->cmd(cmdstr.str().c_str()); this->nplots++; return;}// ----------------------------------------------------------------------------void Gnuplot::plot_x(vector<double> d, const string &title){ ofstream tmp; ostringstream cmdstr;#ifdef WIN32 char name[] = "gnuplotiXXXXXX";#else char name[] = "/tmp/gnuplotiXXXXXX";#endif if (this->to_delete.size() == GP_MAX_TMP_FILES - 1) { cerr << "Maximum number of temporary files reached (" << GP_MAX_TMP_FILES << "): cannot open more files" << endl; return; } // //open temporary files for output#ifdef WIN32 if ( _mktemp(name) == NULL)#else if ( mkstemp(name) == -1 )#endif { cerr << "Cannot create temporary file: exiting plot" << endl; return; } tmp.open(name); if (tmp.bad()) { cerr << "Cannot create temorary file: exiting plot" << endl; return; } // // Save the temporary filename // this->to_delete.push_back(name); // // write the data to file // for (size_t i = 0; i < d.size(); i++) tmp << d[i] << endl; tmp.flush(); tmp.close(); // // command to be sent to gnuplot // cmdstr << ( (this->nplots > 0) ? "replot " : "plot "); if (title.empty()) cmdstr << "\"" << name << "\" with " << this->pstyle; else cmdstr << "\"" << name << "\" title \"" << title << "\" with " << this->pstyle; // // Do the actual plot // this->cmd(cmdstr.str().c_str()); this->nplots++; return;}// ---------------------------------------------------------------------------- void Gnuplot::plot_xy(vector<double> x, vector<double> y, const string &title){ ofstream tmp; ostringstream cmdstr;#ifdef WIN32 char name[] = "gnuplotiXXXXXX";#else char name[] = "/tmp/gnuplotiXXXXXX";#endif // should raise an exception if (x.size() != y.size()) return; if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1) { std::stringstream s; s << "Maximum number of temporary files reached (" << GP_MAX_TMP_FILES << "): cannot open more files" << endl; throw GnuplotException( s.str() ); } //open temporary files for output // if (MKTEMP_AND_CHECK_FAILED(name)) throw GnuplotException("Cannot create temporary file: exiting plot"); tmp.open(name); if (tmp.bad()) throw GnuplotException("Cannot create temorary file: exiting plot"); // Save the temporary filename // this->to_delete.push_back(name); // Write the data to file // size_t N = std::min(x.size(), y.size()); for (size_t i = 0; i < N; i++) tmp << x[i] << " " << y[i] << endl; tmp.flush(); tmp.close(); // // command to be sent to gnuplot // if (this->nplots > 0) cmdstr << "replot "; else cmdstr << "plot "; if (title == "") cmdstr << "\"" << name << "\" with " << this->pstyle; else cmdstr << "\"" << name << "\" title \"" << title << "\" with " << this->pstyle; // // Do the actual plot // this->cmd(cmdstr.str().c_str()); this->nplots++; return;}// ----------------------------------------------------------------------------void Gnuplot::init(){ if (!this->get_program_path(gnuplot_executable_)) { this->valid = false; throw GnuplotException("Can't find gnuplot in your PATH"); } this->gnucmd = popen(gnuplot_executable_.c_str(),"w"); if (!this->gnucmd) { this->valid = false; throw GnuplotException("Couldn't open connection to gnuplot"); } this->nplots = 0; this->valid = true;}// ============================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -