1
0

matplotlibcpp.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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(args);
  119. Py_DECREF(kwargs);
  120. if(res) Py_DECREF(res);
  121. return res;
  122. }
  123. template<typename Numeric>
  124. bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
  125. {
  126. assert(x.size() == y.size());
  127. // using python lists
  128. PyObject* xlist = PyList_New(x.size());
  129. PyObject* ylist = PyList_New(y.size());
  130. for(size_t i = 0; i < x.size(); ++i) {
  131. PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
  132. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  133. }
  134. // construct positional args
  135. PyObject* args = PyTuple_New(2);
  136. PyTuple_SetItem(args, 0, xlist);
  137. PyTuple_SetItem(args, 1, ylist);
  138. Py_DECREF(xlist);
  139. Py_DECREF(ylist);
  140. // construct keyword args
  141. PyObject* kwargs = PyDict_New();
  142. for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
  143. {
  144. PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
  145. }
  146. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
  147. Py_DECREF(args);
  148. Py_DECREF(kwargs);
  149. if(res) Py_DECREF(res);
  150. return res;
  151. }
  152. template< typename Numeric>
  153. bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0){
  154. PyObject* ylist = PyList_New(y.size());
  155. PyObject* kwargs = PyDict_New();
  156. PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
  157. PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
  158. PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
  159. for(size_t i = 0; i < y.size(); ++i) {
  160. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  161. }
  162. PyObject* plot_args = PyTuple_New(1);
  163. PyTuple_SetItem(plot_args, 0, ylist);
  164. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
  165. Py_DECREF(plot_args);
  166. Py_DECREF(kwargs);
  167. if(res) Py_DECREF(res);
  168. return res;
  169. }
  170. template< typename Numeric>
  171. bool named_hist(std::string label,const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0){
  172. PyObject* ylist = PyList_New(y.size());
  173. PyObject* kwargs = PyDict_New();
  174. PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
  175. PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
  176. PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
  177. PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
  178. for(size_t i = 0; i < y.size(); ++i) {
  179. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  180. }
  181. PyObject* plot_args = PyTuple_New(1);
  182. PyTuple_SetItem(plot_args, 0, ylist);
  183. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
  184. Py_DECREF(plot_args);
  185. Py_DECREF(kwargs);
  186. if(res) Py_DECREF(res);
  187. return res;
  188. }
  189. template<typename NumericX, typename NumericY>
  190. bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
  191. {
  192. assert(x.size() == y.size());
  193. PyObject* xlist = PyList_New(x.size());
  194. PyObject* ylist = PyList_New(y.size());
  195. PyObject* pystring = PyString_FromString(s.c_str());
  196. for(size_t i = 0; i < x.size(); ++i) {
  197. PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
  198. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  199. }
  200. PyObject* plot_args = PyTuple_New(3);
  201. PyTuple_SetItem(plot_args, 0, xlist);
  202. PyTuple_SetItem(plot_args, 1, ylist);
  203. PyTuple_SetItem(plot_args, 2, pystring);
  204. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
  205. Py_DECREF(plot_args);
  206. if(res) Py_DECREF(res);
  207. return res;
  208. }
  209. template<typename Numeric>
  210. bool named_plot(const std::string& name, const std::vector<Numeric>& y, const std::string& format = "") {
  211. PyObject* kwargs = PyDict_New();
  212. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  213. PyObject* ylist = PyList_New(y.size());
  214. PyObject* pystring = PyString_FromString(format.c_str());
  215. for(size_t i = 0; i < y.size(); ++i) {
  216. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  217. }
  218. PyObject* plot_args = PyTuple_New(2);
  219. PyTuple_SetItem(plot_args, 0, ylist);
  220. PyTuple_SetItem(plot_args, 1, pystring);
  221. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
  222. Py_DECREF(kwargs);
  223. Py_DECREF(plot_args);
  224. if(res) Py_DECREF(res);
  225. return res;
  226. }
  227. template<typename Numeric>
  228. bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "") {
  229. PyObject* kwargs = PyDict_New();
  230. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  231. PyObject* xlist = PyList_New(x.size());
  232. PyObject* ylist = PyList_New(y.size());
  233. PyObject* pystring = PyString_FromString(format.c_str());
  234. for(size_t i = 0; i < x.size(); ++i) {
  235. PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
  236. PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
  237. }
  238. PyObject* plot_args = PyTuple_New(3);
  239. PyTuple_SetItem(plot_args, 0, xlist);
  240. PyTuple_SetItem(plot_args, 1, ylist);
  241. PyTuple_SetItem(plot_args, 2, pystring);
  242. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
  243. Py_DECREF(kwargs);
  244. Py_DECREF(plot_args);
  245. if(res) Py_DECREF(res);
  246. return res;
  247. }
  248. template<typename Numeric>
  249. bool plot(const std::vector<Numeric>& y, const std::string& format = "")
  250. {
  251. std::vector<Numeric> x(y.size());
  252. for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
  253. return plot(x,y,format);
  254. }
  255. inline void figure(){
  256. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple);
  257. if(!res) throw std::runtime_error("Call to figure() failed.");
  258. Py_DECREF(res);
  259. }
  260. inline void legend() {
  261. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
  262. if(!res) throw std::runtime_error("Call to legend() failed.");
  263. Py_DECREF(res);
  264. }
  265. template<typename Numeric>
  266. void ylim(Numeric left, Numeric right)
  267. {
  268. PyObject* list = PyList_New(2);
  269. PyList_SetItem(list, 0, PyFloat_FromDouble(left));
  270. PyList_SetItem(list, 1, PyFloat_FromDouble(right));
  271. PyObject* args = PyTuple_New(1);
  272. PyTuple_SetItem(args, 0, list);
  273. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
  274. if(!res) throw std::runtime_error("Call to ylim() failed.");
  275. Py_DECREF(args);
  276. Py_DECREF(res);
  277. }
  278. template<typename Numeric>
  279. void xlim(Numeric left, Numeric right)
  280. {
  281. PyObject* list = PyList_New(2);
  282. PyList_SetItem(list, 0, PyFloat_FromDouble(left));
  283. PyList_SetItem(list, 1, PyFloat_FromDouble(right));
  284. PyObject* args = PyTuple_New(1);
  285. PyTuple_SetItem(args, 0, list);
  286. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
  287. if(!res) throw std::runtime_error("Call to xlim() failed.");
  288. Py_DECREF(args);
  289. Py_DECREF(res);
  290. }
  291. double * xlim()
  292. {
  293. PyObject* args = PyTuple_New(0);
  294. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
  295. PyObject * left = PyTuple_GetItem(res,0);
  296. PyObject * right = PyTuple_GetItem(res,1);
  297. double * arr = new double[2];
  298. arr[0] = PyFloat_AsDouble(left);
  299. arr[1] = PyFloat_AsDouble(right);
  300. if(!res) throw std::runtime_error("Call to xlim() failed.");
  301. Py_DECREF(res);
  302. return arr;
  303. }
  304. double * ylim()
  305. {
  306. PyObject* args = PyTuple_New(0);
  307. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
  308. PyObject * left = PyTuple_GetItem(res,0);
  309. PyObject * right = PyTuple_GetItem(res,1);
  310. double * arr = new double[2];
  311. arr[0] = PyFloat_AsDouble(left);
  312. arr[1] = PyFloat_AsDouble(right);
  313. if(!res) throw std::runtime_error("Call to ylim() failed.");
  314. Py_DECREF(res);
  315. return arr;
  316. }
  317. inline void subplot(long nrows, long ncols, long plot_number) {
  318. // construct positional args
  319. PyObject* args = PyTuple_New(3);
  320. PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
  321. PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
  322. PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));
  323. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
  324. if(!res) throw std::runtime_error("Call to subplot() failed.");
  325. Py_DECREF(args);
  326. Py_DECREF(res);
  327. }
  328. inline void title(const std::string &titlestr)
  329. {
  330. PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
  331. PyObject* args = PyTuple_New(1);
  332. PyTuple_SetItem(args, 0, pytitlestr);
  333. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_title, args);
  334. if(!res) throw std::runtime_error("Call to title() failed.");
  335. // if PyDeCRFF, the function doesn't work on Mac OS
  336. }
  337. inline void axis(const std::string &axisstr)
  338. {
  339. PyObject* str = PyString_FromString(axisstr.c_str());
  340. PyObject* args = PyTuple_New(1);
  341. PyTuple_SetItem(args, 0, str);
  342. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args);
  343. if(!res) throw std::runtime_error("Call to title() failed.");
  344. // if PyDeCRFF, the function doesn't work on Mac OS
  345. }
  346. inline void xlabel(const std::string &str)
  347. {
  348. PyObject* pystr = PyString_FromString(str.c_str());
  349. PyObject* args = PyTuple_New(1);
  350. PyTuple_SetItem(args, 0, pystr);
  351. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlabel, args);
  352. if(!res) throw std::runtime_error("Call to xlabel() failed.");
  353. // if PyDeCRFF, the function doesn't work on Mac OS
  354. }
  355. inline void ylabel(const std::string &str)
  356. {
  357. PyObject* pystr = PyString_FromString(str.c_str());
  358. PyObject* args = PyTuple_New(1);
  359. PyTuple_SetItem(args, 0, pystr);
  360. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylabel, args);
  361. if(!res) throw std::runtime_error("Call to ylabel() failed.");
  362. // if PyDeCRFF, the function doesn't work on Mac OS
  363. }
  364. inline void grid(bool flag)
  365. {
  366. PyObject* pyflag = flag ? Py_True : Py_False;
  367. PyObject* args = PyTuple_New(1);
  368. PyTuple_SetItem(args, 0, pyflag);
  369. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
  370. if(!res) throw std::runtime_error("Call to grid() failed.");
  371. // if PyDeCRFF, the function doesn't work on Mac OS
  372. }
  373. inline void show()
  374. {
  375. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple);
  376. if(!res) throw std::runtime_error("Call to show() failed.");
  377. Py_DECREF(res);
  378. }
  379. inline void save(const std::string& filename)
  380. {
  381. PyObject* pyfilename = PyString_FromString(filename.c_str());
  382. PyObject* args = PyTuple_New(1);
  383. PyTuple_SetItem(args, 0, pyfilename);
  384. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args);
  385. if(!res) throw std::runtime_error("Call to save() failed.");
  386. Py_DECREF(pyfilename);
  387. Py_DECREF(args);
  388. Py_DECREF(res);
  389. }
  390. #if __cplusplus > 199711L
  391. // C++11-exclusive content starts here (variadic plot() and initializer list support)
  392. namespace detail {
  393. template<typename T>
  394. using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
  395. template<bool obj, typename T>
  396. struct is_callable_impl;
  397. template<typename T>
  398. struct is_callable_impl<false, T>
  399. {
  400. typedef is_function<T> type;
  401. }; // a non-object is callable iff it is a function
  402. template<typename T>
  403. struct is_callable_impl<true, T>
  404. {
  405. struct Fallback { void operator()(); };
  406. struct Derived : T, Fallback { };
  407. template<typename U, U> struct Check;
  408. template<typename U>
  409. static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
  410. template<typename U>
  411. static std::false_type test( Check<void(Fallback::*)(), &U::operator()>* );
  412. public:
  413. typedef decltype(test<Derived>(nullptr)) type;
  414. typedef decltype(&Fallback::operator()) dtype;
  415. static constexpr bool value = type::value;
  416. }; // an object is callable iff it defines operator()
  417. template<typename T>
  418. struct is_callable
  419. {
  420. // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
  421. typedef typename is_callable_impl<std::is_class<T>::value, T>::type type;
  422. };
  423. template<typename IsYDataCallable>
  424. struct plot_impl { };
  425. template<>
  426. struct plot_impl<std::false_type>
  427. {
  428. template<typename IterableX, typename IterableY>
  429. bool operator()(const IterableX& x, const IterableY& y, const std::string& format)
  430. {
  431. // 2-phase lookup for distance, begin, end
  432. using std::distance;
  433. using std::begin;
  434. using std::end;
  435. auto xs = distance(begin(x), end(x));
  436. auto ys = distance(begin(y), end(y));
  437. assert(xs == ys && "x and y data must have the same number of elements!");
  438. PyObject* xlist = PyList_New(xs);
  439. PyObject* ylist = PyList_New(ys);
  440. PyObject* pystring = PyString_FromString(format.c_str());
  441. auto itx = begin(x), ity = begin(y);
  442. for(size_t i = 0; i < xs; ++i) {
  443. PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
  444. PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
  445. }
  446. PyObject* plot_args = PyTuple_New(3);
  447. PyTuple_SetItem(plot_args, 0, xlist);
  448. PyTuple_SetItem(plot_args, 1, ylist);
  449. PyTuple_SetItem(plot_args, 2, pystring);
  450. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
  451. Py_DECREF(xlist);
  452. Py_DECREF(ylist);
  453. Py_DECREF(plot_args);
  454. if(res) Py_DECREF(res);
  455. return res;
  456. }
  457. };
  458. template<>
  459. struct plot_impl<std::true_type>
  460. {
  461. template<typename Iterable, typename Callable>
  462. bool operator()(const Iterable& ticks, const Callable& f, const std::string& format)
  463. {
  464. //std::cout << "Callable impl called" << std::endl;
  465. if(begin(ticks) == end(ticks)) return true;
  466. // We could use additional meta-programming to deduce the correct element type of y,
  467. // but all values have to be convertible to double anyways
  468. std::vector<double> y;
  469. for(auto x : ticks) y.push_back(f(x));
  470. return plot_impl<std::false_type>()(ticks,y,format);
  471. }
  472. };
  473. }
  474. // recursion stop for the above
  475. template<typename... Args>
  476. bool plot() { return true; }
  477. template<typename A, typename B, typename... Args>
  478. bool plot(const A& a, const B& b, const std::string& format, Args... args)
  479. {
  480. return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot(args...);
  481. }
  482. /*
  483. * This group of plot() functions is needed to support initializer lists, i.e. calling
  484. * plot( {1,2,3,4} )
  485. */
  486. bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
  487. return plot<double,double>(x,y,format);
  488. }
  489. bool plot(const std::vector<double>& y, const std::string& format = "") {
  490. return plot<double>(y,format);
  491. }
  492. bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords) {
  493. return plot<double>(x,y,keywords);
  494. }
  495. bool named_plot(const std::string& name, const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
  496. return named_plot<double>(name,x,y,format);
  497. }
  498. #endif
  499. }