41 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
42 #include <numpy/arrayobject.h>
45 #include <opencv2/opencv.hpp>
47 #endif // WITHOUT_NUMPY
49 #if PY_MAJOR_VERSION >= 3
50 #define PyString_FromString PyUnicode_FromString
51 #define PyInt_FromLong PyLong_FromLong
52 #define PyString_FromString PyUnicode_FromString
116 PyObject* fn = PyObject_GetAttrString(module, fname.c_str());
119 throw std::runtime_error(
120 std::string(
"Couldn't find required function: ") + fname);
122 if (!PyFunction_Check(fn))
123 throw std::runtime_error(
124 fname + std::string(
" is unexpectedly not a PyFunction."));
130 #ifndef WITHOUT_NUMPY
131 #if PY_MAJOR_VERSION >= 3
149 #if PY_MAJOR_VERSION >= 3
150 wchar_t name[] = L
"plotting";
152 char name[] =
"plotting";
154 Py_SetProgramName(name);
157 #ifndef WITHOUT_NUMPY
161 PyObject* matplotlibname = PyString_FromString(
"matplotlib");
162 PyObject* pyplotname = PyString_FromString(
"matplotlib.pyplot");
163 PyObject* cmname = PyString_FromString(
"matplotlib.cm");
164 PyObject* pylabname = PyString_FromString(
"pylab");
165 if (!pyplotname || !pylabname || !matplotlibname || !cmname) {
166 throw std::runtime_error(
"couldnt create string");
169 PyObject* matplotlib = PyImport_Import(matplotlibname);
170 Py_DECREF(matplotlibname);
173 throw std::runtime_error(
"Error loading module matplotlib!");
179 PyObject_CallMethod(matplotlib,
const_cast<char*
>(
"use"),
180 const_cast<char*
>(
"s"),
s_backend.c_str());
183 PyObject* pymod = PyImport_Import(pyplotname);
184 Py_DECREF(pyplotname);
186 throw std::runtime_error(
"Error loading module matplotlib.pyplot!");
192 throw std::runtime_error(
"Error loading module matplotlib.cm!");
195 PyObject* pylabmod = PyImport_Import(pylabname);
196 Py_DECREF(pylabname);
198 throw std::runtime_error(
"Error loading module pylab!");
240 #ifndef WITHOUT_NUMPY
255 inline bool annotate(std::string annotation,
double x,
double y) {
256 PyObject* xy = PyTuple_New(2);
257 PyObject*
str = PyString_FromString(annotation.c_str());
259 PyTuple_SetItem(xy, 0, PyFloat_FromDouble(
x));
260 PyTuple_SetItem(xy, 1, PyFloat_FromDouble(
y));
262 PyObject* kwargs = PyDict_New();
263 PyDict_SetItemString(kwargs,
"xy", xy);
265 PyObject*
args = PyTuple_New(1);
268 PyObject* res = PyObject_Call(
274 if (res) Py_DECREF(res);
279 #ifndef WITHOUT_NUMPY
281 template <
typename T>
283 const static NPY_TYPES
type = NPY_NOTYPE;
287 const static NPY_TYPES
type = NPY_DOUBLE;
291 const static NPY_TYPES
type = NPY_FLOAT;
295 const static NPY_TYPES
type = NPY_BOOL;
299 const static NPY_TYPES
type = NPY_INT8;
303 const static NPY_TYPES
type = NPY_SHORT;
307 const static NPY_TYPES
type = NPY_INT;
311 const static NPY_TYPES
type = NPY_INT64;
315 const static NPY_TYPES
type = NPY_UINT8;
319 const static NPY_TYPES
type = NPY_USHORT;
323 const static NPY_TYPES
type = NPY_ULONG;
327 const static NPY_TYPES
type = NPY_UINT64;
330 template <
typename Numeric>
335 if (
type == NPY_NOTYPE) {
336 std::vector<double> vd(v.size());
337 npy_intp vsize = v.size();
338 std::copy(v.begin(), v.end(), vd.begin());
340 PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (
void*)(vd.data()));
344 npy_intp vsize = v.size();
346 PyArray_SimpleNewFromData(1, &vsize,
type, (
void*)(v.data()));
350 template <
typename Numeric>
354 if (v.size() < 1)
throw std::runtime_error(
"get_2d_array v too small");
356 npy_intp vsize[2] = {
static_cast<npy_intp
>(v.size()),
357 static_cast<npy_intp
>(v[0].size())};
359 PyArrayObject* varray =
360 (PyArrayObject*)PyArray_SimpleNew(2, vsize, NPY_DOUBLE);
362 double* vd_begin =
static_cast<double*
>(PyArray_DATA(varray));
364 for (const ::std::vector<Numeric>& v_row : v) {
365 if (v_row.size() !=
static_cast<size_t>(vsize[1]))
366 throw std::runtime_error(
"Missmatched array size");
367 std::copy(v_row.begin(), v_row.end(), vd_begin);
368 vd_begin += vsize[1];
371 return reinterpret_cast<PyObject*
>(varray);
374 #else // fallback if we don't have numpy: copy every element of the given vector
376 template <
typename Numeric>
377 PyObject*
get_array(
const std::vector<Numeric>& v) {
378 PyObject* list = PyList_New(v.size());
379 for (
size_t i = 0;
i < v.size(); ++
i) {
380 PyList_SetItem(list,
i, PyFloat_FromDouble(v.at(
i)));
385 #endif // WITHOUT_NUMPY
387 template <
typename Numeric>
388 bool plot(
const std::vector<Numeric>&
x,
const std::vector<Numeric>&
y,
389 const std::map<std::string, std::string>& keywords) {
397 PyObject*
args = PyTuple_New(2);
398 PyTuple_SetItem(
args, 0, xarray);
399 PyTuple_SetItem(
args, 1, yarray);
402 PyObject* kwargs = PyDict_New();
403 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
404 it != keywords.end(); ++it) {
405 PyDict_SetItemString(kwargs, it->first.c_str(),
406 PyString_FromString(it->second.c_str()));
409 PyObject* res = PyObject_Call(
414 if (res) Py_DECREF(res);
419 template <
typename Numeric>
423 const std::map<std::string, std::string>& keywords =
424 std::map<std::string, std::string>()) {
429 static PyObject *mpl_toolkitsmod =
nullptr, *axis3dmod =
nullptr;
430 if (!mpl_toolkitsmod) {
433 PyObject* mpl_toolkits = PyString_FromString(
"mpl_toolkits");
434 PyObject* axis3d = PyString_FromString(
"mpl_toolkits.mplot3d");
435 if (!mpl_toolkits || !axis3d) {
436 throw std::runtime_error(
"couldnt create string");
439 mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
440 Py_DECREF(mpl_toolkits);
441 if (!mpl_toolkitsmod) {
442 throw std::runtime_error(
"Error loading module mpl_toolkits!");
445 axis3dmod = PyImport_Import(axis3d);
448 throw std::runtime_error(
"Error loading module mpl_toolkits.mplot3d!");
461 PyObject*
args = PyTuple_New(3);
462 PyTuple_SetItem(
args, 0, xarray);
463 PyTuple_SetItem(
args, 1, yarray);
464 PyTuple_SetItem(
args, 2, zarray);
467 PyObject* kwargs = PyDict_New();
468 PyDict_SetItemString(kwargs,
"rstride", PyInt_FromLong(1));
469 PyDict_SetItemString(kwargs,
"cstride", PyInt_FromLong(1));
471 PyObject* python_colormap_coolwarm = PyObject_GetAttrString(
474 PyDict_SetItemString(kwargs,
"cmap", python_colormap_coolwarm);
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(),
479 PyString_FromString(it->second.c_str()));
485 if (!
fig)
throw std::runtime_error(
"Call to figure() failed.");
487 PyObject* gca_kwargs = PyDict_New();
488 PyDict_SetItemString(gca_kwargs,
"projection", PyString_FromString(
"3d"));
490 PyObject* gca = PyObject_GetAttrString(
fig,
"gca");
491 if (!gca)
throw std::runtime_error(
"No gca");
493 PyObject*
axis = PyObject_Call(
496 if (!
axis)
throw std::runtime_error(
"No axis");
500 Py_DECREF(gca_kwargs);
503 if (!
plot_surface)
throw std::runtime_error(
"No surface");
506 if (!res)
throw std::runtime_error(
"failed surface");
512 if (res) Py_DECREF(res);
515 template <
typename Numeric>
516 bool stem(
const std::vector<Numeric>&
x,
const std::vector<Numeric>&
y,
517 const std::map<std::string, std::string>& keywords) {
525 PyObject*
args = PyTuple_New(2);
526 PyTuple_SetItem(
args, 0, xarray);
527 PyTuple_SetItem(
args, 1, yarray);
530 PyObject* kwargs = PyDict_New();
531 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
532 it != keywords.end(); ++it) {
533 PyDict_SetItemString(kwargs, it->first.c_str(),
534 PyString_FromString(it->second.c_str()));
537 PyObject* res = PyObject_Call(
542 if (res) Py_DECREF(res);
547 template <
typename Numeric>
548 bool fill(
const std::vector<Numeric>&
x,
const std::vector<Numeric>&
y,
549 const std::map<std::string, std::string>& keywords) {
557 PyObject*
args = PyTuple_New(2);
558 PyTuple_SetItem(
args, 0, xarray);
559 PyTuple_SetItem(
args, 1, yarray);
562 PyObject* kwargs = PyDict_New();
563 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
564 PyDict_SetItemString(kwargs, it->first.c_str(),
565 PyUnicode_FromString(it->second.c_str()));
568 PyObject* res = PyObject_Call(
574 if (res) Py_DECREF(res);
579 template <
typename Numeric>
580 bool fill_between(
const std::vector<Numeric>&
x,
const std::vector<Numeric>& y1,
581 const std::vector<Numeric>& y2,
582 const std::map<std::string, std::string>& keywords) {
592 PyObject*
args = PyTuple_New(3);
593 PyTuple_SetItem(
args, 0, xarray);
594 PyTuple_SetItem(
args, 1, y1array);
595 PyTuple_SetItem(
args, 2, y2array);
598 PyObject* kwargs = PyDict_New();
599 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
600 it != keywords.end(); ++it) {
601 PyDict_SetItemString(kwargs, it->first.c_str(),
602 PyUnicode_FromString(it->second.c_str()));
605 PyObject* res = PyObject_Call(
610 if (res) Py_DECREF(res);
615 template <
typename Numeric>
616 bool hist(
const std::vector<Numeric>&
y,
long bins = 10,
617 std::string color =
"b",
double alpha = 1.0,
618 bool cumulative =
false) {
621 PyObject* kwargs = PyDict_New();
622 PyDict_SetItemString(kwargs,
"bins", PyLong_FromLong(bins));
623 PyDict_SetItemString(kwargs,
"color", PyString_FromString(color.c_str()));
624 PyDict_SetItemString(kwargs,
"alpha", PyFloat_FromDouble(alpha));
625 PyDict_SetItemString(kwargs,
"cumulative", cumulative ? Py_True : Py_False);
627 PyObject* plot_args = PyTuple_New(1);
629 PyTuple_SetItem(plot_args, 0, yarray);
631 PyObject* res = PyObject_Call(
634 Py_DECREF(plot_args);
636 if (res) Py_DECREF(res);
641 #ifndef WITHOUT_NUMPY
643 void imshow(
void* ptr,
const NPY_TYPES
type,
const int rows,
const int columns,
645 const std::map<std::string, std::string>& keywords) {
647 assert(colors == 1 || colors == 3 || colors == 4);
653 npy_intp dims[3] = {rows, columns, colors};
654 PyObject*
args = PyTuple_New(1);
656 args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims,
type, ptr));
659 PyObject* kwargs = PyDict_New();
660 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
661 it != keywords.end(); ++it) {
662 PyDict_SetItemString(kwargs, it->first.c_str(),
663 PyUnicode_FromString(it->second.c_str()));
666 PyObject* res = PyObject_Call(
670 if (!res)
throw std::runtime_error(
"Call to imshow() failed");
675 void imshow(
const unsigned char* ptr,
const int rows,
const int columns,
677 const std::map<std::string, std::string>& keywords = {}) {
681 void imshow(
const float* ptr,
const int rows,
const int columns,
683 const std::map<std::string, std::string>& keywords = {}) {
688 void imshow(
const cv::Mat& image,
689 const std::map<std::string, std::string>& keywords = {}) {
692 NPY_TYPES npy_type = NPY_UINT8;
693 switch (image.type() & CV_MAT_DEPTH_MASK) {
699 npy_type = NPY_FLOAT;
702 image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels()));
706 switch (image2.channels()) {
708 cv::cvtColor(image2, image2, CV_BGR2RGB);
711 cv::cvtColor(image2, image2, CV_BGRA2RGBA);
715 image2.channels(), keywords);
717 #endif // WITH_OPENCV
718 #endif // WITHOUT_NUMPY
720 template <
typename NumericX,
typename NumericY>
721 bool scatter(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
722 const double s = 1.0)
729 PyObject* kwargs = PyDict_New();
730 PyDict_SetItemString(kwargs,
"s", PyLong_FromLong(s));
732 PyObject* plot_args = PyTuple_New(2);
733 PyTuple_SetItem(plot_args, 0, xarray);
734 PyTuple_SetItem(plot_args, 1, yarray);
736 PyObject* res = PyObject_Call(
739 Py_DECREF(plot_args);
741 if (res) Py_DECREF(res);
746 template <
typename Numeric>
747 bool bar(
const std::vector<Numeric>&
y, std::string ec =
"black",
748 std::string ls =
"-",
double lw = 1.0,
749 const std::map<std::string, std::string>& keywords = {}) {
753 for (
int i = 0;
i <
y.size();
i++)
x.push_back(
i);
757 PyObject* kwargs = PyDict_New();
759 PyDict_SetItemString(kwargs,
"ec", PyString_FromString(ec.c_str()));
760 PyDict_SetItemString(kwargs,
"ls", PyString_FromString(ls.c_str()));
761 PyDict_SetItemString(kwargs,
"lw", PyFloat_FromDouble(lw));
763 PyObject* plot_args = PyTuple_New(2);
764 PyTuple_SetItem(plot_args, 0, xarray);
765 PyTuple_SetItem(plot_args, 1, yarray);
767 PyObject* res = PyObject_Call(
770 Py_DECREF(plot_args);
772 if (res) Py_DECREF(res);
778 const std::map<std::string, double>& keywords = {}) {
779 PyObject* kwargs = PyDict_New();
780 for (std::map<std::string, double>::const_iterator it = keywords.begin();
781 it != keywords.end(); ++it) {
782 PyDict_SetItemString(kwargs, it->first.c_str(),
783 PyFloat_FromDouble(it->second));
786 PyObject* plot_args = PyTuple_New(0);
788 PyObject* res = PyObject_Call(
792 Py_DECREF(plot_args);
794 if (res) Py_DECREF(res);
799 template <
typename Numeric>
801 long bins = 10, std::string color =
"b",
double alpha = 1.0) {
804 PyObject* kwargs = PyDict_New();
805 PyDict_SetItemString(kwargs,
"label", PyString_FromString(
label.c_str()));
806 PyDict_SetItemString(kwargs,
"bins", PyLong_FromLong(bins));
807 PyDict_SetItemString(kwargs,
"color", PyString_FromString(color.c_str()));
808 PyDict_SetItemString(kwargs,
"alpha", PyFloat_FromDouble(alpha));
810 PyObject* plot_args = PyTuple_New(1);
811 PyTuple_SetItem(plot_args, 0, yarray);
813 PyObject* res = PyObject_Call(
816 Py_DECREF(plot_args);
818 if (res) Py_DECREF(res);
823 template <
typename NumericX,
typename NumericY>
824 bool plot(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
825 const std::string& s =
"") {
831 PyObject* pystring = PyString_FromString(s.c_str());
833 PyObject* plot_args = PyTuple_New(3);
834 PyTuple_SetItem(plot_args, 0, xarray);
835 PyTuple_SetItem(plot_args, 1, yarray);
836 PyTuple_SetItem(plot_args, 2, pystring);
838 PyObject* res = PyObject_CallObject(
841 Py_DECREF(plot_args);
842 if (res) Py_DECREF(res);
847 template <
typename NumericX,
typename NumericY,
typename NumericU,
849 bool quiver(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
850 const std::vector<NumericU>& u,
const std::vector<NumericW>&
w,
851 const std::map<std::string, std::string>& keywords = {}) {
852 assert(
x.size() ==
y.size() &&
x.size() == u.size() && u.size() ==
w.size());
859 PyObject* plot_args = PyTuple_New(4);
860 PyTuple_SetItem(plot_args, 0, xarray);
861 PyTuple_SetItem(plot_args, 1, yarray);
862 PyTuple_SetItem(plot_args, 2, uarray);
863 PyTuple_SetItem(plot_args, 3, warray);
866 PyObject* kwargs = PyDict_New();
867 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
868 it != keywords.end(); ++it) {
869 PyDict_SetItemString(kwargs, it->first.c_str(),
870 PyUnicode_FromString(it->second.c_str()));
873 PyObject* res = PyObject_Call(
877 Py_DECREF(plot_args);
878 if (res) Py_DECREF(res);
883 template <
typename NumericX,
typename NumericY>
884 bool stem(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
885 const std::string& s =
"") {
891 PyObject* pystring = PyString_FromString(s.c_str());
893 PyObject* plot_args = PyTuple_New(3);
894 PyTuple_SetItem(plot_args, 0, xarray);
895 PyTuple_SetItem(plot_args, 1, yarray);
896 PyTuple_SetItem(plot_args, 2, pystring);
898 PyObject* res = PyObject_CallObject(
901 Py_DECREF(plot_args);
902 if (res) Py_DECREF(res);
907 template <
typename NumericX,
typename NumericY>
908 bool semilogx(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
909 const std::string& s =
"") {
915 PyObject* pystring = PyString_FromString(s.c_str());
917 PyObject* plot_args = PyTuple_New(3);
918 PyTuple_SetItem(plot_args, 0, xarray);
919 PyTuple_SetItem(plot_args, 1, yarray);
920 PyTuple_SetItem(plot_args, 2, pystring);
922 PyObject* res = PyObject_CallObject(
925 Py_DECREF(plot_args);
926 if (res) Py_DECREF(res);
931 template <
typename NumericX,
typename NumericY>
932 bool semilogy(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
933 const std::string& s =
"") {
939 PyObject* pystring = PyString_FromString(s.c_str());
941 PyObject* plot_args = PyTuple_New(3);
942 PyTuple_SetItem(plot_args, 0, xarray);
943 PyTuple_SetItem(plot_args, 1, yarray);
944 PyTuple_SetItem(plot_args, 2, pystring);
946 PyObject* res = PyObject_CallObject(
949 Py_DECREF(plot_args);
950 if (res) Py_DECREF(res);
955 template <
typename NumericX,
typename NumericY>
956 bool loglog(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
957 const std::string& s =
"") {
963 PyObject* pystring = PyString_FromString(s.c_str());
965 PyObject* plot_args = PyTuple_New(3);
966 PyTuple_SetItem(plot_args, 0, xarray);
967 PyTuple_SetItem(plot_args, 1, yarray);
968 PyTuple_SetItem(plot_args, 2, pystring);
970 PyObject* res = PyObject_CallObject(
973 Py_DECREF(plot_args);
974 if (res) Py_DECREF(res);
979 template <
typename NumericX,
typename NumericY>
980 bool errorbar(
const std::vector<NumericX>&
x,
const std::vector<NumericY>&
y,
981 const std::vector<NumericX>& yerr,
982 const std::map<std::string, std::string>& keywords = {}) {
990 PyObject* kwargs = PyDict_New();
991 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
992 it != keywords.end(); ++it) {
993 PyDict_SetItemString(kwargs, it->first.c_str(),
994 PyString_FromString(it->second.c_str()));
997 PyDict_SetItemString(kwargs,
"yerr", yerrarray);
999 PyObject* plot_args = PyTuple_New(2);
1000 PyTuple_SetItem(plot_args, 0, xarray);
1001 PyTuple_SetItem(plot_args, 1, yarray);
1008 Py_DECREF(plot_args);
1013 throw std::runtime_error(
"Call to errorbar() failed.");
1018 template <
typename Numeric>
1019 bool named_plot(
const std::string& name,
const std::vector<Numeric>&
y,
1020 const std::string&
format =
"") {
1021 PyObject* kwargs = PyDict_New();
1022 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1026 PyObject* pystring = PyString_FromString(
format.c_str());
1028 PyObject* plot_args = PyTuple_New(2);
1030 PyTuple_SetItem(plot_args, 0, yarray);
1031 PyTuple_SetItem(plot_args, 1, pystring);
1033 PyObject* res = PyObject_Call(
1037 Py_DECREF(plot_args);
1038 if (res) Py_DECREF(res);
1043 template <
typename Numeric>
1044 bool named_plot(
const std::string& name,
const std::vector<Numeric>&
x,
1045 const std::vector<Numeric>&
y,
const std::string&
format =
"") {
1046 PyObject* kwargs = PyDict_New();
1047 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1052 PyObject* pystring = PyString_FromString(
format.c_str());
1054 PyObject* plot_args = PyTuple_New(3);
1055 PyTuple_SetItem(plot_args, 0, xarray);
1056 PyTuple_SetItem(plot_args, 1, yarray);
1057 PyTuple_SetItem(plot_args, 2, pystring);
1059 PyObject* res = PyObject_Call(
1063 Py_DECREF(plot_args);
1064 if (res) Py_DECREF(res);
1069 template <
typename Numeric>
1071 const std::vector<Numeric>&
y,
1072 const std::string&
format =
"") {
1073 PyObject* kwargs = PyDict_New();
1074 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1079 PyObject* pystring = PyString_FromString(
format.c_str());
1081 PyObject* plot_args = PyTuple_New(3);
1082 PyTuple_SetItem(plot_args, 0, xarray);
1083 PyTuple_SetItem(plot_args, 1, yarray);
1084 PyTuple_SetItem(plot_args, 2, pystring);
1091 Py_DECREF(plot_args);
1092 if (res) Py_DECREF(res);
1097 template <
typename Numeric>
1099 const std::vector<Numeric>&
y,
1100 const std::string&
format =
"") {
1101 PyObject* kwargs = PyDict_New();
1102 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1107 PyObject* pystring = PyString_FromString(
format.c_str());
1109 PyObject* plot_args = PyTuple_New(3);
1110 PyTuple_SetItem(plot_args, 0, xarray);
1111 PyTuple_SetItem(plot_args, 1, yarray);
1112 PyTuple_SetItem(plot_args, 2, pystring);
1119 Py_DECREF(plot_args);
1120 if (res) Py_DECREF(res);
1125 template <
typename Numeric>
1127 const std::vector<Numeric>&
y,
1128 const std::string&
format =
"") {
1129 PyObject* kwargs = PyDict_New();
1130 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1135 PyObject* pystring = PyString_FromString(
format.c_str());
1137 PyObject* plot_args = PyTuple_New(3);
1138 PyTuple_SetItem(plot_args, 0, xarray);
1139 PyTuple_SetItem(plot_args, 1, yarray);
1140 PyTuple_SetItem(plot_args, 2, pystring);
1142 PyObject* res = PyObject_Call(
1146 Py_DECREF(plot_args);
1147 if (res) Py_DECREF(res);
1152 template <
typename Numeric>
1153 bool plot(
const std::vector<Numeric>&
y,
const std::string&
format =
"") {
1154 std::vector<Numeric>
x(
y.size());
1155 for (
size_t i = 0;
i <
x.size(); ++
i)
x.at(
i) =
i;
1159 template <
typename Numeric>
1160 bool plot(
const std::vector<Numeric>&
y,
1161 const std::map<std::string, std::string>& keywords) {
1162 std::vector<Numeric>
x(
y.size());
1163 for (
size_t i = 0;
i <
x.size(); ++
i)
x.at(
i) =
i;
1164 return plot(
x,
y, keywords);
1167 template <
typename Numeric>
1168 bool stem(
const std::vector<Numeric>&
y,
const std::string&
format =
"") {
1169 std::vector<Numeric>
x(
y.size());
1170 for (
size_t i = 0;
i <
x.size(); ++
i)
x.at(
i) =
i;
1174 template <
typename Numeric>
1175 void text(Numeric
x, Numeric
y,
const std::string& s =
"") {
1176 PyObject*
args = PyTuple_New(3);
1177 PyTuple_SetItem(
args, 0, PyFloat_FromDouble(
x));
1178 PyTuple_SetItem(
args, 1, PyFloat_FromDouble(
y));
1179 PyTuple_SetItem(
args, 2, PyString_FromString(s.c_str()));
1181 PyObject* res = PyObject_CallObject(
1183 if (!res)
throw std::runtime_error(
"Call to text() failed.");
1192 res = PyObject_CallObject(
1201 PyObject*
args = PyTuple_New(1);
1202 PyTuple_SetItem(
args, 0, PyLong_FromLong(number));
1203 res = PyObject_CallObject(
1208 if (!res)
throw std::runtime_error(
"Call to figure() failed.");
1210 PyObject* num = PyObject_GetAttrString(res,
"number");
1212 throw std::runtime_error(
"Could not get number attribute of figure object");
1213 const long figureNumber = PyLong_AsLong(num);
1218 return figureNumber;
1225 PyObject*
args = PyTuple_New(1);
1226 PyTuple_SetItem(
args, 0, PyLong_FromLong(number));
1227 PyObject* res = PyObject_CallObject(
1229 if (!res)
throw std::runtime_error(
"Call to fignum_exists() failed.");
1231 bool ret = PyObject_IsTrue(res);
1242 const size_t dpi = 100;
1243 PyObject* size = PyTuple_New(2);
1244 PyTuple_SetItem(size, 0, PyFloat_FromDouble((
double)
w / dpi));
1245 PyTuple_SetItem(size, 1, PyFloat_FromDouble((
double)
h / dpi));
1247 PyObject* kwargs = PyDict_New();
1248 PyDict_SetItemString(kwargs,
"figsize", size);
1249 PyDict_SetItemString(kwargs,
"dpi", PyLong_FromSize_t(dpi));
1257 if (!res)
throw std::runtime_error(
"Call to figure_size() failed.");
1265 if (!res)
throw std::runtime_error(
"Call to legend() failed.");
1270 template <
typename Numeric>
1271 void ylim(Numeric left, Numeric right) {
1272 PyObject* list = PyList_New(2);
1273 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1274 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1276 PyObject*
args = PyTuple_New(1);
1277 PyTuple_SetItem(
args, 0, list);
1279 PyObject* res = PyObject_CallObject(
1281 if (!res)
throw std::runtime_error(
"Call to ylim() failed.");
1287 template <
typename Numeric>
1288 void xlim(Numeric left, Numeric right) {
1289 PyObject* list = PyList_New(2);
1290 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1291 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1293 PyObject*
args = PyTuple_New(1);
1294 PyTuple_SetItem(
args, 0, list);
1296 PyObject* res = PyObject_CallObject(
1298 if (!res)
throw std::runtime_error(
"Call to xlim() failed.");
1305 PyObject*
args = PyTuple_New(0);
1306 PyObject* res = PyObject_CallObject(
1308 PyObject* left = PyTuple_GetItem(res, 0);
1309 PyObject* right = PyTuple_GetItem(res, 1);
1311 double* arr =
new double[2];
1312 arr[0] = PyFloat_AsDouble(left);
1313 arr[1] = PyFloat_AsDouble(right);
1315 if (!res)
throw std::runtime_error(
"Call to xlim() failed.");
1322 PyObject*
args = PyTuple_New(0);
1323 PyObject* res = PyObject_CallObject(
1325 PyObject* left = PyTuple_GetItem(res, 0);
1326 PyObject* right = PyTuple_GetItem(res, 1);
1328 double* arr =
new double[2];
1329 arr[0] = PyFloat_AsDouble(left);
1330 arr[1] = PyFloat_AsDouble(right);
1332 if (!res)
throw std::runtime_error(
"Call to ylim() failed.");
1338 template <
typename Numeric>
1339 inline void xticks(
const std::vector<Numeric>& ticks,
1340 const std::vector<std::string>& labels = {},
1341 const std::map<std::string, std::string>& keywords = {}) {
1342 assert(labels.size() == 0 || ticks.size() == labels.size());
1345 PyObject* ticksarray =
get_array(ticks);
1348 if (labels.size() == 0) {
1350 args = PyTuple_New(1);
1351 PyTuple_SetItem(
args, 0, ticksarray);
1354 PyObject* labelstuple = PyTuple_New(labels.size());
1355 for (
size_t i = 0;
i < labels.size();
i++)
1356 PyTuple_SetItem(labelstuple,
i, PyUnicode_FromString(labels[
i].c_str()));
1359 args = PyTuple_New(2);
1360 PyTuple_SetItem(
args, 0, ticksarray);
1361 PyTuple_SetItem(
args, 1, labelstuple);
1365 PyObject* kwargs = PyDict_New();
1366 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1367 it != keywords.end(); ++it) {
1368 PyDict_SetItemString(kwargs, it->first.c_str(),
1369 PyString_FromString(it->second.c_str()));
1372 PyObject* res = PyObject_Call(
1377 if (!res)
throw std::runtime_error(
"Call to xticks() failed");
1382 template <
typename Numeric>
1383 inline void xticks(
const std::vector<Numeric>& ticks,
1384 const std::map<std::string, std::string>& keywords) {
1385 xticks(ticks, {}, keywords);
1388 template <
typename Numeric>
1389 inline void yticks(
const std::vector<Numeric>& ticks,
1390 const std::vector<std::string>& labels = {},
1391 const std::map<std::string, std::string>& keywords = {}) {
1392 assert(labels.size() == 0 || ticks.size() == labels.size());
1395 PyObject* ticksarray =
get_array(ticks);
1398 if (labels.size() == 0) {
1400 args = PyTuple_New(1);
1401 PyTuple_SetItem(
args, 0, ticksarray);
1404 PyObject* labelstuple = PyTuple_New(labels.size());
1405 for (
size_t i = 0;
i < labels.size();
i++)
1406 PyTuple_SetItem(labelstuple,
i, PyUnicode_FromString(labels[
i].c_str()));
1409 args = PyTuple_New(2);
1410 PyTuple_SetItem(
args, 0, ticksarray);
1411 PyTuple_SetItem(
args, 1, labelstuple);
1415 PyObject* kwargs = PyDict_New();
1416 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1417 it != keywords.end(); ++it) {
1418 PyDict_SetItemString(kwargs, it->first.c_str(),
1419 PyString_FromString(it->second.c_str()));
1422 PyObject* res = PyObject_Call(
1427 if (!res)
throw std::runtime_error(
"Call to yticks() failed");
1432 template <
typename Numeric>
1433 inline void yticks(
const std::vector<Numeric>& ticks,
1434 const std::map<std::string, std::string>& keywords) {
1435 yticks(ticks, {}, keywords);
1438 inline void subplot(
long nrows,
long ncols,
long plot_number) {
1440 PyObject*
args = PyTuple_New(3);
1441 PyTuple_SetItem(
args, 0, PyFloat_FromDouble(nrows));
1442 PyTuple_SetItem(
args, 1, PyFloat_FromDouble(ncols));
1443 PyTuple_SetItem(
args, 2, PyFloat_FromDouble(plot_number));
1445 PyObject* res = PyObject_CallObject(
1447 if (!res)
throw std::runtime_error(
"Call to subplot() failed.");
1453 inline void title(
const std::string& titlestr,
1454 const std::map<std::string, std::string>& keywords = {}) {
1455 PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
1456 PyObject*
args = PyTuple_New(1);
1457 PyTuple_SetItem(
args, 0, pytitlestr);
1459 PyObject* kwargs = PyDict_New();
1460 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1461 PyDict_SetItemString(kwargs, it->first.c_str(),
1462 PyUnicode_FromString(it->second.c_str()));
1465 PyObject* res = PyObject_Call(
1467 if (!res)
throw std::runtime_error(
"Call to title() failed.");
1475 const std::map<std::string, std::string>& keywords = {}) {
1476 PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str());
1477 PyObject*
args = PyTuple_New(1);
1478 PyTuple_SetItem(
args, 0, pysuptitlestr);
1480 PyObject* kwargs = PyDict_New();
1481 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1482 PyDict_SetItemString(kwargs, it->first.c_str(),
1483 PyUnicode_FromString(it->second.c_str()));
1486 PyObject* res = PyObject_Call(
1488 if (!res)
throw std::runtime_error(
"Call to suptitle() failed.");
1495 inline void axis(
const std::string& axisstr) {
1496 PyObject*
str = PyString_FromString(axisstr.c_str());
1497 PyObject*
args = PyTuple_New(1);
1498 PyTuple_SetItem(
args, 0,
str);
1500 PyObject* res = PyObject_CallObject(
1502 if (!res)
throw std::runtime_error(
"Call to title() failed.");
1509 const std::map<std::string, std::string>& keywords = {}) {
1510 PyObject* pystr = PyString_FromString(
str.c_str());
1511 PyObject*
args = PyTuple_New(1);
1512 PyTuple_SetItem(
args, 0, pystr);
1514 PyObject* kwargs = PyDict_New();
1515 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1516 PyDict_SetItemString(kwargs, it->first.c_str(),
1517 PyUnicode_FromString(it->second.c_str()));
1520 PyObject* res = PyObject_Call(
1522 if (!res)
throw std::runtime_error(
"Call to xlabel() failed.");
1530 const std::map<std::string, std::string>& keywords = {}) {
1531 PyObject* pystr = PyString_FromString(
str.c_str());
1532 PyObject*
args = PyTuple_New(1);
1533 PyTuple_SetItem(
args, 0, pystr);
1535 PyObject* kwargs = PyDict_New();
1536 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1537 PyDict_SetItemString(kwargs, it->first.c_str(),
1538 PyUnicode_FromString(it->second.c_str()));
1541 PyObject* res = PyObject_Call(
1543 if (!res)
throw std::runtime_error(
"Call to ylabel() failed.");
1551 PyObject* pyflag = flag ? Py_True : Py_False;
1554 PyObject*
args = PyTuple_New(1);
1555 PyTuple_SetItem(
args, 0, pyflag);
1557 PyObject* res = PyObject_CallObject(
1559 if (!res)
throw std::runtime_error(
"Call to grid() failed.");
1565 inline void show(
const bool block =
true) {
1572 PyObject* kwargs = PyDict_New();
1573 PyDict_SetItemString(kwargs,
"block", Py_False);
1580 if (!res)
throw std::runtime_error(
"Call to show() failed.");
1590 if (!res)
throw std::runtime_error(
"Call to close() failed.");
1597 PyObject* kwargs = PyDict_New();
1604 if (!res)
throw std::runtime_error(
"Call to show() failed.");
1614 if (!res)
throw std::runtime_error(
"Call to draw() failed.");
1619 template <
typename Numeric>
1621 PyObject*
args = PyTuple_New(1);
1622 PyTuple_SetItem(
args, 0, PyFloat_FromDouble(interval));
1624 PyObject* res = PyObject_CallObject(
1626 if (!res)
throw std::runtime_error(
"Call to pause() failed.");
1633 PyObject* pyfilename = PyString_FromString(
filename.c_str());
1635 PyObject*
args = PyTuple_New(1);
1636 PyTuple_SetItem(
args, 0, pyfilename);
1638 PyObject* res = PyObject_CallObject(
1640 if (!res)
throw std::runtime_error(
"Call to save() failed.");
1651 if (!res)
throw std::runtime_error(
"Call to clf() failed.");
1661 if (!res)
throw std::runtime_error(
"Call to ion() failed.");
1666 inline std::vector<std::array<double, 2>>
ginput(
1667 const int numClicks = 1,
1668 const std::map<std::string, std::string>& keywords = {}) {
1669 PyObject*
args = PyTuple_New(1);
1670 PyTuple_SetItem(
args, 0, PyLong_FromLong(numClicks));
1673 PyObject* kwargs = PyDict_New();
1674 for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
1675 it != keywords.end(); ++it) {
1676 PyDict_SetItemString(kwargs, it->first.c_str(),
1677 PyUnicode_FromString(it->second.c_str()));
1680 PyObject* res = PyObject_Call(
1685 if (!res)
throw std::runtime_error(
"Call to ginput() failed.");
1687 const size_t len = PyList_Size(res);
1688 std::vector<std::array<double, 2>> out;
1690 for (
size_t i = 0;
i <
len;
i++) {
1691 PyObject* current = PyList_GetItem(res,
i);
1692 std::array<double, 2> position;
1693 position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0));
1694 position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1));
1695 out.push_back(position);
1704 PyObject* res = PyObject_CallObject(
1708 if (!res)
throw std::runtime_error(
"Call to tight_layout() failed.");
1717 template <
typename T>
1719 std::remove_pointer<std::remove_reference<T>>>
::type;
1721 template <
bool obj,
typename T>
1724 template <
typename T>
1729 template <
typename T>
1734 struct Derived : T, Fallback {};
1736 template <
typename U, U>
1739 template <
typename U>
1740 static std::true_type test(
1743 template <
typename U>
1744 static std::false_type test(Check<
void (Fallback::*)(), &U::operator()>*);
1747 typedef decltype(test<Derived>(
nullptr))
type;
1748 typedef decltype(&Fallback::operator()) dtype;
1752 template <typename T>
1758 template <
typename IsYDataCallable>
1763 template <
typename IterableX,
typename IterableY>
1765 const std::string&
format) {
1768 using std::distance;
1771 auto xs = distance(begin(
x),
end(
x));
1772 auto ys = distance(begin(
y),
end(
y));
1773 assert(
xs == ys &&
"x and y data must have the same number of elements!");
1775 PyObject* xlist = PyList_New(
xs);
1776 PyObject* ylist = PyList_New(ys);
1777 PyObject* pystring = PyString_FromString(
format.c_str());
1779 auto itx = begin(
x), ity = begin(
y);
1780 for (
size_t i = 0;
i <
xs; ++
i) {
1781 PyList_SetItem(xlist,
i, PyFloat_FromDouble(*itx++));
1782 PyList_SetItem(ylist,
i, PyFloat_FromDouble(*ity++));
1785 PyObject* plot_args = PyTuple_New(3);
1786 PyTuple_SetItem(plot_args, 0, xlist);
1787 PyTuple_SetItem(plot_args, 1, ylist);
1788 PyTuple_SetItem(plot_args, 2, pystring);
1790 PyObject* res = PyObject_CallObject(
1793 Py_DECREF(plot_args);
1794 if (res) Py_DECREF(res);
1802 template <
typename Iterable,
typename Callable>
1804 const std::string&
format) {
1805 if (begin(ticks) ==
end(ticks))
return true;
1809 std::vector<double>
y;
1810 for (
auto x : ticks)
y.push_back(f(
x));
1818 template <
typename... Args>
1823 template <
typename A,
typename B,
typename... Args>
1834 inline bool plot(
const std::vector<double>&
x,
const std::vector<double>&
y,
1835 const std::string&
format =
"") {
1836 return plot<double, double>(
x,
y,
format);
1839 inline bool plot(
const std::vector<double>&
y,
const std::string&
format =
"") {
1840 return plot<double>(
y,
format);
1843 inline bool plot(
const std::vector<double>&
x,
const std::vector<double>&
y,
1844 const std::map<std::string, std::string>& keywords) {
1845 return plot<double>(
x,
y, keywords);
1855 template <
typename Numeric>
1856 Plot(
const std::string& name,
const std::vector<Numeric>&
x,
1857 const std::vector<Numeric>&
y,
const std::string&
format =
"") {
1860 PyObject* kwargs = PyDict_New();
1862 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1867 PyObject* pystring = PyString_FromString(
format.c_str());
1869 PyObject* plot_args = PyTuple_New(3);
1870 PyTuple_SetItem(plot_args, 0, xarray);
1871 PyTuple_SetItem(plot_args, 1, yarray);
1872 PyTuple_SetItem(plot_args, 2, pystring);
1874 PyObject* res = PyObject_Call(
1878 Py_DECREF(plot_args);
1881 line = PyList_GetItem(res, 0);
1884 set_data_fct = PyObject_GetAttrString(
line,
"set_data");
1893 Plot(
const std::string& name =
"",
const std::string&
format =
"")
1896 template <
typename Numeric>
1897 bool update(
const std::vector<Numeric>&
x,
const std::vector<Numeric>&
y) {
1903 PyObject* plot_args = PyTuple_New(2);
1904 PyTuple_SetItem(plot_args, 0, xarray);
1905 PyTuple_SetItem(plot_args, 1, yarray);
1907 PyObject* res = PyObject_CallObject(set_data_fct, plot_args);
1908 if (res) Py_DECREF(res);
1915 bool clear() {
return update(std::vector<double>(), std::vector<double>()); }
1920 auto remove_fct = PyObject_GetAttrString(
line,
"remove");
1921 PyObject*
args = PyTuple_New(0);
1922 PyObject* res = PyObject_CallObject(remove_fct,
args);
1923 if (res) Py_DECREF(res);
1933 if (set_data_fct) Py_DECREF(set_data_fct);
1937 PyObject* set_data_fct =
nullptr;