Gnuplot.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  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. if (!this->get_program_path("gnuplot"))
  122. {
  123. this->valid = false;
  124. throw GnuplotException("Can't find gnuplot in your PATH");
  125. }
  126. this->gnucmd = popen("gnuplot", "w");
  127. if (!this->gnucmd)
  128. {
  129. this->valid = false;
  130. throw GnuplotException("Could'nt open connection to gnuplot");
  131. }
  132. if (getenv("DISPLAY") == NULL)
  133. {
  134. if (this->gnucmd)
  135. {
  136. fprintf(stderr, "no Display found, changing to Terminal PNG\n");
  137. setFileOutput("png", "gnuplot_automatic_tmp_image.png");
  138. }
  139. }
  140. this->nplots = 0;
  141. this->valid = true;
  142. }
  143. Gnuplot::~Gnuplot()
  144. {
  145. if (pclose(this->gnucmd) == -1)
  146. cerr << "Problem closing communication to gnuplot" << endl;
  147. if ((this->to_delete).size() > 0)
  148. {
  149. for (vector<string>::size_type i = 0; i < this->to_delete.size(); i++)
  150. remove(this->to_delete[i].c_str());
  151. to_delete.clear();
  152. }
  153. return;
  154. }
  155. bool Gnuplot::is_valid(void)
  156. {
  157. return (this->valid);
  158. }
  159. bool Gnuplot::get_program_path(const std::string pname)
  160. {
  161. list<string> ls;
  162. char *path;
  163. path = getenv("PATH");
  164. if (!path)
  165. {
  166. cerr << "Path is not set" << endl;
  167. return false;
  168. }
  169. else
  170. {
  171. stringtok(ls, path, ":");
  172. for (list<string>::const_iterator i = ls.begin(); i != ls.end(); ++i)
  173. {
  174. std::string tmp = (*i) + "/" + pname;
  175. if (access(tmp.c_str(), X_OK) == 0)
  176. return true;
  177. }
  178. }
  179. return false;
  180. }
  181. void Gnuplot::reset_plot(void)
  182. {
  183. if (this->to_delete.size() > 0)
  184. {
  185. for (vector<string>::size_type i = 0; i < this->to_delete.size(); i++)
  186. remove(this->to_delete[i].c_str());
  187. to_delete.clear();
  188. }
  189. this->nplots = 0;
  190. return;
  191. }
  192. void Gnuplot::set_style(const std::string &stylestr)
  193. {
  194. if (stylestr != "lines" && stylestr != "points" && stylestr
  195. != "linespoints" && stylestr != "impulses" && stylestr != "dots"
  196. && stylestr != "steps" && stylestr != "errorbars" && stylestr
  197. != "boxes" && stylestr != "boxerrorbars")
  198. this->pstyle = string("points");
  199. else
  200. this->pstyle = stylestr;
  201. }
  202. void Gnuplot::cmd(const char *cmdstr, ...)
  203. {
  204. va_list ap;
  205. char local_cmd[GP_CMD_SIZE];
  206. va_start(ap, cmdstr);
  207. vsprintf(local_cmd, cmdstr, ap);
  208. va_end(ap);
  209. strcat(local_cmd, "\n");
  210. fputs(local_cmd, this->gnucmd);
  211. fflush(this->gnucmd);
  212. return;
  213. }
  214. void Gnuplot::setFileOutput(const string &terminal, const string &filename)
  215. {
  216. ostringstream cmdstr;
  217. cmdstr << "set terminal " << terminal;
  218. this->cmd(cmdstr.str().c_str());
  219. cmdstr.str("");
  220. cmdstr << "set output \"" << filename << "\"";
  221. this->cmd(cmdstr.str().c_str());
  222. }
  223. void Gnuplot::set_ylabel(const std::string &label)
  224. {
  225. std::ostringstream cmdstr;
  226. cmdstr << "set xlabel \"" << label << "\"";
  227. this->cmd(cmdstr.str().c_str());
  228. return;
  229. }
  230. void Gnuplot::set_xlabel(const std::string &label)
  231. {
  232. std::ostringstream cmdstr;
  233. cmdstr << "set xlabel \"" << label << "\"";
  234. this->cmd(cmdstr.str().c_str());
  235. return;
  236. }
  237. void Gnuplot::set_zlabel(const std::string &label)
  238. {
  239. std::ostringstream cmdstr;
  240. cmdstr << "set zlabel \"" << label << "\"";
  241. this->cmd(cmdstr.str().c_str());
  242. return;
  243. }
  244. // set the xrange
  245. void Gnuplot::set_xrange(const int iFrom, const int iTo)
  246. {
  247. std::ostringstream cmdstr;
  248. cmdstr << "set xrange[" << iFrom << ":" << iTo << "]";
  249. this->cmd(cmdstr.str().c_str());
  250. return;
  251. }
  252. // set the yrange
  253. void Gnuplot::set_yrange(const int iFrom, const int iTo)
  254. {
  255. std::ostringstream cmdstr;
  256. cmdstr << "set yrange[" << iFrom << ":" << iTo << "]";
  257. this->cmd(cmdstr.str().c_str());
  258. return;
  259. }
  260. // set the zrange
  261. void Gnuplot::set_zrange(const int iFrom, const int iTo)
  262. {
  263. std::ostringstream cmdstr;
  264. cmdstr << "set zrange[" << iFrom << ":" << iTo << "]";
  265. this->cmd(cmdstr.str().c_str());
  266. return;
  267. }
  268. // set the palette range
  269. void Gnuplot::set_cbrange(const int iFrom, const int iTo)
  270. {
  271. std::ostringstream cmdstr;
  272. cmdstr << "set cbrange[" << iFrom << ":" << iTo << "]";
  273. this->cmd(cmdstr.str().c_str());
  274. return;
  275. }
  276. //
  277. // Plots a linear equation (where you supply the
  278. // slope and intercept)
  279. //
  280. void Gnuplot::plot_slope(double a, double b, const std::string &title)
  281. {
  282. std::ostringstream stitle;
  283. std::ostringstream cmdstr;
  284. if (title == "")
  285. stitle << "no title";
  286. else
  287. stitle << title;
  288. if (this->nplots > 0)
  289. cmdstr << "replot " << a << " * x + " << b << " title \""
  290. << stitle.str() << "\" with " << pstyle;
  291. else
  292. cmdstr << "plot " << a << " * x + " << b << " title \"" << stitle.str()
  293. << "\" with " << pstyle;
  294. this->cmd(cmdstr.str().c_str());
  295. this->nplots++;
  296. return;
  297. }
  298. //
  299. // Plot an equation which is supplied as a string
  300. //
  301. void Gnuplot::plot_equation(const std::string &equation,
  302. const std::string &title)
  303. {
  304. std::string titlestr, plotstr;
  305. std::ostringstream cmdstr;
  306. if (title == "")
  307. titlestr = "no title";
  308. else
  309. titlestr = title;
  310. if (this->nplots > 0)
  311. plotstr = "replot";
  312. else
  313. plotstr = "plot";
  314. cmdstr << plotstr << " " << equation << " " << "title \"" << titlestr
  315. << "\" with " << this->pstyle;
  316. this->cmd(cmdstr.str().c_str());
  317. this->nplots++;
  318. return;
  319. }
  320. void Gnuplot::plot_x(vector<double> d, const std::string &title)
  321. {
  322. ofstream tmp;
  323. std::ostringstream cmdstr;
  324. char name[] = "/tmp/gnuplotiXXXXXX";
  325. if (this->to_delete.size() == GP_MAX_TMP_FILES - 1)
  326. {
  327. cerr << "Maximum number of temporary files reached ("
  328. << GP_MAX_TMP_FILES << "): cannot open more files" << endl;
  329. return;
  330. }
  331. //
  332. //open temporary files for output
  333. if (mkstemp(name) == -1)
  334. {
  335. cerr << "Cannot create temporary file: exiting plot" << endl;
  336. return;
  337. }
  338. tmp.open(name);
  339. if (tmp.bad())
  340. {
  341. cerr << "Cannot create temorary file: exiting plot" << endl;
  342. return;
  343. }
  344. //
  345. // Save the temporary filename
  346. //
  347. this->to_delete.push_back(name);
  348. //
  349. // write the data to file
  350. //
  351. for (vector<double>::size_type i = 0; i < d.size(); i++)
  352. tmp << d[i] << endl;
  353. tmp.flush();
  354. tmp.close();
  355. //
  356. // command to be sent to gnuplot
  357. //
  358. if (this->nplots > 0)
  359. cmdstr << "replot ";
  360. else
  361. cmdstr << "plot ";
  362. if (title == "")
  363. cmdstr << "\"" << name << "\" with " << this->pstyle;
  364. else
  365. cmdstr << "\"" << name << "\" title \"" << title << "\" with "
  366. << this->pstyle;
  367. //
  368. // Do the actual plot
  369. //
  370. this->cmd(cmdstr.str().c_str());
  371. this->nplots++;
  372. return;
  373. }
  374. void Gnuplot::plot_xy(map<double, double> xy, const std::string &title)
  375. {
  376. vector<double> x;
  377. vector<double> y;
  378. for (map<double, double>::const_iterator i = xy.begin(); i != xy.end(); i++)
  379. {
  380. x.push_back(i->first);
  381. y.push_back(i->second);
  382. }
  383. plot_xy(x, y, title);
  384. }
  385. void Gnuplot::plot_xy(vector<double> x, vector<double> y,
  386. const std::string &title)
  387. {
  388. ofstream tmp;
  389. std::ostringstream cmdstr;
  390. char name[] = "/tmp/gnuplotiXXXXXX";
  391. // should raise an exception
  392. if (x.size() != y.size())
  393. return;
  394. if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1)
  395. {
  396. cerr << "Maximum number of temporary files reached ("
  397. << GP_MAX_TMP_FILES << "): cannot open more files" << endl;
  398. return;
  399. }
  400. //
  401. //open temporary files for output
  402. //
  403. if (mkstemp(name) == -1)
  404. {
  405. cerr << "Cannot create temporary file: exiting plot" << endl;
  406. return;
  407. }
  408. tmp.open(name);
  409. if (tmp.bad())
  410. {
  411. cerr << "Cannot create temorary file: exiting plot" << endl;
  412. return;
  413. }
  414. //
  415. // Save the temporary filename
  416. //
  417. this->to_delete.push_back(name);
  418. //
  419. // write the data to file
  420. //
  421. for (vector<double>::size_type i = 0; i < x.size(); i++)
  422. tmp << x[i] << " " << y[i] << endl;
  423. tmp.flush();
  424. tmp.close();
  425. //
  426. // command to be sent to gnuplot
  427. //
  428. if (this->nplots > 0)
  429. cmdstr << "replot ";
  430. else
  431. cmdstr << "plot ";
  432. if (title == "")
  433. cmdstr << "\"" << name << "\" with " << this->pstyle;
  434. else
  435. cmdstr << "\"" << name << "\" title \"" << title << "\" with "
  436. << this->pstyle;
  437. //
  438. // Do the actual plot
  439. //
  440. this->cmd(cmdstr.str().c_str());
  441. this->nplots++;
  442. return;
  443. }
  444. void Gnuplot::plot_xyz(vector<double> x, vector<double> y, vector<double> z,
  445. const std::string &title)
  446. {
  447. ofstream tmp;
  448. std::ostringstream cmdstr;
  449. char name[] = "/tmp/gnuplotiXXXXXX";
  450. // should raise an exception
  451. if (x.size() != y.size() || x.size() != z.size())
  452. {
  453. return;
  454. }
  455. if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1)
  456. {
  457. cerr << "Maximum number of temporary files reached ("
  458. << GP_MAX_TMP_FILES << "): cannot open more files" << endl;
  459. return;
  460. }
  461. //
  462. //open temporary files for output
  463. //
  464. if (mkstemp(name) == -1)
  465. {
  466. cerr << "Cannot create temporary file: exiting plot" << endl;
  467. return;
  468. }
  469. tmp.open(name);
  470. if (tmp.bad())
  471. {
  472. cerr << "Cannot create temorary file: exiting plot" << endl;
  473. return;
  474. }
  475. //
  476. // Save the temporary filename
  477. //
  478. this->to_delete.push_back(name);
  479. //
  480. // write the data to file
  481. //
  482. for (unsigned int i = 0; i < x.size(); i++)
  483. {
  484. tmp << x[i] << " " << y[i] << " " << z[i] << endl;
  485. }
  486. tmp.flush();
  487. tmp.close();
  488. //
  489. // command to be sent to gnuplot
  490. //
  491. if (this->nplots > 0)
  492. cmdstr << "replot ";
  493. else
  494. cmdstr << "splot ";
  495. if (title == "")
  496. cmdstr << "\"" << name << "\" with " << this->pstyle;
  497. else
  498. cmdstr << "\"" << name << "\" title \"" << title << "\" with "
  499. << this->pstyle;
  500. //
  501. // Do the actual plot
  502. //
  503. this->cmd(cmdstr.str().c_str());
  504. this->nplots++;
  505. return;
  506. }
  507. /**
  508. * note that this function is not valid for versions of GNUPlot below 4.2
  509. *
  510. **/
  511. void Gnuplot::plot_image(unsigned char * ucPicBuf, int iWidth, int iHeight,
  512. const std::string &title)
  513. {
  514. ofstream tmp;
  515. std::ostringstream cmdstr;
  516. char name[] = "/tmp/gnuplotiXXXXXX";
  517. if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1)
  518. {
  519. cerr << "Maximum number of temporary files reached ("
  520. << GP_MAX_TMP_FILES << "): cannot open more files" << endl;
  521. return;
  522. }
  523. //
  524. //open temporary files for output
  525. //
  526. if (mkstemp(name) == -1)
  527. {
  528. cerr << "Cannot create temporary file: exiting plot" << endl;
  529. return;
  530. }
  531. tmp.open(name);
  532. if (tmp.bad())
  533. {
  534. cerr << "Cannot create temorary file: exiting plot" << endl;
  535. return;
  536. }
  537. //
  538. // Save the temporary filename
  539. //
  540. this->to_delete.push_back(name);
  541. //
  542. // write the data to file
  543. //
  544. int iIndex = 0;
  545. for (int iRow = 0; iRow < iHeight; iRow++)
  546. {
  547. for (int iColumn = 0; iColumn < iWidth; iColumn++)
  548. {
  549. tmp << iColumn << " " << iRow << " "
  550. << static_cast<float> (ucPicBuf[iIndex++]) << endl;
  551. ;
  552. }
  553. }
  554. tmp.flush();
  555. tmp.close();
  556. //
  557. // command to be sent to gnuplot
  558. //
  559. if (this->nplots > 0)
  560. cmdstr << "replot ";
  561. else
  562. cmdstr << "plot ";
  563. if (title == "")
  564. cmdstr << "\"" << name << "\" with " << this->pstyle;
  565. else
  566. cmdstr << "\"" << name << "\" title \"" << title << "\" with image ";// << this->pstyle;
  567. //
  568. // Do the actual plot
  569. //
  570. this->cmd(cmdstr.str().c_str());
  571. this->nplots++;
  572. return;
  573. }