matplotlibcpp.h 25 KB

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