//////////////////////////////////////////// // // 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 // // // 07/03/03 // //////////////////////////////////////////// #include "vislearning/baselib/Gnuplot.h" using namespace OBJREC; #define PATH_MAXNAMESZ 4096 using 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 void stringtok(Container &container, std::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; } } // // Constructors // Gnuplot::Gnuplot(void) { checkSystemVariablesOpenGnuplotCommand(); this->set_style("points"); } Gnuplot::Gnuplot(const std::string &style) { checkSystemVariablesOpenGnuplotCommand(); this->set_style(style); } Gnuplot::Gnuplot(const std::string &title, const std::string &style, const std::string &labelx, const std::string &labely, vector x, vector y) { checkSystemVariablesOpenGnuplotCommand(); 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 std::string &title, const std::string &style, const std::string &labelx, const std::string &labely, vector x) { checkSystemVariablesOpenGnuplotCommand(); 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') { } } void Gnuplot::checkSystemVariablesOpenGnuplotCommand() { if (!this->get_program_path("gnuplot")) { this->valid = false; throw GnuplotException("Can't find gnuplot in your PATH"); } this->gnucmd = popen("gnuplot", "w"); if (!this->gnucmd) { this->valid = false; throw GnuplotException("Could'nt open connection to gnuplot"); } if (getenv("DISPLAY") == NULL) { if (this->gnucmd) { fprintf(stderr, "no Display found, changing to Terminal PNG\n"); setFileOutput("png", "gnuplot_automatic_tmp_image.png"); } } this->nplots = 0; this->valid = true; } Gnuplot::~Gnuplot() { if (pclose(this->gnucmd) == -1) cerr << "Problem closing communication to gnuplot" << endl; if ((this->to_delete).size() > 0) { for (vector::size_type i = 0; i < this->to_delete.size(); i++) remove(this->to_delete[i].c_str()); to_delete.clear(); } return; } bool Gnuplot::is_valid(void) { return (this->valid); } bool Gnuplot::get_program_path(const std::string pname) { list ls; char *path; path = getenv("PATH"); if (!path) { cerr << "Path is not set" << endl; return false; } else { stringtok(ls, path, ":"); for (list::const_iterator i = ls.begin(); i != ls.end(); ++i) { std::string tmp = (*i) + "/" + pname; if (access(tmp.c_str(), X_OK) == 0) return true; } } return false; } void Gnuplot::reset_plot(void) { if (this->to_delete.size() > 0) { for (vector::size_type i = 0; i < this->to_delete.size(); i++) remove(this->to_delete[i].c_str()); to_delete.clear(); } this->nplots = 0; return; } void Gnuplot::set_style(const std::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 *cmdstr, ...) { va_list ap; char local_cmd[GP_CMD_SIZE]; va_start(ap, cmdstr); vsprintf(local_cmd, cmdstr, ap); va_end(ap); strcat(local_cmd, "\n"); fputs(local_cmd, this->gnucmd); fflush(this->gnucmd); return; } void Gnuplot::setFileOutput(const string &terminal, const string &filename) { ostringstream cmdstr; cmdstr << "set terminal " << terminal; this->cmd(cmdstr.str().c_str()); cmdstr.str(""); cmdstr << "set output \"" << filename << "\""; this->cmd(cmdstr.str().c_str()); } void Gnuplot::set_ylabel(const std::string &label) { std::ostringstream cmdstr; cmdstr << "set xlabel \"" << label << "\""; this->cmd(cmdstr.str().c_str()); return; } void Gnuplot::set_xlabel(const std::string &label) { std::ostringstream cmdstr; cmdstr << "set xlabel \"" << label << "\""; this->cmd(cmdstr.str().c_str()); return; } void Gnuplot::set_zlabel(const std::string &label) { std::ostringstream cmdstr; cmdstr << "set zlabel \"" << label << "\""; this->cmd(cmdstr.str().c_str()); return; } // set the xrange void Gnuplot::set_xrange(const int iFrom, const int iTo) { std::ostringstream cmdstr; cmdstr << "set xrange[" << iFrom << ":" << iTo << "]"; this->cmd(cmdstr.str().c_str()); return; } // set the yrange void Gnuplot::set_yrange(const int iFrom, const int iTo) { std::ostringstream cmdstr; cmdstr << "set yrange[" << iFrom << ":" << iTo << "]"; this->cmd(cmdstr.str().c_str()); return; } // set the zrange void Gnuplot::set_zrange(const int iFrom, const int iTo) { std::ostringstream cmdstr; cmdstr << "set zrange[" << iFrom << ":" << iTo << "]"; this->cmd(cmdstr.str().c_str()); return; } // set the palette range void Gnuplot::set_cbrange(const int iFrom, const int iTo) { std::ostringstream cmdstr; cmdstr << "set cbrange[" << iFrom << ":" << iTo << "]"; 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 std::string &title) { std::ostringstream stitle; std::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 std::string &equation, const std::string &title) { std::string titlestr, plotstr; std::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 d, const std::string &title) { ofstream tmp; std::ostringstream cmdstr; char name[] = "/tmp/gnuplotiXXXXXX"; 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 if (mkstemp(name) == -1) { 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 (vector::size_type i = 0; i < d.size(); i++) tmp << d[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::plot_xy(map xy, const std::string &title) { vector x; vector y; for (map::const_iterator i = xy.begin(); i != xy.end(); i++) { x.push_back(i->first); y.push_back(i->second); } plot_xy(x, y, title); } void Gnuplot::plot_xy(vector x, vector y, const std::string &title) { ofstream tmp; std::ostringstream cmdstr; char name[] = "/tmp/gnuplotiXXXXXX"; // should raise an exception if (x.size() != y.size()) return; 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 // if (mkstemp(name) == -1) { 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 (vector::size_type i = 0; i < x.size(); 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::plot_xyz(vector x, vector y, vector z, const std::string &title) { ofstream tmp; std::ostringstream cmdstr; char name[] = "/tmp/gnuplotiXXXXXX"; // should raise an exception if (x.size() != y.size() || x.size() != z.size()) { return; } 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 // if (mkstemp(name) == -1) { 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 (unsigned int i = 0; i < x.size(); i++) { tmp << x[i] << " " << y[i] << " " << z[i] << endl; } tmp.flush(); tmp.close(); // // command to be sent to gnuplot // if (this->nplots > 0) cmdstr << "replot "; else cmdstr << "splot "; 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; } /** * note that this function is not valid for versions of GNUPlot below 4.2 * **/ void Gnuplot::plot_image(unsigned char * ucPicBuf, int iWidth, int iHeight, const std::string &title) { ofstream tmp; std::ostringstream cmdstr; char name[] = "/tmp/gnuplotiXXXXXX"; 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 // if (mkstemp(name) == -1) { 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 // int iIndex = 0; for (int iRow = 0; iRow < iHeight; iRow++) { for (int iColumn = 0; iColumn < iWidth; iColumn++) { tmp << iColumn << " " << iRow << " " << static_cast (ucPicBuf[iIndex++]) << 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 image ";// << this->pstyle; // // Do the actual plot // this->cmd(cmdstr.str().c_str()); this->nplots++; return; }