blob: 0391b3fee935fc21fcc892247090c2eec8317b0d [file] [log] [blame]
Austin Schuh6c8ec4c2018-01-23 11:18:57 -08001#pragma once
2
3#include <vector>
4#include <map>
5#include <numeric>
6#include <algorithm>
7#include <stdexcept>
8#include <iostream>
9#include <stdint.h> // <cstdint> requires c++11 support
10
11#if __cplusplus > 199711L || _MSC_VER > 1800
12# include <functional>
13#endif
14
15#include <Python.h>
16
17#ifndef WITHOUT_NUMPY
18# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
19# include <numpy/arrayobject.h>
20#endif // WITHOUT_NUMPY
21
22#if PY_MAJOR_VERSION >= 3
23# define PyString_FromString PyUnicode_FromString
24#endif
25
26
27namespace matplotlibcpp {
28namespace detail {
29
30static std::string s_backend;
31
32struct _interpreter {
33 PyObject *s_python_function_show;
34 PyObject *s_python_function_close;
35 PyObject *s_python_function_draw;
36 PyObject *s_python_function_pause;
37 PyObject *s_python_function_save;
38 PyObject *s_python_function_figure;
39 PyObject *s_python_function_plot;
40 PyObject *s_python_function_semilogx;
41 PyObject *s_python_function_semilogy;
42 PyObject *s_python_function_loglog;
43 PyObject *s_python_function_fill_between;
44 PyObject *s_python_function_hist;
45 PyObject *s_python_function_subplot;
46 PyObject *s_python_function_legend;
47 PyObject *s_python_function_xlim;
48 PyObject *s_python_function_ion;
49 PyObject *s_python_function_ylim;
50 PyObject *s_python_function_title;
51 PyObject *s_python_function_axis;
52 PyObject *s_python_function_xlabel;
53 PyObject *s_python_function_ylabel;
54 PyObject *s_python_function_grid;
55 PyObject *s_python_function_clf;
56 PyObject *s_python_function_errorbar;
57 PyObject *s_python_function_annotate;
58 PyObject *s_python_function_tight_layout;
59 PyObject *s_python_empty_tuple;
60 PyObject *s_python_function_stem;
61 PyObject *s_python_function_xkcd;
62
63 /* For now, _interpreter is implemented as a singleton since its currently not possible to have
64 multiple independent embedded python interpreters without patching the python source code
65 or starting a separate process for each.
66 http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
67 */
68
69 static _interpreter& get() {
70 static _interpreter ctx;
71 return ctx;
72 }
73
74private:
75
76#ifndef WITHOUT_NUMPY
77# if PY_MAJOR_VERSION >= 3
78
79 void *import_numpy() {
80 import_array(); // initialize C-API
81 return NULL;
82 }
83
84# else
85
86 void import_numpy() {
87 import_array(); // initialize C-API
88 }
89
90# endif
91#endif
92
93 _interpreter() {
94
95 // optional but recommended
96#if PY_MAJOR_VERSION >= 3
97 wchar_t name[] = L"plotting";
98#else
99 char name[] = "plotting";
100#endif
101 Py_SetProgramName(name);
102 Py_Initialize();
103
104#ifndef WITHOUT_NUMPY
105 import_numpy(); // initialize numpy C-API
106#endif
107
108 PyObject* matplotlibname = PyString_FromString("matplotlib");
109 PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
110 PyObject* pylabname = PyString_FromString("pylab");
111 if (!pyplotname || !pylabname || !matplotlibname) {
112 throw std::runtime_error("couldnt create string");
113 }
114
115 PyObject* matplotlib = PyImport_Import(matplotlibname);
116 Py_DECREF(matplotlibname);
117 if (!matplotlib) { throw std::runtime_error("Error loading module matplotlib!"); }
118
119 // matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
120 // or matplotlib.backends is imported for the first time
121 if (!s_backend.empty()) {
122 PyObject_CallMethod(matplotlib, const_cast<char*>("use"), const_cast<char*>("s"), s_backend.c_str());
123 }
124
125 PyObject* pymod = PyImport_Import(pyplotname);
126 Py_DECREF(pyplotname);
127 if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); }
128
129
130 PyObject* pylabmod = PyImport_Import(pylabname);
131 Py_DECREF(pylabname);
132 if (!pylabmod) { throw std::runtime_error("Error loading module pylab!"); }
133
134 s_python_function_show = PyObject_GetAttrString(pymod, "show");
135 s_python_function_close = PyObject_GetAttrString(pymod, "close");
136 s_python_function_draw = PyObject_GetAttrString(pymod, "draw");
137 s_python_function_pause = PyObject_GetAttrString(pymod, "pause");
138 s_python_function_figure = PyObject_GetAttrString(pymod, "figure");
139 s_python_function_plot = PyObject_GetAttrString(pymod, "plot");
140 s_python_function_semilogx = PyObject_GetAttrString(pymod, "semilogx");
141 s_python_function_semilogy = PyObject_GetAttrString(pymod, "semilogy");
142 s_python_function_loglog = PyObject_GetAttrString(pymod, "loglog");
143 s_python_function_fill_between = PyObject_GetAttrString(pymod, "fill_between");
144 s_python_function_hist = PyObject_GetAttrString(pymod,"hist");
145 s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot");
146 s_python_function_legend = PyObject_GetAttrString(pymod, "legend");
147 s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim");
148 s_python_function_title = PyObject_GetAttrString(pymod, "title");
149 s_python_function_axis = PyObject_GetAttrString(pymod, "axis");
150 s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel");
151 s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel");
152 s_python_function_grid = PyObject_GetAttrString(pymod, "grid");
153 s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim");
154 s_python_function_ion = PyObject_GetAttrString(pymod, "ion");
155 s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig");
156 s_python_function_annotate = PyObject_GetAttrString(pymod,"annotate");
157 s_python_function_clf = PyObject_GetAttrString(pymod, "clf");
158 s_python_function_errorbar = PyObject_GetAttrString(pymod, "errorbar");
159 s_python_function_tight_layout = PyObject_GetAttrString(pymod, "tight_layout");
160 s_python_function_stem = PyObject_GetAttrString(pymod, "stem");
161 s_python_function_xkcd = PyObject_GetAttrString(pymod, "xkcd");
162
163 if( !s_python_function_show
164 || !s_python_function_close
165 || !s_python_function_draw
166 || !s_python_function_pause
167 || !s_python_function_figure
168 || !s_python_function_plot
169 || !s_python_function_semilogx
170 || !s_python_function_semilogy
171 || !s_python_function_loglog
172 || !s_python_function_fill_between
173 || !s_python_function_subplot
174 || !s_python_function_legend
175 || !s_python_function_ylim
176 || !s_python_function_title
177 || !s_python_function_axis
178 || !s_python_function_xlabel
179 || !s_python_function_ylabel
180 || !s_python_function_grid
181 || !s_python_function_xlim
182 || !s_python_function_ion
183 || !s_python_function_save
184 || !s_python_function_clf
185 || !s_python_function_annotate
186 || !s_python_function_errorbar
187 || !s_python_function_errorbar
188 || !s_python_function_tight_layout
189 || !s_python_function_stem
190 || !s_python_function_xkcd
191 ) { throw std::runtime_error("Couldn't find required function!"); }
192
193 if ( !PyFunction_Check(s_python_function_show)
194 || !PyFunction_Check(s_python_function_close)
195 || !PyFunction_Check(s_python_function_draw)
196 || !PyFunction_Check(s_python_function_pause)
197 || !PyFunction_Check(s_python_function_figure)
198 || !PyFunction_Check(s_python_function_plot)
199 || !PyFunction_Check(s_python_function_semilogx)
200 || !PyFunction_Check(s_python_function_semilogy)
201 || !PyFunction_Check(s_python_function_loglog)
202 || !PyFunction_Check(s_python_function_fill_between)
203 || !PyFunction_Check(s_python_function_subplot)
204 || !PyFunction_Check(s_python_function_legend)
205 || !PyFunction_Check(s_python_function_annotate)
206 || !PyFunction_Check(s_python_function_ylim)
207 || !PyFunction_Check(s_python_function_title)
208 || !PyFunction_Check(s_python_function_axis)
209 || !PyFunction_Check(s_python_function_xlabel)
210 || !PyFunction_Check(s_python_function_ylabel)
211 || !PyFunction_Check(s_python_function_grid)
212 || !PyFunction_Check(s_python_function_xlim)
213 || !PyFunction_Check(s_python_function_ion)
214 || !PyFunction_Check(s_python_function_save)
215 || !PyFunction_Check(s_python_function_clf)
216 || !PyFunction_Check(s_python_function_tight_layout)
217 || !PyFunction_Check(s_python_function_errorbar)
218 || !PyFunction_Check(s_python_function_stem)
219 || !PyFunction_Check(s_python_function_xkcd)
220 ) { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); }
221
222 s_python_empty_tuple = PyTuple_New(0);
223 }
224
225 ~_interpreter() {
226 Py_Finalize();
227 }
228};
229
230} // end namespace detail
231
232// must be called before the first regular call to matplotlib to have any effect
233inline void backend(const std::string& name)
234{
235 detail::s_backend = name;
236}
237
238inline bool annotate(std::string annotation, double x, double y)
239{
240 PyObject * xy = PyTuple_New(2);
241 PyObject * str = PyString_FromString(annotation.c_str());
242
243 PyTuple_SetItem(xy,0,PyFloat_FromDouble(x));
244 PyTuple_SetItem(xy,1,PyFloat_FromDouble(y));
245
246 PyObject* kwargs = PyDict_New();
247 PyDict_SetItemString(kwargs, "xy", xy);
248
249 PyObject* args = PyTuple_New(1);
250 PyTuple_SetItem(args, 0, str);
251
252 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs);
253
254 Py_DECREF(args);
255 Py_DECREF(kwargs);
256
257 if(res) Py_DECREF(res);
258
259 return res;
260}
261
262#ifndef WITHOUT_NUMPY
263// Type selector for numpy array conversion
264template <typename T> struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default
265template <> struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
266template <> struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
267template <> struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
268template <> struct select_npy_type<int8_t> { const static NPY_TYPES type = NPY_INT8; };
269template <> struct select_npy_type<int16_t> { const static NPY_TYPES type = NPY_SHORT; };
270template <> struct select_npy_type<int32_t> { const static NPY_TYPES type = NPY_INT; };
271template <> struct select_npy_type<int64_t> { const static NPY_TYPES type = NPY_INT64; };
272template <> struct select_npy_type<uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
273template <> struct select_npy_type<uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
274template <> struct select_npy_type<uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
275template <> struct select_npy_type<uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
276
277template<typename Numeric>
278PyObject* get_array(const std::vector<Numeric>& v)
279{
280 detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
281 NPY_TYPES type = select_npy_type<Numeric>::type;
282 if (type == NPY_NOTYPE)
283 {
284 std::vector<double> vd(v.size());
285 npy_intp vsize = v.size();
286 std::copy(v.begin(),v.end(),vd.begin());
287 PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data()));
288 return varray;
289 }
290
291 npy_intp vsize = v.size();
292 PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
293 return varray;
294}
295
296#else // fallback if we don't have numpy: copy every element of the given vector
297
298template<typename Numeric>
299PyObject* get_array(const std::vector<Numeric>& v)
300{
301 PyObject* list = PyList_New(v.size());
302 for(size_t i = 0; i < v.size(); ++i) {
303 PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i)));
304 }
305 return list;
306}
307
308#endif // WITHOUT_NUMPY
309
310template<typename Numeric>
311bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
312{
313 assert(x.size() == y.size());
314
315 // using numpy arrays
316 PyObject* xarray = get_array(x);
317 PyObject* yarray = get_array(y);
318
319 // construct positional args
320 PyObject* args = PyTuple_New(2);
321 PyTuple_SetItem(args, 0, xarray);
322 PyTuple_SetItem(args, 1, yarray);
323
324 // construct keyword args
325 PyObject* kwargs = PyDict_New();
326 for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
327 {
328 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
329 }
330
331 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
332
333 Py_DECREF(args);
334 Py_DECREF(kwargs);
335 if(res) Py_DECREF(res);
336
337 return res;
338}
339
340template<typename Numeric>
341bool stem(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
342{
343 assert(x.size() == y.size());
344
345 // using numpy arrays
346 PyObject* xarray = get_array(x);
347 PyObject* yarray = get_array(y);
348
349 // construct positional args
350 PyObject* args = PyTuple_New(2);
351 PyTuple_SetItem(args, 0, xarray);
352 PyTuple_SetItem(args, 1, yarray);
353
354 // construct keyword args
355 PyObject* kwargs = PyDict_New();
356 for (std::map<std::string, std::string>::const_iterator it =
357 keywords.begin(); it != keywords.end(); ++it) {
358 PyDict_SetItemString(kwargs, it->first.c_str(),
359 PyString_FromString(it->second.c_str()));
360 }
361
362 PyObject* res = PyObject_Call(
363 detail::_interpreter::get().s_python_function_stem, args, kwargs);
364
365 Py_DECREF(args);
366 Py_DECREF(kwargs);
367 if (res)
368 Py_DECREF(res);
369
370 return res;
371}
372
373template< typename Numeric >
374bool fill_between(const std::vector<Numeric>& x, const std::vector<Numeric>& y1, const std::vector<Numeric>& y2, const std::map<std::string, std::string>& keywords)
375{
376 assert(x.size() == y1.size());
377 assert(x.size() == y2.size());
378
379 // using numpy arrays
380 PyObject* xarray = get_array(x);
381 PyObject* y1array = get_array(y1);
382 PyObject* y2array = get_array(y2);
383
384 // construct positional args
385 PyObject* args = PyTuple_New(3);
386 PyTuple_SetItem(args, 0, xarray);
387 PyTuple_SetItem(args, 1, y1array);
388 PyTuple_SetItem(args, 2, y2array);
389
390 // construct keyword args
391 PyObject* kwargs = PyDict_New();
392 for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
393 {
394 PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
395 }
396
397 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs);
398
399 Py_DECREF(args);
400 Py_DECREF(kwargs);
401 if(res) Py_DECREF(res);
402
403 return res;
404}
405
406template< typename Numeric>
407bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0)
408{
409
410 PyObject* yarray = get_array(y);
411
412 PyObject* kwargs = PyDict_New();
413 PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
414 PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
415 PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
416
417
418 PyObject* plot_args = PyTuple_New(1);
419
420 PyTuple_SetItem(plot_args, 0, yarray);
421
422
423 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
424
425
426 Py_DECREF(plot_args);
427 Py_DECREF(kwargs);
428 if(res) Py_DECREF(res);
429
430 return res;
431}
432
433template< typename Numeric>
434bool named_hist(std::string label,const std::vector<Numeric>& y, long bins=10, std::string color="b", double alpha=1.0)
435{
436 PyObject* yarray = get_array(y);
437
438 PyObject* kwargs = PyDict_New();
439 PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
440 PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
441 PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
442 PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
443
444
445 PyObject* plot_args = PyTuple_New(1);
446 PyTuple_SetItem(plot_args, 0, yarray);
447
448 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
449
450 Py_DECREF(plot_args);
451 Py_DECREF(kwargs);
452 if(res) Py_DECREF(res);
453
454 return res;
455}
456
457template<typename NumericX, typename NumericY>
458bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
459{
460 assert(x.size() == y.size());
461
462 PyObject* xarray = get_array(x);
463 PyObject* yarray = get_array(y);
464
465 PyObject* pystring = PyString_FromString(s.c_str());
466
467 PyObject* plot_args = PyTuple_New(3);
468 PyTuple_SetItem(plot_args, 0, xarray);
469 PyTuple_SetItem(plot_args, 1, yarray);
470 PyTuple_SetItem(plot_args, 2, pystring);
471
472 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
473
474 Py_DECREF(plot_args);
475 if(res) Py_DECREF(res);
476
477 return res;
478}
479
480template<typename NumericX, typename NumericY>
481bool stem(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
482{
483 assert(x.size() == y.size());
484
485 PyObject* xarray = get_array(x);
486 PyObject* yarray = get_array(y);
487
488 PyObject* pystring = PyString_FromString(s.c_str());
489
490 PyObject* plot_args = PyTuple_New(3);
491 PyTuple_SetItem(plot_args, 0, xarray);
492 PyTuple_SetItem(plot_args, 1, yarray);
493 PyTuple_SetItem(plot_args, 2, pystring);
494
495 PyObject* res = PyObject_CallObject(
496 detail::_interpreter::get().s_python_function_stem, plot_args);
497
498 Py_DECREF(plot_args);
499 if (res)
500 Py_DECREF(res);
501
502 return res;
503}
504
505template<typename NumericX, typename NumericY>
506bool semilogx(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
507{
508 assert(x.size() == y.size());
509
510 PyObject* xarray = get_array(x);
511 PyObject* yarray = get_array(y);
512
513 PyObject* pystring = PyString_FromString(s.c_str());
514
515 PyObject* plot_args = PyTuple_New(3);
516 PyTuple_SetItem(plot_args, 0, xarray);
517 PyTuple_SetItem(plot_args, 1, yarray);
518 PyTuple_SetItem(plot_args, 2, pystring);
519
520 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args);
521
522 Py_DECREF(plot_args);
523 if(res) Py_DECREF(res);
524
525 return res;
526}
527
528template<typename NumericX, typename NumericY>
529bool semilogy(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
530{
531 assert(x.size() == y.size());
532
533 PyObject* xarray = get_array(x);
534 PyObject* yarray = get_array(y);
535
536 PyObject* pystring = PyString_FromString(s.c_str());
537
538 PyObject* plot_args = PyTuple_New(3);
539 PyTuple_SetItem(plot_args, 0, xarray);
540 PyTuple_SetItem(plot_args, 1, yarray);
541 PyTuple_SetItem(plot_args, 2, pystring);
542
543 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args);
544
545 Py_DECREF(plot_args);
546 if(res) Py_DECREF(res);
547
548 return res;
549}
550
551template<typename NumericX, typename NumericY>
552bool loglog(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
553{
554 assert(x.size() == y.size());
555
556 PyObject* xarray = get_array(x);
557 PyObject* yarray = get_array(y);
558
559 PyObject* pystring = PyString_FromString(s.c_str());
560
561 PyObject* plot_args = PyTuple_New(3);
562 PyTuple_SetItem(plot_args, 0, xarray);
563 PyTuple_SetItem(plot_args, 1, yarray);
564 PyTuple_SetItem(plot_args, 2, pystring);
565
566 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args);
567
568 Py_DECREF(plot_args);
569 if(res) Py_DECREF(res);
570
571 return res;
572}
573
574template<typename NumericX, typename NumericY>
Austin Schuhf3bac672018-01-23 11:18:57 -0800575bool errorbar(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::vector<NumericX> &yerr, const std::string & /*s*/ = "")
Austin Schuh6c8ec4c2018-01-23 11:18:57 -0800576{
577 assert(x.size() == y.size());
578
579 PyObject* xarray = get_array(x);
580 PyObject* yarray = get_array(y);
581 PyObject* yerrarray = get_array(yerr);
582
583 PyObject *kwargs = PyDict_New();
584
585 PyDict_SetItemString(kwargs, "yerr", yerrarray);
586
Austin Schuhf3bac672018-01-23 11:18:57 -0800587 //PyObject *pystring = PyString_FromString(s.c_str());
Austin Schuh6c8ec4c2018-01-23 11:18:57 -0800588
589 PyObject *plot_args = PyTuple_New(2);
590 PyTuple_SetItem(plot_args, 0, xarray);
591 PyTuple_SetItem(plot_args, 1, yarray);
592
593 PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs);
594
595 Py_DECREF(kwargs);
596 Py_DECREF(plot_args);
597
598 if (res)
599 Py_DECREF(res);
600 else
601 throw std::runtime_error("Call to errorbar() failed.");
602
603 return res;
604}
605
606template<typename Numeric>
607bool named_plot(const std::string& name, const std::vector<Numeric>& y, const std::string& format = "")
608{
609 PyObject* kwargs = PyDict_New();
610 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
611
612 PyObject* yarray = get_array(y);
613
614 PyObject* pystring = PyString_FromString(format.c_str());
615
616 PyObject* plot_args = PyTuple_New(2);
617
618 PyTuple_SetItem(plot_args, 0, yarray);
619 PyTuple_SetItem(plot_args, 1, pystring);
620
621 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
622
623 Py_DECREF(kwargs);
624 Py_DECREF(plot_args);
625 if (res) Py_DECREF(res);
626
627 return res;
628}
629
630template<typename Numeric>
631bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
632{
633 PyObject* kwargs = PyDict_New();
634 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
635
636 PyObject* xarray = get_array(x);
637 PyObject* yarray = get_array(y);
638
639 PyObject* pystring = PyString_FromString(format.c_str());
640
641 PyObject* plot_args = PyTuple_New(3);
642 PyTuple_SetItem(plot_args, 0, xarray);
643 PyTuple_SetItem(plot_args, 1, yarray);
644 PyTuple_SetItem(plot_args, 2, pystring);
645
646 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
647
648 Py_DECREF(kwargs);
649 Py_DECREF(plot_args);
650 if (res) Py_DECREF(res);
651
652 return res;
653}
654
655template<typename Numeric>
656bool named_semilogx(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
657{
658 PyObject* kwargs = PyDict_New();
659 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
660
661 PyObject* xarray = get_array(x);
662 PyObject* yarray = get_array(y);
663
664 PyObject* pystring = PyString_FromString(format.c_str());
665
666 PyObject* plot_args = PyTuple_New(3);
667 PyTuple_SetItem(plot_args, 0, xarray);
668 PyTuple_SetItem(plot_args, 1, yarray);
669 PyTuple_SetItem(plot_args, 2, pystring);
670
671 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs);
672
673 Py_DECREF(kwargs);
674 Py_DECREF(plot_args);
675 if (res) Py_DECREF(res);
676
677 return res;
678}
679
680template<typename Numeric>
681bool named_semilogy(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
682{
683 PyObject* kwargs = PyDict_New();
684 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
685
686 PyObject* xarray = get_array(x);
687 PyObject* yarray = get_array(y);
688
689 PyObject* pystring = PyString_FromString(format.c_str());
690
691 PyObject* plot_args = PyTuple_New(3);
692 PyTuple_SetItem(plot_args, 0, xarray);
693 PyTuple_SetItem(plot_args, 1, yarray);
694 PyTuple_SetItem(plot_args, 2, pystring);
695
696 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs);
697
698 Py_DECREF(kwargs);
699 Py_DECREF(plot_args);
700 if (res) Py_DECREF(res);
701
702 return res;
703}
704
705template<typename Numeric>
706bool named_loglog(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
707{
708 PyObject* kwargs = PyDict_New();
709 PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
710
711 PyObject* xarray = get_array(x);
712 PyObject* yarray = get_array(y);
713
714 PyObject* pystring = PyString_FromString(format.c_str());
715
716 PyObject* plot_args = PyTuple_New(3);
717 PyTuple_SetItem(plot_args, 0, xarray);
718 PyTuple_SetItem(plot_args, 1, yarray);
719 PyTuple_SetItem(plot_args, 2, pystring);
720
721 PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs);
722
723 Py_DECREF(kwargs);
724 Py_DECREF(plot_args);
725 if (res) Py_DECREF(res);
726
727 return res;
728}
729
730template<typename Numeric>
731bool plot(const std::vector<Numeric>& y, const std::string& format = "")
732{
733 std::vector<Numeric> x(y.size());
734 for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
735 return plot(x,y,format);
736}
737
738template<typename Numeric>
739bool stem(const std::vector<Numeric>& y, const std::string& format = "")
740{
741 std::vector<Numeric> x(y.size());
742 for (size_t i = 0; i < x.size(); ++i) x.at(i) = i;
743 return stem(x, y, format);
744}
745
746inline void figure()
747{
748 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple);
749 if(!res) throw std::runtime_error("Call to figure() failed.");
750
751 Py_DECREF(res);
752}
753
754inline void legend()
755{
756 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
757 if(!res) throw std::runtime_error("Call to legend() failed.");
758
759 Py_DECREF(res);
760}
761
762template<typename Numeric>
763void ylim(Numeric left, Numeric right)
764{
765 PyObject* list = PyList_New(2);
766 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
767 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
768
769 PyObject* args = PyTuple_New(1);
770 PyTuple_SetItem(args, 0, list);
771
772 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
773 if(!res) throw std::runtime_error("Call to ylim() failed.");
774
775 Py_DECREF(args);
776 Py_DECREF(res);
777}
778
779template<typename Numeric>
780void xlim(Numeric left, Numeric right)
781{
782 PyObject* list = PyList_New(2);
783 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
784 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
785
786 PyObject* args = PyTuple_New(1);
787 PyTuple_SetItem(args, 0, list);
788
789 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
790 if(!res) throw std::runtime_error("Call to xlim() failed.");
791
792 Py_DECREF(args);
793 Py_DECREF(res);
794}
795
796
797inline double* xlim()
798{
799 PyObject* args = PyTuple_New(0);
800 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
801 PyObject* left = PyTuple_GetItem(res,0);
802 PyObject* right = PyTuple_GetItem(res,1);
803
804 double* arr = new double[2];
805 arr[0] = PyFloat_AsDouble(left);
806 arr[1] = PyFloat_AsDouble(right);
807
808 if(!res) throw std::runtime_error("Call to xlim() failed.");
809
810 Py_DECREF(res);
811 return arr;
812}
813
814
815inline double* ylim()
816{
817 PyObject* args = PyTuple_New(0);
818 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
819 PyObject* left = PyTuple_GetItem(res,0);
820 PyObject* right = PyTuple_GetItem(res,1);
821
822 double* arr = new double[2];
823 arr[0] = PyFloat_AsDouble(left);
824 arr[1] = PyFloat_AsDouble(right);
825
826 if(!res) throw std::runtime_error("Call to ylim() failed.");
827
828 Py_DECREF(res);
829 return arr;
830}
831
832inline void subplot(long nrows, long ncols, long plot_number)
833{
834 // construct positional args
835 PyObject* args = PyTuple_New(3);
836 PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
837 PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
838 PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));
839
840 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
841 if(!res) throw std::runtime_error("Call to subplot() failed.");
842
843 Py_DECREF(args);
844 Py_DECREF(res);
845}
846
847inline void title(const std::string &titlestr)
848{
849 PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
850 PyObject* args = PyTuple_New(1);
851 PyTuple_SetItem(args, 0, pytitlestr);
852
853 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_title, args);
854 if(!res) throw std::runtime_error("Call to title() failed.");
855
856 Py_DECREF(args);
857 Py_DECREF(res);
858}
859
860inline void axis(const std::string &axisstr)
861{
862 PyObject* str = PyString_FromString(axisstr.c_str());
863 PyObject* args = PyTuple_New(1);
864 PyTuple_SetItem(args, 0, str);
865
866 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args);
867 if(!res) throw std::runtime_error("Call to title() failed.");
868
869 Py_DECREF(args);
870 Py_DECREF(res);
871}
872
873inline void xlabel(const std::string &str)
874{
875 PyObject* pystr = PyString_FromString(str.c_str());
876 PyObject* args = PyTuple_New(1);
877 PyTuple_SetItem(args, 0, pystr);
878
879 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlabel, args);
880 if(!res) throw std::runtime_error("Call to xlabel() failed.");
881
882 Py_DECREF(args);
883 Py_DECREF(res);
884}
885
886inline void ylabel(const std::string &str)
887{
888 PyObject* pystr = PyString_FromString(str.c_str());
889 PyObject* args = PyTuple_New(1);
890 PyTuple_SetItem(args, 0, pystr);
891
892 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylabel, args);
893 if(!res) throw std::runtime_error("Call to ylabel() failed.");
894
895 Py_DECREF(args);
896 Py_DECREF(res);
897}
898
899inline void grid(bool flag)
900{
901 PyObject* pyflag = flag ? Py_True : Py_False;
902 Py_INCREF(pyflag);
903
904 PyObject* args = PyTuple_New(1);
905 PyTuple_SetItem(args, 0, pyflag);
906
907 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
908 if(!res) throw std::runtime_error("Call to grid() failed.");
909
910 Py_DECREF(args);
911 Py_DECREF(res);
912}
913
914inline void show(const bool block = true)
915{
916 PyObject* res;
917 if(block)
918 {
919 res = PyObject_CallObject(
920 detail::_interpreter::get().s_python_function_show,
921 detail::_interpreter::get().s_python_empty_tuple);
922 }
923 else
924 {
925 PyObject *kwargs = PyDict_New();
926 PyDict_SetItemString(kwargs, "block", Py_False);
927 res = PyObject_Call( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs);
928 Py_DECREF(kwargs);
929 }
930
931
932 if (!res) throw std::runtime_error("Call to show() failed.");
933
934 Py_DECREF(res);
935}
936
937inline void close()
938{
939 PyObject* res = PyObject_CallObject(
940 detail::_interpreter::get().s_python_function_close,
941 detail::_interpreter::get().s_python_empty_tuple);
942
943 if (!res) throw std::runtime_error("Call to close() failed.");
944
945 Py_DECREF(res);
946}
947
948inline void xkcd() {
949 PyObject* res;
950 PyObject *kwargs = PyDict_New();
951
952 res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd,
953 detail::_interpreter::get().s_python_empty_tuple, kwargs);
954
955 Py_DECREF(kwargs);
956
957 if (!res)
958 throw std::runtime_error("Call to show() failed.");
959
960 Py_DECREF(res);
961}
962
963inline void draw()
964{
965 PyObject* res = PyObject_CallObject(
966 detail::_interpreter::get().s_python_function_draw,
967 detail::_interpreter::get().s_python_empty_tuple);
968
969 if (!res) throw std::runtime_error("Call to draw() failed.");
970
971 Py_DECREF(res);
972}
973
974template<typename Numeric>
975inline void pause(Numeric interval)
976{
977 PyObject* args = PyTuple_New(1);
978 PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval));
979
980 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args);
981 if(!res) throw std::runtime_error("Call to pause() failed.");
982
983 Py_DECREF(args);
984 Py_DECREF(res);
985}
986
987inline void save(const std::string& filename)
988{
989 PyObject* pyfilename = PyString_FromString(filename.c_str());
990
991 PyObject* args = PyTuple_New(1);
992 PyTuple_SetItem(args, 0, pyfilename);
993
994 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args);
995 if (!res) throw std::runtime_error("Call to save() failed.");
996
997 Py_DECREF(args);
998 Py_DECREF(res);
999}
1000
1001inline void clf() {
1002 PyObject *res = PyObject_CallObject(
1003 detail::_interpreter::get().s_python_function_clf,
1004 detail::_interpreter::get().s_python_empty_tuple);
1005
1006 if (!res) throw std::runtime_error("Call to clf() failed.");
1007
1008 Py_DECREF(res);
1009}
1010
1011 inline void ion() {
1012 PyObject *res = PyObject_CallObject(
1013 detail::_interpreter::get().s_python_function_ion,
1014 detail::_interpreter::get().s_python_empty_tuple);
1015
1016 if (!res) throw std::runtime_error("Call to ion() failed.");
1017
1018 Py_DECREF(res);
1019}
1020
1021// Actually, is there any reason not to call this automatically for every plot?
1022inline void tight_layout() {
1023 PyObject *res = PyObject_CallObject(
1024 detail::_interpreter::get().s_python_function_tight_layout,
1025 detail::_interpreter::get().s_python_empty_tuple);
1026
1027 if (!res) throw std::runtime_error("Call to tight_layout() failed.");
1028
1029 Py_DECREF(res);
1030}
1031
1032#if __cplusplus > 199711L || _MSC_VER > 1800
1033// C++11-exclusive content starts here (variadic plot() and initializer list support)
1034
1035namespace detail {
1036
1037template<typename T>
1038using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
1039
1040template<bool obj, typename T>
1041struct is_callable_impl;
1042
1043template<typename T>
1044struct is_callable_impl<false, T>
1045{
1046 typedef is_function<T> type;
1047}; // a non-object is callable iff it is a function
1048
1049template<typename T>
1050struct is_callable_impl<true, T>
1051{
1052 struct Fallback { void operator()(); };
1053 struct Derived : T, Fallback { };
1054
1055 template<typename U, U> struct Check;
1056
1057 template<typename U>
1058 static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
1059
1060 template<typename U>
1061 static std::false_type test( Check<void(Fallback::*)(), &U::operator()>* );
1062
1063public:
1064 typedef decltype(test<Derived>(nullptr)) type;
1065 typedef decltype(&Fallback::operator()) dtype;
1066 static constexpr bool value = type::value;
1067}; // an object is callable iff it defines operator()
1068
1069template<typename T>
1070struct is_callable
1071{
1072 // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
1073 typedef typename is_callable_impl<std::is_class<T>::value, T>::type type;
1074};
1075
1076template<typename IsYDataCallable>
1077struct plot_impl { };
1078
1079template<>
1080struct plot_impl<std::false_type>
1081{
1082 template<typename IterableX, typename IterableY>
1083 bool operator()(const IterableX& x, const IterableY& y, const std::string& format)
1084 {
1085 // 2-phase lookup for distance, begin, end
1086 using std::distance;
1087 using std::begin;
1088 using std::end;
1089
1090 auto xs = distance(begin(x), end(x));
1091 auto ys = distance(begin(y), end(y));
1092 assert(xs == ys && "x and y data must have the same number of elements!");
1093
1094 PyObject* xlist = PyList_New(xs);
1095 PyObject* ylist = PyList_New(ys);
1096 PyObject* pystring = PyString_FromString(format.c_str());
1097
1098 auto itx = begin(x), ity = begin(y);
1099 for(size_t i = 0; i < xs; ++i) {
1100 PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
1101 PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
1102 }
1103
1104 PyObject* plot_args = PyTuple_New(3);
1105 PyTuple_SetItem(plot_args, 0, xlist);
1106 PyTuple_SetItem(plot_args, 1, ylist);
1107 PyTuple_SetItem(plot_args, 2, pystring);
1108
1109 PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
1110
1111 Py_DECREF(plot_args);
1112 if(res) Py_DECREF(res);
1113
1114 return res;
1115 }
1116};
1117
1118template<>
1119struct plot_impl<std::true_type>
1120{
1121 template<typename Iterable, typename Callable>
1122 bool operator()(const Iterable& ticks, const Callable& f, const std::string& format)
1123 {
1124 if(begin(ticks) == end(ticks)) return true;
1125
1126 // We could use additional meta-programming to deduce the correct element type of y,
1127 // but all values have to be convertible to double anyways
1128 std::vector<double> y;
1129 for(auto x : ticks) y.push_back(f(x));
1130 return plot_impl<std::false_type>()(ticks,y,format);
1131 }
1132};
1133
1134} // end namespace detail
1135
1136// recursion stop for the above
1137template<typename... Args>
1138bool plot() { return true; }
1139
1140template<typename A, typename B, typename... Args>
1141bool plot(const A& a, const B& b, const std::string& format, Args... args)
1142{
1143 return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot(args...);
1144}
1145
1146/*
1147 * This group of plot() functions is needed to support initializer lists, i.e. calling
1148 * plot( {1,2,3,4} )
1149 */
1150inline bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
1151 return plot<double,double>(x,y,format);
1152}
1153
1154inline bool plot(const std::vector<double>& y, const std::string& format = "") {
1155 return plot<double>(y,format);
1156}
1157
1158inline bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords) {
1159 return plot<double>(x,y,keywords);
1160}
1161
1162#endif
1163
1164} // end namespace matplotlibcpp