AlgoPlus v0.1.0
Loading...
Searching...
No Matches
matplotlibcpp.h
1#pragma once
2
3// Python headers must be included before any system headers, since
4// they define _POSIX_C_SOURCE
5#include <Python.h>
6
7#include <algorithm>
8#include <array>
9#include <cstdint> // <cstdint> requires c++11 support
10#include <functional>
11#include <iostream>
12#include <map>
13#include <numeric>
14#include <stdexcept>
15#include <string> // std::stod
16#include <vector>
17
18#ifndef WITHOUT_NUMPY
19#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
20#include <numpy/arrayobject.h>
21
22#ifdef WITH_OPENCV
23#include <opencv2/opencv.hpp>
24#endif // WITH_OPENCV
25
26/*
27 * A bunch of constants were removed in OpenCV 4 in favour of enum classes, so
28 * define the ones we need here.
29 */
30#if CV_MAJOR_VERSION > 3
31#define CV_BGR2RGB cv::COLOR_BGR2RGB
32#define CV_BGRA2RGBA cv::COLOR_BGRA2RGBA
33#endif
34#endif // WITHOUT_NUMPY
35
36#if PY_MAJOR_VERSION >= 3
37#define PyString_FromString PyUnicode_FromString
38#define PyInt_FromLong PyLong_FromLong
39#define PyString_FromString PyUnicode_FromString
40#endif
41
42namespace matplotlibcpp {
43namespace detail {
44
45static std::string s_backend;
46
47struct _interpreter {
48 PyObject* s_python_function_arrow;
49 PyObject* s_python_function_show;
50 PyObject* s_python_function_close;
51 PyObject* s_python_function_draw;
52 PyObject* s_python_function_pause;
53 PyObject* s_python_function_save;
54 PyObject* s_python_function_figure;
55 PyObject* s_python_function_fignum_exists;
56 PyObject* s_python_function_plot;
57 PyObject* s_python_function_quiver;
58 PyObject* s_python_function_contour;
59 PyObject* s_python_function_semilogx;
60 PyObject* s_python_function_semilogy;
61 PyObject* s_python_function_loglog;
62 PyObject* s_python_function_fill;
63 PyObject* s_python_function_fill_between;
64 PyObject* s_python_function_hist;
65 PyObject* s_python_function_imshow;
66 PyObject* s_python_function_scatter;
67 PyObject* s_python_function_boxplot;
68 PyObject* s_python_function_subplot;
69 PyObject* s_python_function_subplot2grid;
70 PyObject* s_python_function_legend;
71 PyObject* s_python_function_xlim;
72 PyObject* s_python_function_ion;
73 PyObject* s_python_function_ginput;
74 PyObject* s_python_function_ylim;
75 PyObject* s_python_function_title;
76 PyObject* s_python_function_axis;
77 PyObject* s_python_function_axhline;
78 PyObject* s_python_function_axvline;
79 PyObject* s_python_function_axvspan;
80 PyObject* s_python_function_xlabel;
81 PyObject* s_python_function_ylabel;
82 PyObject* s_python_function_gca;
83 PyObject* s_python_function_xticks;
84 PyObject* s_python_function_yticks;
85 PyObject* s_python_function_margins;
86 PyObject* s_python_function_tick_params;
87 PyObject* s_python_function_grid;
88 PyObject* s_python_function_cla;
89 PyObject* s_python_function_clf;
90 PyObject* s_python_function_errorbar;
91 PyObject* s_python_function_annotate;
92 PyObject* s_python_function_tight_layout;
93 PyObject* s_python_colormap;
94 PyObject* s_python_empty_tuple;
95 PyObject* s_python_function_stem;
96 PyObject* s_python_function_xkcd;
97 PyObject* s_python_function_text;
98 PyObject* s_python_function_suptitle;
99 PyObject* s_python_function_bar;
100 PyObject* s_python_function_barh;
101 PyObject* s_python_function_colorbar;
102 PyObject* s_python_function_subplots_adjust;
103 PyObject* s_python_function_rcparams;
104 PyObject* s_python_function_spy;
105
106 /* For now, _interpreter is implemented as a singleton since its currently not
107 possible to have multiple independent embedded python interpreters without
108 patching the python source code or starting a separate process for each.
109 [1] Furthermore, many python objects expect that they are destructed in the
110 same thread as they were constructed. [2] So for advanced usage, a `kill()`
111 function is provided so that library users can manually ensure that the
112 interpreter is constructed and destroyed within the same thread.
113
114 1:
115 http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
116 2: https://github.com/lava/matplotlib-cpp/pull/202#issue-436220256
117 */
118
119 static _interpreter& get() { return interkeeper(false); }
120
121 static _interpreter& kill() { return interkeeper(true); }
122
123 // Stores the actual singleton object referenced by `get()` and `kill()`.
124 static _interpreter& interkeeper(bool should_kill) {
125 static _interpreter ctx;
126 if (should_kill)
127 ctx.~_interpreter();
128 return ctx;
129 }
130
131 PyObject* safe_import(PyObject* module, std::string fname) {
132 PyObject* fn = PyObject_GetAttrString(module, fname.c_str());
133
134 if (!fn)
135 throw std::runtime_error(std::string("Couldn't find required function: ") + fname);
136
137 if (!PyFunction_Check(fn))
138 throw std::runtime_error(fname + std::string(" is unexpectedly not a PyFunction."));
139
140 return fn;
141 }
142
143 private:
144#ifndef WITHOUT_NUMPY
145#if PY_MAJOR_VERSION >= 3
146
147 void* import_numpy() {
148 import_array(); // initialize C-API
149 return NULL;
150 }
151
152#else
153
154 void import_numpy() {
155 import_array(); // initialize C-API
156 }
157
158#endif
159#endif
160
161 _interpreter() {
162
163 // optional but recommended
164#if PY_MAJOR_VERSION >= 3
165 wchar_t name[] = L"plotting";
166#else
167 char name[] = "plotting";
168#endif
169 Py_SetProgramName(name);
170 Py_Initialize();
171
172 wchar_t const* dummy_args[] = {
173 L"Python", NULL}; // const is needed because literals must not be modified
174 wchar_t const** argv = dummy_args;
175 int argc = sizeof(dummy_args) / sizeof(dummy_args[0]) - 1;
176
177#if PY_MAJOR_VERSION >= 3
178 PySys_SetArgv(argc, const_cast<wchar_t**>(argv));
179#else
180 PySys_SetArgv(argc, (char**)(argv));
181#endif
182
183#ifndef WITHOUT_NUMPY
184 import_numpy(); // initialize numpy C-API
185#endif
186
187 PyObject* matplotlibname = PyString_FromString("matplotlib");
188 PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
189 PyObject* cmname = PyString_FromString("matplotlib.cm");
190 PyObject* pylabname = PyString_FromString("pylab");
191 if (!pyplotname || !pylabname || !matplotlibname || !cmname) {
192 throw std::runtime_error("couldnt create string");
193 }
194
195 PyObject* matplotlib = PyImport_Import(matplotlibname);
196
197 Py_DECREF(matplotlibname);
198 if (!matplotlib) {
199 PyErr_Print();
200 throw std::runtime_error("Error loading module matplotlib!");
201 }
202
203 // matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
204 // or matplotlib.backends is imported for the first time
205 if (!s_backend.empty()) {
206 PyObject_CallMethod(matplotlib, const_cast<char*>("use"), const_cast<char*>("s"),
207 s_backend.c_str());
208 }
209
210 PyObject* pymod = PyImport_Import(pyplotname);
211 Py_DECREF(pyplotname);
212 if (!pymod) {
213 throw std::runtime_error("Error loading module matplotlib.pyplot!");
214 }
215
216 s_python_colormap = PyImport_Import(cmname);
217 Py_DECREF(cmname);
218 if (!s_python_colormap) {
219 throw std::runtime_error("Error loading module matplotlib.cm!");
220 }
221
222 PyObject* pylabmod = PyImport_Import(pylabname);
223 Py_DECREF(pylabname);
224 if (!pylabmod) {
225 throw std::runtime_error("Error loading module pylab!");
226 }
227
228 s_python_function_arrow = safe_import(pymod, "arrow");
229 s_python_function_show = safe_import(pymod, "show");
230 s_python_function_close = safe_import(pymod, "close");
231 s_python_function_draw = safe_import(pymod, "draw");
232 s_python_function_pause = safe_import(pymod, "pause");
233 s_python_function_figure = safe_import(pymod, "figure");
234 s_python_function_fignum_exists = safe_import(pymod, "fignum_exists");
235 s_python_function_plot = safe_import(pymod, "plot");
236 s_python_function_quiver = safe_import(pymod, "quiver");
237 s_python_function_contour = safe_import(pymod, "contour");
238 s_python_function_semilogx = safe_import(pymod, "semilogx");
239 s_python_function_semilogy = safe_import(pymod, "semilogy");
240 s_python_function_loglog = safe_import(pymod, "loglog");
241 s_python_function_fill = safe_import(pymod, "fill");
242 s_python_function_fill_between = safe_import(pymod, "fill_between");
243 s_python_function_hist = safe_import(pymod, "hist");
244 s_python_function_scatter = safe_import(pymod, "scatter");
245 s_python_function_boxplot = safe_import(pymod, "boxplot");
246 s_python_function_subplot = safe_import(pymod, "subplot");
247 s_python_function_subplot2grid = safe_import(pymod, "subplot2grid");
248 s_python_function_legend = safe_import(pymod, "legend");
249 s_python_function_xlim = safe_import(pymod, "xlim");
250 s_python_function_ylim = safe_import(pymod, "ylim");
251 s_python_function_title = safe_import(pymod, "title");
252 s_python_function_axis = safe_import(pymod, "axis");
253 s_python_function_axhline = safe_import(pymod, "axhline");
254 s_python_function_axvline = safe_import(pymod, "axvline");
255 s_python_function_axvspan = safe_import(pymod, "axvspan");
256 s_python_function_xlabel = safe_import(pymod, "xlabel");
257 s_python_function_ylabel = safe_import(pymod, "ylabel");
258 s_python_function_gca = safe_import(pymod, "gca");
259 s_python_function_xticks = safe_import(pymod, "xticks");
260 s_python_function_yticks = safe_import(pymod, "yticks");
261 s_python_function_margins = safe_import(pymod, "margins");
262 s_python_function_tick_params = safe_import(pymod, "tick_params");
263 s_python_function_grid = safe_import(pymod, "grid");
264 s_python_function_ion = safe_import(pymod, "ion");
265 s_python_function_ginput = safe_import(pymod, "ginput");
266 s_python_function_save = safe_import(pylabmod, "savefig");
267 s_python_function_annotate = safe_import(pymod, "annotate");
268 s_python_function_cla = safe_import(pymod, "cla");
269 s_python_function_clf = safe_import(pymod, "clf");
270 s_python_function_errorbar = safe_import(pymod, "errorbar");
271 s_python_function_tight_layout = safe_import(pymod, "tight_layout");
272 s_python_function_stem = safe_import(pymod, "stem");
273 s_python_function_xkcd = safe_import(pymod, "xkcd");
274 s_python_function_text = safe_import(pymod, "text");
275 s_python_function_suptitle = safe_import(pymod, "suptitle");
276 s_python_function_bar = safe_import(pymod, "bar");
277 s_python_function_barh = safe_import(pymod, "barh");
278 s_python_function_colorbar = PyObject_GetAttrString(pymod, "colorbar");
279 s_python_function_subplots_adjust = safe_import(pymod, "subplots_adjust");
280 s_python_function_rcparams = PyObject_GetAttrString(pymod, "rcParams");
281 s_python_function_spy = PyObject_GetAttrString(pymod, "spy");
282#ifndef WITHOUT_NUMPY
283 s_python_function_imshow = safe_import(pymod, "imshow");
284#endif
285 s_python_empty_tuple = PyTuple_New(0);
286 }
287
288 ~_interpreter() { Py_Finalize(); }
289};
290
291} // end namespace detail
292
303inline void backend(const std::string& name) {
304 detail::s_backend = name;
305}
306
307inline bool annotate(std::string annotation, double x, double y) {
308 detail::_interpreter::get();
309
310 PyObject* xy = PyTuple_New(2);
311 PyObject* str = PyString_FromString(annotation.c_str());
312
313 PyTuple_SetItem(xy, 0, PyFloat_FromDouble(x));
314 PyTuple_SetItem(xy, 1, PyFloat_FromDouble(y));
315
316 PyObject* kwargs = PyDict_New();
317 PyDict_SetItemString(kwargs, "xy", xy);
318
319 PyObject* args = PyTuple_New(1);
320 PyTuple_SetItem(args, 0, str);
321
322 PyObject* res =
323 PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs);
324
325 Py_DECREF(args);
326 Py_DECREF(kwargs);
327
328 if (res)
329 Py_DECREF(res);
330
331 return res;
332}
333
334namespace detail {
335
336#ifndef WITHOUT_NUMPY
337// Type selector for numpy array conversion
338template <typename T> struct select_npy_type {
339 const static NPY_TYPES type = NPY_NOTYPE;
340}; // Default
341template <> struct select_npy_type<double> {
342 const static NPY_TYPES type = NPY_DOUBLE;
343};
344template <> struct select_npy_type<float> {
345 const static NPY_TYPES type = NPY_FLOAT;
346};
347template <> struct select_npy_type<bool> {
348 const static NPY_TYPES type = NPY_BOOL;
349};
350template <> struct select_npy_type<int8_t> {
351 const static NPY_TYPES type = NPY_INT8;
352};
353template <> struct select_npy_type<int16_t> {
354 const static NPY_TYPES type = NPY_SHORT;
355};
356template <> struct select_npy_type<int32_t> {
357 const static NPY_TYPES type = NPY_INT;
358};
359template <> struct select_npy_type<int64_t> {
360 const static NPY_TYPES type = NPY_INT64;
361};
362template <> struct select_npy_type<uint8_t> {
363 const static NPY_TYPES type = NPY_UINT8;
364};
365template <> struct select_npy_type<uint16_t> {
366 const static NPY_TYPES type = NPY_USHORT;
367};
368template <> struct select_npy_type<uint32_t> {
369 const static NPY_TYPES type = NPY_ULONG;
370};
371template <> struct select_npy_type<uint64_t> {
372 const static NPY_TYPES type = NPY_UINT64;
373};
374
375// Sanity checks; comment them out or change the numpy type below if you're
376// compiling on a platform where they don't apply
377static_assert(sizeof(long long) == 8);
378template <> struct select_npy_type<long long> {
379 const static NPY_TYPES type = NPY_INT64;
380};
381static_assert(sizeof(unsigned long long) == 8);
382template <> struct select_npy_type<unsigned long long> {
383 const static NPY_TYPES type = NPY_UINT64;
384};
385
386template <typename Numeric> PyObject* get_array(const std::vector<Numeric>& v) {
387 npy_intp vsize = v.size();
388 NPY_TYPES type = select_npy_type<Numeric>::type;
389 if (type == NPY_NOTYPE) {
390 size_t memsize = v.size() * sizeof(double);
391 double* dp = static_cast<double*>(::malloc(memsize));
392 for (size_t i = 0; i < v.size(); ++i)
393 dp[i] = v[i];
394 PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, dp);
395 PyArray_UpdateFlags(reinterpret_cast<PyArrayObject*>(varray), NPY_ARRAY_OWNDATA);
396 return varray;
397 }
398
399 PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
400 return varray;
401}
402
403template <typename Numeric> PyObject* get_2darray(const std::vector<::std::vector<Numeric>>& v) {
404 if (v.size() < 1)
405 throw std::runtime_error("get_2d_array v too small");
406
407 npy_intp vsize[2] = {static_cast<npy_intp>(v.size()), static_cast<npy_intp>(v[0].size())};
408
409 PyArrayObject* varray = (PyArrayObject*)PyArray_SimpleNew(2, vsize, NPY_DOUBLE);
410
411 double* vd_begin = static_cast<double*>(PyArray_DATA(varray));
412
413 for (const ::std::vector<Numeric>& v_row : v) {
414 if (v_row.size() != static_cast<size_t>(vsize[1]))
415 throw std::runtime_error("Missmatched array size");
416 std::copy(v_row.begin(), v_row.end(), vd_begin);
417 vd_begin += vsize[1];
418 }
419
420 return reinterpret_cast<PyObject*>(varray);
421}
422
423#else // fallback if we don't have numpy: copy every element of the given vector
424
425template <typename Numeric> PyObject* get_array(const std::vector<Numeric>& v) {
426 PyObject* list = PyList_New(v.size());
427 for (size_t i = 0; i < v.size(); ++i) {
428 PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i)));
429 }
430 return list;
431}
432
433#endif // WITHOUT_NUMPY
434
435// sometimes, for labels and such, we need string arrays
436inline PyObject* get_array(const std::vector<std::string>& strings) {
437 PyObject* list = PyList_New(strings.size());
438 for (std::size_t i = 0; i < strings.size(); ++i) {
439 PyList_SetItem(list, i, PyString_FromString(strings[i].c_str()));
440 }
441 return list;
442}
443
444// not all matplotlib need 2d arrays, some prefer lists of lists
445template <typename Numeric> PyObject* get_listlist(const std::vector<std::vector<Numeric>>& ll) {
446 PyObject* listlist = PyList_New(ll.size());
447 for (std::size_t i = 0; i < ll.size(); ++i) {
448 PyList_SetItem(listlist, i, get_array(ll[i]));
449 }
450 return listlist;
451}
452
453} // namespace detail
454
458template <typename Numeric>
459bool plot(const std::vector<Numeric>& x, const std::vector<Numeric>& y,
460 const std::map<std::string, std::string>& keywords) {
461 assert(x.size() == y.size());
462
463 detail::_interpreter::get();
464
465 // using numpy arrays
466 PyObject* xarray = detail::get_array(x);
467 PyObject* yarray = detail::get_array(y);
468
469 // construct positional args
470 PyObject* args = PyTuple_New(2);
471 PyTuple_SetItem(args, 0, xarray);
472 PyTuple_SetItem(args, 1, yarray);
473
474 // construct keyword args
475 PyObject* kwargs = PyDict_New();
476 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
477 it != keywords.end(); ++it) {
478 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
479 }
480
481 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
482
483 Py_DECREF(args);
484 Py_DECREF(kwargs);
485 if (res)
486 Py_DECREF(res);
487
488 return res;
489}
490
491// TODO - it should be possible to make this work by implementing
492// a non-numpy alternative for `detail::get_2darray()`.
493#ifndef WITHOUT_NUMPY
494template <typename Numeric>
495void plot_surface(
496 const std::vector<::std::vector<Numeric>>& x, const std::vector<::std::vector<Numeric>>& y,
497 const std::vector<::std::vector<Numeric>>& z,
498 const std::map<std::string, std::string>& keywords = std::map<std::string, std::string>(),
499 const long fig_number = 0) {
500 detail::_interpreter::get();
501
502 // We lazily load the modules here the first time this function is called
503 // because I'm not sure that we can assume "matplotlib installed" implies
504 // "mpl_toolkits installed" on all platforms, and we don't want to require
505 // it for people who don't need 3d plots.
506 static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
507 if (!mpl_toolkitsmod) {
508 detail::_interpreter::get();
509
510 PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
511 PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
512 if (!mpl_toolkits || !axis3d) {
513 throw std::runtime_error("couldnt create string");
514 }
515
516 mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
517 Py_DECREF(mpl_toolkits);
518 if (!mpl_toolkitsmod) {
519 throw std::runtime_error("Error loading module mpl_toolkits!");
520 }
521
522 axis3dmod = PyImport_Import(axis3d);
523 Py_DECREF(axis3d);
524 if (!axis3dmod) {
525 throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!");
526 }
527 }
528
529 assert(x.size() == y.size());
530 assert(y.size() == z.size());
531
532 // using numpy arrays
533 PyObject* xarray = detail::get_2darray(x);
534 PyObject* yarray = detail::get_2darray(y);
535 PyObject* zarray = detail::get_2darray(z);
536
537 // construct positional args
538 PyObject* args = PyTuple_New(3);
539 PyTuple_SetItem(args, 0, xarray);
540 PyTuple_SetItem(args, 1, yarray);
541 PyTuple_SetItem(args, 2, zarray);
542
543 // Build up the kw args.
544 PyObject* kwargs = PyDict_New();
545 PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1));
546 PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1));
547
548 PyObject* python_colormap_coolwarm =
549 PyObject_GetAttrString(detail::_interpreter::get().s_python_colormap, "coolwarm");
550
551 PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm);
552
553 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
554 it != keywords.end(); ++it) {
555 if (it->first == "linewidth" || it->first == "alpha") {
556 PyDict_SetItemString(kwargs, it->first.c_str(),
557 PyFloat_FromDouble(std::stod(it->second)));
558 } else {
559 PyDict_SetItemString(kwargs, it->first.c_str(),
560 PyString_FromString(it->second.c_str()));
561 }
562 }
563
564 PyObject* fig_args = PyTuple_New(1);
565 PyObject* fig = nullptr;
566 PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number));
567 PyObject* fig_exists =
568 PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args);
569 if (!PyObject_IsTrue(fig_exists)) {
570 fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure,
571 detail::_interpreter::get().s_python_empty_tuple);
572 } else {
573 fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, fig_args);
574 }
575 Py_DECREF(fig_exists);
576 if (!fig)
577 throw std::runtime_error("Call to figure() failed.");
578
579 PyObject* gca_kwargs = PyDict_New();
580 PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
581
582 PyObject* gca = PyObject_GetAttrString(fig, "gca");
583 if (!gca)
584 throw std::runtime_error("No gca");
585 Py_INCREF(gca);
586 PyObject* axis =
587 PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
588
589 if (!axis)
590 throw std::runtime_error("No axis");
591 Py_INCREF(axis);
592
593 Py_DECREF(gca);
594 Py_DECREF(gca_kwargs);
595
596 PyObject* plot_surface = PyObject_GetAttrString(axis, "plot_surface");
597 if (!plot_surface)
598 throw std::runtime_error("No surface");
599 Py_INCREF(plot_surface);
600 PyObject* res = PyObject_Call(plot_surface, args, kwargs);
601 if (!res)
602 throw std::runtime_error("failed surface");
603 Py_DECREF(plot_surface);
604
605 Py_DECREF(axis);
606 Py_DECREF(args);
607 Py_DECREF(kwargs);
608 if (res)
609 Py_DECREF(res);
610}
611
612template <typename Numeric>
613void contour(const std::vector<::std::vector<Numeric>>& x,
614 const std::vector<::std::vector<Numeric>>& y,
615 const std::vector<::std::vector<Numeric>>& z,
616 const std::map<std::string, std::string>& keywords = {}) {
617 detail::_interpreter::get();
618
619 // using numpy arrays
620 PyObject* xarray = detail::get_2darray(x);
621 PyObject* yarray = detail::get_2darray(y);
622 PyObject* zarray = detail::get_2darray(z);
623
624 // construct positional args
625 PyObject* args = PyTuple_New(3);
626 PyTuple_SetItem(args, 0, xarray);
627 PyTuple_SetItem(args, 1, yarray);
628 PyTuple_SetItem(args, 2, zarray);
629
630 // Build up the kw args.
631 PyObject* kwargs = PyDict_New();
632
633 PyObject* python_colormap_coolwarm =
634 PyObject_GetAttrString(detail::_interpreter::get().s_python_colormap, "coolwarm");
635
636 PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm);
637
638 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
639 it != keywords.end(); ++it) {
640 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
641 }
642
643 PyObject* res =
644 PyObject_Call(detail::_interpreter::get().s_python_function_contour, args, kwargs);
645 if (!res)
646 throw std::runtime_error("failed contour");
647
648 Py_DECREF(args);
649 Py_DECREF(kwargs);
650 if (res)
651 Py_DECREF(res);
652}
653
654template <typename Numeric>
655void spy(const std::vector<::std::vector<Numeric>>& x,
656 const double markersize = -1, // -1 for default matplotlib size
657 const std::map<std::string, std::string>& keywords = {}) {
658 detail::_interpreter::get();
659
660 PyObject* xarray = detail::get_2darray(x);
661
662 PyObject* kwargs = PyDict_New();
663 if (markersize != -1) {
664 PyDict_SetItemString(kwargs, "markersize", PyFloat_FromDouble(markersize));
665 }
666 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
667 it != keywords.end(); ++it) {
668 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
669 }
670
671 PyObject* plot_args = PyTuple_New(1);
672 PyTuple_SetItem(plot_args, 0, xarray);
673
674 PyObject* res =
675 PyObject_Call(detail::_interpreter::get().s_python_function_spy, plot_args, kwargs);
676
677 Py_DECREF(plot_args);
678 Py_DECREF(kwargs);
679 if (res)
680 Py_DECREF(res);
681}
682#endif // WITHOUT_NUMPY
683
684template <typename Numeric>
685void plot3(
686 const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::vector<Numeric>& z,
687 const std::map<std::string, std::string>& keywords = std::map<std::string, std::string>(),
688 const long fig_number = 0) {
689 detail::_interpreter::get();
690
691 // Same as with plot_surface: We lazily load the modules here the first time
692 // this function is called because I'm not sure that we can assume "matplotlib
693 // installed" implies "mpl_toolkits installed" on all platforms, and we don't
694 // want to require it for people who don't need 3d plots.
695 static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
696 if (!mpl_toolkitsmod) {
697 detail::_interpreter::get();
698
699 PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
700 PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
701 if (!mpl_toolkits || !axis3d) {
702 throw std::runtime_error("couldnt create string");
703 }
704
705 mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
706 Py_DECREF(mpl_toolkits);
707 if (!mpl_toolkitsmod) {
708 throw std::runtime_error("Error loading module mpl_toolkits!");
709 }
710
711 axis3dmod = PyImport_Import(axis3d);
712 Py_DECREF(axis3d);
713 if (!axis3dmod) {
714 throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!");
715 }
716 }
717
718 assert(x.size() == y.size());
719 assert(y.size() == z.size());
720
721 PyObject* xarray = detail::get_array(x);
722 PyObject* yarray = detail::get_array(y);
723 PyObject* zarray = detail::get_array(z);
724
725 // construct positional args
726 PyObject* args = PyTuple_New(3);
727 PyTuple_SetItem(args, 0, xarray);
728 PyTuple_SetItem(args, 1, yarray);
729 PyTuple_SetItem(args, 2, zarray);
730
731 // Build up the kw args.
732 PyObject* kwargs = PyDict_New();
733
734 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
735 it != keywords.end(); ++it) {
736 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
737 }
738
739 PyObject* fig_args = PyTuple_New(1);
740 PyObject* fig = nullptr;
741 PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number));
742 PyObject* fig_exists =
743 PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args);
744 if (!PyObject_IsTrue(fig_exists)) {
745 fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure,
746 detail::_interpreter::get().s_python_empty_tuple);
747 } else {
748 fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, fig_args);
749 }
750 if (!fig)
751 throw std::runtime_error("Call to figure() failed.");
752
753 PyObject* gca_kwargs = PyDict_New();
754 PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
755
756 PyObject* gca = PyObject_GetAttrString(fig, "gca");
757 if (!gca)
758 throw std::runtime_error("No gca");
759 Py_INCREF(gca);
760 PyObject* axis =
761 PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
762
763 if (!axis)
764 throw std::runtime_error("No axis");
765 Py_INCREF(axis);
766
767 Py_DECREF(gca);
768 Py_DECREF(gca_kwargs);
769
770 PyObject* plot3 = PyObject_GetAttrString(axis, "plot");
771 if (!plot3)
772 throw std::runtime_error("No 3D line plot");
773 Py_INCREF(plot3);
774 PyObject* res = PyObject_Call(plot3, args, kwargs);
775 if (!res)
776 throw std::runtime_error("Failed 3D line plot");
777 Py_DECREF(plot3);
778
779 Py_DECREF(axis);
780 Py_DECREF(args);
781 Py_DECREF(kwargs);
782 if (res)
783 Py_DECREF(res);
784}
785
786template <typename Numeric>
787bool stem(const std::vector<Numeric>& x, const std::vector<Numeric>& y,
788 const std::map<std::string, std::string>& keywords) {
789 assert(x.size() == y.size());
790
791 detail::_interpreter::get();
792
793 // using numpy arrays
794 PyObject* xarray = detail::get_array(x);
795 PyObject* yarray = detail::get_array(y);
796
797 // construct positional args
798 PyObject* args = PyTuple_New(2);
799 PyTuple_SetItem(args, 0, xarray);
800 PyTuple_SetItem(args, 1, yarray);
801
802 // construct keyword args
803 PyObject* kwargs = PyDict_New();
804 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
805 it != keywords.end(); ++it) {
806 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
807 }
808
809 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_stem, args, kwargs);
810
811 Py_DECREF(args);
812 Py_DECREF(kwargs);
813 if (res)
814 Py_DECREF(res);
815
816 return res;
817}
818
819template <typename Numeric>
820bool fill(const std::vector<Numeric>& x, const std::vector<Numeric>& y,
821 const std::map<std::string, std::string>& keywords) {
822 assert(x.size() == y.size());
823
824 detail::_interpreter::get();
825
826 // using numpy arrays
827 PyObject* xarray = detail::get_array(x);
828 PyObject* yarray = detail::get_array(y);
829
830 // construct positional args
831 PyObject* args = PyTuple_New(2);
832 PyTuple_SetItem(args, 0, xarray);
833 PyTuple_SetItem(args, 1, yarray);
834
835 // construct keyword args
836 PyObject* kwargs = PyDict_New();
837 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
838 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
839 }
840
841 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill, args, kwargs);
842
843 Py_DECREF(args);
844 Py_DECREF(kwargs);
845
846 if (res)
847 Py_DECREF(res);
848
849 return res;
850}
851
852template <typename Numeric>
853bool fill_between(const std::vector<Numeric>& x, const std::vector<Numeric>& y1,
854 const std::vector<Numeric>& y2,
855 const std::map<std::string, std::string>& keywords) {
856 assert(x.size() == y1.size());
857 assert(x.size() == y2.size());
858
859 detail::_interpreter::get();
860
861 // using numpy arrays
862 PyObject* xarray = detail::get_array(x);
863 PyObject* y1array = detail::get_array(y1);
864 PyObject* y2array = detail::get_array(y2);
865
866 // construct positional args
867 PyObject* args = PyTuple_New(3);
868 PyTuple_SetItem(args, 0, xarray);
869 PyTuple_SetItem(args, 1, y1array);
870 PyTuple_SetItem(args, 2, y2array);
871
872 // construct keyword args
873 PyObject* kwargs = PyDict_New();
874 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
875 it != keywords.end(); ++it) {
876 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
877 }
878
879 PyObject* res =
880 PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs);
881
882 Py_DECREF(args);
883 Py_DECREF(kwargs);
884 if (res)
885 Py_DECREF(res);
886
887 return res;
888}
889
890template <typename Numeric>
891bool arrow(Numeric x, Numeric y, Numeric end_x, Numeric end_y, const std::string& fc = "r",
892 const std::string ec = "k", Numeric head_length = 0.25, Numeric head_width = 0.1625) {
893 PyObject* obj_x = PyFloat_FromDouble(x);
894 PyObject* obj_y = PyFloat_FromDouble(y);
895 PyObject* obj_end_x = PyFloat_FromDouble(end_x);
896 PyObject* obj_end_y = PyFloat_FromDouble(end_y);
897
898 PyObject* kwargs = PyDict_New();
899 PyDict_SetItemString(kwargs, "fc", PyString_FromString(fc.c_str()));
900 PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str()));
901 PyDict_SetItemString(kwargs, "head_width", PyFloat_FromDouble(head_width));
902 PyDict_SetItemString(kwargs, "head_length", PyFloat_FromDouble(head_length));
903
904 PyObject* plot_args = PyTuple_New(4);
905 PyTuple_SetItem(plot_args, 0, obj_x);
906 PyTuple_SetItem(plot_args, 1, obj_y);
907 PyTuple_SetItem(plot_args, 2, obj_end_x);
908 PyTuple_SetItem(plot_args, 3, obj_end_y);
909
910 PyObject* res =
911 PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs);
912
913 Py_DECREF(plot_args);
914 Py_DECREF(kwargs);
915 if (res)
916 Py_DECREF(res);
917
918 return res;
919}
920
921template <typename Numeric>
922bool hist(const std::vector<Numeric>& y, long bins = 10, std::string color = "b",
923 double alpha = 1.0, bool cumulative = false) {
924 detail::_interpreter::get();
925
926 PyObject* yarray = detail::get_array(y);
927
928 PyObject* kwargs = PyDict_New();
929 PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
930 PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
931 PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
932 PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False);
933
934 PyObject* plot_args = PyTuple_New(1);
935
936 PyTuple_SetItem(plot_args, 0, yarray);
937
938 PyObject* res =
939 PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
940
941 Py_DECREF(plot_args);
942 Py_DECREF(kwargs);
943 if (res)
944 Py_DECREF(res);
945
946 return res;
947}
948
949#ifndef WITHOUT_NUMPY
950namespace detail {
951
952inline void imshow(void* ptr, const NPY_TYPES type, const int rows, const int columns,
953 const int colors, const std::map<std::string, std::string>& keywords,
954 PyObject** out) {
955 assert(type == NPY_UINT8 || type == NPY_FLOAT);
956 assert(colors == 1 || colors == 3 || colors == 4);
957
958 detail::_interpreter::get();
959
960 // construct args
961 npy_intp dims[3] = {rows, columns, colors};
962 PyObject* args = PyTuple_New(1);
963 PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr));
964
965 // construct keyword args
966 PyObject* kwargs = PyDict_New();
967 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
968 it != keywords.end(); ++it) {
969 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
970 }
971
972 PyObject* res =
973 PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs);
974 Py_DECREF(args);
975 Py_DECREF(kwargs);
976 if (!res)
977 throw std::runtime_error("Call to imshow() failed");
978 if (out)
979 *out = res;
980 else
981 Py_DECREF(res);
982}
983
984} // namespace detail
985
986inline void imshow(const unsigned char* ptr, const int rows, const int columns, const int colors,
987 const std::map<std::string, std::string>& keywords = {},
988 PyObject** out = nullptr) {
989 detail::imshow((void*)ptr, NPY_UINT8, rows, columns, colors, keywords, out);
990}
991
992inline void imshow(const float* ptr, const int rows, const int columns, const int colors,
993 const std::map<std::string, std::string>& keywords = {},
994 PyObject** out = nullptr) {
995 detail::imshow((void*)ptr, NPY_FLOAT, rows, columns, colors, keywords, out);
996}
997
998#ifdef WITH_OPENCV
999void imshow(const cv::Mat& image, const std::map<std::string, std::string>& keywords = {}) {
1000 // Convert underlying type of matrix, if needed
1001 cv::Mat image2;
1002 NPY_TYPES npy_type = NPY_UINT8;
1003 switch (image.type() & CV_MAT_DEPTH_MASK) {
1004 case CV_8U:
1005 image2 = image;
1006 break;
1007 case CV_32F:
1008 image2 = image;
1009 npy_type = NPY_FLOAT;
1010 break;
1011 default:
1012 image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels()));
1013 }
1014
1015 // If color image, convert from BGR to RGB
1016 switch (image2.channels()) {
1017 case 3:
1018 cv::cvtColor(image2, image2, CV_BGR2RGB);
1019 break;
1020 case 4:
1021 cv::cvtColor(image2, image2, CV_BGRA2RGBA);
1022 }
1023
1024 detail::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords);
1025}
1026#endif // WITH_OPENCV
1027#endif // WITHOUT_NUMPY
1028
1029template <typename NumericX, typename NumericY>
1030bool scatter(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1031 const double s = 1.0, // The marker size in points**2
1032 const std::map<std::string, std::string>& keywords = {}) {
1033 detail::_interpreter::get();
1034
1035 assert(x.size() == y.size());
1036
1037 PyObject* xarray = detail::get_array(x);
1038 PyObject* yarray = detail::get_array(y);
1039
1040 PyObject* kwargs = PyDict_New();
1041 PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s));
1042 for (const auto& it : keywords) {
1043 PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str()));
1044 }
1045
1046 PyObject* plot_args = PyTuple_New(2);
1047 PyTuple_SetItem(plot_args, 0, xarray);
1048 PyTuple_SetItem(plot_args, 1, yarray);
1049
1050 PyObject* res =
1051 PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs);
1052
1053 Py_DECREF(plot_args);
1054 Py_DECREF(kwargs);
1055 if (res)
1056 Py_DECREF(res);
1057
1058 return res;
1059}
1060
1061template <typename NumericX, typename NumericY, typename NumericColors>
1062bool scatter_colored(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1063 const std::vector<NumericColors>& colors,
1064 const double s = 1.0, // The marker size in points**2
1065 const std::map<std::string, std::string>& keywords = {}) {
1066 detail::_interpreter::get();
1067
1068 assert(x.size() == y.size());
1069
1070 PyObject* xarray = detail::get_array(x);
1071 PyObject* yarray = detail::get_array(y);
1072 PyObject* colors_array = detail::get_array(colors);
1073
1074 PyObject* kwargs = PyDict_New();
1075 PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s));
1076 PyDict_SetItemString(kwargs, "c", colors_array);
1077
1078 for (const auto& it : keywords) {
1079 PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str()));
1080 }
1081
1082 PyObject* plot_args = PyTuple_New(2);
1083 PyTuple_SetItem(plot_args, 0, xarray);
1084 PyTuple_SetItem(plot_args, 1, yarray);
1085
1086 PyObject* res =
1087 PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs);
1088
1089 Py_DECREF(plot_args);
1090 Py_DECREF(kwargs);
1091 if (res)
1092 Py_DECREF(res);
1093
1094 return res;
1095}
1096
1097template <typename NumericX, typename NumericY, typename NumericZ>
1098bool scatter(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1099 const std::vector<NumericZ>& z,
1100 const double s = 1.0, // The marker size in points**2
1101 const std::map<std::string, std::string>& keywords = {}, const long fig_number = 0) {
1102 detail::_interpreter::get();
1103
1104 // Same as with plot_surface: We lazily load the modules here the first time
1105 // this function is called because I'm not sure that we can assume "matplotlib
1106 // installed" implies "mpl_toolkits installed" on all platforms, and we don't
1107 // want to require it for people who don't need 3d plots.
1108 static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
1109 if (!mpl_toolkitsmod) {
1110 detail::_interpreter::get();
1111
1112 PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
1113 PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
1114 if (!mpl_toolkits || !axis3d) {
1115 throw std::runtime_error("couldnt create string");
1116 }
1117
1118 mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
1119 Py_DECREF(mpl_toolkits);
1120 if (!mpl_toolkitsmod) {
1121 throw std::runtime_error("Error loading module mpl_toolkits!");
1122 }
1123
1124 axis3dmod = PyImport_Import(axis3d);
1125 Py_DECREF(axis3d);
1126 if (!axis3dmod) {
1127 throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!");
1128 }
1129 }
1130
1131 assert(x.size() == y.size());
1132 assert(y.size() == z.size());
1133
1134 PyObject* xarray = detail::get_array(x);
1135 PyObject* yarray = detail::get_array(y);
1136 PyObject* zarray = detail::get_array(z);
1137
1138 // construct positional args
1139 PyObject* args = PyTuple_New(3);
1140 PyTuple_SetItem(args, 0, xarray);
1141 PyTuple_SetItem(args, 1, yarray);
1142 PyTuple_SetItem(args, 2, zarray);
1143
1144 // Build up the kw args.
1145 PyObject* kwargs = PyDict_New();
1146
1147 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1148 it != keywords.end(); ++it) {
1149 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1150 }
1151 PyObject* fig_args = PyTuple_New(1);
1152 PyObject* fig = nullptr;
1153 PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number));
1154 PyObject* fig_exists =
1155 PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args);
1156 if (!PyObject_IsTrue(fig_exists)) {
1157 fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure,
1158 detail::_interpreter::get().s_python_empty_tuple);
1159 } else {
1160 fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, fig_args);
1161 }
1162 Py_DECREF(fig_exists);
1163 if (!fig)
1164 throw std::runtime_error("Call to figure() failed.");
1165
1166 PyObject* gca_kwargs = PyDict_New();
1167 PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
1168
1169 PyObject* gca = PyObject_GetAttrString(fig, "gca");
1170 if (!gca)
1171 throw std::runtime_error("No gca");
1172 Py_INCREF(gca);
1173 PyObject* axis =
1174 PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
1175
1176 if (!axis)
1177 throw std::runtime_error("No axis");
1178 Py_INCREF(axis);
1179
1180 Py_DECREF(gca);
1181 Py_DECREF(gca_kwargs);
1182
1183 PyObject* plot3 = PyObject_GetAttrString(axis, "scatter");
1184 if (!plot3)
1185 throw std::runtime_error("No 3D line plot");
1186 Py_INCREF(plot3);
1187 PyObject* res = PyObject_Call(plot3, args, kwargs);
1188 if (!res)
1189 throw std::runtime_error("Failed 3D line plot");
1190 Py_DECREF(plot3);
1191
1192 Py_DECREF(axis);
1193 Py_DECREF(args);
1194 Py_DECREF(kwargs);
1195 Py_DECREF(fig);
1196 if (res)
1197 Py_DECREF(res);
1198 return res;
1199}
1200
1201template <typename Numeric>
1202bool boxplot(const std::vector<std::vector<Numeric>>& data,
1203 const std::vector<std::string>& labels = {},
1204 const std::map<std::string, std::string>& keywords = {}) {
1205 detail::_interpreter::get();
1206
1207 PyObject* listlist = detail::get_listlist(data);
1208 PyObject* args = PyTuple_New(1);
1209 PyTuple_SetItem(args, 0, listlist);
1210
1211 PyObject* kwargs = PyDict_New();
1212
1213 // kwargs needs the labels, if there are (the correct number of) labels
1214 if (!labels.empty() && labels.size() == data.size()) {
1215 PyDict_SetItemString(kwargs, "labels", detail::get_array(labels));
1216 }
1217
1218 // take care of the remaining keywords
1219 for (const auto& it : keywords) {
1220 PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str()));
1221 }
1222
1223 PyObject* res =
1224 PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs);
1225
1226 Py_DECREF(args);
1227 Py_DECREF(kwargs);
1228
1229 if (res)
1230 Py_DECREF(res);
1231
1232 return res;
1233}
1234
1235template <typename Numeric>
1236bool boxplot(const std::vector<Numeric>& data,
1237 const std::map<std::string, std::string>& keywords = {}) {
1238 detail::_interpreter::get();
1239
1240 PyObject* vector = detail::get_array(data);
1241 PyObject* args = PyTuple_New(1);
1242 PyTuple_SetItem(args, 0, vector);
1243
1244 PyObject* kwargs = PyDict_New();
1245 for (const auto& it : keywords) {
1246 PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str()));
1247 }
1248
1249 PyObject* res =
1250 PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs);
1251
1252 Py_DECREF(args);
1253 Py_DECREF(kwargs);
1254
1255 if (res)
1256 Py_DECREF(res);
1257
1258 return res;
1259}
1260
1261template <typename Numeric>
1262bool bar(const std::vector<Numeric>& x, const std::vector<Numeric>& y, std::string ec = "black",
1263 std::string ls = "-", double lw = 1.0,
1264 const std::map<std::string, std::string>& keywords = {}) {
1265 detail::_interpreter::get();
1266
1267 PyObject* xarray = detail::get_array(x);
1268 PyObject* yarray = detail::get_array(y);
1269
1270 PyObject* kwargs = PyDict_New();
1271
1272 PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str()));
1273 PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str()));
1274 PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw));
1275
1276 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1277 it != keywords.end(); ++it) {
1278 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1279 }
1280
1281 PyObject* plot_args = PyTuple_New(2);
1282 PyTuple_SetItem(plot_args, 0, xarray);
1283 PyTuple_SetItem(plot_args, 1, yarray);
1284
1285 PyObject* res =
1286 PyObject_Call(detail::_interpreter::get().s_python_function_bar, plot_args, kwargs);
1287
1288 Py_DECREF(plot_args);
1289 Py_DECREF(kwargs);
1290 if (res)
1291 Py_DECREF(res);
1292
1293 return res;
1294}
1295
1296template <typename Numeric>
1297bool bar(const std::vector<Numeric>& y, std::string ec = "black", std::string ls = "-",
1298 double lw = 1.0, const std::map<std::string, std::string>& keywords = {}) {
1299 using T = typename std::remove_reference<decltype(y)>::type::value_type;
1300
1301 detail::_interpreter::get();
1302
1303 std::vector<T> x;
1304 for (std::size_t i = 0; i < y.size(); i++) {
1305 x.push_back(i);
1306 }
1307
1308 return bar(x, y, ec, ls, lw, keywords);
1309}
1310
1311template <typename Numeric>
1312bool barh(const std::vector<Numeric>& x, const std::vector<Numeric>& y, std::string ec = "black",
1313 std::string ls = "-", double lw = 1.0,
1314 const std::map<std::string, std::string>& keywords = {}) {
1315 PyObject* xarray = detail::get_array(x);
1316 PyObject* yarray = detail::get_array(y);
1317
1318 PyObject* kwargs = PyDict_New();
1319
1320 PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str()));
1321 PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str()));
1322 PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw));
1323
1324 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1325 it != keywords.end(); ++it) {
1326 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1327 }
1328
1329 PyObject* plot_args = PyTuple_New(2);
1330 PyTuple_SetItem(plot_args, 0, xarray);
1331 PyTuple_SetItem(plot_args, 1, yarray);
1332
1333 PyObject* res =
1334 PyObject_Call(detail::_interpreter::get().s_python_function_barh, plot_args, kwargs);
1335
1336 Py_DECREF(plot_args);
1337 Py_DECREF(kwargs);
1338 if (res)
1339 Py_DECREF(res);
1340
1341 return res;
1342}
1343
1344inline bool subplots_adjust(const std::map<std::string, double>& keywords = {}) {
1345 detail::_interpreter::get();
1346
1347 PyObject* kwargs = PyDict_New();
1348 for (std::map<std::string, double>::const_iterator it = keywords.begin(); it != keywords.end();
1349 ++it) {
1350 PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second));
1351 }
1352
1353 PyObject* plot_args = PyTuple_New(0);
1354
1355 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust,
1356 plot_args, kwargs);
1357
1358 Py_DECREF(plot_args);
1359 Py_DECREF(kwargs);
1360 if (res)
1361 Py_DECREF(res);
1362
1363 return res;
1364}
1365
1366template <typename Numeric>
1367bool named_hist(std::string label, const std::vector<Numeric>& y, long bins = 10,
1368 std::string color = "b", double alpha = 1.0) {
1369 detail::_interpreter::get();
1370
1371 PyObject* yarray = detail::get_array(y);
1372
1373 PyObject* kwargs = PyDict_New();
1374 PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
1375 PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
1376 PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
1377 PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
1378
1379 PyObject* plot_args = PyTuple_New(1);
1380 PyTuple_SetItem(plot_args, 0, yarray);
1381
1382 PyObject* res =
1383 PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
1384
1385 Py_DECREF(plot_args);
1386 Py_DECREF(kwargs);
1387 if (res)
1388 Py_DECREF(res);
1389
1390 return res;
1391}
1392
1393template <typename NumericX, typename NumericY>
1394bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1395 const std::string& s = "") {
1396 assert(x.size() == y.size());
1397
1398 detail::_interpreter::get();
1399
1400 PyObject* xarray = detail::get_array(x);
1401 PyObject* yarray = detail::get_array(y);
1402
1403 PyObject* pystring = PyString_FromString(s.c_str());
1404
1405 PyObject* plot_args = PyTuple_New(3);
1406 PyTuple_SetItem(plot_args, 0, xarray);
1407 PyTuple_SetItem(plot_args, 1, yarray);
1408 PyTuple_SetItem(plot_args, 2, pystring);
1409
1410 PyObject* res =
1411 PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
1412
1413 Py_DECREF(plot_args);
1414 if (res)
1415 Py_DECREF(res);
1416
1417 return res;
1418}
1419
1420template <typename NumericX, typename NumericY, typename NumericZ>
1421bool contour(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1422 const std::vector<NumericZ>& z,
1423 const std::map<std::string, std::string>& keywords = {}) {
1424 assert(x.size() == y.size() && x.size() == z.size());
1425
1426 PyObject* xarray = detail::get_array(x);
1427 PyObject* yarray = detail::get_array(y);
1428 PyObject* zarray = detail::get_array(z);
1429
1430 PyObject* plot_args = PyTuple_New(3);
1431 PyTuple_SetItem(plot_args, 0, xarray);
1432 PyTuple_SetItem(plot_args, 1, yarray);
1433 PyTuple_SetItem(plot_args, 2, zarray);
1434
1435 // construct keyword args
1436 PyObject* kwargs = PyDict_New();
1437 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1438 it != keywords.end(); ++it) {
1439 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1440 }
1441
1442 PyObject* res =
1443 PyObject_Call(detail::_interpreter::get().s_python_function_contour, plot_args, kwargs);
1444
1445 Py_DECREF(kwargs);
1446 Py_DECREF(plot_args);
1447 if (res)
1448 Py_DECREF(res);
1449
1450 return res;
1451}
1452
1453template <typename NumericX, typename NumericY, typename NumericU, typename NumericW>
1454bool quiver(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1455 const std::vector<NumericU>& u, const std::vector<NumericW>& w,
1456 const std::map<std::string, std::string>& keywords = {}) {
1457 assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size());
1458
1459 detail::_interpreter::get();
1460
1461 PyObject* xarray = detail::get_array(x);
1462 PyObject* yarray = detail::get_array(y);
1463 PyObject* uarray = detail::get_array(u);
1464 PyObject* warray = detail::get_array(w);
1465
1466 PyObject* plot_args = PyTuple_New(4);
1467 PyTuple_SetItem(plot_args, 0, xarray);
1468 PyTuple_SetItem(plot_args, 1, yarray);
1469 PyTuple_SetItem(plot_args, 2, uarray);
1470 PyTuple_SetItem(plot_args, 3, warray);
1471
1472 // construct keyword args
1473 PyObject* kwargs = PyDict_New();
1474 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1475 it != keywords.end(); ++it) {
1476 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1477 }
1478
1479 PyObject* res =
1480 PyObject_Call(detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs);
1481
1482 Py_DECREF(kwargs);
1483 Py_DECREF(plot_args);
1484 if (res)
1485 Py_DECREF(res);
1486
1487 return res;
1488}
1489
1490template <typename NumericX, typename NumericY, typename NumericZ, typename NumericU,
1491 typename NumericW, typename NumericV>
1492bool quiver(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1493 const std::vector<NumericZ>& z, const std::vector<NumericU>& u,
1494 const std::vector<NumericW>& w, const std::vector<NumericV>& v,
1495 const std::map<std::string, std::string>& keywords = {}) {
1496 // set up 3d axes stuff
1497 static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
1498 if (!mpl_toolkitsmod) {
1499 detail::_interpreter::get();
1500
1501 PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
1502 PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
1503 if (!mpl_toolkits || !axis3d) {
1504 throw std::runtime_error("couldnt create string");
1505 }
1506
1507 mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
1508 Py_DECREF(mpl_toolkits);
1509 if (!mpl_toolkitsmod) {
1510 throw std::runtime_error("Error loading module mpl_toolkits!");
1511 }
1512
1513 axis3dmod = PyImport_Import(axis3d);
1514 Py_DECREF(axis3d);
1515 if (!axis3dmod) {
1516 throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!");
1517 }
1518 }
1519
1520 // assert sizes match up
1521 assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size() &&
1522 x.size() == z.size() && x.size() == v.size() && u.size() == v.size());
1523
1524 // set up parameters
1525 detail::_interpreter::get();
1526
1527 PyObject* xarray = detail::get_array(x);
1528 PyObject* yarray = detail::get_array(y);
1529 PyObject* zarray = detail::get_array(z);
1530 PyObject* uarray = detail::get_array(u);
1531 PyObject* warray = detail::get_array(w);
1532 PyObject* varray = detail::get_array(v);
1533
1534 PyObject* plot_args = PyTuple_New(6);
1535 PyTuple_SetItem(plot_args, 0, xarray);
1536 PyTuple_SetItem(plot_args, 1, yarray);
1537 PyTuple_SetItem(plot_args, 2, zarray);
1538 PyTuple_SetItem(plot_args, 3, uarray);
1539 PyTuple_SetItem(plot_args, 4, warray);
1540 PyTuple_SetItem(plot_args, 5, varray);
1541
1542 // construct keyword args
1543 PyObject* kwargs = PyDict_New();
1544 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1545 it != keywords.end(); ++it) {
1546 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1547 }
1548
1549 // get figure gca to enable 3d projection
1550 PyObject* fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure,
1551 detail::_interpreter::get().s_python_empty_tuple);
1552 if (!fig)
1553 throw std::runtime_error("Call to figure() failed.");
1554
1555 PyObject* gca_kwargs = PyDict_New();
1556 PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
1557
1558 PyObject* gca = PyObject_GetAttrString(fig, "gca");
1559 if (!gca)
1560 throw std::runtime_error("No gca");
1561 Py_INCREF(gca);
1562 PyObject* axis =
1563 PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
1564
1565 if (!axis)
1566 throw std::runtime_error("No axis");
1567 Py_INCREF(axis);
1568 Py_DECREF(gca);
1569 Py_DECREF(gca_kwargs);
1570
1571 // plot our boys bravely, plot them strongly, plot them with a wink and clap
1572 PyObject* plot3 = PyObject_GetAttrString(axis, "quiver");
1573 if (!plot3)
1574 throw std::runtime_error("No 3D line plot");
1575 Py_INCREF(plot3);
1576 PyObject* res = PyObject_Call(plot3, plot_args, kwargs);
1577 if (!res)
1578 throw std::runtime_error("Failed 3D plot");
1579 Py_DECREF(plot3);
1580 Py_DECREF(axis);
1581 Py_DECREF(kwargs);
1582 Py_DECREF(plot_args);
1583 if (res)
1584 Py_DECREF(res);
1585
1586 return res;
1587}
1588
1589template <typename NumericX, typename NumericY>
1590bool stem(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1591 const std::string& s = "") {
1592 assert(x.size() == y.size());
1593
1594 detail::_interpreter::get();
1595
1596 PyObject* xarray = detail::get_array(x);
1597 PyObject* yarray = detail::get_array(y);
1598
1599 PyObject* pystring = PyString_FromString(s.c_str());
1600
1601 PyObject* plot_args = PyTuple_New(3);
1602 PyTuple_SetItem(plot_args, 0, xarray);
1603 PyTuple_SetItem(plot_args, 1, yarray);
1604 PyTuple_SetItem(plot_args, 2, pystring);
1605
1606 PyObject* res =
1607 PyObject_CallObject(detail::_interpreter::get().s_python_function_stem, plot_args);
1608
1609 Py_DECREF(plot_args);
1610 if (res)
1611 Py_DECREF(res);
1612
1613 return res;
1614}
1615
1616template <typename NumericX, typename NumericY>
1617bool semilogx(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1618 const std::string& s = "") {
1619 assert(x.size() == y.size());
1620
1621 detail::_interpreter::get();
1622
1623 PyObject* xarray = detail::get_array(x);
1624 PyObject* yarray = detail::get_array(y);
1625
1626 PyObject* pystring = PyString_FromString(s.c_str());
1627
1628 PyObject* plot_args = PyTuple_New(3);
1629 PyTuple_SetItem(plot_args, 0, xarray);
1630 PyTuple_SetItem(plot_args, 1, yarray);
1631 PyTuple_SetItem(plot_args, 2, pystring);
1632
1633 PyObject* res =
1634 PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args);
1635
1636 Py_DECREF(plot_args);
1637 if (res)
1638 Py_DECREF(res);
1639
1640 return res;
1641}
1642
1643template <typename NumericX, typename NumericY>
1644bool semilogy(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1645 const std::string& s = "") {
1646 assert(x.size() == y.size());
1647
1648 detail::_interpreter::get();
1649
1650 PyObject* xarray = detail::get_array(x);
1651 PyObject* yarray = detail::get_array(y);
1652
1653 PyObject* pystring = PyString_FromString(s.c_str());
1654
1655 PyObject* plot_args = PyTuple_New(3);
1656 PyTuple_SetItem(plot_args, 0, xarray);
1657 PyTuple_SetItem(plot_args, 1, yarray);
1658 PyTuple_SetItem(plot_args, 2, pystring);
1659
1660 PyObject* res =
1661 PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args);
1662
1663 Py_DECREF(plot_args);
1664 if (res)
1665 Py_DECREF(res);
1666
1667 return res;
1668}
1669
1670template <typename NumericX, typename NumericY>
1671bool loglog(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1672 const std::string& s = "") {
1673 assert(x.size() == y.size());
1674
1675 detail::_interpreter::get();
1676
1677 PyObject* xarray = detail::get_array(x);
1678 PyObject* yarray = detail::get_array(y);
1679
1680 PyObject* pystring = PyString_FromString(s.c_str());
1681
1682 PyObject* plot_args = PyTuple_New(3);
1683 PyTuple_SetItem(plot_args, 0, xarray);
1684 PyTuple_SetItem(plot_args, 1, yarray);
1685 PyTuple_SetItem(plot_args, 2, pystring);
1686
1687 PyObject* res =
1688 PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args);
1689
1690 Py_DECREF(plot_args);
1691 if (res)
1692 Py_DECREF(res);
1693
1694 return res;
1695}
1696
1697template <typename NumericX, typename NumericY>
1698bool errorbar(const std::vector<NumericX>& x, const std::vector<NumericY>& y,
1699 const std::vector<NumericX>& yerr,
1700 const std::map<std::string, std::string>& keywords = {}) {
1701 assert(x.size() == y.size());
1702
1703 detail::_interpreter::get();
1704
1705 PyObject* xarray = detail::get_array(x);
1706 PyObject* yarray = detail::get_array(y);
1707 PyObject* yerrarray = detail::get_array(yerr);
1708
1709 // construct keyword args
1710 PyObject* kwargs = PyDict_New();
1711 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1712 it != keywords.end(); ++it) {
1713 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1714 }
1715
1716 PyDict_SetItemString(kwargs, "yerr", yerrarray);
1717
1718 PyObject* plot_args = PyTuple_New(2);
1719 PyTuple_SetItem(plot_args, 0, xarray);
1720 PyTuple_SetItem(plot_args, 1, yarray);
1721
1722 PyObject* res =
1723 PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs);
1724
1725 Py_DECREF(kwargs);
1726 Py_DECREF(plot_args);
1727
1728 if (res)
1729 Py_DECREF(res);
1730 else
1731 throw std::runtime_error("Call to errorbar() failed.");
1732
1733 return res;
1734}
1735
1736template <typename Numeric>
1737bool named_plot(const std::string& name, const std::vector<Numeric>& y,
1738 const std::string& format = "") {
1739 detail::_interpreter::get();
1740
1741 PyObject* kwargs = PyDict_New();
1742 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1743
1744 PyObject* yarray = detail::get_array(y);
1745
1746 PyObject* pystring = PyString_FromString(format.c_str());
1747
1748 PyObject* plot_args = PyTuple_New(2);
1749
1750 PyTuple_SetItem(plot_args, 0, yarray);
1751 PyTuple_SetItem(plot_args, 1, pystring);
1752
1753 PyObject* res =
1754 PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
1755
1756 Py_DECREF(kwargs);
1757 Py_DECREF(plot_args);
1758 if (res)
1759 Py_DECREF(res);
1760
1761 return res;
1762}
1763
1764template <typename NumericX, typename NumericY>
1765bool named_plot(const std::string& name, const std::vector<NumericX>& x,
1766 const std::vector<NumericY>& y, const std::string& format = "") {
1767 detail::_interpreter::get();
1768
1769 PyObject* kwargs = PyDict_New();
1770 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1771
1772 PyObject* xarray = detail::get_array(x);
1773 PyObject* yarray = detail::get_array(y);
1774
1775 PyObject* pystring = PyString_FromString(format.c_str());
1776
1777 PyObject* plot_args = PyTuple_New(3);
1778 PyTuple_SetItem(plot_args, 0, xarray);
1779 PyTuple_SetItem(plot_args, 1, yarray);
1780 PyTuple_SetItem(plot_args, 2, pystring);
1781
1782 PyObject* res =
1783 PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
1784
1785 Py_DECREF(kwargs);
1786 Py_DECREF(plot_args);
1787 if (res)
1788 Py_DECREF(res);
1789
1790 return res;
1791}
1792
1793template <typename NumericX, typename NumericY>
1794bool named_semilogx(const std::string& name, const std::vector<NumericX>& x,
1795 const std::vector<NumericY>& y, const std::string& format = "") {
1796 detail::_interpreter::get();
1797
1798 PyObject* kwargs = PyDict_New();
1799 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1800
1801 PyObject* xarray = detail::get_array(x);
1802 PyObject* yarray = detail::get_array(y);
1803
1804 PyObject* pystring = PyString_FromString(format.c_str());
1805
1806 PyObject* plot_args = PyTuple_New(3);
1807 PyTuple_SetItem(plot_args, 0, xarray);
1808 PyTuple_SetItem(plot_args, 1, yarray);
1809 PyTuple_SetItem(plot_args, 2, pystring);
1810
1811 PyObject* res =
1812 PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs);
1813
1814 Py_DECREF(kwargs);
1815 Py_DECREF(plot_args);
1816 if (res)
1817 Py_DECREF(res);
1818
1819 return res;
1820}
1821
1822template <typename NumericX, typename NumericY>
1823bool named_semilogy(const std::string& name, const std::vector<NumericX>& x,
1824 const std::vector<NumericY>& y, const std::string& format = "") {
1825 detail::_interpreter::get();
1826
1827 PyObject* kwargs = PyDict_New();
1828 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1829
1830 PyObject* xarray = detail::get_array(x);
1831 PyObject* yarray = detail::get_array(y);
1832
1833 PyObject* pystring = PyString_FromString(format.c_str());
1834
1835 PyObject* plot_args = PyTuple_New(3);
1836 PyTuple_SetItem(plot_args, 0, xarray);
1837 PyTuple_SetItem(plot_args, 1, yarray);
1838 PyTuple_SetItem(plot_args, 2, pystring);
1839
1840 PyObject* res =
1841 PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs);
1842
1843 Py_DECREF(kwargs);
1844 Py_DECREF(plot_args);
1845 if (res)
1846 Py_DECREF(res);
1847
1848 return res;
1849}
1850
1851template <typename NumericX, typename NumericY>
1852bool named_loglog(const std::string& name, const std::vector<NumericX>& x,
1853 const std::vector<NumericY>& y, const std::string& format = "") {
1854 detail::_interpreter::get();
1855
1856 PyObject* kwargs = PyDict_New();
1857 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1858
1859 PyObject* xarray = detail::get_array(x);
1860 PyObject* yarray = detail::get_array(y);
1861
1862 PyObject* pystring = PyString_FromString(format.c_str());
1863
1864 PyObject* plot_args = PyTuple_New(3);
1865 PyTuple_SetItem(plot_args, 0, xarray);
1866 PyTuple_SetItem(plot_args, 1, yarray);
1867 PyTuple_SetItem(plot_args, 2, pystring);
1868 PyObject* res =
1869 PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs);
1870
1871 Py_DECREF(kwargs);
1872 Py_DECREF(plot_args);
1873 if (res)
1874 Py_DECREF(res);
1875
1876 return res;
1877}
1878
1879template <typename Numeric>
1880bool plot(const std::vector<Numeric>& y, const std::string& format = "") {
1881 std::vector<Numeric> x(y.size());
1882 for (size_t i = 0; i < x.size(); ++i)
1883 x.at(i) = i;
1884 return plot(x, y, format);
1885}
1886
1887template <typename Numeric>
1888bool plot(const std::vector<Numeric>& y, const std::map<std::string, std::string>& keywords) {
1889 std::vector<Numeric> x(y.size());
1890 for (size_t i = 0; i < x.size(); ++i)
1891 x.at(i) = i;
1892 return plot(x, y, keywords);
1893}
1894
1895template <typename Numeric>
1896bool stem(const std::vector<Numeric>& y, const std::string& format = "") {
1897 std::vector<Numeric> x(y.size());
1898 for (size_t i = 0; i < x.size(); ++i)
1899 x.at(i) = i;
1900 return stem(x, y, format);
1901}
1902
1903template <typename Numeric> void text(Numeric x, Numeric y, const std::string& s = "") {
1904 detail::_interpreter::get();
1905
1906 PyObject* args = PyTuple_New(3);
1907 PyTuple_SetItem(args, 0, PyFloat_FromDouble(x));
1908 PyTuple_SetItem(args, 1, PyFloat_FromDouble(y));
1909 PyTuple_SetItem(args, 2, PyString_FromString(s.c_str()));
1910
1911 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args);
1912 if (!res)
1913 throw std::runtime_error("Call to text() failed.");
1914
1915 Py_DECREF(args);
1916 Py_DECREF(res);
1917}
1918
1919inline void colorbar(PyObject* mappable = NULL, const std::map<std::string, float>& keywords = {}) {
1920 if (mappable == NULL)
1921 throw std::runtime_error("Must call colorbar with PyObject* returned from "
1922 "an image, contour, surface, etc.");
1923
1924 detail::_interpreter::get();
1925
1926 PyObject* args = PyTuple_New(1);
1927 PyTuple_SetItem(args, 0, mappable);
1928
1929 PyObject* kwargs = PyDict_New();
1930 for (std::map<std::string, float>::const_iterator it = keywords.begin(); it != keywords.end();
1931 ++it) {
1932 PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second));
1933 }
1934
1935 PyObject* res =
1936 PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs);
1937 if (!res)
1938 throw std::runtime_error("Call to colorbar() failed.");
1939
1940 Py_DECREF(args);
1941 Py_DECREF(kwargs);
1942 Py_DECREF(res);
1943}
1944
1945inline long figure(long number = -1) {
1946 detail::_interpreter::get();
1947
1948 PyObject* res;
1949 if (number == -1)
1950 res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure,
1951 detail::_interpreter::get().s_python_empty_tuple);
1952 else {
1953 assert(number > 0);
1954
1955 // Make sure interpreter is initialised
1956 detail::_interpreter::get();
1957
1958 PyObject* args = PyTuple_New(1);
1959 PyTuple_SetItem(args, 0, PyLong_FromLong(number));
1960 res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args);
1961 Py_DECREF(args);
1962 }
1963
1964 if (!res)
1965 throw std::runtime_error("Call to figure() failed.");
1966
1967 PyObject* num = PyObject_GetAttrString(res, "number");
1968 if (!num)
1969 throw std::runtime_error("Could not get number attribute of figure object");
1970 const long figureNumber = PyLong_AsLong(num);
1971
1972 Py_DECREF(num);
1973 Py_DECREF(res);
1974
1975 return figureNumber;
1976}
1977
1978inline bool fignum_exists(long number) {
1979 detail::_interpreter::get();
1980
1981 PyObject* args = PyTuple_New(1);
1982 PyTuple_SetItem(args, 0, PyLong_FromLong(number));
1983 PyObject* res =
1984 PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, args);
1985 if (!res)
1986 throw std::runtime_error("Call to fignum_exists() failed.");
1987
1988 bool ret = PyObject_IsTrue(res);
1989 Py_DECREF(res);
1990 Py_DECREF(args);
1991
1992 return ret;
1993}
1994
1995inline void figure_size(size_t w, size_t h) {
1996 detail::_interpreter::get();
1997
1998 const size_t dpi = 100;
1999 PyObject* size = PyTuple_New(2);
2000 PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi));
2001 PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi));
2002
2003 PyObject* kwargs = PyDict_New();
2004 PyDict_SetItemString(kwargs, "figsize", size);
2005 PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi));
2006
2007 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure,
2008 detail::_interpreter::get().s_python_empty_tuple, kwargs);
2009
2010 Py_DECREF(kwargs);
2011
2012 if (!res)
2013 throw std::runtime_error("Call to figure_size() failed.");
2014 Py_DECREF(res);
2015}
2016
2017inline void legend() {
2018 detail::_interpreter::get();
2019
2020 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend,
2021 detail::_interpreter::get().s_python_empty_tuple);
2022 if (!res)
2023 throw std::runtime_error("Call to legend() failed.");
2024
2025 Py_DECREF(res);
2026}
2027
2028inline void legend(const std::map<std::string, std::string>& keywords) {
2029 detail::_interpreter::get();
2030
2031 // construct keyword args
2032 PyObject* kwargs = PyDict_New();
2033 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
2034 it != keywords.end(); ++it) {
2035 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
2036 }
2037
2038 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend,
2039 detail::_interpreter::get().s_python_empty_tuple, kwargs);
2040 if (!res)
2041 throw std::runtime_error("Call to legend() failed.");
2042
2043 Py_DECREF(kwargs);
2044 Py_DECREF(res);
2045}
2046
2047template <typename Numeric> inline void set_aspect(Numeric ratio) {
2048 detail::_interpreter::get();
2049
2050 PyObject* args = PyTuple_New(1);
2051 PyTuple_SetItem(args, 0, PyFloat_FromDouble(ratio));
2052 PyObject* kwargs = PyDict_New();
2053
2054 PyObject* ax = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca,
2055 detail::_interpreter::get().s_python_empty_tuple);
2056 if (!ax)
2057 throw std::runtime_error("Call to gca() failed.");
2058 Py_INCREF(ax);
2059
2060 PyObject* set_aspect = PyObject_GetAttrString(ax, "set_aspect");
2061 if (!set_aspect)
2062 throw std::runtime_error("Attribute set_aspect not found.");
2063 Py_INCREF(set_aspect);
2064
2065 PyObject* res = PyObject_Call(set_aspect, args, kwargs);
2066 if (!res)
2067 throw std::runtime_error("Call to set_aspect() failed.");
2068 Py_DECREF(set_aspect);
2069
2070 Py_DECREF(ax);
2071 Py_DECREF(args);
2072 Py_DECREF(kwargs);
2073}
2074
2075inline void set_aspect_equal() {
2076 // expect ratio == "equal". Leaving error handling to matplotlib.
2077 detail::_interpreter::get();
2078
2079 PyObject* args = PyTuple_New(1);
2080 PyTuple_SetItem(args, 0, PyString_FromString("equal"));
2081 PyObject* kwargs = PyDict_New();
2082
2083 PyObject* ax = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca,
2084 detail::_interpreter::get().s_python_empty_tuple);
2085 if (!ax)
2086 throw std::runtime_error("Call to gca() failed.");
2087 Py_INCREF(ax);
2088
2089 PyObject* set_aspect = PyObject_GetAttrString(ax, "set_aspect");
2090 if (!set_aspect)
2091 throw std::runtime_error("Attribute set_aspect not found.");
2092 Py_INCREF(set_aspect);
2093
2094 PyObject* res = PyObject_Call(set_aspect, args, kwargs);
2095 if (!res)
2096 throw std::runtime_error("Call to set_aspect() failed.");
2097 Py_DECREF(set_aspect);
2098
2099 Py_DECREF(ax);
2100 Py_DECREF(args);
2101 Py_DECREF(kwargs);
2102}
2103
2104template <typename Numeric> void ylim(Numeric left, Numeric right) {
2105 detail::_interpreter::get();
2106
2107 PyObject* list = PyList_New(2);
2108 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
2109 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
2110
2111 PyObject* args = PyTuple_New(1);
2112 PyTuple_SetItem(args, 0, list);
2113
2114 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
2115 if (!res)
2116 throw std::runtime_error("Call to ylim() failed.");
2117
2118 Py_DECREF(args);
2119 Py_DECREF(res);
2120}
2121
2122template <typename Numeric> void xlim(Numeric left, Numeric right) {
2123 detail::_interpreter::get();
2124
2125 PyObject* list = PyList_New(2);
2126 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
2127 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
2128
2129 PyObject* args = PyTuple_New(1);
2130 PyTuple_SetItem(args, 0, list);
2131
2132 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
2133 if (!res)
2134 throw std::runtime_error("Call to xlim() failed.");
2135
2136 Py_DECREF(args);
2137 Py_DECREF(res);
2138}
2139
2140inline std::array<double, 2> xlim() {
2141 PyObject* args = PyTuple_New(0);
2142 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
2143
2144 if (!res)
2145 throw std::runtime_error("Call to xlim() failed.");
2146
2147 Py_DECREF(res);
2148
2149 PyObject* left = PyTuple_GetItem(res, 0);
2150 PyObject* right = PyTuple_GetItem(res, 1);
2151 return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)};
2152}
2153
2154inline std::array<double, 2> ylim() {
2155 PyObject* args = PyTuple_New(0);
2156 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
2157
2158 if (!res)
2159 throw std::runtime_error("Call to ylim() failed.");
2160
2161 Py_DECREF(res);
2162
2163 PyObject* left = PyTuple_GetItem(res, 0);
2164 PyObject* right = PyTuple_GetItem(res, 1);
2165 return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)};
2166}
2167
2168template <typename Numeric>
2169inline void xticks(const std::vector<Numeric>& ticks, const std::vector<std::string>& labels = {},
2170 const std::map<std::string, std::string>& keywords = {}) {
2171 assert(labels.size() == 0 || ticks.size() == labels.size());
2172
2173 detail::_interpreter::get();
2174
2175 // using numpy array
2176 PyObject* ticksarray = detail::get_array(ticks);
2177
2178 PyObject* args;
2179 if (labels.size() == 0) {
2180 // construct positional args
2181 args = PyTuple_New(1);
2182 PyTuple_SetItem(args, 0, ticksarray);
2183 } else {
2184 // make tuple of tick labels
2185 PyObject* labelstuple = PyTuple_New(labels.size());
2186 for (size_t i = 0; i < labels.size(); i++)
2187 PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str()));
2188
2189 // construct positional args
2190 args = PyTuple_New(2);
2191 PyTuple_SetItem(args, 0, ticksarray);
2192 PyTuple_SetItem(args, 1, labelstuple);
2193 }
2194
2195 // construct keyword args
2196 PyObject* kwargs = PyDict_New();
2197 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
2198 it != keywords.end(); ++it) {
2199 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
2200 }
2201
2202 PyObject* res =
2203 PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs);
2204
2205 Py_DECREF(args);
2206 Py_DECREF(kwargs);
2207 if (!res)
2208 throw std::runtime_error("Call to xticks() failed");
2209
2210 Py_DECREF(res);
2211}
2212
2213template <typename Numeric>
2214inline void xticks(const std::vector<Numeric>& ticks,
2215 const std::map<std::string, std::string>& keywords) {
2216 xticks(ticks, {}, keywords);
2217}
2218
2219template <typename Numeric>
2220inline void yticks(const std::vector<Numeric>& ticks, const std::vector<std::string>& labels = {},
2221 const std::map<std::string, std::string>& keywords = {}) {
2222 assert(labels.size() == 0 || ticks.size() == labels.size());
2223
2224 detail::_interpreter::get();
2225
2226 // using numpy array
2227 PyObject* ticksarray = detail::get_array(ticks);
2228
2229 PyObject* args;
2230 if (labels.size() == 0) {
2231 // construct positional args
2232 args = PyTuple_New(1);
2233 PyTuple_SetItem(args, 0, ticksarray);
2234 } else {
2235 // make tuple of tick labels
2236 PyObject* labelstuple = PyTuple_New(labels.size());
2237 for (size_t i = 0; i < labels.size(); i++)
2238 PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str()));
2239
2240 // construct positional args
2241 args = PyTuple_New(2);
2242 PyTuple_SetItem(args, 0, ticksarray);
2243 PyTuple_SetItem(args, 1, labelstuple);
2244 }
2245
2246 // construct keyword args
2247 PyObject* kwargs = PyDict_New();
2248 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
2249 it != keywords.end(); ++it) {
2250 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
2251 }
2252
2253 PyObject* res =
2254 PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs);
2255
2256 Py_DECREF(args);
2257 Py_DECREF(kwargs);
2258 if (!res)
2259 throw std::runtime_error("Call to yticks() failed");
2260
2261 Py_DECREF(res);
2262}
2263
2264template <typename Numeric>
2265inline void yticks(const std::vector<Numeric>& ticks,
2266 const std::map<std::string, std::string>& keywords) {
2267 yticks(ticks, {}, keywords);
2268}
2269
2270template <typename Numeric> inline void margins(Numeric margin) {
2271 // construct positional args
2272 PyObject* args = PyTuple_New(1);
2273 PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin));
2274
2275 PyObject* res =
2276 PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args);
2277 if (!res)
2278 throw std::runtime_error("Call to margins() failed.");
2279
2280 Py_DECREF(args);
2281 Py_DECREF(res);
2282}
2283
2284template <typename Numeric> inline void margins(Numeric margin_x, Numeric margin_y) {
2285 // construct positional args
2286 PyObject* args = PyTuple_New(2);
2287 PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin_x));
2288 PyTuple_SetItem(args, 1, PyFloat_FromDouble(margin_y));
2289
2290 PyObject* res =
2291 PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args);
2292 if (!res)
2293 throw std::runtime_error("Call to margins() failed.");
2294
2295 Py_DECREF(args);
2296 Py_DECREF(res);
2297}
2298
2299inline void tick_params(const std::map<std::string, std::string>& keywords,
2300 const std::string axis = "both") {
2301 detail::_interpreter::get();
2302
2303 // construct positional args
2304 PyObject* args;
2305 args = PyTuple_New(1);
2306 PyTuple_SetItem(args, 0, PyString_FromString(axis.c_str()));
2307
2308 // construct keyword args
2309 PyObject* kwargs = PyDict_New();
2310 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
2311 it != keywords.end(); ++it) {
2312 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
2313 }
2314
2315 PyObject* res =
2316 PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs);
2317
2318 Py_DECREF(args);
2319 Py_DECREF(kwargs);
2320 if (!res)
2321 throw std::runtime_error("Call to tick_params() failed");
2322
2323 Py_DECREF(res);
2324}
2325
2326inline void subplot(long nrows, long ncols, long plot_number) {
2327 detail::_interpreter::get();
2328
2329 // construct positional args
2330 PyObject* args = PyTuple_New(3);
2331 PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
2332 PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
2333 PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));
2334
2335 PyObject* res =
2336 PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
2337 if (!res)
2338 throw std::runtime_error("Call to subplot() failed.");
2339
2340 Py_DECREF(args);
2341 Py_DECREF(res);
2342}
2343
2344inline void subplot2grid(long nrows, long ncols, long rowid = 0, long colid = 0, long rowspan = 1,
2345 long colspan = 1) {
2346 detail::_interpreter::get();
2347
2348 PyObject* shape = PyTuple_New(2);
2349 PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows));
2350 PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols));
2351
2352 PyObject* loc = PyTuple_New(2);
2353 PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid));
2354 PyTuple_SetItem(loc, 1, PyLong_FromLong(colid));
2355
2356 PyObject* args = PyTuple_New(4);
2357 PyTuple_SetItem(args, 0, shape);
2358 PyTuple_SetItem(args, 1, loc);
2359 PyTuple_SetItem(args, 2, PyLong_FromLong(rowspan));
2360 PyTuple_SetItem(args, 3, PyLong_FromLong(colspan));
2361
2362 PyObject* res =
2363 PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot2grid, args);
2364 if (!res)
2365 throw std::runtime_error("Call to subplot2grid() failed.");
2366
2367 Py_DECREF(shape);
2368 Py_DECREF(loc);
2369 Py_DECREF(args);
2370 Py_DECREF(res);
2371}
2372
2373inline void title(const std::string& titlestr,
2374 const std::map<std::string, std::string>& keywords = {}) {
2375 detail::_interpreter::get();
2376
2377 PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
2378 PyObject* args = PyTuple_New(1);
2379 PyTuple_SetItem(args, 0, pytitlestr);
2380
2381 PyObject* kwargs = PyDict_New();
2382 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2383 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
2384 }
2385
2386 PyObject* res =
2387 PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs);
2388 if (!res)
2389 throw std::runtime_error("Call to title() failed.");
2390
2391 Py_DECREF(args);
2392 Py_DECREF(kwargs);
2393 Py_DECREF(res);
2394}
2395
2396inline void suptitle(const std::string& suptitlestr,
2397 const std::map<std::string, std::string>& keywords = {}) {
2398 detail::_interpreter::get();
2399
2400 PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str());
2401 PyObject* args = PyTuple_New(1);
2402 PyTuple_SetItem(args, 0, pysuptitlestr);
2403
2404 PyObject* kwargs = PyDict_New();
2405 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2406 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
2407 }
2408
2409 PyObject* res =
2410 PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs);
2411 if (!res)
2412 throw std::runtime_error("Call to suptitle() failed.");
2413
2414 Py_DECREF(args);
2415 Py_DECREF(kwargs);
2416 Py_DECREF(res);
2417}
2418
2419inline void axis(const std::string& axisstr) {
2420 detail::_interpreter::get();
2421
2422 PyObject* str = PyString_FromString(axisstr.c_str());
2423 PyObject* args = PyTuple_New(1);
2424 PyTuple_SetItem(args, 0, str);
2425
2426 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args);
2427 if (!res)
2428 throw std::runtime_error("Call to title() failed.");
2429
2430 Py_DECREF(args);
2431 Py_DECREF(res);
2432}
2433
2434inline void
2435axhline(double y, double xmin = 0., double xmax = 1.,
2436 const std::map<std::string, std::string>& keywords = std::map<std::string, std::string>()) {
2437 detail::_interpreter::get();
2438
2439 // construct positional args
2440 PyObject* args = PyTuple_New(3);
2441 PyTuple_SetItem(args, 0, PyFloat_FromDouble(y));
2442 PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmin));
2443 PyTuple_SetItem(args, 2, PyFloat_FromDouble(xmax));
2444
2445 // construct keyword args
2446 PyObject* kwargs = PyDict_New();
2447 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
2448 it != keywords.end(); ++it) {
2449 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
2450 }
2451
2452 PyObject* res =
2453 PyObject_Call(detail::_interpreter::get().s_python_function_axhline, args, kwargs);
2454
2455 Py_DECREF(args);
2456 Py_DECREF(kwargs);
2457
2458 if (res)
2459 Py_DECREF(res);
2460}
2461
2462inline void
2463axvline(double x, double ymin = 0., double ymax = 1.,
2464 const std::map<std::string, std::string>& keywords = std::map<std::string, std::string>()) {
2465 detail::_interpreter::get();
2466
2467 // construct positional args
2468 PyObject* args = PyTuple_New(3);
2469 PyTuple_SetItem(args, 0, PyFloat_FromDouble(x));
2470 PyTuple_SetItem(args, 1, PyFloat_FromDouble(ymin));
2471 PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymax));
2472
2473 // construct keyword args
2474 PyObject* kwargs = PyDict_New();
2475 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
2476 it != keywords.end(); ++it) {
2477 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
2478 }
2479
2480 PyObject* res =
2481 PyObject_Call(detail::_interpreter::get().s_python_function_axvline, args, kwargs);
2482
2483 Py_DECREF(args);
2484 Py_DECREF(kwargs);
2485
2486 if (res)
2487 Py_DECREF(res);
2488}
2489
2490inline void
2491axvspan(double xmin, double xmax, double ymin = 0., double ymax = 1.,
2492 const std::map<std::string, std::string>& keywords = std::map<std::string, std::string>()) {
2493 // construct positional args
2494 PyObject* args = PyTuple_New(4);
2495 PyTuple_SetItem(args, 0, PyFloat_FromDouble(xmin));
2496 PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmax));
2497 PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymin));
2498 PyTuple_SetItem(args, 3, PyFloat_FromDouble(ymax));
2499
2500 // construct keyword args
2501 PyObject* kwargs = PyDict_New();
2502 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2503 if (it->first == "linewidth" || it->first == "alpha") {
2504 PyDict_SetItemString(kwargs, it->first.c_str(),
2505 PyFloat_FromDouble(std::stod(it->second)));
2506 } else {
2507 PyDict_SetItemString(kwargs, it->first.c_str(),
2508 PyString_FromString(it->second.c_str()));
2509 }
2510 }
2511
2512 PyObject* res =
2513 PyObject_Call(detail::_interpreter::get().s_python_function_axvspan, args, kwargs);
2514 Py_DECREF(args);
2515 Py_DECREF(kwargs);
2516
2517 if (res)
2518 Py_DECREF(res);
2519}
2520
2521inline void xlabel(const std::string& str,
2522 const std::map<std::string, std::string>& keywords = {}) {
2523 detail::_interpreter::get();
2524
2525 PyObject* pystr = PyString_FromString(str.c_str());
2526 PyObject* args = PyTuple_New(1);
2527 PyTuple_SetItem(args, 0, pystr);
2528
2529 PyObject* kwargs = PyDict_New();
2530 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2531 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
2532 }
2533
2534 PyObject* res =
2535 PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs);
2536 if (!res)
2537 throw std::runtime_error("Call to xlabel() failed.");
2538
2539 Py_DECREF(args);
2540 Py_DECREF(kwargs);
2541 Py_DECREF(res);
2542}
2543
2544inline void ylabel(const std::string& str,
2545 const std::map<std::string, std::string>& keywords = {}) {
2546 detail::_interpreter::get();
2547
2548 PyObject* pystr = PyString_FromString(str.c_str());
2549 PyObject* args = PyTuple_New(1);
2550 PyTuple_SetItem(args, 0, pystr);
2551
2552 PyObject* kwargs = PyDict_New();
2553 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2554 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
2555 }
2556
2557 PyObject* res =
2558 PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs);
2559 if (!res)
2560 throw std::runtime_error("Call to ylabel() failed.");
2561
2562 Py_DECREF(args);
2563 Py_DECREF(kwargs);
2564 Py_DECREF(res);
2565}
2566
2567inline void set_zlabel(const std::string& str,
2568 const std::map<std::string, std::string>& keywords = {}) {
2569 detail::_interpreter::get();
2570
2571 // Same as with plot_surface: We lazily load the modules here the first time
2572 // this function is called because I'm not sure that we can assume "matplotlib
2573 // installed" implies "mpl_toolkits installed" on all platforms, and we don't
2574 // want to require it for people who don't need 3d plots.
2575 static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
2576 if (!mpl_toolkitsmod) {
2577 PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
2578 PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
2579 if (!mpl_toolkits || !axis3d) {
2580 throw std::runtime_error("couldnt create string");
2581 }
2582
2583 mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
2584 Py_DECREF(mpl_toolkits);
2585 if (!mpl_toolkitsmod) {
2586 throw std::runtime_error("Error loading module mpl_toolkits!");
2587 }
2588
2589 axis3dmod = PyImport_Import(axis3d);
2590 Py_DECREF(axis3d);
2591 if (!axis3dmod) {
2592 throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!");
2593 }
2594 }
2595
2596 PyObject* pystr = PyString_FromString(str.c_str());
2597 PyObject* args = PyTuple_New(1);
2598 PyTuple_SetItem(args, 0, pystr);
2599
2600 PyObject* kwargs = PyDict_New();
2601 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2602 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
2603 }
2604
2605 PyObject* ax = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca,
2606 detail::_interpreter::get().s_python_empty_tuple);
2607 if (!ax)
2608 throw std::runtime_error("Call to gca() failed.");
2609 Py_INCREF(ax);
2610
2611 PyObject* zlabel = PyObject_GetAttrString(ax, "set_zlabel");
2612 if (!zlabel)
2613 throw std::runtime_error("Attribute set_zlabel not found.");
2614 Py_INCREF(zlabel);
2615
2616 PyObject* res = PyObject_Call(zlabel, args, kwargs);
2617 if (!res)
2618 throw std::runtime_error("Call to set_zlabel() failed.");
2619 Py_DECREF(zlabel);
2620
2621 Py_DECREF(ax);
2622 Py_DECREF(args);
2623 Py_DECREF(kwargs);
2624 if (res)
2625 Py_DECREF(res);
2626}
2627
2628inline void grid(bool flag) {
2629 detail::_interpreter::get();
2630
2631 PyObject* pyflag = flag ? Py_True : Py_False;
2632 Py_INCREF(pyflag);
2633
2634 PyObject* args = PyTuple_New(1);
2635 PyTuple_SetItem(args, 0, pyflag);
2636
2637 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
2638 if (!res)
2639 throw std::runtime_error("Call to grid() failed.");
2640
2641 Py_DECREF(args);
2642 Py_DECREF(res);
2643}
2644
2645inline void show(const bool block = true) {
2646 detail::_interpreter::get();
2647
2648 PyObject* res;
2649 if (block) {
2650 res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show,
2651 detail::_interpreter::get().s_python_empty_tuple);
2652 } else {
2653 PyObject* kwargs = PyDict_New();
2654 PyDict_SetItemString(kwargs, "block", Py_False);
2655 res = PyObject_Call(detail::_interpreter::get().s_python_function_show,
2656 detail::_interpreter::get().s_python_empty_tuple, kwargs);
2657 Py_DECREF(kwargs);
2658 }
2659
2660 if (!res)
2661 throw std::runtime_error("Call to show() failed.");
2662
2663 Py_DECREF(res);
2664}
2665
2666inline void close() {
2667 detail::_interpreter::get();
2668
2669 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_close,
2670 detail::_interpreter::get().s_python_empty_tuple);
2671
2672 if (!res)
2673 throw std::runtime_error("Call to close() failed.");
2674
2675 Py_DECREF(res);
2676}
2677
2678inline void xkcd() {
2679 detail::_interpreter::get();
2680
2681 PyObject* res;
2682 PyObject* kwargs = PyDict_New();
2683
2684 res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd,
2685 detail::_interpreter::get().s_python_empty_tuple, kwargs);
2686
2687 Py_DECREF(kwargs);
2688
2689 if (!res)
2690 throw std::runtime_error("Call to show() failed.");
2691
2692 Py_DECREF(res);
2693}
2694
2695inline void draw() {
2696 detail::_interpreter::get();
2697
2698 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_draw,
2699 detail::_interpreter::get().s_python_empty_tuple);
2700
2701 if (!res)
2702 throw std::runtime_error("Call to draw() failed.");
2703
2704 Py_DECREF(res);
2705}
2706
2707template <typename Numeric> inline void pause(Numeric interval) {
2708 detail::_interpreter::get();
2709
2710 PyObject* args = PyTuple_New(1);
2711 PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval));
2712
2713 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args);
2714 if (!res)
2715 throw std::runtime_error("Call to pause() failed.");
2716
2717 Py_DECREF(args);
2718 Py_DECREF(res);
2719}
2720
2721inline void save(const std::string& filename, const int dpi = 0) {
2722 detail::_interpreter::get();
2723
2724 PyObject* pyfilename = PyString_FromString(filename.c_str());
2725
2726 PyObject* args = PyTuple_New(1);
2727 PyTuple_SetItem(args, 0, pyfilename);
2728
2729 PyObject* kwargs = PyDict_New();
2730
2731 if (dpi > 0) {
2732 PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi));
2733 }
2734
2735 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_save, args, kwargs);
2736 if (!res)
2737 throw std::runtime_error("Call to save() failed.");
2738
2739 Py_DECREF(args);
2740 Py_DECREF(kwargs);
2741 Py_DECREF(res);
2742}
2743
2744inline void rcparams(const std::map<std::string, std::string>& keywords = {}) {
2745 detail::_interpreter::get();
2746 PyObject* args = PyTuple_New(0);
2747 PyObject* kwargs = PyDict_New();
2748 for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2749 if ("text.usetex" == it->first)
2750 PyDict_SetItemString(kwargs, it->first.c_str(),
2751 PyLong_FromLong(std::stoi(it->second.c_str())));
2752 else
2753 PyDict_SetItemString(kwargs, it->first.c_str(),
2754 PyString_FromString(it->second.c_str()));
2755 }
2756
2757 PyObject* update =
2758 PyObject_GetAttrString(detail::_interpreter::get().s_python_function_rcparams, "update");
2759 PyObject* res = PyObject_Call(update, args, kwargs);
2760 if (!res)
2761 throw std::runtime_error("Call to rcParams.update() failed.");
2762 Py_DECREF(args);
2763 Py_DECREF(kwargs);
2764 Py_DECREF(update);
2765 Py_DECREF(res);
2766}
2767
2768inline void clf() {
2769 detail::_interpreter::get();
2770
2771 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_clf,
2772 detail::_interpreter::get().s_python_empty_tuple);
2773
2774 if (!res)
2775 throw std::runtime_error("Call to clf() failed.");
2776
2777 Py_DECREF(res);
2778}
2779
2780inline void cla() {
2781 detail::_interpreter::get();
2782
2783 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla,
2784 detail::_interpreter::get().s_python_empty_tuple);
2785
2786 if (!res)
2787 throw std::runtime_error("Call to cla() failed.");
2788
2789 Py_DECREF(res);
2790}
2791
2792inline void ion() {
2793 detail::_interpreter::get();
2794
2795 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ion,
2796 detail::_interpreter::get().s_python_empty_tuple);
2797
2798 if (!res)
2799 throw std::runtime_error("Call to ion() failed.");
2800
2801 Py_DECREF(res);
2802}
2803
2804inline std::vector<std::array<double, 2>>
2805ginput(const int numClicks = 1, const std::map<std::string, std::string>& keywords = {}) {
2806 detail::_interpreter::get();
2807
2808 PyObject* args = PyTuple_New(1);
2809 PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks));
2810
2811 // construct keyword args
2812 PyObject* kwargs = PyDict_New();
2813 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
2814 it != keywords.end(); ++it) {
2815 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
2816 }
2817
2818 PyObject* res =
2819 PyObject_Call(detail::_interpreter::get().s_python_function_ginput, args, kwargs);
2820
2821 Py_DECREF(kwargs);
2822 Py_DECREF(args);
2823 if (!res)
2824 throw std::runtime_error("Call to ginput() failed.");
2825
2826 const size_t len = PyList_Size(res);
2827 std::vector<std::array<double, 2>> out;
2828 out.reserve(len);
2829 for (size_t i = 0; i < len; i++) {
2830 PyObject* current = PyList_GetItem(res, i);
2831 std::array<double, 2> position;
2832 position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0));
2833 position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1));
2834 out.push_back(position);
2835 }
2836 Py_DECREF(res);
2837
2838 return out;
2839}
2840
2841// Actually, is there any reason not to call this automatically for every plot?
2842inline void tight_layout() {
2843 detail::_interpreter::get();
2844
2845 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_tight_layout,
2846 detail::_interpreter::get().s_python_empty_tuple);
2847
2848 if (!res)
2849 throw std::runtime_error("Call to tight_layout() failed.");
2850
2851 Py_DECREF(res);
2852}
2853
2854// Support for variadic plot() and initializer lists:
2855
2856namespace detail {
2857
2858template <typename T>
2859using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
2860
2861template <bool obj, typename T> struct is_callable_impl;
2862
2863template <typename T> struct is_callable_impl<false, T> {
2864 typedef is_function<T> type;
2865}; // a non-object is callable iff it is a function
2866
2867template <typename T> struct is_callable_impl<true, T> {
2868 struct Fallback {
2869 void operator()();
2870 };
2871 struct Derived : T, Fallback {};
2872
2873 template <typename U, U> struct Check;
2874
2875 template <typename U>
2876 static std::true_type test(...); // use a variadic function to make sure (1) it accepts
2877 // everything and (2) its always the worst match
2878
2879 template <typename U> static std::false_type test(Check<void (Fallback::*)(), &U::operator()>*);
2880
2881 public:
2882 typedef decltype(test<Derived>(nullptr)) type;
2883 typedef decltype(&Fallback::operator()) dtype;
2884 static constexpr bool value = type::value;
2885}; // an object is callable iff it defines operator()
2886
2887template <typename T> struct is_callable {
2888 // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T>
2889 // depending on whether T is of class type or not
2890 typedef typename is_callable_impl<std::is_class<T>::value, T>::type type;
2891};
2892
2893template <typename IsYDataCallable> struct plot_impl {};
2894
2895template <> struct plot_impl<std::false_type> {
2896 template <typename IterableX, typename IterableY>
2897 bool operator()(const IterableX& x, const IterableY& y, const std::string& format) {
2898 detail::_interpreter::get();
2899
2900 // 2-phase lookup for distance, begin, end
2901 using std::begin;
2902 using std::distance;
2903 using std::end;
2904
2905 auto xs = distance(begin(x), end(x));
2906 auto ys = distance(begin(y), end(y));
2907 assert(xs == ys && "x and y data must have the same number of elements!");
2908
2909 PyObject* xlist = PyList_New(xs);
2910 PyObject* ylist = PyList_New(ys);
2911 PyObject* pystring = PyString_FromString(format.c_str());
2912
2913 auto itx = begin(x), ity = begin(y);
2914 for (size_t i = 0; i < xs; ++i) {
2915 PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
2916 PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
2917 }
2918
2919 PyObject* plot_args = PyTuple_New(3);
2920 PyTuple_SetItem(plot_args, 0, xlist);
2921 PyTuple_SetItem(plot_args, 1, ylist);
2922 PyTuple_SetItem(plot_args, 2, pystring);
2923
2924 PyObject* res =
2925 PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
2926
2927 Py_DECREF(plot_args);
2928 if (res)
2929 Py_DECREF(res);
2930
2931 return res;
2932 }
2933};
2934
2935template <> struct plot_impl<std::true_type> {
2936 template <typename Iterable, typename Callable>
2937 bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) {
2938 if (begin(ticks) == end(ticks))
2939 return true;
2940
2941 // We could use additional meta-programming to deduce the correct element
2942 // type of y, but all values have to be convertible to double anyways
2943 std::vector<double> y;
2944 for (auto x : ticks)
2945 y.push_back(f(x));
2946 return plot_impl<std::false_type>()(ticks, y, format);
2947 }
2948};
2949
2950} // end namespace detail
2951
2952// recursion stop for the above
2953template <typename... Args> bool plot() {
2954 return true;
2955}
2956
2957template <typename A, typename B, typename... Args>
2958bool plot(const A& a, const B& b, const std::string& format, Args... args) {
2959 return detail::plot_impl<typename detail::is_callable<B>::type>()(a, b, format) &&
2960 plot(args...);
2961}
2962
2963/*
2964 * This group of plot() functions is needed to support initializer lists, i.e.
2965 * calling plot( {1,2,3,4} )
2966 */
2967inline bool plot(const std::vector<double>& x, const std::vector<double>& y,
2968 const std::string& format = "") {
2969 return plot<double, double>(x, y, format);
2970}
2971
2972inline bool plot(const std::vector<double>& y, const std::string& format = "") {
2973 return plot<double>(y, format);
2974}
2975
2976inline bool plot(const std::vector<double>& x, const std::vector<double>& y,
2977 const std::map<std::string, std::string>& keywords) {
2978 return plot<double>(x, y, keywords);
2979}
2980
2981/*
2982 * This class allows dynamic plots, ie changing the plotted data without
2983 * clearing and re-plotting
2984 */
2985class Plot {
2986 public:
2987 // default initialization with plot label, some data and format
2988 template <typename Numeric>
2989 Plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y,
2990 const std::string& format = "") {
2991 detail::_interpreter::get();
2992
2993 assert(x.size() == y.size());
2994
2995 PyObject* kwargs = PyDict_New();
2996 if (name != "")
2997 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
2998
2999 PyObject* xarray = detail::get_array(x);
3000 PyObject* yarray = detail::get_array(y);
3001
3002 PyObject* pystring = PyString_FromString(format.c_str());
3003
3004 PyObject* plot_args = PyTuple_New(3);
3005 PyTuple_SetItem(plot_args, 0, xarray);
3006 PyTuple_SetItem(plot_args, 1, yarray);
3007 PyTuple_SetItem(plot_args, 2, pystring);
3008
3009 PyObject* res =
3010 PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
3011
3012 Py_DECREF(kwargs);
3013 Py_DECREF(plot_args);
3014
3015 if (res) {
3016 line = PyList_GetItem(res, 0);
3017
3018 if (line)
3019 set_data_fct = PyObject_GetAttrString(line, "set_data");
3020 else
3021 Py_DECREF(line);
3022 Py_DECREF(res);
3023 }
3024 }
3025
3026 // shorter initialization with name or format only
3027 // basically calls line, = plot([], [])
3028 Plot(const std::string& name = "", const std::string& format = "")
3029 : Plot(name, std::vector<double>(), std::vector<double>(), format) {}
3030
3031 template <typename Numeric>
3032 bool update(const std::vector<Numeric>& x, const std::vector<Numeric>& y) {
3033 assert(x.size() == y.size());
3034 if (set_data_fct) {
3035 PyObject* xarray = detail::get_array(x);
3036 PyObject* yarray = detail::get_array(y);
3037
3038 PyObject* plot_args = PyTuple_New(2);
3039 PyTuple_SetItem(plot_args, 0, xarray);
3040 PyTuple_SetItem(plot_args, 1, yarray);
3041
3042 PyObject* res = PyObject_CallObject(set_data_fct, plot_args);
3043 if (res)
3044 Py_DECREF(res);
3045 return res;
3046 }
3047 return false;
3048 }
3049
3050 // clears the plot but keep it available
3051 bool clear() { return update(std::vector<double>(), std::vector<double>()); }
3052
3053 // definitely remove this line
3054 void remove() {
3055 if (line) {
3056 auto remove_fct = PyObject_GetAttrString(line, "remove");
3057 PyObject* args = PyTuple_New(0);
3058 PyObject* res = PyObject_CallObject(remove_fct, args);
3059 if (res)
3060 Py_DECREF(res);
3061 }
3062 decref();
3063 }
3064
3065 ~Plot() { decref(); }
3066
3067 private:
3068 void decref() {
3069 if (line)
3070 Py_DECREF(line);
3071 if (set_data_fct)
3072 Py_DECREF(set_data_fct);
3073 }
3074
3075 PyObject* line = nullptr;
3076 PyObject* set_data_fct = nullptr;
3077};
3078
3079} // end namespace matplotlibcpp
Definition matplotlibcpp.h:2887
Definition matplotlibcpp.h:2893
Definition matplotlibcpp.h:338