Gnuplot.cpp 14 KB

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