matplotlibcpp.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <array>
5 #include <cstdint> // <cstdint> requires c++11 support
6 #include <functional>
7 #include <iostream>
8 #include <map>
9 #include <numeric>
10 #include <stdexcept>
11 #include <vector>
12 
13 #include <Python.h>
14 
15 #define WITHOUT_NUMPY
16 
17 #ifndef WITHOUT_NUMPY
18 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
19 #include <numpy/arrayobject.h>
20 
21 #ifdef WITH_OPENCV
22 #include <opencv2/opencv.hpp>
23 #endif // WITH_OPENCV
24 #endif // WITHOUT_NUMPY
25 
26 #if PY_MAJOR_VERSION >= 3
27 #define PyString_FromString PyUnicode_FromString
28 #define PyInt_FromLong PyLong_FromLong
29 #define PyString_FromString PyUnicode_FromString
30 #endif
31 
32 namespace matplotlibcpp {
33 namespace detail {
34 
35 static std::string s_backend;
36 
37 struct _interpreter {
74  PyObject *s_python_colormap;
82 
83  /* For now, _interpreter is implemented as a singleton since its currently not possible to have
84  multiple independent embedded python interpreters without patching the python source code
85  or starting a separate process for each.
86  http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
87  */
88 
89  static _interpreter &get() {
90  static _interpreter ctx;
91  return ctx;
92  }
93 
94  PyObject *safe_import(PyObject *module, std::string fname) {
95  PyObject *fn = PyObject_GetAttrString(module, fname.c_str());
96 
97  if (!fn)
98  throw std::runtime_error(std::string("Couldn't find required function: ") + fname);
99 
100  if (!PyFunction_Check(fn))
101  throw std::runtime_error(fname + std::string(" is unexpectedly not a PyFunction."));
102 
103  return fn;
104  }
105 
106 private:
107 #ifndef WITHOUT_NUMPY
108 #if PY_MAJOR_VERSION >= 3
109 
110  void *import_numpy() {
111  import_array(); // initialize C-API
112  return NULL;
113  }
114 
115 #else
116 
117  void import_numpy() {
118  import_array(); // initialize C-API
119  }
120 
121 #endif
122 #endif
123 
125 
126  // optional but recommended
127 #if PY_MAJOR_VERSION >= 3
128  wchar_t name[] = L"plotting";
129 #else
130  char name[] = "plotting";
131 #endif
132  Py_SetProgramName(name);
133  Py_Initialize();
134 
135 #ifndef WITHOUT_NUMPY
136  import_numpy(); // initialize numpy C-API
137 #endif
138 
139  PyObject *matplotlibname = PyString_FromString("matplotlib");
140  PyObject *pyplotname = PyString_FromString("matplotlib.pyplot");
141  PyObject *cmname = PyString_FromString("matplotlib.cm");
142  PyObject *pylabname = PyString_FromString("pylab");
143  if (!pyplotname || !pylabname || !matplotlibname || !cmname) {
144  throw std::runtime_error("couldnt create string");
145  }
146 
147  PyObject *matplotlib = PyImport_Import(matplotlibname);
148  Py_DECREF(matplotlibname);
149  if (!matplotlib) {
150  PyErr_Print();
151  throw std::runtime_error("Error loading module matplotlib!");
152  }
153 
154  // matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
155  // or matplotlib.backends is imported for the first time
156  if (!s_backend.empty()) {
157  PyObject_CallMethod(matplotlib, const_cast<char *>("use"), const_cast<char *>("s"), s_backend.c_str());
158  }
159 
160  PyObject *pymod = PyImport_Import(pyplotname);
161  Py_DECREF(pyplotname);
162  if (!pymod) {
163  throw std::runtime_error("Error loading module matplotlib.pyplot!");
164  }
165 
166  s_python_colormap = PyImport_Import(cmname);
167  Py_DECREF(cmname);
168  if (!s_python_colormap) {
169  throw std::runtime_error("Error loading module matplotlib.cm!");
170  }
171 
172  PyObject *pylabmod = PyImport_Import(pylabname);
173  Py_DECREF(pylabname);
174  if (!pylabmod) {
175  throw std::runtime_error("Error loading module pylab!");
176  }
177 
178  s_python_function_show = safe_import(pymod, "show");
179  s_python_function_close = safe_import(pymod, "close");
180  s_python_function_draw = safe_import(pymod, "draw");
181  s_python_function_pause = safe_import(pymod, "pause");
182  s_python_function_figure = safe_import(pymod, "figure");
183  s_python_function_fignum_exists = safe_import(pymod, "fignum_exists");
184  s_python_function_plot = safe_import(pymod, "plot");
185  s_python_function_quiver = safe_import(pymod, "quiver");
186  s_python_function_boxplot = safe_import(pymod, "boxplot");
187  s_python_function_stackplot = safe_import(pymod, "stackplot");
188  s_python_function_semilogx = safe_import(pymod, "semilogx");
189  s_python_function_semilogy = safe_import(pymod, "semilogy");
190  s_python_function_loglog = safe_import(pymod, "loglog");
191  s_python_function_fill = safe_import(pymod, "fill");
192  s_python_function_fill_between = safe_import(pymod, "fill_between");
193  s_python_function_hist = safe_import(pymod, "hist");
194  s_python_function_scatter = safe_import(pymod, "scatter");
195  s_python_function_subplot = safe_import(pymod, "subplot");
196  s_python_function_legend = safe_import(pymod, "legend");
197  s_python_function_ylim = safe_import(pymod, "ylim");
198  s_python_function_title = safe_import(pymod, "title");
199  s_python_function_axis = safe_import(pymod, "axis");
200  s_python_function_xlabel = safe_import(pymod, "xlabel");
201  s_python_function_ylabel = safe_import(pymod, "ylabel");
202  s_python_function_xticks = safe_import(pymod, "xticks");
203  s_python_function_yticks = safe_import(pymod, "yticks");
204  s_python_function_grid = safe_import(pymod, "grid");
205  s_python_function_xlim = safe_import(pymod, "xlim");
206  s_python_function_ion = safe_import(pymod, "ion");
207  s_python_function_ginput = safe_import(pymod, "ginput");
208  s_python_function_save = safe_import(pylabmod, "savefig");
209  s_python_function_annotate = safe_import(pymod, "annotate");
210  s_python_function_clf = safe_import(pymod, "clf");
211  s_python_function_errorbar = safe_import(pymod, "errorbar");
212  s_python_function_tight_layout = safe_import(pymod, "tight_layout");
213  s_python_function_stem = safe_import(pymod, "stem");
214  s_python_function_xkcd = safe_import(pymod, "xkcd");
215  s_python_function_text = safe_import(pymod, "text");
216  s_python_function_suptitle = safe_import(pymod, "suptitle");
217  s_python_function_bar = safe_import(pymod, "bar");
218  s_python_function_subplots_adjust = safe_import(pymod, "subplots_adjust");
219 #ifndef WITHOUT_NUMPY
220  s_python_function_imshow = safe_import(pymod, "imshow");
221 #endif
222 
223  s_python_empty_tuple = PyTuple_New(0);
224  }
225 
226  ~_interpreter() { Py_Finalize(); }
227 };
228 
229 } // end namespace detail
230 
231 // must be called before the first regular call to matplotlib to have any effect
232 inline void backend(const std::string &name) { detail::s_backend = name; }
233 
234 inline bool annotate(std::string annotation, double x, double y) {
235  PyObject *xy = PyTuple_New(2);
236  PyObject *str = PyString_FromString(annotation.c_str());
237 
238  PyTuple_SetItem(xy, 0, PyFloat_FromDouble(x));
239  PyTuple_SetItem(xy, 1, PyFloat_FromDouble(y));
240 
241  PyObject *kwargs = PyDict_New();
242  PyDict_SetItemString(kwargs, "xy", xy);
243 
244  PyObject *args = PyTuple_New(1);
245  PyTuple_SetItem(args, 0, str);
246 
247  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs);
248 
249  Py_DECREF(args);
250  Py_DECREF(kwargs);
251 
252  if (res)
253  Py_DECREF(res);
254 
255  return res;
256 }
257 
258 #ifndef WITHOUT_NUMPY
259 // Type selector for numpy array conversion
260 template <typename T> struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; // Default
261 template <> struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
262 template <> struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
263 template <> struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
264 template <> struct select_npy_type<int8_t> { const static NPY_TYPES type = NPY_INT8; };
265 template <> struct select_npy_type<int16_t> { const static NPY_TYPES type = NPY_SHORT; };
266 template <> struct select_npy_type<int32_t> { const static NPY_TYPES type = NPY_INT; };
267 template <> struct select_npy_type<int64_t> { const static NPY_TYPES type = NPY_INT64; };
268 template <> struct select_npy_type<uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
269 template <> struct select_npy_type<uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
270 template <> struct select_npy_type<uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
271 template <> struct select_npy_type<uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
272 
273 template <typename Numeric> PyObject *get_array(const std::vector<Numeric> &v) {
274  detail::_interpreter::get(); // interpreter needs to be initialized for the numpy commands to work
275  NPY_TYPES type = select_npy_type<Numeric>::type;
276  if (type == NPY_NOTYPE) {
277  std::vector<double> vd(v.size());
278  npy_intp vsize = v.size();
279  std::copy(v.begin(), v.end(), vd.begin());
280  PyObject *varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void *)(vd.data()));
281  return varray;
282  }
283 
284  npy_intp vsize = v.size();
285  PyObject *varray = PyArray_SimpleNewFromData(1, &vsize, type, (void *)(v.data()));
286  return varray;
287 }
288 
289 template <typename Numeric> PyObject *get_2darray(const std::vector<::std::vector<Numeric>> &v) {
290  detail::_interpreter::get(); // interpreter needs to be initialized for the numpy commands to work
291  if (v.size() < 1)
292  throw std::runtime_error("get_2d_array v too small");
293 
294  npy_intp vsize[2] = {static_cast<npy_intp>(v.size()), static_cast<npy_intp>(v[0].size())};
295 
296  PyArrayObject *varray = (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE);
297 
298  double *vd_begin = static_cast<double *>(PyArray_DATA(varray));
299 
300  for (const ::std::vector<Numeric> &v_row : v) {
301  if (v_row.size() != static_cast<size_t>(vsize[1]))
302  throw std::runtime_error("Missmatched array size");
303  std::copy(v_row.begin(), v_row.end(), vd_begin);
304  vd_begin += vsize[1];
305  }
306 
307  return reinterpret_cast<PyObject *>(varray);
308 }
309 
310 #else // fallback if we don't have numpy: copy every element of the given vector
311 
312 template <typename Numeric> PyObject *get_array(const std::vector<Numeric> &v) {
313  PyObject *list = PyList_New(v.size());
314  for (size_t i = 0; i < v.size(); ++i) {
315  PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i)));
316  }
317  return list;
318 }
319 
320 #endif // WITHOUT_NUMPY
321 
322 template <typename Numeric>
323 bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string> &keywords) {
324  assert(x.size() == y.size());
325 
326  // using numpy arrays
327  PyObject *xarray = get_array(x);
328  PyObject *yarray = get_array(y);
329 
330  // construct positional args
331  PyObject *args = PyTuple_New(2);
332  PyTuple_SetItem(args, 0, xarray);
333  PyTuple_SetItem(args, 1, yarray);
334 
335  // construct keyword args
336  PyObject *kwargs = PyDict_New();
337  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
338  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
339  }
340 
341  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
342 
343  Py_DECREF(args);
344  Py_DECREF(kwargs);
345  if (res)
346  Py_DECREF(res);
347 
348  return res;
349 }
350 
351 template <typename Numeric>
352 void plot_surface(const std::vector<::std::vector<Numeric>> &x, const std::vector<::std::vector<Numeric>> &y,
353  const std::vector<::std::vector<Numeric>> &z,
354  const std::map<std::string, std::string> &keywords = std::map<std::string, std::string>()) {
355  // We lazily load the modules here the first time this function is called
356  // because I'm not sure that we can assume "matplotlib installed" implies
357  // "mpl_toolkits installed" on all platforms, and we don't want to require
358  // it for people who don't need 3d plots.
359  static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
360  if (!mpl_toolkitsmod) {
362 
363  PyObject *mpl_toolkits = PyString_FromString("mpl_toolkits");
364  PyObject *axis3d = PyString_FromString("mpl_toolkits.mplot3d");
365  if (!mpl_toolkits || !axis3d) {
366  throw std::runtime_error("couldnt create string");
367  }
368 
369  mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
370  Py_DECREF(mpl_toolkits);
371  if (!mpl_toolkitsmod) {
372  throw std::runtime_error("Error loading module mpl_toolkits!");
373  }
374 
375  axis3dmod = PyImport_Import(axis3d);
376  Py_DECREF(axis3d);
377  if (!axis3dmod) {
378  throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!");
379  }
380  }
381 
382  assert(x.size() == y.size());
383  assert(y.size() == z.size());
384 
385  // using numpy arrays
386  PyObject *xarray = get_2darray(x);
387  PyObject *yarray = get_2darray(y);
388  PyObject *zarray = get_2darray(z);
389 
390  // construct positional args
391  PyObject *args = PyTuple_New(3);
392  PyTuple_SetItem(args, 0, xarray);
393  PyTuple_SetItem(args, 1, yarray);
394  PyTuple_SetItem(args, 2, zarray);
395 
396  // Build up the kw args.
397  PyObject *kwargs = PyDict_New();
398  PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1));
399  PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1));
400 
401  PyObject *python_colormap_coolwarm = PyObject_GetAttrString(detail::_interpreter::get().s_python_colormap, "coolwarm");
402 
403  PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm);
404 
405  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
406  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
407  }
408 
409  PyObject *fig =
410  PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple);
411  if (!fig)
412  throw std::runtime_error("Call to figure() failed.");
413 
414  PyObject *gca_kwargs = PyDict_New();
415  PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
416 
417  PyObject *gca = PyObject_GetAttrString(fig, "gca");
418  if (!gca)
419  throw std::runtime_error("No gca");
420  Py_INCREF(gca);
421  PyObject *axis = PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
422 
423  if (!axis)
424  throw std::runtime_error("No axis");
425  Py_INCREF(axis);
426 
427  Py_DECREF(gca);
428  Py_DECREF(gca_kwargs);
429 
430  PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface");
431  if (!plot_surface)
432  throw std::runtime_error("No surface");
433  Py_INCREF(plot_surface);
434  PyObject *res = PyObject_Call(plot_surface, args, kwargs);
435  if (!res)
436  throw std::runtime_error("failed surface");
437  Py_DECREF(plot_surface);
438 
439  Py_DECREF(axis);
440  Py_DECREF(args);
441  Py_DECREF(kwargs);
442  if (res)
443  Py_DECREF(res);
444 }
445 
446 template <typename Numeric>
447 bool stem(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string> &keywords) {
448  assert(x.size() == y.size());
449 
450  // using numpy arrays
451  PyObject *xarray = get_array(x);
452  PyObject *yarray = get_array(y);
453 
454  // construct positional args
455  PyObject *args = PyTuple_New(2);
456  PyTuple_SetItem(args, 0, xarray);
457  PyTuple_SetItem(args, 1, yarray);
458 
459  // construct keyword args
460  PyObject *kwargs = PyDict_New();
461  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
462  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
463  }
464 
465  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_stem, args, kwargs);
466 
467  Py_DECREF(args);
468  Py_DECREF(kwargs);
469  if (res)
470  Py_DECREF(res);
471 
472  return res;
473 }
474 
475 template <typename Numeric>
476 bool fill(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string> &keywords) {
477  assert(x.size() == y.size());
478 
479  // using numpy arrays
480  PyObject *xarray = get_array(x);
481  PyObject *yarray = get_array(y);
482 
483  // construct positional args
484  PyObject *args = PyTuple_New(2);
485  PyTuple_SetItem(args, 0, xarray);
486  PyTuple_SetItem(args, 1, yarray);
487 
488  // construct keyword args
489  PyObject *kwargs = PyDict_New();
490  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
491  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
492  }
493 
494  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_fill, args, kwargs);
495 
496  Py_DECREF(args);
497  Py_DECREF(kwargs);
498 
499  if (res)
500  Py_DECREF(res);
501 
502  return res;
503 }
504 
505 template <typename Numeric>
506 bool fill_between(const std::vector<Numeric> &x, const std::vector<Numeric> &y1, const std::vector<Numeric> &y2,
507  const std::map<std::string, std::string> &keywords) {
508  assert(x.size() == y1.size());
509  assert(x.size() == y2.size());
510 
511  // using numpy arrays
512  PyObject *xarray = get_array(x);
513  PyObject *y1array = get_array(y1);
514  PyObject *y2array = get_array(y2);
515 
516  // construct positional args
517  PyObject *args = PyTuple_New(3);
518  PyTuple_SetItem(args, 0, xarray);
519  PyTuple_SetItem(args, 1, y1array);
520  PyTuple_SetItem(args, 2, y2array);
521 
522  // construct keyword args
523  PyObject *kwargs = PyDict_New();
524  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
525  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
526  }
527 
528  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs);
529 
530  Py_DECREF(args);
531  Py_DECREF(kwargs);
532  if (res)
533  Py_DECREF(res);
534 
535  return res;
536 }
537 
538 template <typename Numeric>
539 bool hist(const std::vector<Numeric> &y, long bins = 10, std::string color = "b", double alpha = 1.0, bool cumulative = false) {
540 
541  PyObject *yarray = get_array(y);
542 
543  PyObject *kwargs = PyDict_New();
544  PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
545  PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
546  PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
547  PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False);
548 
549  PyObject *plot_args = PyTuple_New(1);
550 
551  PyTuple_SetItem(plot_args, 0, yarray);
552 
553  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
554 
555  Py_DECREF(plot_args);
556  Py_DECREF(kwargs);
557  if (res)
558  Py_DECREF(res);
559 
560  return res;
561 }
562 
563 #ifndef WITHOUT_NUMPY
564 namespace internal {
565 void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors,
566  const std::map<std::string, std::string> &keywords) {
567  assert(type == NPY_UINT8 || type == NPY_FLOAT);
568  assert(colors == 1 || colors == 3 || colors == 4);
569 
570  detail::_interpreter::get(); // interpreter needs to be initialized for the numpy commands to work
571 
572  // construct args
573  npy_intp dims[3] = {rows, columns, colors};
574  PyObject *args = PyTuple_New(1);
575  PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr));
576 
577  // construct keyword args
578  PyObject *kwargs = PyDict_New();
579  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
580  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
581  }
582 
583  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs);
584  Py_DECREF(args);
585  Py_DECREF(kwargs);
586  if (!res)
587  throw std::runtime_error("Call to imshow() failed");
588  Py_DECREF(res);
589 }
590 } // namespace internal
591 
592 void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors,
593  const std::map<std::string, std::string> &keywords = {}) {
594  internal::imshow((void *)ptr, NPY_UINT8, rows, columns, colors, keywords);
595 }
596 
597 void imshow(const float *ptr, const int rows, const int columns, const int colors,
598  const std::map<std::string, std::string> &keywords = {}) {
599  internal::imshow((void *)ptr, NPY_FLOAT, rows, columns, colors, keywords);
600 }
601 
602 #ifdef WITH_OPENCV
603 void imshow(const cv::Mat &image, const std::map<std::string, std::string> &keywords = {}) {
604  // Convert underlying type of matrix, if needed
605  cv::Mat image2;
606  NPY_TYPES npy_type = NPY_UINT8;
607  switch (image.type() & CV_MAT_DEPTH_MASK) {
608  case CV_8U:
609  image2 = image;
610  break;
611  case CV_32F:
612  image2 = image;
613  npy_type = NPY_FLOAT;
614  break;
615  default:
616  image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels()));
617  }
618 
619  // If color image, convert from BGR to RGB
620  switch (image2.channels()) {
621  case 3:
622  cv::cvtColor(image2, image2, CV_BGR2RGB);
623  break;
624  case 4:
625  cv::cvtColor(image2, image2, CV_BGRA2RGBA);
626  }
627 
628  internal::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords);
629 }
630 #endif // WITH_OPENCV
631 #endif // WITHOUT_NUMPY
632 
633 template <typename NumericX, typename NumericY>
634 bool scatter(const std::vector<NumericX> &x, const std::vector<NumericY> &y,
635  const double s = 1.0) // The marker size in points**2
636 {
637  assert(x.size() == y.size());
638 
639  PyObject *xarray = get_array(x);
640  PyObject *yarray = get_array(y);
641 
642  PyObject *kwargs = PyDict_New();
643  PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s));
644 
645  PyObject *plot_args = PyTuple_New(2);
646  PyTuple_SetItem(plot_args, 0, xarray);
647  PyTuple_SetItem(plot_args, 1, yarray);
648 
649  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs);
650 
651  Py_DECREF(plot_args);
652  Py_DECREF(kwargs);
653  if (res)
654  Py_DECREF(res);
655 
656  return res;
657 }
658 
659 template <typename Numeric>
660 bool bar(const std::vector<Numeric> &y, std::string ec = "black", std::string ls = "-", double lw = 1.0,
661  const std::map<std::string, std::string> &keywords = {}) {
662  PyObject *yarray = get_array(y);
663 
664  std::vector<int> x;
665  for (int i = 0; i < y.size(); i++)
666  x.push_back(i);
667 
668  PyObject *xarray = get_array(x);
669 
670  PyObject *kwargs = PyDict_New();
671 
672  PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str()));
673  PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str()));
674  PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw));
675 
676  PyObject *plot_args = PyTuple_New(2);
677  PyTuple_SetItem(plot_args, 0, xarray);
678  PyTuple_SetItem(plot_args, 1, yarray);
679 
680  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_bar, plot_args, kwargs);
681 
682  Py_DECREF(plot_args);
683  Py_DECREF(kwargs);
684  if (res)
685  Py_DECREF(res);
686 
687  return res;
688 }
689 
690 inline bool subplots_adjust(const std::map<std::string, double> &keywords = {}) {
691 
692  PyObject *kwargs = PyDict_New();
693  for (std::map<std::string, double>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
694  PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second));
695  }
696 
697  PyObject *plot_args = PyTuple_New(0);
698 
699  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs);
700 
701  Py_DECREF(plot_args);
702  Py_DECREF(kwargs);
703  if (res)
704  Py_DECREF(res);
705 
706  return res;
707 }
708 
709 template <typename Numeric>
710 bool named_hist(std::string label, const std::vector<Numeric> &y, long bins = 10, std::string color = "b", double alpha = 1.0) {
711  PyObject *yarray = get_array(y);
712 
713  PyObject *kwargs = PyDict_New();
714  PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
715  PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
716  PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
717  PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
718 
719  PyObject *plot_args = PyTuple_New(1);
720  PyTuple_SetItem(plot_args, 0, yarray);
721 
722  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
723 
724  Py_DECREF(plot_args);
725  Py_DECREF(kwargs);
726  if (res)
727  Py_DECREF(res);
728 
729  return res;
730 }
731 
732 template <typename NumericX, typename NumericY>
733 bool plot(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::string &s = "") {
734  assert(x.size() == y.size());
735 
736  PyObject *xarray = get_array(x);
737  PyObject *yarray = get_array(y);
738 
739  PyObject *pystring = PyString_FromString(s.c_str());
740 
741  PyObject *plot_args = PyTuple_New(3);
742  PyTuple_SetItem(plot_args, 0, xarray);
743  PyTuple_SetItem(plot_args, 1, yarray);
744  PyTuple_SetItem(plot_args, 2, pystring);
745 
746  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
747 
748  Py_DECREF(plot_args);
749  if (res)
750  Py_DECREF(res);
751 
752  return res;
753 }
754 
755 template <typename NumericX, typename NumericY, typename NumericU, typename NumericW>
756 bool quiver(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::vector<NumericU> &u, const std::vector<NumericW> &w,
757  const std::map<std::string, std::string> &keywords = {}) {
758  assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size());
759 
760  PyObject *xarray = get_array(x);
761  PyObject *yarray = get_array(y);
762  PyObject *uarray = get_array(u);
763  PyObject *warray = get_array(w);
764 
765  PyObject *plot_args = PyTuple_New(4);
766  PyTuple_SetItem(plot_args, 0, xarray);
767  PyTuple_SetItem(plot_args, 1, yarray);
768  PyTuple_SetItem(plot_args, 2, uarray);
769  PyTuple_SetItem(plot_args, 3, warray);
770 
771  // construct keyword args
772  PyObject *kwargs = PyDict_New();
773  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
774  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
775  }
776 
777  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs);
778 
779  Py_DECREF(kwargs);
780  Py_DECREF(plot_args);
781  if (res)
782  Py_DECREF(res);
783 
784  return res;
785 }
786 
787 template <typename NumericX>
788 bool boxplot(const std::vector<NumericX> &x, const double &position, const double &width, const std::string &color,
789  const std::string &linestyle, const std::map<std::string, std::string> &keywords = {}, bool vert = true) {
790 
791  // Create a sequence of vectors
792  PyObject *plot_args = PyTuple_New(1);
793  PyTuple_SetItem(plot_args, 0, get_array(x));
794 
795  // construct keyword args
796  PyObject *kwargs = PyDict_New();
797  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
798  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
799  }
800 
801  // append position
802  PyObject *positions = PyTuple_New(1);
803  PyTuple_SetItem(positions, 0, PyFloat_FromDouble(position));
804  PyDict_SetItemString(kwargs, "positions", positions);
805 
806  // append width (can be scalar or tuple)
807  PyDict_SetItemString(kwargs, "widths", PyFloat_FromDouble(width));
808 
809  // append color setting to all lines
810  PyObject *cargs1 = PyDict_New();
811  PyDict_SetItemString(cargs1, "color", PyUnicode_FromString(color.c_str()));
812  PyDict_SetItemString(cargs1, "linestyle", PyUnicode_FromString(linestyle.c_str()));
813  PyDict_SetItemString(kwargs, "capprops", cargs1);
814  PyDict_SetItemString(kwargs, "whiskerprops", cargs1);
815  PyDict_SetItemString(kwargs, "medianprops", cargs1);
816  PyDict_SetItemString(kwargs, "boxprops", cargs1);
817 
818  // set if vertical or not
819  if (vert)
820  PyDict_SetItemString(kwargs, "vert", Py_True);
821  else
822  PyDict_SetItemString(kwargs, "vert", Py_False);
823 
824  // finally call the external python function
825  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, plot_args, kwargs);
826 
827  Py_DECREF(kwargs);
828  Py_DECREF(plot_args);
829  if (res)
830  Py_DECREF(res);
831  return res;
832 }
833 
834 template <typename NumericX, typename NumericY>
835 bool stackplot(const std::vector<NumericX> &x, const std::vector<std::vector<NumericY>> &ys, const std::vector<std::string> &labels,
836  const std::vector<std::string> &colors, const std::string &baseline = "zero") {
837 
838  // assert we have enough labels and colors to go around
839  assert(ys.size() == labels.size());
840  assert(ys.size() == colors.size());
841 
842  // Append the datapoints
843  PyObject *plot_args = PyTuple_New(1 + (int)ys.size());
844  PyTuple_SetItem(plot_args, 0, get_array(x));
845  for (size_t i = 0; i < ys.size(); i++) {
846  assert(x.size() == ys.at(i).size());
847  PyTuple_SetItem(plot_args, 1 + (int)i, get_array(ys.at(i)));
848  }
849 
850  // Labels
851  PyObject *list_labels = PyList_New(labels.size());
852  for (size_t i = 0; i < labels.size(); i++) {
853  PyList_SetItem(list_labels, i, PyString_FromString(labels.at(i).c_str()));
854  }
855 
856  // Colors
857  PyObject *list_colors = PyList_New(colors.size());
858  for (size_t i = 0; i < colors.size(); i++) {
859  PyList_SetItem(list_colors, i, PyString_FromString(colors.at(i).c_str()));
860  }
861 
862  // append the baseline [‘zero’, ‘sym’, ‘wiggle’, ‘weighted_wiggle’]
863  PyObject *kwargs = PyDict_New();
864  PyDict_SetItemString(kwargs, "baseline", PyUnicode_FromString(baseline.c_str()));
865  PyDict_SetItemString(kwargs, "labels", list_labels);
866  PyDict_SetItemString(kwargs, "colors", list_colors);
867  PyDict_SetItemString(kwargs, "edgecolors", PyUnicode_FromString("none"));
868 
869  // finally call the external python function
870  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_stackplot, plot_args, kwargs);
871 
872  Py_DECREF(kwargs);
873  Py_DECREF(plot_args);
874  if (res)
875  Py_DECREF(res);
876  return res;
877 }
878 
879 template <typename NumericX, typename NumericY>
880 bool stem(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::string &s = "") {
881  assert(x.size() == y.size());
882 
883  PyObject *xarray = get_array(x);
884  PyObject *yarray = get_array(y);
885 
886  PyObject *pystring = PyString_FromString(s.c_str());
887 
888  PyObject *plot_args = PyTuple_New(3);
889  PyTuple_SetItem(plot_args, 0, xarray);
890  PyTuple_SetItem(plot_args, 1, yarray);
891  PyTuple_SetItem(plot_args, 2, pystring);
892 
893  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_stem, plot_args);
894 
895  Py_DECREF(plot_args);
896  if (res)
897  Py_DECREF(res);
898 
899  return res;
900 }
901 
902 template <typename NumericX, typename NumericY>
903 bool semilogx(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::string &s = "") {
904  assert(x.size() == y.size());
905 
906  PyObject *xarray = get_array(x);
907  PyObject *yarray = get_array(y);
908 
909  PyObject *pystring = PyString_FromString(s.c_str());
910 
911  PyObject *plot_args = PyTuple_New(3);
912  PyTuple_SetItem(plot_args, 0, xarray);
913  PyTuple_SetItem(plot_args, 1, yarray);
914  PyTuple_SetItem(plot_args, 2, pystring);
915 
916  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args);
917 
918  Py_DECREF(plot_args);
919  if (res)
920  Py_DECREF(res);
921 
922  return res;
923 }
924 
925 template <typename NumericX, typename NumericY>
926 bool semilogy(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::string &s = "") {
927  assert(x.size() == y.size());
928 
929  PyObject *xarray = get_array(x);
930  PyObject *yarray = get_array(y);
931 
932  PyObject *pystring = PyString_FromString(s.c_str());
933 
934  PyObject *plot_args = PyTuple_New(3);
935  PyTuple_SetItem(plot_args, 0, xarray);
936  PyTuple_SetItem(plot_args, 1, yarray);
937  PyTuple_SetItem(plot_args, 2, pystring);
938 
939  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args);
940 
941  Py_DECREF(plot_args);
942  if (res)
943  Py_DECREF(res);
944 
945  return res;
946 }
947 
948 template <typename NumericX, typename NumericY>
949 bool loglog(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::string &s = "") {
950  assert(x.size() == y.size());
951 
952  PyObject *xarray = get_array(x);
953  PyObject *yarray = get_array(y);
954 
955  PyObject *pystring = PyString_FromString(s.c_str());
956 
957  PyObject *plot_args = PyTuple_New(3);
958  PyTuple_SetItem(plot_args, 0, xarray);
959  PyTuple_SetItem(plot_args, 1, yarray);
960  PyTuple_SetItem(plot_args, 2, pystring);
961 
962  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args);
963 
964  Py_DECREF(plot_args);
965  if (res)
966  Py_DECREF(res);
967 
968  return res;
969 }
970 
971 template <typename NumericX, typename NumericY>
972 bool errorbar(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::vector<NumericX> &yerr,
973  const std::map<std::string, std::string> &keywords = {}) {
974  assert(x.size() == y.size());
975 
976  PyObject *xarray = get_array(x);
977  PyObject *yarray = get_array(y);
978  PyObject *yerrarray = get_array(yerr);
979 
980  // construct keyword args
981  PyObject *kwargs = PyDict_New();
982  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
983  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
984  }
985 
986  PyDict_SetItemString(kwargs, "yerr", yerrarray);
987 
988  PyObject *plot_args = PyTuple_New(2);
989  PyTuple_SetItem(plot_args, 0, xarray);
990  PyTuple_SetItem(plot_args, 1, yarray);
991 
992  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs);
993 
994  Py_DECREF(kwargs);
995  Py_DECREF(plot_args);
996 
997  if (res)
998  Py_DECREF(res);
999  else
1000  throw std::runtime_error("Call to errorbar() failed.");
1001 
1002  return res;
1003 }
1004 
1005 template <typename Numeric> bool named_plot(const std::string &name, const std::vector<Numeric> &y, const std::string &format = "") {
1006  PyObject *kwargs = PyDict_New();
1007  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1008 
1009  PyObject *yarray = get_array(y);
1010 
1011  PyObject *pystring = PyString_FromString(format.c_str());
1012 
1013  PyObject *plot_args = PyTuple_New(2);
1014 
1015  PyTuple_SetItem(plot_args, 0, yarray);
1016  PyTuple_SetItem(plot_args, 1, pystring);
1017 
1018  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
1019 
1020  Py_DECREF(kwargs);
1021  Py_DECREF(plot_args);
1022  if (res)
1023  Py_DECREF(res);
1024 
1025  return res;
1026 }
1027 
1028 template <typename Numeric>
1029 bool named_plot(const std::string &name, const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::string &format = "") {
1030  PyObject *kwargs = PyDict_New();
1031  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1032 
1033  PyObject *xarray = get_array(x);
1034  PyObject *yarray = get_array(y);
1035 
1036  PyObject *pystring = PyString_FromString(format.c_str());
1037 
1038  PyObject *plot_args = PyTuple_New(3);
1039  PyTuple_SetItem(plot_args, 0, xarray);
1040  PyTuple_SetItem(plot_args, 1, yarray);
1041  PyTuple_SetItem(plot_args, 2, pystring);
1042 
1043  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
1044 
1045  Py_DECREF(kwargs);
1046  Py_DECREF(plot_args);
1047  if (res)
1048  Py_DECREF(res);
1049 
1050  return res;
1051 }
1052 
1053 template <typename Numeric>
1054 bool named_semilogx(const std::string &name, const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::string &format = "") {
1055  PyObject *kwargs = PyDict_New();
1056  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1057 
1058  PyObject *xarray = get_array(x);
1059  PyObject *yarray = get_array(y);
1060 
1061  PyObject *pystring = PyString_FromString(format.c_str());
1062 
1063  PyObject *plot_args = PyTuple_New(3);
1064  PyTuple_SetItem(plot_args, 0, xarray);
1065  PyTuple_SetItem(plot_args, 1, yarray);
1066  PyTuple_SetItem(plot_args, 2, pystring);
1067 
1068  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs);
1069 
1070  Py_DECREF(kwargs);
1071  Py_DECREF(plot_args);
1072  if (res)
1073  Py_DECREF(res);
1074 
1075  return res;
1076 }
1077 
1078 template <typename Numeric>
1079 bool named_semilogy(const std::string &name, const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::string &format = "") {
1080  PyObject *kwargs = PyDict_New();
1081  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1082 
1083  PyObject *xarray = get_array(x);
1084  PyObject *yarray = get_array(y);
1085 
1086  PyObject *pystring = PyString_FromString(format.c_str());
1087 
1088  PyObject *plot_args = PyTuple_New(3);
1089  PyTuple_SetItem(plot_args, 0, xarray);
1090  PyTuple_SetItem(plot_args, 1, yarray);
1091  PyTuple_SetItem(plot_args, 2, pystring);
1092 
1093  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs);
1094 
1095  Py_DECREF(kwargs);
1096  Py_DECREF(plot_args);
1097  if (res)
1098  Py_DECREF(res);
1099 
1100  return res;
1101 }
1102 
1103 template <typename Numeric>
1104 bool named_loglog(const std::string &name, const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::string &format = "") {
1105  PyObject *kwargs = PyDict_New();
1106  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1107 
1108  PyObject *xarray = get_array(x);
1109  PyObject *yarray = get_array(y);
1110 
1111  PyObject *pystring = PyString_FromString(format.c_str());
1112 
1113  PyObject *plot_args = PyTuple_New(3);
1114  PyTuple_SetItem(plot_args, 0, xarray);
1115  PyTuple_SetItem(plot_args, 1, yarray);
1116  PyTuple_SetItem(plot_args, 2, pystring);
1117 
1118  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs);
1119 
1120  Py_DECREF(kwargs);
1121  Py_DECREF(plot_args);
1122  if (res)
1123  Py_DECREF(res);
1124 
1125  return res;
1126 }
1127 
1128 template <typename Numeric> bool plot(const std::vector<Numeric> &y, const std::string &format = "") {
1129  std::vector<Numeric> x(y.size());
1130  for (size_t i = 0; i < x.size(); ++i)
1131  x.at(i) = i;
1132  return plot(x, y, format);
1133 }
1134 
1135 template <typename Numeric> bool plot(const std::vector<Numeric> &y, const std::map<std::string, std::string> &keywords) {
1136  std::vector<Numeric> x(y.size());
1137  for (size_t i = 0; i < x.size(); ++i)
1138  x.at(i) = i;
1139  return plot(x, y, keywords);
1140 }
1141 
1142 template <typename Numeric> bool stem(const std::vector<Numeric> &y, const std::string &format = "") {
1143  std::vector<Numeric> x(y.size());
1144  for (size_t i = 0; i < x.size(); ++i)
1145  x.at(i) = i;
1146  return stem(x, y, format);
1147 }
1148 
1149 template <typename Numeric> void text(Numeric x, Numeric y, const std::string &s = "") {
1150  PyObject *args = PyTuple_New(3);
1151  PyTuple_SetItem(args, 0, PyFloat_FromDouble(x));
1152  PyTuple_SetItem(args, 1, PyFloat_FromDouble(y));
1153  PyTuple_SetItem(args, 2, PyString_FromString(s.c_str()));
1154 
1155  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args);
1156  if (!res)
1157  throw std::runtime_error("Call to text() failed.");
1158 
1159  Py_DECREF(args);
1160  Py_DECREF(res);
1161 }
1162 
1163 inline long figure(long number = -1) {
1164  PyObject *res;
1165  if (number == -1)
1166  res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple);
1167  else {
1168  assert(number > 0);
1169 
1170  // Make sure interpreter is initialised
1172 
1173  PyObject *args = PyTuple_New(1);
1174  PyTuple_SetItem(args, 0, PyLong_FromLong(number));
1175  res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args);
1176  Py_DECREF(args);
1177  }
1178 
1179  if (!res)
1180  throw std::runtime_error("Call to figure() failed.");
1181 
1182  PyObject *num = PyObject_GetAttrString(res, "number");
1183  if (!num)
1184  throw std::runtime_error("Could not get number attribute of figure object");
1185  const long figureNumber = PyLong_AsLong(num);
1186 
1187  Py_DECREF(num);
1188  Py_DECREF(res);
1189 
1190  return figureNumber;
1191 }
1192 
1193 inline bool fignum_exists(long number) {
1194  // Make sure interpreter is initialised
1196 
1197  PyObject *args = PyTuple_New(1);
1198  PyTuple_SetItem(args, 0, PyLong_FromLong(number));
1199  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, args);
1200  if (!res)
1201  throw std::runtime_error("Call to fignum_exists() failed.");
1202 
1203  bool ret = PyObject_IsTrue(res);
1204  Py_DECREF(res);
1205  Py_DECREF(args);
1206 
1207  return ret;
1208 }
1209 
1210 inline void figure_size(size_t w, size_t h) {
1211  // Make sure interpreter is initialised
1213 
1214  const size_t dpi = 100;
1215  PyObject *size = PyTuple_New(2);
1216  PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi));
1217  PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi));
1218 
1219  PyObject *kwargs = PyDict_New();
1220  PyDict_SetItemString(kwargs, "figsize", size);
1221  PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi));
1222 
1223  PyObject *res =
1224  PyObject_Call(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple, kwargs);
1225 
1226  Py_DECREF(kwargs);
1227 
1228  if (!res)
1229  throw std::runtime_error("Call to figure_size() failed.");
1230  Py_DECREF(res);
1231 }
1232 
1233 inline void legend() {
1234  PyObject *res =
1235  PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
1236  if (!res)
1237  throw std::runtime_error("Call to legend() failed.");
1238 
1239  Py_DECREF(res);
1240 }
1241 
1242 template <typename Numeric> void ylim(Numeric left, Numeric right) {
1243  PyObject *list = PyList_New(2);
1244  PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1245  PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1246 
1247  PyObject *args = PyTuple_New(1);
1248  PyTuple_SetItem(args, 0, list);
1249 
1250  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
1251  if (!res)
1252  throw std::runtime_error("Call to ylim() failed.");
1253 
1254  Py_DECREF(args);
1255  Py_DECREF(res);
1256 }
1257 
1258 template <typename Numeric> void xlim(Numeric left, Numeric right) {
1259  PyObject *list = PyList_New(2);
1260  PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1261  PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1262 
1263  PyObject *args = PyTuple_New(1);
1264  PyTuple_SetItem(args, 0, list);
1265 
1266  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
1267  if (!res)
1268  throw std::runtime_error("Call to xlim() failed.");
1269 
1270  Py_DECREF(args);
1271  Py_DECREF(res);
1272 }
1273 
1274 inline double *xlim() {
1275  PyObject *args = PyTuple_New(0);
1276  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
1277  PyObject *left = PyTuple_GetItem(res, 0);
1278  PyObject *right = PyTuple_GetItem(res, 1);
1279 
1280  double *arr = new double[2];
1281  arr[0] = PyFloat_AsDouble(left);
1282  arr[1] = PyFloat_AsDouble(right);
1283 
1284  if (!res)
1285  throw std::runtime_error("Call to xlim() failed.");
1286 
1287  Py_DECREF(res);
1288  return arr;
1289 }
1290 
1291 inline double *ylim() {
1292  PyObject *args = PyTuple_New(0);
1293  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
1294  PyObject *left = PyTuple_GetItem(res, 0);
1295  PyObject *right = PyTuple_GetItem(res, 1);
1296 
1297  double *arr = new double[2];
1298  arr[0] = PyFloat_AsDouble(left);
1299  arr[1] = PyFloat_AsDouble(right);
1300 
1301  if (!res)
1302  throw std::runtime_error("Call to ylim() failed.");
1303 
1304  Py_DECREF(res);
1305  return arr;
1306 }
1307 
1308 template <typename Numeric>
1309 inline void xticks(const std::vector<Numeric> &ticks, const std::vector<std::string> &labels = {},
1310  const std::map<std::string, std::string> &keywords = {}) {
1311  assert(labels.size() == 0 || ticks.size() == labels.size());
1312 
1313  // using numpy array
1314  PyObject *ticksarray = get_array(ticks);
1315 
1316  PyObject *args;
1317  if (labels.size() == 0) {
1318  // construct positional args
1319  args = PyTuple_New(1);
1320  PyTuple_SetItem(args, 0, ticksarray);
1321  } else {
1322  // make tuple of tick labels
1323  PyObject *labelstuple = PyTuple_New(labels.size());
1324  for (size_t i = 0; i < labels.size(); i++)
1325  PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str()));
1326 
1327  // construct positional args
1328  args = PyTuple_New(2);
1329  PyTuple_SetItem(args, 0, ticksarray);
1330  PyTuple_SetItem(args, 1, labelstuple);
1331  }
1332 
1333  // construct keyword args
1334  PyObject *kwargs = PyDict_New();
1335  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
1336  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1337  }
1338 
1339  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs);
1340 
1341  Py_DECREF(args);
1342  Py_DECREF(kwargs);
1343  if (!res)
1344  throw std::runtime_error("Call to xticks() failed");
1345 
1346  Py_DECREF(res);
1347 }
1348 
1349 template <typename Numeric> inline void xticks(const std::vector<Numeric> &ticks, const std::map<std::string, std::string> &keywords) {
1350  xticks(ticks, {}, keywords);
1351 }
1352 
1353 template <typename Numeric>
1354 inline void yticks(const std::vector<Numeric> &ticks, const std::vector<std::string> &labels = {},
1355  const std::map<std::string, std::string> &keywords = {}) {
1356  assert(labels.size() == 0 || ticks.size() == labels.size());
1357 
1358  // using numpy array
1359  PyObject *ticksarray = get_array(ticks);
1360 
1361  PyObject *args;
1362  if (labels.size() == 0) {
1363  // construct positional args
1364  args = PyTuple_New(1);
1365  PyTuple_SetItem(args, 0, ticksarray);
1366  } else {
1367  // make tuple of tick labels
1368  PyObject *labelstuple = PyTuple_New(labels.size());
1369  for (size_t i = 0; i < labels.size(); i++)
1370  PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str()));
1371 
1372  // construct positional args
1373  args = PyTuple_New(2);
1374  PyTuple_SetItem(args, 0, ticksarray);
1375  PyTuple_SetItem(args, 1, labelstuple);
1376  }
1377 
1378  // construct keyword args
1379  PyObject *kwargs = PyDict_New();
1380  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
1381  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1382  }
1383 
1384  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs);
1385 
1386  Py_DECREF(args);
1387  Py_DECREF(kwargs);
1388  if (!res)
1389  throw std::runtime_error("Call to yticks() failed");
1390 
1391  Py_DECREF(res);
1392 }
1393 
1394 template <typename Numeric> inline void yticks(const std::vector<Numeric> &ticks, const std::map<std::string, std::string> &keywords) {
1395  yticks(ticks, {}, keywords);
1396 }
1397 
1398 inline void subplot(long nrows, long ncols, long plot_number) {
1399  // construct positional args
1400  PyObject *args = PyTuple_New(3);
1401  PyTuple_SetItem(args, 0, PyLong_FromLong(nrows));
1402  PyTuple_SetItem(args, 1, PyLong_FromLong(ncols));
1403  PyTuple_SetItem(args, 2, PyLong_FromLong(plot_number));
1404 
1405  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
1406  if (!res)
1407  throw std::runtime_error("Call to subplot() failed.");
1408 
1409  Py_DECREF(args);
1410  Py_DECREF(res);
1411 }
1412 
1413 inline void title(const std::string &titlestr, const std::map<std::string, std::string> &keywords = {}) {
1414  PyObject *pytitlestr = PyString_FromString(titlestr.c_str());
1415  PyObject *args = PyTuple_New(1);
1416  PyTuple_SetItem(args, 0, pytitlestr);
1417 
1418  PyObject *kwargs = PyDict_New();
1419  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1420  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1421  }
1422 
1423  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs);
1424  if (!res)
1425  throw std::runtime_error("Call to title() failed.");
1426 
1427  Py_DECREF(args);
1428  Py_DECREF(kwargs);
1429  Py_DECREF(res);
1430 }
1431 
1432 inline void suptitle(const std::string &suptitlestr, const std::map<std::string, std::string> &keywords = {}) {
1433  PyObject *pysuptitlestr = PyString_FromString(suptitlestr.c_str());
1434  PyObject *args = PyTuple_New(1);
1435  PyTuple_SetItem(args, 0, pysuptitlestr);
1436 
1437  PyObject *kwargs = PyDict_New();
1438  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1439  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1440  }
1441 
1442  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs);
1443  if (!res)
1444  throw std::runtime_error("Call to suptitle() failed.");
1445 
1446  Py_DECREF(args);
1447  Py_DECREF(kwargs);
1448  Py_DECREF(res);
1449 }
1450 
1451 inline void axis(const std::string &axisstr) {
1452  PyObject *str = PyString_FromString(axisstr.c_str());
1453  PyObject *args = PyTuple_New(1);
1454  PyTuple_SetItem(args, 0, str);
1455 
1456  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args);
1457  if (!res)
1458  throw std::runtime_error("Call to title() failed.");
1459 
1460  Py_DECREF(args);
1461  Py_DECREF(res);
1462 }
1463 
1464 inline void xlabel(const std::string &str, const std::map<std::string, std::string> &keywords = {}) {
1465  PyObject *pystr = PyString_FromString(str.c_str());
1466  PyObject *args = PyTuple_New(1);
1467  PyTuple_SetItem(args, 0, pystr);
1468 
1469  PyObject *kwargs = PyDict_New();
1470  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1471  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1472  }
1473 
1474  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs);
1475  if (!res)
1476  throw std::runtime_error("Call to xlabel() failed.");
1477 
1478  Py_DECREF(args);
1479  Py_DECREF(kwargs);
1480  Py_DECREF(res);
1481 }
1482 
1483 inline void ylabel(const std::string &str, const std::map<std::string, std::string> &keywords = {}) {
1484  PyObject *pystr = PyString_FromString(str.c_str());
1485  PyObject *args = PyTuple_New(1);
1486  PyTuple_SetItem(args, 0, pystr);
1487 
1488  PyObject *kwargs = PyDict_New();
1489  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1490  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1491  }
1492 
1493  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs);
1494  if (!res)
1495  throw std::runtime_error("Call to ylabel() failed.");
1496 
1497  Py_DECREF(args);
1498  Py_DECREF(kwargs);
1499  Py_DECREF(res);
1500 }
1501 
1502 inline void grid(bool flag) {
1503  PyObject *pyflag = flag ? Py_True : Py_False;
1504  Py_INCREF(pyflag);
1505 
1506  PyObject *args = PyTuple_New(1);
1507  PyTuple_SetItem(args, 0, pyflag);
1508 
1509  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
1510  if (!res)
1511  throw std::runtime_error("Call to grid() failed.");
1512 
1513  Py_DECREF(args);
1514  Py_DECREF(res);
1515 }
1516 
1517 inline void show(const bool block = true) {
1518  PyObject *res;
1519  if (block) {
1520  res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple);
1521  } else {
1522  PyObject *kwargs = PyDict_New();
1523  PyDict_SetItemString(kwargs, "block", Py_False);
1524  res = PyObject_Call(detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs);
1525  Py_DECREF(kwargs);
1526  }
1527 
1528  if (!res)
1529  throw std::runtime_error("Call to show() failed.");
1530 
1531  Py_DECREF(res);
1532 }
1533 
1534 inline void close() {
1535  PyObject *res =
1536  PyObject_CallObject(detail::_interpreter::get().s_python_function_close, detail::_interpreter::get().s_python_empty_tuple);
1537 
1538  if (!res)
1539  throw std::runtime_error("Call to close() failed.");
1540 
1541  Py_DECREF(res);
1542 }
1543 
1544 inline void xkcd() {
1545  PyObject *res;
1546  PyObject *kwargs = PyDict_New();
1547 
1548  res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, detail::_interpreter::get().s_python_empty_tuple, kwargs);
1549 
1550  Py_DECREF(kwargs);
1551 
1552  if (!res)
1553  throw std::runtime_error("Call to show() failed.");
1554 
1555  Py_DECREF(res);
1556 }
1557 
1558 inline void draw() {
1559  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_draw, detail::_interpreter::get().s_python_empty_tuple);
1560 
1561  if (!res)
1562  throw std::runtime_error("Call to draw() failed.");
1563 
1564  Py_DECREF(res);
1565 }
1566 
1567 template <typename Numeric> inline void pause(Numeric interval) {
1568  PyObject *args = PyTuple_New(1);
1569  PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval));
1570 
1571  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args);
1572  if (!res)
1573  throw std::runtime_error("Call to pause() failed.");
1574 
1575  Py_DECREF(args);
1576  Py_DECREF(res);
1577 }
1578 
1579 inline void save(const std::string &filename) {
1580  PyObject *pyfilename = PyString_FromString(filename.c_str());
1581 
1582  PyObject *args = PyTuple_New(1);
1583  PyTuple_SetItem(args, 0, pyfilename);
1584 
1585  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args);
1586  if (!res)
1587  throw std::runtime_error("Call to save() failed.");
1588 
1589  Py_DECREF(args);
1590  Py_DECREF(res);
1591 }
1592 
1593 inline void clf() {
1594  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_clf, detail::_interpreter::get().s_python_empty_tuple);
1595 
1596  if (!res)
1597  throw std::runtime_error("Call to clf() failed.");
1598 
1599  Py_DECREF(res);
1600 }
1601 
1602 inline void ion() {
1603  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ion, detail::_interpreter::get().s_python_empty_tuple);
1604 
1605  if (!res)
1606  throw std::runtime_error("Call to ion() failed.");
1607 
1608  Py_DECREF(res);
1609 }
1610 
1611 inline std::vector<std::array<double, 2>> ginput(const int numClicks = 1, const std::map<std::string, std::string> &keywords = {}) {
1612  PyObject *args = PyTuple_New(1);
1613  PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks));
1614 
1615  // construct keyword args
1616  PyObject *kwargs = PyDict_New();
1617  for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
1618  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1619  }
1620 
1621  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_ginput, args, kwargs);
1622 
1623  Py_DECREF(kwargs);
1624  Py_DECREF(args);
1625  if (!res)
1626  throw std::runtime_error("Call to ginput() failed.");
1627 
1628  const size_t len = PyList_Size(res);
1629  std::vector<std::array<double, 2>> out;
1630  out.reserve(len);
1631  for (size_t i = 0; i < len; i++) {
1632  PyObject *current = PyList_GetItem(res, i);
1633  std::array<double, 2> position;
1634  position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0));
1635  position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1));
1636  out.push_back(position);
1637  }
1638  Py_DECREF(res);
1639 
1640  return out;
1641 }
1642 
1643 // Actually, is there any reason not to call this automatically for every plot?
1644 inline void tight_layout() {
1645  PyObject *res =
1646  PyObject_CallObject(detail::_interpreter::get().s_python_function_tight_layout, detail::_interpreter::get().s_python_empty_tuple);
1647 
1648  if (!res)
1649  throw std::runtime_error("Call to tight_layout() failed.");
1650 
1651  Py_DECREF(res);
1652 }
1653 
1654 // Support for variadic plot() and initializer lists:
1655 
1656 namespace detail {
1657 
1658 template <typename T> using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
1659 
1660 template <bool obj, typename T> struct is_callable_impl;
1661 
1662 template <typename T> struct is_callable_impl<false, T> { typedef is_function<T> type; }; // a non-object is callable iff it is a function
1663 
1664 template <typename T> struct is_callable_impl<true, T> {
1665  struct Fallback {
1666  void operator()();
1667  };
1668  struct Derived : T, Fallback {};
1669 
1670  template <typename U, U> struct Check;
1671 
1672  template <typename U>
1673  static std::true_type test(...); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
1674 
1675  template <typename U> static std::false_type test(Check<void (Fallback::*)(), &U::operator()> *);
1676 
1677 public:
1678  typedef decltype(test<Derived>(nullptr)) type;
1679  typedef decltype(&Fallback::operator()) dtype;
1680  static constexpr bool value = type::value;
1681 }; // an object is callable iff it defines operator()
1682 
1683 template <typename T> struct is_callable {
1684  // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
1686 };
1687 
1688 template <typename IsYDataCallable> struct plot_impl {};
1689 
1690 template <> struct plot_impl<std::false_type> {
1691  template <typename IterableX, typename IterableY> bool operator()(const IterableX &x, const IterableY &y, const std::string &format) {
1692  // 2-phase lookup for distance, begin, end
1693  using std::begin;
1694  using std::distance;
1695  using std::end;
1696 
1697  auto xs = distance(begin(x), end(x));
1698  auto ys = distance(begin(y), end(y));
1699  assert(xs == ys && "x and y data must have the same number of elements!");
1700 
1701  PyObject *xlist = PyList_New(xs);
1702  PyObject *ylist = PyList_New(ys);
1703  PyObject *pystring = PyString_FromString(format.c_str());
1704 
1705  auto itx = begin(x), ity = begin(y);
1706  for (size_t i = 0; i < xs; ++i) {
1707  PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
1708  PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
1709  }
1710 
1711  PyObject *plot_args = PyTuple_New(3);
1712  PyTuple_SetItem(plot_args, 0, xlist);
1713  PyTuple_SetItem(plot_args, 1, ylist);
1714  PyTuple_SetItem(plot_args, 2, pystring);
1715 
1716  PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
1717 
1718  Py_DECREF(plot_args);
1719  if (res)
1720  Py_DECREF(res);
1721 
1722  return res;
1723  }
1724 };
1725 
1726 template <> struct plot_impl<std::true_type> {
1727  template <typename Iterable, typename Callable> bool operator()(const Iterable &ticks, const Callable &f, const std::string &format) {
1728  if (begin(ticks) == end(ticks))
1729  return true;
1730 
1731  // We could use additional meta-programming to deduce the correct element type of y,
1732  // but all values have to be convertible to double anyways
1733  std::vector<double> y;
1734  for (auto x : ticks)
1735  y.push_back(f(x));
1736  return plot_impl<std::false_type>()(ticks, y, format);
1737  }
1738 };
1739 
1740 } // end namespace detail
1741 
1742 // recursion stop for the above
1743 template <typename... Args> bool plot() { return true; }
1744 
1745 template <typename A, typename B, typename... Args> bool plot(const A &a, const B &b, const std::string &format, Args... args) {
1746  return detail::plot_impl<typename detail::is_callable<B>::type>()(a, b, format) && plot(args...);
1747 }
1748 
1749 /*
1750  * This group of plot() functions is needed to support initializer lists, i.e. calling
1751  * plot( {1,2,3,4} )
1752  */
1753 inline bool plot(const std::vector<double> &x, const std::vector<double> &y, const std::string &format = "") {
1754  return plot<double, double>(x, y, format);
1755 }
1756 
1757 inline bool plot(const std::vector<double> &y, const std::string &format = "") { return plot<double>(y, format); }
1758 
1759 inline bool plot(const std::vector<double> &x, const std::vector<double> &y, const std::map<std::string, std::string> &keywords) {
1760  return plot<double>(x, y, keywords);
1761 }
1762 
1763 /*
1764  * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting
1765  */
1766 
1767 class Plot {
1768 public:
1769  // default initialization with plot label, some data and format
1770  template <typename Numeric>
1771  Plot(const std::string &name, const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::string &format = "") {
1772 
1773  assert(x.size() == y.size());
1774 
1775  PyObject *kwargs = PyDict_New();
1776  if (name != "")
1777  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1778 
1779  PyObject *xarray = get_array(x);
1780  PyObject *yarray = get_array(y);
1781 
1782  PyObject *pystring = PyString_FromString(format.c_str());
1783 
1784  PyObject *plot_args = PyTuple_New(3);
1785  PyTuple_SetItem(plot_args, 0, xarray);
1786  PyTuple_SetItem(plot_args, 1, yarray);
1787  PyTuple_SetItem(plot_args, 2, pystring);
1788 
1789  PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
1790 
1791  Py_DECREF(kwargs);
1792  Py_DECREF(plot_args);
1793 
1794  if (res) {
1795  line = PyList_GetItem(res, 0);
1796 
1797  if (line)
1798  set_data_fct = PyObject_GetAttrString(line, "set_data");
1799  else
1800  Py_DECREF(line);
1801  Py_DECREF(res);
1802  }
1803  }
1804 
1805  // shorter initialization with name or format only
1806  // basically calls line, = plot([], [])
1807  Plot(const std::string &name = "", const std::string &format = "") : Plot(name, std::vector<double>(), std::vector<double>(), format) {}
1808 
1809  template <typename Numeric> bool update(const std::vector<Numeric> &x, const std::vector<Numeric> &y) {
1810  assert(x.size() == y.size());
1811  if (set_data_fct) {
1812  PyObject *xarray = get_array(x);
1813  PyObject *yarray = get_array(y);
1814 
1815  PyObject *plot_args = PyTuple_New(2);
1816  PyTuple_SetItem(plot_args, 0, xarray);
1817  PyTuple_SetItem(plot_args, 1, yarray);
1818 
1819  PyObject *res = PyObject_CallObject(set_data_fct, plot_args);
1820  if (res)
1821  Py_DECREF(res);
1822  return res;
1823  }
1824  return false;
1825  }
1826 
1827  // clears the plot but keep it available
1828  bool clear() { return update(std::vector<double>(), std::vector<double>()); }
1829 
1830  // definitely remove this line
1831  void remove() {
1832  if (line) {
1833  auto remove_fct = PyObject_GetAttrString(line, "remove");
1834  PyObject *args = PyTuple_New(0);
1835  PyObject *res = PyObject_CallObject(remove_fct, args);
1836  if (res)
1837  Py_DECREF(res);
1838  }
1839  decref();
1840  }
1841 
1842  ~Plot() { decref(); }
1843 
1844 private:
1845  void decref() {
1846  if (line)
1847  Py_DECREF(line);
1848  if (set_data_fct)
1849  Py_DECREF(set_data_fct);
1850  }
1851 
1852  PyObject *line = nullptr;
1853  PyObject *set_data_fct = nullptr;
1854 };
1855 
1856 } // end namespace matplotlibcpp
matplotlibcpp::scatter
bool scatter(const std::vector< NumericX > &x, const std::vector< NumericY > &y, const double s=1.0)
Definition: matplotlibcpp.h:634
matplotlibcpp::Plot::clear
bool clear()
Definition: matplotlibcpp.h:1828
matplotlibcpp::detail::plot_impl
Definition: matplotlibcpp.h:1688
matplotlibcpp::Plot::update
bool update(const std::vector< Numeric > &x, const std::vector< Numeric > &y)
Definition: matplotlibcpp.h:1809
matplotlibcpp::Plot
Definition: matplotlibcpp.h:1767
matplotlibcpp::detail::_interpreter::s_python_function_ylim
PyObject * s_python_function_ylim
Definition: matplotlibcpp.h:62
matplotlibcpp::draw
void draw()
Definition: matplotlibcpp.h:1558
matplotlibcpp::detail::is_callable_impl
Definition: matplotlibcpp.h:1660
matplotlibcpp::detail::_interpreter::s_python_function_xlabel
PyObject * s_python_function_xlabel
Definition: matplotlibcpp.h:65
matplotlibcpp::detail::_interpreter::s_python_function_subplot
PyObject * s_python_function_subplot
Definition: matplotlibcpp.h:57
matplotlibcpp::detail::_interpreter::s_python_function_clf
PyObject * s_python_function_clf
Definition: matplotlibcpp.h:70
matplotlibcpp::hist
bool hist(const std::vector< Numeric > &y, long bins=10, std::string color="b", double alpha=1.0, bool cumulative=false)
Definition: matplotlibcpp.h:539
matplotlibcpp::plot_surface
void plot_surface(const std::vector<::std::vector< Numeric >> &x, const std::vector<::std::vector< Numeric >> &y, const std::vector<::std::vector< Numeric >> &z, const std::map< std::string, std::string > &keywords=std::map< std::string, std::string >())
Definition: matplotlibcpp.h:352
matplotlibcpp::plot
bool plot(const std::vector< Numeric > &x, const std::vector< Numeric > &y, const std::map< std::string, std::string > &keywords)
Definition: matplotlibcpp.h:323
matplotlibcpp::quiver
bool quiver(const std::vector< NumericX > &x, const std::vector< NumericY > &y, const std::vector< NumericU > &u, const std::vector< NumericW > &w, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:756
matplotlibcpp::semilogx
bool semilogx(const std::vector< NumericX > &x, const std::vector< NumericY > &y, const std::string &s="")
Definition: matplotlibcpp.h:903
matplotlibcpp::detail::_interpreter::s_python_function_show
PyObject * s_python_function_show
Definition: matplotlibcpp.h:38
matplotlibcpp::backend
void backend(const std::string &name)
Definition: matplotlibcpp.h:232
PyUnicode_FromString
#define PyUnicode_FromString
matplotlibcpp::detail::_interpreter::s_python_function_tight_layout
PyObject * s_python_function_tight_layout
Definition: matplotlibcpp.h:73
matplotlibcpp::detail::_interpreter::~_interpreter
~_interpreter()
Definition: matplotlibcpp.h:226
matplotlibcpp::detail::_interpreter::s_python_function_boxplot
PyObject * s_python_function_boxplot
Definition: matplotlibcpp.h:47
matplotlibcpp::detail::is_callable
Definition: matplotlibcpp.h:1683
matplotlibcpp::stem
bool stem(const std::vector< Numeric > &x, const std::vector< Numeric > &y, const std::map< std::string, std::string > &keywords)
Definition: matplotlibcpp.h:447
s
XmlRpcServer s
matplotlibcpp::detail::_interpreter::s_python_function_fignum_exists
PyObject * s_python_function_fignum_exists
Definition: matplotlibcpp.h:44
matplotlibcpp::named_plot
bool named_plot(const std::string &name, const std::vector< Numeric > &y, const std::string &format="")
Definition: matplotlibcpp.h:1005
matplotlibcpp::detail::_interpreter::s_python_function_stem
PyObject * s_python_function_stem
Definition: matplotlibcpp.h:76
matplotlibcpp::yticks
void yticks(const std::vector< Numeric > &ticks, const std::vector< std::string > &labels={}, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1354
matplotlibcpp::detail::is_callable::type
is_callable_impl< std::is_class< T >::value, T >::type type
Definition: matplotlibcpp.h:1685
matplotlibcpp::detail::_interpreter::s_python_function_grid
PyObject * s_python_function_grid
Definition: matplotlibcpp.h:69
matplotlibcpp::named_hist
bool named_hist(std::string label, const std::vector< Numeric > &y, long bins=10, std::string color="b", double alpha=1.0)
Definition: matplotlibcpp.h:710
matplotlibcpp::xticks
void xticks(const std::vector< Numeric > &ticks, const std::vector< std::string > &labels={}, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1309
matplotlibcpp::detail::_interpreter::s_python_function_xlim
PyObject * s_python_function_xlim
Definition: matplotlibcpp.h:59
matplotlibcpp::detail::_interpreter::s_python_function_title
PyObject * s_python_function_title
Definition: matplotlibcpp.h:63
matplotlibcpp::fignum_exists
bool fignum_exists(long number)
Definition: matplotlibcpp.h:1193
matplotlibcpp::grid
void grid(bool flag)
Definition: matplotlibcpp.h:1502
matplotlibcpp::Plot::Plot
Plot(const std::string &name, const std::vector< Numeric > &x, const std::vector< Numeric > &y, const std::string &format="")
Definition: matplotlibcpp.h:1771
matplotlibcpp::xkcd
void xkcd()
Definition: matplotlibcpp.h:1544
matplotlibcpp::detail::_interpreter::s_python_function_ginput
PyObject * s_python_function_ginput
Definition: matplotlibcpp.h:61
matplotlibcpp::detail::plot_impl< std::true_type >::operator()
bool operator()(const Iterable &ticks, const Callable &f, const std::string &format)
Definition: matplotlibcpp.h:1727
matplotlibcpp::legend
void legend()
Definition: matplotlibcpp.h:1233
matplotlibcpp::detail::_interpreter::safe_import
PyObject * safe_import(PyObject *module, std::string fname)
Definition: matplotlibcpp.h:94
matplotlibcpp::detail::_interpreter::get
static _interpreter & get()
Definition: matplotlibcpp.h:89
matplotlibcpp::detail::_interpreter
Definition: matplotlibcpp.h:37
matplotlibcpp::figure_size
void figure_size(size_t w, size_t h)
Definition: matplotlibcpp.h:1210
matplotlibcpp::Plot::decref
void decref()
Definition: matplotlibcpp.h:1845
matplotlibcpp::fill
bool fill(const std::vector< Numeric > &x, const std::vector< Numeric > &y, const std::map< std::string, std::string > &keywords)
Definition: matplotlibcpp.h:476
matplotlibcpp::bar
bool bar(const std::vector< Numeric > &y, std::string ec="black", std::string ls="-", double lw=1.0, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:660
matplotlibcpp::detail::_interpreter::s_python_function_plot
PyObject * s_python_function_plot
Definition: matplotlibcpp.h:45
matplotlibcpp::figure
long figure(long number=-1)
Definition: matplotlibcpp.h:1163
matplotlibcpp::detail::_interpreter::s_python_function_errorbar
PyObject * s_python_function_errorbar
Definition: matplotlibcpp.h:71
f
f
test
matplotlibcpp::detail::_interpreter::_interpreter
_interpreter()
Definition: matplotlibcpp.h:124
matplotlibcpp::close
void close()
Definition: matplotlibcpp.h:1534
matplotlibcpp::detail::_interpreter::s_python_function_annotate
PyObject * s_python_function_annotate
Definition: matplotlibcpp.h:72
matplotlibcpp::detail::_interpreter::s_python_function_ion
PyObject * s_python_function_ion
Definition: matplotlibcpp.h:60
matplotlibcpp
Definition: matplotlibcpp.h:32
matplotlibcpp::detail::_interpreter::s_python_function_pause
PyObject * s_python_function_pause
Definition: matplotlibcpp.h:41
matplotlibcpp::detail::_interpreter::s_python_function_fill
PyObject * s_python_function_fill
Definition: matplotlibcpp.h:52
matplotlibcpp::named_semilogy
bool named_semilogy(const std::string &name, const std::vector< Numeric > &x, const std::vector< Numeric > &y, const std::string &format="")
Definition: matplotlibcpp.h:1079
matplotlibcpp::detail::_interpreter::s_python_function_close
PyObject * s_python_function_close
Definition: matplotlibcpp.h:39
matplotlibcpp::detail::_interpreter::s_python_function_fill_between
PyObject * s_python_function_fill_between
Definition: matplotlibcpp.h:53
matplotlibcpp::Plot::Plot
Plot(const std::string &name="", const std::string &format="")
Definition: matplotlibcpp.h:1807
matplotlibcpp::detail::_interpreter::s_python_function_bar
PyObject * s_python_function_bar
Definition: matplotlibcpp.h:80
matplotlibcpp::errorbar
bool errorbar(const std::vector< NumericX > &x, const std::vector< NumericY > &y, const std::vector< NumericX > &yerr, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:972
matplotlibcpp::detail::plot_impl< std::false_type >
Definition: matplotlibcpp.h:1690
matplotlibcpp::detail::_interpreter::s_python_function_figure
PyObject * s_python_function_figure
Definition: matplotlibcpp.h:43
matplotlibcpp::semilogy
bool semilogy(const std::vector< NumericX > &x, const std::vector< NumericY > &y, const std::string &s="")
Definition: matplotlibcpp.h:926
matplotlibcpp::annotate
bool annotate(std::string annotation, double x, double y)
Definition: matplotlibcpp.h:234
update
void update(const std::string &key, const XmlRpc::XmlRpcValue &v)
matplotlibcpp::detail::_interpreter::s_python_function_yticks
PyObject * s_python_function_yticks
Definition: matplotlibcpp.h:68
matplotlibcpp::xlim
void xlim(Numeric left, Numeric right)
Definition: matplotlibcpp.h:1258
matplotlibcpp::detail::_interpreter::s_python_function_stackplot
PyObject * s_python_function_stackplot
Definition: matplotlibcpp.h:48
matplotlibcpp::detail::_interpreter::s_python_function_legend
PyObject * s_python_function_legend
Definition: matplotlibcpp.h:58
matplotlibcpp::detail::_interpreter::s_python_function_imshow
PyObject * s_python_function_imshow
Definition: matplotlibcpp.h:55
matplotlibcpp::detail::_interpreter::s_python_function_save
PyObject * s_python_function_save
Definition: matplotlibcpp.h:42
matplotlibcpp::ginput
std::vector< std::array< double, 2 > > ginput(const int numClicks=1, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1611
matplotlibcpp::subplots_adjust
bool subplots_adjust(const std::map< std::string, double > &keywords={})
Definition: matplotlibcpp.h:690
matplotlibcpp::show
void show(const bool block=true)
Definition: matplotlibcpp.h:1517
matplotlibcpp::suptitle
void suptitle(const std::string &suptitlestr, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1432
matplotlibcpp::detail::_interpreter::s_python_function_subplots_adjust
PyObject * s_python_function_subplots_adjust
Definition: matplotlibcpp.h:81
matplotlibcpp::detail::_interpreter::s_python_function_quiver
PyObject * s_python_function_quiver
Definition: matplotlibcpp.h:46
matplotlibcpp::detail::_interpreter::s_python_function_axis
PyObject * s_python_function_axis
Definition: matplotlibcpp.h:64
matplotlibcpp::detail::plot_impl< std::false_type >::operator()
bool operator()(const IterableX &x, const IterableY &y, const std::string &format)
Definition: matplotlibcpp.h:1691
matplotlibcpp::detail::_interpreter::s_python_function_semilogx
PyObject * s_python_function_semilogx
Definition: matplotlibcpp.h:49
matplotlibcpp::text
void text(Numeric x, Numeric y, const std::string &s="")
Definition: matplotlibcpp.h:1149
matplotlibcpp::detail::_interpreter::s_python_function_semilogy
PyObject * s_python_function_semilogy
Definition: matplotlibcpp.h:50
matplotlibcpp::named_semilogx
bool named_semilogx(const std::string &name, const std::vector< Numeric > &x, const std::vector< Numeric > &y, const std::string &format="")
Definition: matplotlibcpp.h:1054
matplotlibcpp::detail::_interpreter::s_python_function_hist
PyObject * s_python_function_hist
Definition: matplotlibcpp.h:54
matplotlibcpp::pause
void pause(Numeric interval)
Definition: matplotlibcpp.h:1567
matplotlibcpp::detail::s_backend
static std::string s_backend
Definition: matplotlibcpp.h:35
matplotlibcpp::detail::_interpreter::s_python_function_draw
PyObject * s_python_function_draw
Definition: matplotlibcpp.h:40
std
matplotlibcpp::detail::_interpreter::s_python_function_xticks
PyObject * s_python_function_xticks
Definition: matplotlibcpp.h:67
matplotlibcpp::tight_layout
void tight_layout()
Definition: matplotlibcpp.h:1644
matplotlibcpp::subplot
void subplot(long nrows, long ncols, long plot_number)
Definition: matplotlibcpp.h:1398
matplotlibcpp::stackplot
bool stackplot(const std::vector< NumericX > &x, const std::vector< std::vector< NumericY >> &ys, const std::vector< std::string > &labels, const std::vector< std::string > &colors, const std::string &baseline="zero")
Definition: matplotlibcpp.h:835
matplotlibcpp::boxplot
bool boxplot(const std::vector< NumericX > &x, const double &position, const double &width, const std::string &color, const std::string &linestyle, const std::map< std::string, std::string > &keywords={}, bool vert=true)
Definition: matplotlibcpp.h:788
matplotlibcpp::detail::_interpreter::s_python_function_loglog
PyObject * s_python_function_loglog
Definition: matplotlibcpp.h:51
matplotlibcpp::save
void save(const std::string &filename)
Definition: matplotlibcpp.h:1579
matplotlibcpp::clf
void clf()
Definition: matplotlibcpp.h:1593
matplotlibcpp::detail::_interpreter::s_python_function_xkcd
PyObject * s_python_function_xkcd
Definition: matplotlibcpp.h:77
matplotlibcpp::detail::_interpreter::s_python_function_suptitle
PyObject * s_python_function_suptitle
Definition: matplotlibcpp.h:79
matplotlibcpp::xlabel
void xlabel(const std::string &str, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1464
matplotlibcpp::detail::is_callable_impl< false, T >::type
is_function< T > type
Definition: matplotlibcpp.h:1662
matplotlibcpp::detail::_interpreter::s_python_function_ylabel
PyObject * s_python_function_ylabel
Definition: matplotlibcpp.h:66
matplotlibcpp::ylim
void ylim(Numeric left, Numeric right)
Definition: matplotlibcpp.h:1242
args
matplotlibcpp::get_array
PyObject * get_array(const std::vector< Numeric > &v)
Definition: matplotlibcpp.h:312
matplotlibcpp::title
void title(const std::string &titlestr, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1413
matplotlibcpp::axis
void axis(const std::string &axisstr)
Definition: matplotlibcpp.h:1451
matplotlibcpp::Plot::remove
void remove()
Definition: matplotlibcpp.h:1831
matplotlibcpp::loglog
bool loglog(const std::vector< NumericX > &x, const std::vector< NumericY > &y, const std::string &s="")
Definition: matplotlibcpp.h:949
matplotlibcpp::named_loglog
bool named_loglog(const std::string &name, const std::vector< Numeric > &x, const std::vector< Numeric > &y, const std::string &format="")
Definition: matplotlibcpp.h:1104
matplotlibcpp::detail::_interpreter::s_python_empty_tuple
PyObject * s_python_empty_tuple
Definition: matplotlibcpp.h:75
matplotlibcpp::ion
void ion()
Definition: matplotlibcpp.h:1602
matplotlibcpp::Plot::~Plot
~Plot()
Definition: matplotlibcpp.h:1842
matplotlibcpp::detail::_interpreter::s_python_function_scatter
PyObject * s_python_function_scatter
Definition: matplotlibcpp.h:56
matplotlibcpp::detail::_interpreter::s_python_colormap
PyObject * s_python_colormap
Definition: matplotlibcpp.h:74
matplotlibcpp::detail::_interpreter::s_python_function_text
PyObject * s_python_function_text
Definition: matplotlibcpp.h:78
matplotlibcpp::detail::is_function
typename std::is_function< std::remove_pointer< std::remove_reference< T > >>::type is_function
Definition: matplotlibcpp.h:1658
matplotlibcpp::fill_between
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)
Definition: matplotlibcpp.h:506
matplotlibcpp::ylabel
void ylabel(const std::string &str, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1483


ov_core
Author(s): Patrick Geneva , Kevin Eckenhoff , Guoquan Huang
autogenerated on Mon Dec 16 2024 03:06:46