matplotlibcpp.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. #pragma once
  2. #include <vector>
  3. #include <map>
  4. #include <numeric>
  5. #include <stdexcept>
  6. #include <iostream>
  7. #if __cplusplus > 199711L
  8. #include <functional>
  9. #endif
  10. #include <python2.7/Python.h>
  11. namespace matplotlibcpp {
  12. namespace detail {
  13. struct _interpreter {
  14. PyObject *s_python_function_show;
  15. PyObject *s_python_function_save;
  16. PyObject *s_python_function_figure;
  17. PyObject *s_python_function_plot;
  18. PyObject *s_python_function_hist;
  19. PyObject *s_python_function_subplot;
  20. PyObject *s_python_function_legend;
  21. PyObject *s_python_function_xlim;
  22. PyObject *s_python_function_ylim;
  23. PyObject *s_python_function_title;
  24. PyObject *s_python_function_axis;
  25. PyObject *s_python_function_xlabel;
  26. PyObject *s_python_function_ylabel;
  27. PyObject *s_python_function_grid;
  28. PyObject *s_python_empty_tuple;
  29. PyObject *s_python_function_annotate;
  30. /* For now, _interpreter is implemented as a singleton since its currently not possible to have
  31. multiple independent embedded python interpreters without patching the python source code
  32. or starting a separate process for each.
  33. http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
  34. */
  35. static _interpreter& get() {
  36. static _interpreter ctx;
  37. return ctx;
  38. }
  39. private:
  40. _interpreter() {
  41. char name[] = "plotting"; // silence compiler warning about const strings
  42. Py_SetProgramName(name); // optional but recommended
  43. Py_Initialize();
  44. PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
  45. PyObject* pylabname = PyString_FromString("pylab");
  46. if(!pyplotname || !pylabname) { throw std::runtime_error("couldnt create string"); }
  47. PyObject* pymod = PyImport_Import(pyplotname);
  48. Py_DECREF(pyplotname);
  49. if(!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); }
  50. PyObject* pylabmod = PyImport_Import(pylabname);
  51. Py_DECREF(pylabname);
  52. if(!pymod) { throw std::runtime_error("Error loading module pylab!"); }
  53. s_python_function_show = PyObject_GetAttrString(pymod, "show");
  54. s_python_function_figure = PyObject_GetAttrString(pymod, "figure");
  55. s_python_function_plot = PyObject_GetAttrString(pymod, "plot");
  56. s_python_function_hist = PyObject_GetAttrString(pymod,"hist");
  57. s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot");
  58. s_python_function_legend = PyObject_GetAttrString(pymod, "legend");
  59. s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim");
  60. s_python_function_title = PyObject_GetAttrString(pymod, "title");
  61. s_python_function_axis = PyObject_GetAttrString(pymod, "axis");
  62. s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel");
  63. s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel");
  64. s_python_function_grid = PyObject_GetAttrString(pymod, "grid");
  65. s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim");
  66. s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig");
  67. s_python_function_annotate = PyObject_GetAttrString(pymod,"annotate");
  68. if( !s_python_function_show
  69. || !s_python_function_figure
  70. || !s_python_function_plot
  71. || !s_python_function_subplot
  72. || !s_python_function_legend
  73. || !s_python_function_ylim
  74. || !s_python_function_title
  75. || !s_python_function_axis
  76. || !s_python_function_xlabel
  77. || !s_python_function_ylabel
  78. || !s_python_function_grid
  79. || !s_python_function_xlim
  80. || !s_python_function_save
  81. || !s_python_function_annotate
  82. )
  83. { throw std::runtime_error("Couldn't find required function!"); }
  84. if( !PyFunction_Check(s_python_function_show)
  85. || !PyFunction_Check(s_python_function_figure)
  86. || !PyFunction_Check(s_python_function_plot)
  87. || !PyFunction_Check(s_python_function_subplot)
  88. || !PyFunction_Check(s_python_function_legend)
  89. || !PyFunction_Check(s_python_function_annotate)
  90. || !PyFunction_Check(s_python_function_ylim)
  91. || !PyFunction_Check(s_python_function_title)
  92. || !PyFunction_Check(s_python_function_axis)
  93. || !PyFunction_Check(s_python_function_xlabel)
  94. || !PyFunction_Check(s_python_function_ylabel)
  95. || !PyFunction_Check(s_python_function_grid)
  96. || !PyFunction_Check(s_python_function_xlim)
  97. || !PyFunction_Check(s_python_function_save)
  98. )
  99. { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); }
  100. s_python_empty_tuple = PyTuple_New(0);
  101. }
  102. ~_interpreter() {
  103. Py_Finalize();
  104. }
  105. };
  106. }
  107. bool annotate(std::string annotation, double x, double y)
  108. {
  109. PyObject * xy = PyTuple_New(2);
  110. PyObject * str = PyString_FromString(annotation.c_str());
  111. PyTuple_SetItem(xy,0,PyFloat_FromDouble(x));
  112. PyTuple_SetItem(xy,1,PyFloat_FromDouble(y));
  113. PyObject* kwargs = PyDict_New();
  114. PyDict_SetItemString(kwargs, "xy", xy);
  115. PyObject* args = PyTuple_New(1);
  116. PyTuple_SetItem(args, 0, str);
  117. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs);
  118. Py_DECREF(xy);
  119. Py_DECREF(args);
  120. Py_DECREF(kwargs);
  121. if(res) Py_DECREF(res);
  122. return res;
  123. }
  124. template<typename Numeric>
  125. bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
  126. {
  127. assert(x.size() == y.size());
  128. // using python lists
  129. PyObject* xlist = PyList_New(x.size());
  130. PyObject* ylist = PyList_New(y.size());
  131. for(size_t i = 0; i < x.size(); ++i) {
  132. PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
  133. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  134. }
  135. // construct positional args
  136. PyObject* args = PyTuple_New(2);
  137. PyTuple_SetItem(args, 0, xlist);
  138. PyTuple_SetItem(args, 1, ylist);
  139. Py_DECREF(xlist);
  140. Py_DECREF(ylist);
  141. // construct keyword args
  142. PyObject* kwargs = PyDict_New();
  143. for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
  144. {
  145. PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
  146. }
  147. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
  148. Py_DECREF(args);
  149. Py_DECREF(kwargs);
  150. if(res) Py_DECREF(res);
  151. return res;
  152. }
  153. template< typename Numeric>
  154. bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0){
  155. PyObject* ylist = PyList_New(y.size());
  156. PyObject* kwargs = PyDict_New();
  157. PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
  158. PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
  159. PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
  160. for(size_t i = 0; i < y.size(); ++i) {
  161. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  162. }
  163. PyObject* plot_args = PyTuple_New(1);
  164. PyTuple_SetItem(plot_args, 0, ylist);
  165. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
  166. Py_DECREF(ylist);
  167. Py_DECREF(plot_args);
  168. Py_DECREF(kwargs);
  169. if(res) Py_DECREF(res);
  170. return res;
  171. }
  172. template< typename Numeric>
  173. bool named_hist(std::string label,const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0){
  174. PyObject* ylist = PyList_New(y.size());
  175. PyObject* kwargs = PyDict_New();
  176. PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
  177. PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
  178. PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
  179. PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
  180. for(size_t i = 0; i < y.size(); ++i) {
  181. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  182. }
  183. PyObject* plot_args = PyTuple_New(1);
  184. PyTuple_SetItem(plot_args, 0, ylist);
  185. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
  186. Py_DECREF(ylist);
  187. Py_DECREF(plot_args);
  188. Py_DECREF(kwargs);
  189. if(res) Py_DECREF(res);
  190. return res;
  191. }
  192. template<typename NumericX, typename NumericY>
  193. bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
  194. {
  195. assert(x.size() == y.size());
  196. PyObject* xlist = PyList_New(x.size());
  197. PyObject* ylist = PyList_New(y.size());
  198. PyObject* pystring = PyString_FromString(s.c_str());
  199. for(size_t i = 0; i < x.size(); ++i) {
  200. PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
  201. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  202. }
  203. PyObject* plot_args = PyTuple_New(3);
  204. PyTuple_SetItem(plot_args, 0, xlist);
  205. PyTuple_SetItem(plot_args, 1, ylist);
  206. PyTuple_SetItem(plot_args, 2, pystring);
  207. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
  208. Py_DECREF(xlist);
  209. Py_DECREF(ylist);
  210. Py_DECREF(plot_args);
  211. if(res) Py_DECREF(res);
  212. return res;
  213. }
  214. template<typename Numeric>
  215. bool named_plot(const std::string& name, const std::vector<Numeric>& y, const std::string& format = "") {
  216. PyObject* kwargs = PyDict_New();
  217. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  218. PyObject* ylist = PyList_New(y.size());
  219. PyObject* pystring = PyString_FromString(format.c_str());
  220. for(size_t i = 0; i < y.size(); ++i) {
  221. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  222. }
  223. PyObject* plot_args = PyTuple_New(2);
  224. PyTuple_SetItem(plot_args, 0, ylist);
  225. PyTuple_SetItem(plot_args, 1, pystring);
  226. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
  227. Py_DECREF(kwargs);
  228. Py_DECREF(ylist);
  229. Py_DECREF(plot_args);
  230. if(res) Py_DECREF(res);
  231. return res;
  232. }
  233. template<typename Numeric>
  234. bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "") {
  235. PyObject* kwargs = PyDict_New();
  236. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  237. PyObject* xlist = PyList_New(x.size());
  238. PyObject* ylist = PyList_New(y.size());
  239. PyObject* pystring = PyString_FromString(format.c_str());
  240. for(size_t i = 0; i < x.size(); ++i) {
  241. PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
  242. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  243. }
  244. PyObject* plot_args = PyTuple_New(3);
  245. PyTuple_SetItem(plot_args, 0, xlist);
  246. PyTuple_SetItem(plot_args, 1, ylist);
  247. PyTuple_SetItem(plot_args, 2, pystring);
  248. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
  249. Py_DECREF(kwargs);
  250. Py_DECREF(xlist);
  251. Py_DECREF(ylist);
  252. Py_DECREF(plot_args);
  253. if(res) Py_DECREF(res);
  254. return res;
  255. }
  256. template<typename Numeric>
  257. bool plot(const std::vector<Numeric>& y, const std::string& format = "")
  258. {
  259. std::vector<Numeric> x(y.size());
  260. for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
  261. return plot(x,y,format);
  262. }
  263. inline void figure(){
  264. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple);
  265. if(!res) throw std::runtime_error("Call to figure() failed.");
  266. Py_DECREF(res);
  267. }
  268. inline void legend() {
  269. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
  270. if(!res) throw std::runtime_error("Call to legend() failed.");
  271. Py_DECREF(res);
  272. }
  273. template<typename Numeric>
  274. void ylim(Numeric left, Numeric right)
  275. {
  276. PyObject* list = PyList_New(2);
  277. PyList_SetItem(list, 0, PyFloat_FromDouble(left));
  278. PyList_SetItem(list, 1, PyFloat_FromDouble(right));
  279. PyObject* args = PyTuple_New(1);
  280. PyTuple_SetItem(args, 0, list);
  281. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
  282. if(!res) throw std::runtime_error("Call to ylim() failed.");
  283. Py_DECREF(list);
  284. Py_DECREF(args);
  285. Py_DECREF(res);
  286. }
  287. template<typename Numeric>
  288. void xlim(Numeric left, Numeric right)
  289. {
  290. PyObject* list = PyList_New(2);
  291. PyList_SetItem(list, 0, PyFloat_FromDouble(left));
  292. PyList_SetItem(list, 1, PyFloat_FromDouble(right));
  293. PyObject* args = PyTuple_New(1);
  294. PyTuple_SetItem(args, 0, list);
  295. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
  296. if(!res) throw std::runtime_error("Call to xlim() failed.");
  297. Py_DECREF(list);
  298. Py_DECREF(args);
  299. Py_DECREF(res);
  300. }
  301. double * xlim()
  302. {
  303. PyObject* args = PyTuple_New(0);
  304. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
  305. PyObject * left = PyTuple_GetItem(res,0);
  306. PyObject * right = PyTuple_GetItem(res,1);
  307. double * arr = new double[2];
  308. arr[0] = PyFloat_AsDouble(left);
  309. arr[1] = PyFloat_AsDouble(right);
  310. if(!res) throw std::runtime_error("Call to xlim() failed.");
  311. Py_DECREF(res);
  312. return arr;
  313. }
  314. double * ylim()
  315. {
  316. PyObject* args = PyTuple_New(0);
  317. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
  318. PyObject * left = PyTuple_GetItem(res,0);
  319. PyObject * right = PyTuple_GetItem(res,1);
  320. double * arr = new double[2];
  321. arr[0] = PyFloat_AsDouble(left);
  322. arr[1] = PyFloat_AsDouble(right);
  323. if(!res) throw std::runtime_error("Call to ylim() failed.");
  324. Py_DECREF(res);
  325. return arr;
  326. }
  327. inline void subplot(long nrows, long ncols, long plot_number) {
  328. // construct positional args
  329. PyObject* args = PyTuple_New(3);
  330. PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
  331. PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
  332. PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));
  333. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
  334. if(!res) throw std::runtime_error("Call to subplot() failed.");
  335. Py_DECREF(args);
  336. Py_DECREF(res);
  337. }
  338. inline void title(const std::string &titlestr)
  339. {
  340. PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
  341. PyObject* args = PyTuple_New(1);
  342. PyTuple_SetItem(args, 0, pytitlestr);
  343. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_title, args);
  344. if(!res) throw std::runtime_error("Call to title() failed.");
  345. // if PyDeCRFF, the function doesn't work on Mac OS
  346. }
  347. inline void axis(const std::string &axisstr)
  348. {
  349. PyObject* str = PyString_FromString(axisstr.c_str());
  350. PyObject* args = PyTuple_New(1);
  351. PyTuple_SetItem(args, 0, str);
  352. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args);
  353. if(!res) throw std::runtime_error("Call to title() failed.");
  354. // if PyDeCRFF, the function doesn't work on Mac OS
  355. }
  356. inline void xlabel(const std::string &str)
  357. {
  358. PyObject* pystr = PyString_FromString(str.c_str());
  359. PyObject* args = PyTuple_New(1);
  360. PyTuple_SetItem(args, 0, pystr);
  361. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlabel, args);
  362. if(!res) throw std::runtime_error("Call to xlabel() failed.");
  363. // if PyDeCRFF, the function doesn't work on Mac OS
  364. }
  365. inline void ylabel(const std::string &str)
  366. {
  367. PyObject* pystr = PyString_FromString(str.c_str());
  368. PyObject* args = PyTuple_New(1);
  369. PyTuple_SetItem(args, 0, pystr);
  370. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylabel, args);
  371. if(!res) throw std::runtime_error("Call to ylabel() failed.");
  372. // if PyDeCRFF, the function doesn't work on Mac OS
  373. }
  374. inline void grid(bool flag)
  375. {
  376. PyObject* pyflag = flag ? Py_True : Py_False;
  377. PyObject* args = PyTuple_New(1);
  378. PyTuple_SetItem(args, 0, pyflag);
  379. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
  380. if(!res) throw std::runtime_error("Call to grid() failed.");
  381. // if PyDeCRFF, the function doesn't work on Mac OS
  382. }
  383. inline void show()
  384. {
  385. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple);
  386. if(!res) throw std::runtime_error("Call to show() failed.");
  387. Py_DECREF(res);
  388. }
  389. inline void save(const std::string& filename)
  390. {
  391. PyObject* pyfilename = PyString_FromString(filename.c_str());
  392. PyObject* args = PyTuple_New(1);
  393. PyTuple_SetItem(args, 0, pyfilename);
  394. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args);
  395. if(!res) throw std::runtime_error("Call to save() failed.");
  396. Py_DECREF(pyfilename);
  397. Py_DECREF(args);
  398. Py_DECREF(res);
  399. }
  400. #if __cplusplus > 199711L
  401. // C++11-exclusive content starts here (variadic plot() and initializer list support)
  402. namespace detail {
  403. template<typename T>
  404. using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
  405. template<bool obj, typename T>
  406. struct is_callable_impl;
  407. template<typename T>
  408. struct is_callable_impl<false, T>
  409. {
  410. typedef is_function<T> type;
  411. }; // a non-object is callable iff it is a function
  412. template<typename T>
  413. struct is_callable_impl<true, T>
  414. {
  415. struct Fallback { void operator()(); };
  416. struct Derived : T, Fallback { };
  417. template<typename U, U> struct Check;
  418. template<typename U>
  419. static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
  420. template<typename U>
  421. static std::false_type test( Check<void(Fallback::*)(), &U::operator()>* );
  422. public:
  423. typedef decltype(test<Derived>(nullptr)) type;
  424. typedef decltype(&Fallback::operator()) dtype;
  425. static constexpr bool value = type::value;
  426. }; // an object is callable iff it defines operator()
  427. template<typename T>
  428. struct is_callable
  429. {
  430. // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
  431. typedef typename is_callable_impl<std::is_class<T>::value, T>::type type;
  432. };
  433. template<typename IsYDataCallable>
  434. struct plot_impl { };
  435. template<>
  436. struct plot_impl<std::false_type>
  437. {
  438. template<typename IterableX, typename IterableY>
  439. bool operator()(const IterableX& x, const IterableY& y, const std::string& format)
  440. {
  441. // 2-phase lookup for distance, begin, end
  442. using std::distance;
  443. using std::begin;
  444. using std::end;
  445. auto xs = distance(begin(x), end(x));
  446. auto ys = distance(begin(y), end(y));
  447. assert(xs == ys && "x and y data must have the same number of elements!");
  448. PyObject* xlist = PyList_New(xs);
  449. PyObject* ylist = PyList_New(ys);
  450. PyObject* pystring = PyString_FromString(format.c_str());
  451. auto itx = begin(x), ity = begin(y);
  452. for(size_t i = 0; i < xs; ++i) {
  453. PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
  454. PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
  455. }
  456. PyObject* plot_args = PyTuple_New(3);
  457. PyTuple_SetItem(plot_args, 0, xlist);
  458. PyTuple_SetItem(plot_args, 1, ylist);
  459. PyTuple_SetItem(plot_args, 2, pystring);
  460. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
  461. Py_DECREF(xlist);
  462. Py_DECREF(ylist);
  463. Py_DECREF(plot_args);
  464. if(res) Py_DECREF(res);
  465. return res;
  466. }
  467. };
  468. template<>
  469. struct plot_impl<std::true_type>
  470. {
  471. template<typename Iterable, typename Callable>
  472. bool operator()(const Iterable& ticks, const Callable& f, const std::string& format)
  473. {
  474. //std::cout << "Callable impl called" << std::endl;
  475. if(begin(ticks) == end(ticks)) return true;
  476. // We could use additional meta-programming to deduce the correct element type of y,
  477. // but all values have to be convertible to double anyways
  478. std::vector<double> y;
  479. for(auto x : ticks) y.push_back(f(x));
  480. return plot_impl<std::false_type>()(ticks,y,format);
  481. }
  482. };
  483. }
  484. // recursion stop for the above
  485. template<typename... Args>
  486. bool plot() { return true; }
  487. template<typename A, typename B, typename... Args>
  488. bool plot(const A& a, const B& b, const std::string& format, Args... args)
  489. {
  490. return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot(args...);
  491. }
  492. /*
  493. * This group of plot() functions is needed to support initializer lists, i.e. calling
  494. * plot( {1,2,3,4} )
  495. */
  496. bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
  497. return plot<double,double>(x,y,format);
  498. }
  499. bool plot(const std::vector<double>& y, const std::string& format = "") {
  500. return plot<double>(y,format);
  501. }
  502. bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords) {
  503. return plot<double>(x,y,keywords);
  504. }
  505. bool named_plot(const std::string& name, const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
  506. return named_plot<double>(name,x,y,format);
  507. }
  508. #endif
  509. }