matplotlibcpp.h 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  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. static std::string s_backend;
  23. struct _interpreter {
  24. PyObject *s_python_function_show;
  25. PyObject *s_python_function_draw;
  26. PyObject *s_python_function_pause;
  27. PyObject *s_python_function_save;
  28. PyObject *s_python_function_figure;
  29. PyObject *s_python_function_plot;
  30. PyObject *s_python_function_semilogx;
  31. PyObject *s_python_function_semilogy;
  32. PyObject *s_python_function_loglog;
  33. PyObject *s_python_function_fill_between;
  34. PyObject *s_python_function_hist;
  35. PyObject *s_python_function_subplot;
  36. PyObject *s_python_function_legend;
  37. PyObject *s_python_function_xlim;
  38. PyObject *s_python_function_ion;
  39. PyObject *s_python_function_ylim;
  40. PyObject *s_python_function_title;
  41. PyObject *s_python_function_axis;
  42. PyObject *s_python_function_xlabel;
  43. PyObject *s_python_function_ylabel;
  44. PyObject *s_python_function_grid;
  45. PyObject *s_python_function_clf;
  46. PyObject *s_python_function_errorbar;
  47. PyObject *s_python_function_annotate;
  48. PyObject *s_python_function_tight_layout;
  49. PyObject *s_python_empty_tuple;
  50. PyObject *s_python_function_stem;
  51. PyObject *s_python_function_xkcd;
  52. /* For now, _interpreter is implemented as a singleton since its currently not possible to have
  53. multiple independent embedded python interpreters without patching the python source code
  54. or starting a separate process for each.
  55. http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
  56. */
  57. static _interpreter& get() {
  58. static _interpreter ctx;
  59. return ctx;
  60. }
  61. private:
  62. #if PY_MAJOR_VERSION >= 3
  63. int import_numpy() {
  64. import_array(); // initialize C-API
  65. }
  66. #else
  67. void import_numpy() {
  68. import_array(); // initialize C-API
  69. }
  70. #endif
  71. _interpreter() {
  72. // optional but recommended
  73. #if PY_MAJOR_VERSION >= 3
  74. wchar_t name[] = L"plotting";
  75. #else
  76. char name[] = "plotting";
  77. #endif
  78. Py_SetProgramName(name);
  79. Py_Initialize();
  80. #ifndef WITHOUT_NUMPY
  81. import_numpy(); // initialize numpy C-API
  82. #endif
  83. PyObject* matplotlibname = PyString_FromString("matplotlib");
  84. PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
  85. PyObject* pylabname = PyString_FromString("pylab");
  86. if (!pyplotname || !pylabname || !matplotlibname) {
  87. throw std::runtime_error("couldnt create string");
  88. }
  89. PyObject* matplotlib = PyImport_Import(matplotlibname);
  90. Py_DECREF(matplotlibname);
  91. if(!matplotlib) { throw std::runtime_error("Error loading module matplotlib!"); }
  92. // matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
  93. // or matplotlib.backends is imported for the first time
  94. if (!s_backend.empty()) {
  95. PyObject_CallMethod(matplotlib, const_cast<char*>("use"), const_cast<char*>("s"), s_backend.c_str());
  96. }
  97. PyObject* pymod = PyImport_Import(pyplotname);
  98. Py_DECREF(pyplotname);
  99. if(!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); }
  100. PyObject* pylabmod = PyImport_Import(pylabname);
  101. Py_DECREF(pylabname);
  102. if(!pylabmod) { throw std::runtime_error("Error loading module pylab!"); }
  103. s_python_function_show = PyObject_GetAttrString(pymod, "show");
  104. s_python_function_draw = PyObject_GetAttrString(pymod, "draw");
  105. s_python_function_pause = PyObject_GetAttrString(pymod, "pause");
  106. s_python_function_figure = PyObject_GetAttrString(pymod, "figure");
  107. s_python_function_plot = PyObject_GetAttrString(pymod, "plot");
  108. s_python_function_semilogx = PyObject_GetAttrString(pymod, "semilogx");
  109. s_python_function_semilogy = PyObject_GetAttrString(pymod, "semilogy");
  110. s_python_function_loglog = PyObject_GetAttrString(pymod, "loglog");
  111. s_python_function_fill_between = PyObject_GetAttrString(pymod, "fill_between");
  112. s_python_function_hist = PyObject_GetAttrString(pymod,"hist");
  113. s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot");
  114. s_python_function_legend = PyObject_GetAttrString(pymod, "legend");
  115. s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim");
  116. s_python_function_title = PyObject_GetAttrString(pymod, "title");
  117. s_python_function_axis = PyObject_GetAttrString(pymod, "axis");
  118. s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel");
  119. s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel");
  120. s_python_function_grid = PyObject_GetAttrString(pymod, "grid");
  121. s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim");
  122. s_python_function_ion = PyObject_GetAttrString(pymod, "ion");
  123. s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig");
  124. s_python_function_annotate = PyObject_GetAttrString(pymod,"annotate");
  125. s_python_function_clf = PyObject_GetAttrString(pymod, "clf");
  126. s_python_function_errorbar = PyObject_GetAttrString(pymod, "errorbar");
  127. s_python_function_tight_layout = PyObject_GetAttrString(pymod, "tight_layout");
  128. s_python_function_stem = PyObject_GetAttrString(pymod, "stem");
  129. s_python_function_xkcd = PyObject_GetAttrString(pymod, "xkcd");
  130. if( !s_python_function_show
  131. || !s_python_function_draw
  132. || !s_python_function_pause
  133. || !s_python_function_figure
  134. || !s_python_function_plot
  135. || !s_python_function_semilogx
  136. || !s_python_function_semilogy
  137. || !s_python_function_loglog
  138. || !s_python_function_fill_between
  139. || !s_python_function_subplot
  140. || !s_python_function_legend
  141. || !s_python_function_ylim
  142. || !s_python_function_title
  143. || !s_python_function_axis
  144. || !s_python_function_xlabel
  145. || !s_python_function_ylabel
  146. || !s_python_function_grid
  147. || !s_python_function_xlim
  148. || !s_python_function_ion
  149. || !s_python_function_save
  150. || !s_python_function_clf
  151. || !s_python_function_annotate
  152. || !s_python_function_errorbar
  153. || !s_python_function_errorbar
  154. || !s_python_function_tight_layout
  155. || !s_python_function_stem
  156. || !s_python_function_xkcd
  157. ) { throw std::runtime_error("Couldn't find required function!"); }
  158. if ( !PyFunction_Check(s_python_function_show)
  159. || !PyFunction_Check(s_python_function_draw)
  160. || !PyFunction_Check(s_python_function_pause)
  161. || !PyFunction_Check(s_python_function_figure)
  162. || !PyFunction_Check(s_python_function_plot)
  163. || !PyFunction_Check(s_python_function_semilogx)
  164. || !PyFunction_Check(s_python_function_semilogy)
  165. || !PyFunction_Check(s_python_function_loglog)
  166. || !PyFunction_Check(s_python_function_fill_between)
  167. || !PyFunction_Check(s_python_function_subplot)
  168. || !PyFunction_Check(s_python_function_legend)
  169. || !PyFunction_Check(s_python_function_annotate)
  170. || !PyFunction_Check(s_python_function_ylim)
  171. || !PyFunction_Check(s_python_function_title)
  172. || !PyFunction_Check(s_python_function_axis)
  173. || !PyFunction_Check(s_python_function_xlabel)
  174. || !PyFunction_Check(s_python_function_ylabel)
  175. || !PyFunction_Check(s_python_function_grid)
  176. || !PyFunction_Check(s_python_function_xlim)
  177. || !PyFunction_Check(s_python_function_ion)
  178. || !PyFunction_Check(s_python_function_save)
  179. || !PyFunction_Check(s_python_function_clf)
  180. || !PyFunction_Check(s_python_function_tight_layout)
  181. || !PyFunction_Check(s_python_function_errorbar)
  182. || !PyFunction_Check(s_python_function_stem)
  183. || !PyFunction_Check(s_python_function_xkcd)
  184. ) { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); }
  185. s_python_empty_tuple = PyTuple_New(0);
  186. }
  187. ~_interpreter() {
  188. Py_Finalize();
  189. }
  190. };
  191. }
  192. // must be called before the first regular call to matplotlib to have any effect
  193. void backend(const std::string& name)
  194. {
  195. detail::s_backend = name;
  196. }
  197. bool annotate(std::string annotation, double x, double y)
  198. {
  199. PyObject * xy = PyTuple_New(2);
  200. PyObject * str = PyString_FromString(annotation.c_str());
  201. PyTuple_SetItem(xy,0,PyFloat_FromDouble(x));
  202. PyTuple_SetItem(xy,1,PyFloat_FromDouble(y));
  203. PyObject* kwargs = PyDict_New();
  204. PyDict_SetItemString(kwargs, "xy", xy);
  205. PyObject* args = PyTuple_New(1);
  206. PyTuple_SetItem(args, 0, str);
  207. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs);
  208. Py_DECREF(args);
  209. Py_DECREF(kwargs);
  210. if(res) Py_DECREF(res);
  211. return res;
  212. }
  213. #ifndef WITHOUT_NUMPY
  214. // Type selector for numpy array conversion
  215. template <typename T> struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default
  216. template <> struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
  217. template <> struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
  218. template <> struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
  219. template <> struct select_npy_type<int8_t> { const static NPY_TYPES type = NPY_INT8; };
  220. template <> struct select_npy_type<int16_t> { const static NPY_TYPES type = NPY_SHORT; };
  221. template <> struct select_npy_type<int32_t> { const static NPY_TYPES type = NPY_INT; };
  222. template <> struct select_npy_type<int64_t> { const static NPY_TYPES type = NPY_INT64; };
  223. template <> struct select_npy_type<uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
  224. template <> struct select_npy_type<uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
  225. template <> struct select_npy_type<uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
  226. template <> struct select_npy_type<uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
  227. template<typename Numeric>
  228. PyObject* get_array(const std::vector<Numeric>& v)
  229. {
  230. detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
  231. NPY_TYPES type = select_npy_type<Numeric>::type;
  232. if (type == NPY_NOTYPE)
  233. {
  234. std::vector<double> vd(v.size());
  235. npy_intp vsize = v.size();
  236. std::copy(v.begin(),v.end(),vd.begin());
  237. PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data()));
  238. return varray;
  239. }
  240. npy_intp vsize = v.size();
  241. PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
  242. return varray;
  243. }
  244. #else // fallback if we don't have numpy: copy every element of the given vector
  245. template<typename Numeric>
  246. PyObject* get_array(const std::vector<Numeric>& v)
  247. {
  248. PyObject* list = PyList_New(v.size());
  249. for(size_t i = 0; i < v.size(); ++i) {
  250. PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i)));
  251. }
  252. return list;
  253. }
  254. #endif // WITHOUT_NUMPY
  255. template<typename Numeric>
  256. bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
  257. {
  258. assert(x.size() == y.size());
  259. // using numpy arrays
  260. PyObject* xarray = get_array(x);
  261. PyObject* yarray = get_array(y);
  262. // construct positional args
  263. PyObject* args = PyTuple_New(2);
  264. PyTuple_SetItem(args, 0, xarray);
  265. PyTuple_SetItem(args, 1, yarray);
  266. // construct keyword args
  267. PyObject* kwargs = PyDict_New();
  268. for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
  269. {
  270. PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
  271. }
  272. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
  273. Py_DECREF(args);
  274. Py_DECREF(kwargs);
  275. if(res) Py_DECREF(res);
  276. return res;
  277. }
  278. template<typename Numeric>
  279. bool stem(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
  280. {
  281. assert(x.size() == y.size());
  282. // using numpy arrays
  283. PyObject* xarray = get_array(x);
  284. PyObject* yarray = get_array(y);
  285. // construct positional args
  286. PyObject* args = PyTuple_New(2);
  287. PyTuple_SetItem(args, 0, xarray);
  288. PyTuple_SetItem(args, 1, yarray);
  289. // construct keyword args
  290. PyObject* kwargs = PyDict_New();
  291. for (std::map<std::string, std::string>::const_iterator it =
  292. keywords.begin(); it != keywords.end(); ++it) {
  293. PyDict_SetItemString(kwargs, it->first.c_str(),
  294. PyString_FromString(it->second.c_str()));
  295. }
  296. PyObject* res = PyObject_Call(
  297. detail::_interpreter::get().s_python_function_stem, args, kwargs);
  298. Py_DECREF(args);
  299. Py_DECREF(kwargs);
  300. if (res)
  301. Py_DECREF(res);
  302. return res;
  303. }
  304. template< typename Numeric >
  305. 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)
  306. {
  307. assert(x.size() == y1.size());
  308. assert(x.size() == y2.size());
  309. // using numpy arrays
  310. PyObject* xarray = get_array(x);
  311. PyObject* y1array = get_array(y1);
  312. PyObject* y2array = get_array(y2);
  313. // construct positional args
  314. PyObject* args = PyTuple_New(3);
  315. PyTuple_SetItem(args, 0, xarray);
  316. PyTuple_SetItem(args, 1, y1array);
  317. PyTuple_SetItem(args, 2, y2array);
  318. // construct keyword args
  319. PyObject* kwargs = PyDict_New();
  320. for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
  321. {
  322. PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
  323. }
  324. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs);
  325. Py_DECREF(args);
  326. Py_DECREF(kwargs);
  327. if(res) Py_DECREF(res);
  328. return res;
  329. }
  330. template< typename Numeric>
  331. bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0)
  332. {
  333. PyObject* yarray = get_array(y);
  334. PyObject* kwargs = PyDict_New();
  335. PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
  336. PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
  337. PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
  338. PyObject* plot_args = PyTuple_New(1);
  339. PyTuple_SetItem(plot_args, 0, yarray);
  340. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
  341. Py_DECREF(plot_args);
  342. Py_DECREF(kwargs);
  343. if(res) Py_DECREF(res);
  344. return res;
  345. }
  346. template< typename Numeric>
  347. bool named_hist(std::string label,const std::vector<Numeric>& y, long bins=10, std::string color="b", double alpha=1.0)
  348. {
  349. PyObject* yarray = get_array(y);
  350. PyObject* kwargs = PyDict_New();
  351. PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
  352. PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
  353. PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
  354. PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
  355. PyObject* plot_args = PyTuple_New(1);
  356. PyTuple_SetItem(plot_args, 0, yarray);
  357. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
  358. Py_DECREF(plot_args);
  359. Py_DECREF(kwargs);
  360. if(res) Py_DECREF(res);
  361. return res;
  362. }
  363. template<typename NumericX, typename NumericY>
  364. bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
  365. {
  366. assert(x.size() == y.size());
  367. PyObject* xarray = get_array(x);
  368. PyObject* yarray = get_array(y);
  369. PyObject* pystring = PyString_FromString(s.c_str());
  370. PyObject* plot_args = PyTuple_New(3);
  371. PyTuple_SetItem(plot_args, 0, xarray);
  372. PyTuple_SetItem(plot_args, 1, yarray);
  373. PyTuple_SetItem(plot_args, 2, pystring);
  374. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
  375. Py_DECREF(plot_args);
  376. if(res) Py_DECREF(res);
  377. return res;
  378. }
  379. template<typename NumericX, typename NumericY>
  380. bool stem(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
  381. {
  382. assert(x.size() == y.size());
  383. PyObject* xarray = get_array(x);
  384. PyObject* yarray = get_array(y);
  385. PyObject* pystring = PyString_FromString(s.c_str());
  386. PyObject* plot_args = PyTuple_New(3);
  387. PyTuple_SetItem(plot_args, 0, xarray);
  388. PyTuple_SetItem(plot_args, 1, yarray);
  389. PyTuple_SetItem(plot_args, 2, pystring);
  390. PyObject* res = PyObject_CallObject(
  391. detail::_interpreter::get().s_python_function_stem, plot_args);
  392. Py_DECREF(plot_args);
  393. if (res)
  394. Py_DECREF(res);
  395. return res;
  396. }
  397. template<typename NumericX, typename NumericY>
  398. bool semilogx(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
  399. {
  400. assert(x.size() == y.size());
  401. PyObject* xarray = get_array(x);
  402. PyObject* yarray = get_array(y);
  403. PyObject* pystring = PyString_FromString(s.c_str());
  404. PyObject* plot_args = PyTuple_New(3);
  405. PyTuple_SetItem(plot_args, 0, xarray);
  406. PyTuple_SetItem(plot_args, 1, yarray);
  407. PyTuple_SetItem(plot_args, 2, pystring);
  408. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args);
  409. Py_DECREF(plot_args);
  410. if(res) Py_DECREF(res);
  411. return res;
  412. }
  413. template<typename NumericX, typename NumericY>
  414. bool semilogy(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
  415. {
  416. assert(x.size() == y.size());
  417. PyObject* xarray = get_array(x);
  418. PyObject* yarray = get_array(y);
  419. PyObject* pystring = PyString_FromString(s.c_str());
  420. PyObject* plot_args = PyTuple_New(3);
  421. PyTuple_SetItem(plot_args, 0, xarray);
  422. PyTuple_SetItem(plot_args, 1, yarray);
  423. PyTuple_SetItem(plot_args, 2, pystring);
  424. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args);
  425. Py_DECREF(plot_args);
  426. if(res) Py_DECREF(res);
  427. return res;
  428. }
  429. template<typename NumericX, typename NumericY>
  430. bool loglog(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
  431. {
  432. assert(x.size() == y.size());
  433. PyObject* xarray = get_array(x);
  434. PyObject* yarray = get_array(y);
  435. PyObject* pystring = PyString_FromString(s.c_str());
  436. PyObject* plot_args = PyTuple_New(3);
  437. PyTuple_SetItem(plot_args, 0, xarray);
  438. PyTuple_SetItem(plot_args, 1, yarray);
  439. PyTuple_SetItem(plot_args, 2, pystring);
  440. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args);
  441. Py_DECREF(plot_args);
  442. if(res) Py_DECREF(res);
  443. return res;
  444. }
  445. template<typename NumericX, typename NumericY>
  446. bool errorbar(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::vector<NumericX> &yerr, const std::string &s = "")
  447. {
  448. assert(x.size() == y.size());
  449. PyObject* xarray = get_array(x);
  450. PyObject* yarray = get_array(y);
  451. PyObject* yerrarray = get_array(yerr);
  452. PyObject *kwargs = PyDict_New();
  453. PyDict_SetItemString(kwargs, "yerr", yerrarray);
  454. PyObject *pystring = PyString_FromString(s.c_str());
  455. PyObject *plot_args = PyTuple_New(2);
  456. PyTuple_SetItem(plot_args, 0, xarray);
  457. PyTuple_SetItem(plot_args, 1, yarray);
  458. PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs);
  459. Py_DECREF(kwargs);
  460. Py_DECREF(plot_args);
  461. if (res)
  462. Py_DECREF(res);
  463. else
  464. throw std::runtime_error("Call to errorbar() failed.");
  465. return res;
  466. }
  467. template<typename Numeric>
  468. bool named_plot(const std::string& name, const std::vector<Numeric>& y, const std::string& format = "")
  469. {
  470. PyObject* kwargs = PyDict_New();
  471. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  472. PyObject* yarray = get_array(y);
  473. PyObject* pystring = PyString_FromString(format.c_str());
  474. PyObject* plot_args = PyTuple_New(2);
  475. PyTuple_SetItem(plot_args, 0, yarray);
  476. PyTuple_SetItem(plot_args, 1, pystring);
  477. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
  478. Py_DECREF(kwargs);
  479. Py_DECREF(plot_args);
  480. if(res) Py_DECREF(res);
  481. return res;
  482. }
  483. template<typename Numeric>
  484. bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
  485. {
  486. PyObject* kwargs = PyDict_New();
  487. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  488. PyObject* xarray = get_array(x);
  489. PyObject* yarray = get_array(y);
  490. PyObject* pystring = PyString_FromString(format.c_str());
  491. PyObject* plot_args = PyTuple_New(3);
  492. PyTuple_SetItem(plot_args, 0, xarray);
  493. PyTuple_SetItem(plot_args, 1, yarray);
  494. PyTuple_SetItem(plot_args, 2, pystring);
  495. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
  496. Py_DECREF(kwargs);
  497. Py_DECREF(plot_args);
  498. if(res) Py_DECREF(res);
  499. return res;
  500. }
  501. template<typename Numeric>
  502. bool named_semilogx(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
  503. {
  504. PyObject* kwargs = PyDict_New();
  505. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  506. PyObject* xarray = get_array(x);
  507. PyObject* yarray = get_array(y);
  508. PyObject* pystring = PyString_FromString(format.c_str());
  509. PyObject* plot_args = PyTuple_New(3);
  510. PyTuple_SetItem(plot_args, 0, xarray);
  511. PyTuple_SetItem(plot_args, 1, yarray);
  512. PyTuple_SetItem(plot_args, 2, pystring);
  513. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs);
  514. Py_DECREF(kwargs);
  515. Py_DECREF(plot_args);
  516. if(res) Py_DECREF(res);
  517. return res;
  518. }
  519. template<typename Numeric>
  520. bool named_semilogy(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
  521. {
  522. PyObject* kwargs = PyDict_New();
  523. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  524. PyObject* xarray = get_array(x);
  525. PyObject* yarray = get_array(y);
  526. PyObject* pystring = PyString_FromString(format.c_str());
  527. PyObject* plot_args = PyTuple_New(3);
  528. PyTuple_SetItem(plot_args, 0, xarray);
  529. PyTuple_SetItem(plot_args, 1, yarray);
  530. PyTuple_SetItem(plot_args, 2, pystring);
  531. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs);
  532. Py_DECREF(kwargs);
  533. Py_DECREF(plot_args);
  534. if(res) Py_DECREF(res);
  535. return res;
  536. }
  537. template<typename Numeric>
  538. bool named_loglog(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
  539. {
  540. PyObject* kwargs = PyDict_New();
  541. PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
  542. PyObject* xarray = get_array(x);
  543. PyObject* yarray = get_array(y);
  544. PyObject* pystring = PyString_FromString(format.c_str());
  545. PyObject* plot_args = PyTuple_New(3);
  546. PyTuple_SetItem(plot_args, 0, xarray);
  547. PyTuple_SetItem(plot_args, 1, yarray);
  548. PyTuple_SetItem(plot_args, 2, pystring);
  549. PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs);
  550. Py_DECREF(kwargs);
  551. Py_DECREF(plot_args);
  552. if(res) Py_DECREF(res);
  553. return res;
  554. }
  555. template<typename Numeric>
  556. bool plot(const std::vector<Numeric>& y, const std::string& format = "")
  557. {
  558. std::vector<Numeric> x(y.size());
  559. for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
  560. return plot(x,y,format);
  561. }
  562. template<typename Numeric>
  563. bool stem(const std::vector<Numeric>& y, const std::string& format = "")
  564. {
  565. std::vector<Numeric> x(y.size());
  566. for (size_t i = 0; i < x.size(); ++i) x.at(i) = i;
  567. return stem(x, y, format);
  568. }
  569. inline void figure()
  570. {
  571. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple);
  572. if(!res) throw std::runtime_error("Call to figure() failed.");
  573. Py_DECREF(res);
  574. }
  575. inline void legend()
  576. {
  577. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
  578. if(!res) throw std::runtime_error("Call to legend() failed.");
  579. Py_DECREF(res);
  580. }
  581. template<typename Numeric>
  582. void ylim(Numeric left, Numeric right)
  583. {
  584. PyObject* list = PyList_New(2);
  585. PyList_SetItem(list, 0, PyFloat_FromDouble(left));
  586. PyList_SetItem(list, 1, PyFloat_FromDouble(right));
  587. PyObject* args = PyTuple_New(1);
  588. PyTuple_SetItem(args, 0, list);
  589. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
  590. if(!res) throw std::runtime_error("Call to ylim() failed.");
  591. Py_DECREF(args);
  592. Py_DECREF(res);
  593. }
  594. template<typename Numeric>
  595. void xlim(Numeric left, Numeric right)
  596. {
  597. PyObject* list = PyList_New(2);
  598. PyList_SetItem(list, 0, PyFloat_FromDouble(left));
  599. PyList_SetItem(list, 1, PyFloat_FromDouble(right));
  600. PyObject* args = PyTuple_New(1);
  601. PyTuple_SetItem(args, 0, list);
  602. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
  603. if(!res) throw std::runtime_error("Call to xlim() failed.");
  604. Py_DECREF(args);
  605. Py_DECREF(res);
  606. }
  607. inline double* xlim()
  608. {
  609. PyObject* args = PyTuple_New(0);
  610. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
  611. PyObject* left = PyTuple_GetItem(res,0);
  612. PyObject* right = PyTuple_GetItem(res,1);
  613. double* arr = new double[2];
  614. arr[0] = PyFloat_AsDouble(left);
  615. arr[1] = PyFloat_AsDouble(right);
  616. if(!res) throw std::runtime_error("Call to xlim() failed.");
  617. Py_DECREF(res);
  618. return arr;
  619. }
  620. inline double* ylim()
  621. {
  622. PyObject* args = PyTuple_New(0);
  623. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
  624. PyObject* left = PyTuple_GetItem(res,0);
  625. PyObject* right = PyTuple_GetItem(res,1);
  626. double* arr = new double[2];
  627. arr[0] = PyFloat_AsDouble(left);
  628. arr[1] = PyFloat_AsDouble(right);
  629. if(!res) throw std::runtime_error("Call to ylim() failed.");
  630. Py_DECREF(res);
  631. return arr;
  632. }
  633. inline void subplot(long nrows, long ncols, long plot_number)
  634. {
  635. // construct positional args
  636. PyObject* args = PyTuple_New(3);
  637. PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
  638. PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
  639. PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));
  640. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
  641. if(!res) throw std::runtime_error("Call to subplot() failed.");
  642. Py_DECREF(args);
  643. Py_DECREF(res);
  644. }
  645. inline void title(const std::string &titlestr)
  646. {
  647. PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
  648. PyObject* args = PyTuple_New(1);
  649. PyTuple_SetItem(args, 0, pytitlestr);
  650. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_title, args);
  651. if(!res) throw std::runtime_error("Call to title() failed.");
  652. // if PyDeCRFF, the function doesn't work on Mac OS
  653. }
  654. inline void axis(const std::string &axisstr)
  655. {
  656. PyObject* str = PyString_FromString(axisstr.c_str());
  657. PyObject* args = PyTuple_New(1);
  658. PyTuple_SetItem(args, 0, str);
  659. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args);
  660. if(!res) throw std::runtime_error("Call to title() failed.");
  661. // if PyDeCRFF, the function doesn't work on Mac OS
  662. }
  663. inline void xlabel(const std::string &str)
  664. {
  665. PyObject* pystr = PyString_FromString(str.c_str());
  666. PyObject* args = PyTuple_New(1);
  667. PyTuple_SetItem(args, 0, pystr);
  668. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlabel, args);
  669. if(!res) throw std::runtime_error("Call to xlabel() failed.");
  670. // if PyDeCRFF, the function doesn't work on Mac OS
  671. }
  672. inline void ylabel(const std::string &str)
  673. {
  674. PyObject* pystr = PyString_FromString(str.c_str());
  675. PyObject* args = PyTuple_New(1);
  676. PyTuple_SetItem(args, 0, pystr);
  677. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylabel, args);
  678. if(!res) throw std::runtime_error("Call to ylabel() failed.");
  679. // if PyDeCRFF, the function doesn't work on Mac OS
  680. }
  681. inline void grid(bool flag)
  682. {
  683. PyObject* pyflag = flag ? Py_True : Py_False;
  684. PyObject* args = PyTuple_New(1);
  685. PyTuple_SetItem(args, 0, pyflag);
  686. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
  687. if(!res) throw std::runtime_error("Call to grid() failed.");
  688. // if PyDeCRFF, the function doesn't work on Mac OS
  689. }
  690. inline void show(const bool block = true)
  691. {
  692. PyObject* res;
  693. if(block)
  694. {
  695. res = PyObject_CallObject(
  696. detail::_interpreter::get().s_python_function_show,
  697. detail::_interpreter::get().s_python_empty_tuple);
  698. }
  699. else
  700. {
  701. PyObject *kwargs = PyDict_New();
  702. PyDict_SetItemString(kwargs, "block", Py_False);
  703. res = PyObject_Call( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs);
  704. }
  705. if (!res) throw std::runtime_error("Call to show() failed.");
  706. Py_DECREF(res);
  707. }
  708. inline void xkcd() {
  709. PyObject* res;
  710. PyObject *kwargs = PyDict_New();
  711. res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd,
  712. detail::_interpreter::get().s_python_empty_tuple, kwargs);
  713. if (!res)
  714. throw std::runtime_error("Call to show() failed.");
  715. Py_DECREF(res);
  716. }
  717. inline void draw()
  718. {
  719. PyObject* res = PyObject_CallObject(
  720. detail::_interpreter::get().s_python_function_draw,
  721. detail::_interpreter::get().s_python_empty_tuple);
  722. if (!res) throw std::runtime_error("Call to draw() failed.");
  723. Py_DECREF(res);
  724. }
  725. template<typename Numeric>
  726. void pause(Numeric interval)
  727. {
  728. PyObject* args = PyTuple_New(1);
  729. PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval));
  730. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args);
  731. if(!res) throw std::runtime_error("Call to pause() failed.");
  732. Py_DECREF(args);
  733. Py_DECREF(res);
  734. }
  735. inline void save(const std::string& filename)
  736. {
  737. PyObject* pyfilename = PyString_FromString(filename.c_str());
  738. PyObject* args = PyTuple_New(1);
  739. PyTuple_SetItem(args, 0, pyfilename);
  740. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args);
  741. if (!res) throw std::runtime_error("Call to save() failed.");
  742. Py_DECREF(args);
  743. Py_DECREF(res);
  744. }
  745. inline void clf() {
  746. PyObject *res = PyObject_CallObject(
  747. detail::_interpreter::get().s_python_function_clf,
  748. detail::_interpreter::get().s_python_empty_tuple);
  749. if (!res) throw std::runtime_error("Call to clf() failed.");
  750. Py_DECREF(res);
  751. }
  752. inline void ion() {
  753. PyObject *res = PyObject_CallObject(
  754. detail::_interpreter::get().s_python_function_ion,
  755. detail::_interpreter::get().s_python_empty_tuple);
  756. if (!res) throw std::runtime_error("Call to ion() failed.");
  757. Py_DECREF(res);
  758. }
  759. // Actually, is there any reason not to call this automatically for every plot?
  760. inline void tight_layout() {
  761. PyObject *res = PyObject_CallObject(
  762. detail::_interpreter::get().s_python_function_tight_layout,
  763. detail::_interpreter::get().s_python_empty_tuple);
  764. if (!res) throw std::runtime_error("Call to tight_layout() failed.");
  765. Py_DECREF(res);
  766. }
  767. #if __cplusplus > 199711L || _MSC_VER > 1800
  768. // C++11-exclusive content starts here (variadic plot() and initializer list support)
  769. namespace detail {
  770. template<typename T>
  771. using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
  772. template<bool obj, typename T>
  773. struct is_callable_impl;
  774. template<typename T>
  775. struct is_callable_impl<false, T>
  776. {
  777. typedef is_function<T> type;
  778. }; // a non-object is callable iff it is a function
  779. template<typename T>
  780. struct is_callable_impl<true, T>
  781. {
  782. struct Fallback { void operator()(); };
  783. struct Derived : T, Fallback { };
  784. template<typename U, U> struct Check;
  785. template<typename U>
  786. static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
  787. template<typename U>
  788. static std::false_type test( Check<void(Fallback::*)(), &U::operator()>* );
  789. public:
  790. typedef decltype(test<Derived>(nullptr)) type;
  791. typedef decltype(&Fallback::operator()) dtype;
  792. static constexpr bool value = type::value;
  793. }; // an object is callable iff it defines operator()
  794. template<typename T>
  795. struct is_callable
  796. {
  797. // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
  798. typedef typename is_callable_impl<std::is_class<T>::value, T>::type type;
  799. };
  800. template<typename IsYDataCallable>
  801. struct plot_impl { };
  802. template<>
  803. struct plot_impl<std::false_type>
  804. {
  805. template<typename IterableX, typename IterableY>
  806. bool operator()(const IterableX& x, const IterableY& y, const std::string& format)
  807. {
  808. // 2-phase lookup for distance, begin, end
  809. using std::distance;
  810. using std::begin;
  811. using std::end;
  812. auto xs = distance(begin(x), end(x));
  813. auto ys = distance(begin(y), end(y));
  814. assert(xs == ys && "x and y data must have the same number of elements!");
  815. PyObject* xlist = PyList_New(xs);
  816. PyObject* ylist = PyList_New(ys);
  817. PyObject* pystring = PyString_FromString(format.c_str());
  818. auto itx = begin(x), ity = begin(y);
  819. for(size_t i = 0; i < xs; ++i) {
  820. PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
  821. PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
  822. }
  823. PyObject* plot_args = PyTuple_New(3);
  824. PyTuple_SetItem(plot_args, 0, xlist);
  825. PyTuple_SetItem(plot_args, 1, ylist);
  826. PyTuple_SetItem(plot_args, 2, pystring);
  827. PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
  828. Py_DECREF(plot_args);
  829. if(res) Py_DECREF(res);
  830. return res;
  831. }
  832. };
  833. template<>
  834. struct plot_impl<std::true_type>
  835. {
  836. template<typename Iterable, typename Callable>
  837. bool operator()(const Iterable& ticks, const Callable& f, const std::string& format)
  838. {
  839. //std::cout << "Callable impl called" << std::endl;
  840. if(begin(ticks) == end(ticks)) return true;
  841. // We could use additional meta-programming to deduce the correct element type of y,
  842. // but all values have to be convertible to double anyways
  843. std::vector<double> y;
  844. for(auto x : ticks) y.push_back(f(x));
  845. return plot_impl<std::false_type>()(ticks,y,format);
  846. }
  847. };
  848. }
  849. // recursion stop for the above
  850. template<typename... Args>
  851. bool plot() { return true; }
  852. template<typename A, typename B, typename... Args>
  853. bool plot(const A& a, const B& b, const std::string& format, Args... args)
  854. {
  855. return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot(args...);
  856. }
  857. /*
  858. * This group of plot() functions is needed to support initializer lists, i.e. calling
  859. * plot( {1,2,3,4} )
  860. */
  861. bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
  862. return plot<double,double>(x,y,format);
  863. }
  864. bool plot(const std::vector<double>& y, const std::string& format = "") {
  865. return plot<double>(y,format);
  866. }
  867. bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords) {
  868. return plot<double>(x,y,keywords);
  869. }
  870. bool stem(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "")
  871. {
  872. return stem<double, double>(x, y, format);
  873. }
  874. bool stem(const std::vector<double>& y, const std::string& format = "")
  875. {
  876. return stem<double>(y, format);
  877. }
  878. bool stem(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords)
  879. {
  880. return stem<double>(x, y, keywords);
  881. }
  882. bool named_plot(const std::string& name, const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
  883. return named_plot<double>(name,x,y,format);
  884. }
  885. #endif
  886. }