18 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
19 #include <numpy/arrayobject.h>
22 #include <opencv2/opencv.hpp>
24 #endif // WITHOUT_NUMPY
26 #if PY_MAJOR_VERSION >= 3
27 #define PyString_FromString PyUnicode_FromString
28 #define PyInt_FromLong PyLong_FromLong
29 #define PyString_FromString PyUnicode_FromString
95 PyObject *fn = PyObject_GetAttrString(module, fname.c_str());
98 throw std::runtime_error(std::string(
"Couldn't find required function: ") + fname);
100 if (!PyFunction_Check(fn))
101 throw std::runtime_error(fname + std::string(
" is unexpectedly not a PyFunction."));
107 #ifndef WITHOUT_NUMPY
108 #if PY_MAJOR_VERSION >= 3
110 void *import_numpy() {
117 void import_numpy() {
127 #if PY_MAJOR_VERSION >= 3
128 wchar_t name[] = L
"plotting";
130 char name[] =
"plotting";
132 Py_SetProgramName(name);
135 #ifndef WITHOUT_NUMPY
139 PyObject *matplotlibname = PyString_FromString(
"matplotlib");
140 PyObject *pyplotname = PyString_FromString(
"matplotlib.pyplot");
141 PyObject *cmname = PyString_FromString(
"matplotlib.cm");
142 PyObject *pylabname = PyString_FromString(
"pylab");
143 if (!pyplotname || !pylabname || !matplotlibname || !cmname) {
144 throw std::runtime_error(
"couldnt create string");
147 PyObject *matplotlib = PyImport_Import(matplotlibname);
148 Py_DECREF(matplotlibname);
151 throw std::runtime_error(
"Error loading module matplotlib!");
157 PyObject_CallMethod(matplotlib,
const_cast<char *
>(
"use"),
const_cast<char *
>(
"s"),
s_backend.c_str());
160 PyObject *pymod = PyImport_Import(pyplotname);
161 Py_DECREF(pyplotname);
163 throw std::runtime_error(
"Error loading module matplotlib.pyplot!");
169 throw std::runtime_error(
"Error loading module matplotlib.cm!");
172 PyObject *pylabmod = PyImport_Import(pylabname);
173 Py_DECREF(pylabname);
175 throw std::runtime_error(
"Error loading module pylab!");
219 #ifndef WITHOUT_NUMPY
234 inline bool annotate(std::string annotation,
double x,
double y) {
235 PyObject *xy = PyTuple_New(2);
236 PyObject *str = PyString_FromString(annotation.c_str());
238 PyTuple_SetItem(xy, 0, PyFloat_FromDouble(x));
239 PyTuple_SetItem(xy, 1, PyFloat_FromDouble(y));
241 PyObject *kwargs = PyDict_New();
242 PyDict_SetItemString(kwargs,
"xy", xy);
244 PyObject *
args = PyTuple_New(1);
245 PyTuple_SetItem(
args, 0, str);
258 #ifndef WITHOUT_NUMPY
260 template <
typename T>
struct select_npy_type {
const static NPY_TYPES type = NPY_NOTYPE; };
261 template <>
struct select_npy_type<double> {
const static NPY_TYPES type = NPY_DOUBLE; };
262 template <>
struct select_npy_type<float> {
const static NPY_TYPES type = NPY_FLOAT; };
263 template <>
struct select_npy_type<bool> {
const static NPY_TYPES type = NPY_BOOL; };
264 template <>
struct select_npy_type<int8_t> {
const static NPY_TYPES type = NPY_INT8; };
265 template <>
struct select_npy_type<int16_t> {
const static NPY_TYPES type = NPY_SHORT; };
266 template <>
struct select_npy_type<int32_t> {
const static NPY_TYPES type = NPY_INT; };
267 template <>
struct select_npy_type<int64_t> {
const static NPY_TYPES type = NPY_INT64; };
268 template <>
struct select_npy_type<uint8_t> {
const static NPY_TYPES type = NPY_UINT8; };
269 template <>
struct select_npy_type<uint16_t> {
const static NPY_TYPES type = NPY_USHORT; };
270 template <>
struct select_npy_type<uint32_t> {
const static NPY_TYPES type = NPY_ULONG; };
271 template <>
struct select_npy_type<uint64_t> {
const static NPY_TYPES type = NPY_UINT64; };
273 template <
typename Numeric> PyObject *
get_array(
const std::vector<Numeric> &v) {
275 NPY_TYPES type = select_npy_type<Numeric>::type;
276 if (type == NPY_NOTYPE) {
277 std::vector<double> vd(v.size());
278 npy_intp vsize = v.size();
279 std::copy(v.begin(), v.end(), vd.begin());
280 PyObject *varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (
void *)(vd.data()));
284 npy_intp vsize = v.size();
285 PyObject *varray = PyArray_SimpleNewFromData(1, &vsize, type, (
void *)(v.data()));
289 template <
typename Numeric> PyObject *get_2darray(
const std::vector<::std::vector<Numeric>> &v) {
292 throw std::runtime_error(
"get_2d_array v too small");
294 npy_intp vsize[2] = {
static_cast<npy_intp
>(v.size()),
static_cast<npy_intp
>(v[0].size())};
296 PyArrayObject *varray = (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE);
298 double *vd_begin =
static_cast<double *
>(PyArray_DATA(varray));
300 for (const ::std::vector<Numeric> &v_row : v) {
301 if (v_row.size() !=
static_cast<size_t>(vsize[1]))
302 throw std::runtime_error(
"Missmatched array size");
303 std::copy(v_row.begin(), v_row.end(), vd_begin);
304 vd_begin += vsize[1];
307 return reinterpret_cast<PyObject *
>(varray);
310 #else // fallback if we don't have numpy: copy every element of the given vector
312 template <
typename Numeric> PyObject *
get_array(
const std::vector<Numeric> &v) {
313 PyObject *list = PyList_New(v.size());
314 for (
size_t i = 0; i < v.size(); ++i) {
315 PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i)));
320 #endif // WITHOUT_NUMPY
322 template <
typename Numeric>
323 bool plot(
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::map<std::string, std::string> &keywords) {
324 assert(x.size() == y.size());
331 PyObject *
args = PyTuple_New(2);
332 PyTuple_SetItem(
args, 0, xarray);
333 PyTuple_SetItem(
args, 1, yarray);
336 PyObject *kwargs = PyDict_New();
337 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
338 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
351 template <
typename Numeric>
352 void plot_surface(
const std::vector<::std::vector<Numeric>> &x,
const std::vector<::std::vector<Numeric>> &y,
353 const std::vector<::std::vector<Numeric>> &z,
354 const std::map<std::string, std::string> &keywords = std::map<std::string, std::string>()) {
359 static PyObject *mpl_toolkitsmod =
nullptr, *axis3dmod =
nullptr;
360 if (!mpl_toolkitsmod) {
363 PyObject *mpl_toolkits = PyString_FromString(
"mpl_toolkits");
364 PyObject *axis3d = PyString_FromString(
"mpl_toolkits.mplot3d");
365 if (!mpl_toolkits || !axis3d) {
366 throw std::runtime_error(
"couldnt create string");
369 mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
370 Py_DECREF(mpl_toolkits);
371 if (!mpl_toolkitsmod) {
372 throw std::runtime_error(
"Error loading module mpl_toolkits!");
375 axis3dmod = PyImport_Import(axis3d);
378 throw std::runtime_error(
"Error loading module mpl_toolkits.mplot3d!");
382 assert(x.size() == y.size());
383 assert(y.size() == z.size());
386 PyObject *xarray = get_2darray(x);
387 PyObject *yarray = get_2darray(y);
388 PyObject *zarray = get_2darray(z);
391 PyObject *
args = PyTuple_New(3);
392 PyTuple_SetItem(
args, 0, xarray);
393 PyTuple_SetItem(
args, 1, yarray);
394 PyTuple_SetItem(
args, 2, zarray);
397 PyObject *kwargs = PyDict_New();
398 PyDict_SetItemString(kwargs,
"rstride", PyInt_FromLong(1));
399 PyDict_SetItemString(kwargs,
"cstride", PyInt_FromLong(1));
403 PyDict_SetItemString(kwargs,
"cmap", python_colormap_coolwarm);
405 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
406 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
412 throw std::runtime_error(
"Call to figure() failed.");
414 PyObject *gca_kwargs = PyDict_New();
415 PyDict_SetItemString(gca_kwargs,
"projection", PyString_FromString(
"3d"));
417 PyObject *gca = PyObject_GetAttrString(fig,
"gca");
419 throw std::runtime_error(
"No gca");
424 throw std::runtime_error(
"No axis");
428 Py_DECREF(gca_kwargs);
432 throw std::runtime_error(
"No surface");
436 throw std::runtime_error(
"failed surface");
446 template <
typename Numeric>
447 bool stem(
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::map<std::string, std::string> &keywords) {
448 assert(x.size() == y.size());
455 PyObject *
args = PyTuple_New(2);
456 PyTuple_SetItem(
args, 0, xarray);
457 PyTuple_SetItem(
args, 1, yarray);
460 PyObject *kwargs = PyDict_New();
461 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
462 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
475 template <
typename Numeric>
476 bool fill(
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::map<std::string, std::string> &keywords) {
477 assert(x.size() == y.size());
484 PyObject *
args = PyTuple_New(2);
485 PyTuple_SetItem(
args, 0, xarray);
486 PyTuple_SetItem(
args, 1, yarray);
489 PyObject *kwargs = PyDict_New();
490 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
505 template <
typename Numeric>
506 bool fill_between(
const std::vector<Numeric> &x,
const std::vector<Numeric> &y1,
const std::vector<Numeric> &y2,
507 const std::map<std::string, std::string> &keywords) {
508 assert(x.size() == y1.size());
509 assert(x.size() == y2.size());
517 PyObject *
args = PyTuple_New(3);
518 PyTuple_SetItem(
args, 0, xarray);
519 PyTuple_SetItem(
args, 1, y1array);
520 PyTuple_SetItem(
args, 2, y2array);
523 PyObject *kwargs = PyDict_New();
524 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
538 template <
typename Numeric>
539 bool hist(
const std::vector<Numeric> &y,
long bins = 10, std::string color =
"b",
double alpha = 1.0,
bool cumulative =
false) {
543 PyObject *kwargs = PyDict_New();
544 PyDict_SetItemString(kwargs,
"bins", PyLong_FromLong(bins));
545 PyDict_SetItemString(kwargs,
"color", PyString_FromString(color.c_str()));
546 PyDict_SetItemString(kwargs,
"alpha", PyFloat_FromDouble(alpha));
547 PyDict_SetItemString(kwargs,
"cumulative", cumulative ? Py_True : Py_False);
549 PyObject *plot_args = PyTuple_New(1);
551 PyTuple_SetItem(plot_args, 0, yarray);
555 Py_DECREF(plot_args);
563 #ifndef WITHOUT_NUMPY
565 void imshow(
void *ptr,
const NPY_TYPES type,
const int rows,
const int columns,
const int colors,
566 const std::map<std::string, std::string> &keywords) {
567 assert(type == NPY_UINT8 || type == NPY_FLOAT);
568 assert(colors == 1 || colors == 3 || colors == 4);
573 npy_intp dims[3] = {rows, columns, colors};
574 PyObject *
args = PyTuple_New(1);
575 PyTuple_SetItem(
args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr));
578 PyObject *kwargs = PyDict_New();
579 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
587 throw std::runtime_error(
"Call to imshow() failed");
592 void imshow(
const unsigned char *ptr,
const int rows,
const int columns,
const int colors,
593 const std::map<std::string, std::string> &keywords = {}) {
594 internal::imshow((
void *)ptr, NPY_UINT8, rows, columns, colors, keywords);
597 void imshow(
const float *ptr,
const int rows,
const int columns,
const int colors,
598 const std::map<std::string, std::string> &keywords = {}) {
599 internal::imshow((
void *)ptr, NPY_FLOAT, rows, columns, colors, keywords);
603 void imshow(
const cv::Mat &image,
const std::map<std::string, std::string> &keywords = {}) {
606 NPY_TYPES npy_type = NPY_UINT8;
607 switch (image.type() & CV_MAT_DEPTH_MASK) {
613 npy_type = NPY_FLOAT;
616 image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels()));
620 switch (image2.channels()) {
622 cv::cvtColor(image2, image2, CV_BGR2RGB);
625 cv::cvtColor(image2, image2, CV_BGRA2RGBA);
628 internal::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords);
630 #endif // WITH_OPENCV
631 #endif // WITHOUT_NUMPY
633 template <
typename NumericX,
typename NumericY>
634 bool scatter(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
635 const double s = 1.0)
637 assert(x.size() == y.size());
642 PyObject *kwargs = PyDict_New();
643 PyDict_SetItemString(kwargs,
"s", PyLong_FromLong(
s));
645 PyObject *plot_args = PyTuple_New(2);
646 PyTuple_SetItem(plot_args, 0, xarray);
647 PyTuple_SetItem(plot_args, 1, yarray);
651 Py_DECREF(plot_args);
659 template <
typename Numeric>
660 bool bar(
const std::vector<Numeric> &y, std::string ec =
"black", std::string ls =
"-",
double lw = 1.0,
661 const std::map<std::string, std::string> &keywords = {}) {
665 for (
int i = 0; i < y.size(); i++)
670 PyObject *kwargs = PyDict_New();
672 PyDict_SetItemString(kwargs,
"ec", PyString_FromString(ec.c_str()));
673 PyDict_SetItemString(kwargs,
"ls", PyString_FromString(ls.c_str()));
674 PyDict_SetItemString(kwargs,
"lw", PyFloat_FromDouble(lw));
676 PyObject *plot_args = PyTuple_New(2);
677 PyTuple_SetItem(plot_args, 0, xarray);
678 PyTuple_SetItem(plot_args, 1, yarray);
682 Py_DECREF(plot_args);
692 PyObject *kwargs = PyDict_New();
693 for (std::map<std::string, double>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
694 PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second));
697 PyObject *plot_args = PyTuple_New(0);
701 Py_DECREF(plot_args);
709 template <
typename Numeric>
710 bool named_hist(std::string label,
const std::vector<Numeric> &y,
long bins = 10, std::string color =
"b",
double alpha = 1.0) {
713 PyObject *kwargs = PyDict_New();
714 PyDict_SetItemString(kwargs,
"label", PyString_FromString(label.c_str()));
715 PyDict_SetItemString(kwargs,
"bins", PyLong_FromLong(bins));
716 PyDict_SetItemString(kwargs,
"color", PyString_FromString(color.c_str()));
717 PyDict_SetItemString(kwargs,
"alpha", PyFloat_FromDouble(alpha));
719 PyObject *plot_args = PyTuple_New(1);
720 PyTuple_SetItem(plot_args, 0, yarray);
724 Py_DECREF(plot_args);
732 template <
typename NumericX,
typename NumericY>
733 bool plot(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
const std::string &s =
"") {
734 assert(x.size() == y.size());
739 PyObject *pystring = PyString_FromString(
s.c_str());
741 PyObject *plot_args = PyTuple_New(3);
742 PyTuple_SetItem(plot_args, 0, xarray);
743 PyTuple_SetItem(plot_args, 1, yarray);
744 PyTuple_SetItem(plot_args, 2, pystring);
748 Py_DECREF(plot_args);
755 template <
typename NumericX,
typename NumericY,
typename NumericU,
typename NumericW>
756 bool quiver(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
const std::vector<NumericU> &u,
const std::vector<NumericW> &w,
757 const std::map<std::string, std::string> &keywords = {}) {
758 assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size());
765 PyObject *plot_args = PyTuple_New(4);
766 PyTuple_SetItem(plot_args, 0, xarray);
767 PyTuple_SetItem(plot_args, 1, yarray);
768 PyTuple_SetItem(plot_args, 2, uarray);
769 PyTuple_SetItem(plot_args, 3, warray);
772 PyObject *kwargs = PyDict_New();
773 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
780 Py_DECREF(plot_args);
787 template <
typename NumericX>
788 bool boxplot(
const std::vector<NumericX> &x,
const double &position,
const double &width,
const std::string &color,
789 const std::string &linestyle,
const std::map<std::string, std::string> &keywords = {},
bool vert =
true) {
792 PyObject *plot_args = PyTuple_New(1);
793 PyTuple_SetItem(plot_args, 0,
get_array(x));
796 PyObject *kwargs = PyDict_New();
797 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
802 PyObject *positions = PyTuple_New(1);
803 PyTuple_SetItem(positions, 0, PyFloat_FromDouble(position));
804 PyDict_SetItemString(kwargs,
"positions", positions);
807 PyDict_SetItemString(kwargs,
"widths", PyFloat_FromDouble(width));
810 PyObject *cargs1 = PyDict_New();
813 PyDict_SetItemString(kwargs,
"capprops", cargs1);
814 PyDict_SetItemString(kwargs,
"whiskerprops", cargs1);
815 PyDict_SetItemString(kwargs,
"medianprops", cargs1);
816 PyDict_SetItemString(kwargs,
"boxprops", cargs1);
820 PyDict_SetItemString(kwargs,
"vert", Py_True);
822 PyDict_SetItemString(kwargs,
"vert", Py_False);
828 Py_DECREF(plot_args);
834 template <
typename NumericX,
typename NumericY>
835 bool stackplot(
const std::vector<NumericX> &x,
const std::vector<std::vector<NumericY>> &ys,
const std::vector<std::string> &labels,
836 const std::vector<std::string> &colors,
const std::string &baseline =
"zero") {
839 assert(ys.size() == labels.size());
840 assert(ys.size() == colors.size());
843 PyObject *plot_args = PyTuple_New(1 + (
int)ys.size());
844 PyTuple_SetItem(plot_args, 0,
get_array(x));
845 for (
size_t i = 0; i < ys.size(); i++) {
846 assert(x.size() == ys.at(i).size());
847 PyTuple_SetItem(plot_args, 1 + (
int)i,
get_array(ys.at(i)));
851 PyObject *list_labels = PyList_New(labels.size());
852 for (
size_t i = 0; i < labels.size(); i++) {
853 PyList_SetItem(list_labels, i, PyString_FromString(labels.at(i).c_str()));
857 PyObject *list_colors = PyList_New(colors.size());
858 for (
size_t i = 0; i < colors.size(); i++) {
859 PyList_SetItem(list_colors, i, PyString_FromString(colors.at(i).c_str()));
863 PyObject *kwargs = PyDict_New();
865 PyDict_SetItemString(kwargs,
"labels", list_labels);
866 PyDict_SetItemString(kwargs,
"colors", list_colors);
873 Py_DECREF(plot_args);
879 template <
typename NumericX,
typename NumericY>
880 bool stem(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
const std::string &s =
"") {
881 assert(x.size() == y.size());
886 PyObject *pystring = PyString_FromString(
s.c_str());
888 PyObject *plot_args = PyTuple_New(3);
889 PyTuple_SetItem(plot_args, 0, xarray);
890 PyTuple_SetItem(plot_args, 1, yarray);
891 PyTuple_SetItem(plot_args, 2, pystring);
895 Py_DECREF(plot_args);
902 template <
typename NumericX,
typename NumericY>
903 bool semilogx(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
const std::string &s =
"") {
904 assert(x.size() == y.size());
909 PyObject *pystring = PyString_FromString(
s.c_str());
911 PyObject *plot_args = PyTuple_New(3);
912 PyTuple_SetItem(plot_args, 0, xarray);
913 PyTuple_SetItem(plot_args, 1, yarray);
914 PyTuple_SetItem(plot_args, 2, pystring);
918 Py_DECREF(plot_args);
925 template <
typename NumericX,
typename NumericY>
926 bool semilogy(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
const std::string &s =
"") {
927 assert(x.size() == y.size());
932 PyObject *pystring = PyString_FromString(
s.c_str());
934 PyObject *plot_args = PyTuple_New(3);
935 PyTuple_SetItem(plot_args, 0, xarray);
936 PyTuple_SetItem(plot_args, 1, yarray);
937 PyTuple_SetItem(plot_args, 2, pystring);
941 Py_DECREF(plot_args);
948 template <
typename NumericX,
typename NumericY>
949 bool loglog(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
const std::string &s =
"") {
950 assert(x.size() == y.size());
955 PyObject *pystring = PyString_FromString(
s.c_str());
957 PyObject *plot_args = PyTuple_New(3);
958 PyTuple_SetItem(plot_args, 0, xarray);
959 PyTuple_SetItem(plot_args, 1, yarray);
960 PyTuple_SetItem(plot_args, 2, pystring);
964 Py_DECREF(plot_args);
971 template <
typename NumericX,
typename NumericY>
972 bool errorbar(
const std::vector<NumericX> &x,
const std::vector<NumericY> &y,
const std::vector<NumericX> &yerr,
973 const std::map<std::string, std::string> &keywords = {}) {
974 assert(x.size() == y.size());
981 PyObject *kwargs = PyDict_New();
982 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
983 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
986 PyDict_SetItemString(kwargs,
"yerr", yerrarray);
988 PyObject *plot_args = PyTuple_New(2);
989 PyTuple_SetItem(plot_args, 0, xarray);
990 PyTuple_SetItem(plot_args, 1, yarray);
995 Py_DECREF(plot_args);
1000 throw std::runtime_error(
"Call to errorbar() failed.");
1005 template <
typename Numeric>
bool named_plot(
const std::string &name,
const std::vector<Numeric> &y,
const std::string &format =
"") {
1006 PyObject *kwargs = PyDict_New();
1007 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1011 PyObject *pystring = PyString_FromString(format.c_str());
1013 PyObject *plot_args = PyTuple_New(2);
1015 PyTuple_SetItem(plot_args, 0, yarray);
1016 PyTuple_SetItem(plot_args, 1, pystring);
1021 Py_DECREF(plot_args);
1028 template <
typename Numeric>
1029 bool named_plot(
const std::string &name,
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::string &format =
"") {
1030 PyObject *kwargs = PyDict_New();
1031 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1036 PyObject *pystring = PyString_FromString(format.c_str());
1038 PyObject *plot_args = PyTuple_New(3);
1039 PyTuple_SetItem(plot_args, 0, xarray);
1040 PyTuple_SetItem(plot_args, 1, yarray);
1041 PyTuple_SetItem(plot_args, 2, pystring);
1046 Py_DECREF(plot_args);
1053 template <
typename Numeric>
1054 bool named_semilogx(
const std::string &name,
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::string &format =
"") {
1055 PyObject *kwargs = PyDict_New();
1056 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1061 PyObject *pystring = PyString_FromString(format.c_str());
1063 PyObject *plot_args = PyTuple_New(3);
1064 PyTuple_SetItem(plot_args, 0, xarray);
1065 PyTuple_SetItem(plot_args, 1, yarray);
1066 PyTuple_SetItem(plot_args, 2, pystring);
1071 Py_DECREF(plot_args);
1078 template <
typename Numeric>
1079 bool named_semilogy(
const std::string &name,
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::string &format =
"") {
1080 PyObject *kwargs = PyDict_New();
1081 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1086 PyObject *pystring = PyString_FromString(format.c_str());
1088 PyObject *plot_args = PyTuple_New(3);
1089 PyTuple_SetItem(plot_args, 0, xarray);
1090 PyTuple_SetItem(plot_args, 1, yarray);
1091 PyTuple_SetItem(plot_args, 2, pystring);
1096 Py_DECREF(plot_args);
1103 template <
typename Numeric>
1104 bool named_loglog(
const std::string &name,
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::string &format =
"") {
1105 PyObject *kwargs = PyDict_New();
1106 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1111 PyObject *pystring = PyString_FromString(format.c_str());
1113 PyObject *plot_args = PyTuple_New(3);
1114 PyTuple_SetItem(plot_args, 0, xarray);
1115 PyTuple_SetItem(plot_args, 1, yarray);
1116 PyTuple_SetItem(plot_args, 2, pystring);
1121 Py_DECREF(plot_args);
1128 template <
typename Numeric>
bool plot(
const std::vector<Numeric> &y,
const std::string &format =
"") {
1129 std::vector<Numeric> x(y.size());
1130 for (
size_t i = 0; i < x.size(); ++i)
1132 return plot(x, y, format);
1135 template <
typename Numeric>
bool plot(
const std::vector<Numeric> &y,
const std::map<std::string, std::string> &keywords) {
1136 std::vector<Numeric> x(y.size());
1137 for (
size_t i = 0; i < x.size(); ++i)
1139 return plot(x, y, keywords);
1142 template <
typename Numeric>
bool stem(
const std::vector<Numeric> &y,
const std::string &format =
"") {
1143 std::vector<Numeric> x(y.size());
1144 for (
size_t i = 0; i < x.size(); ++i)
1146 return stem(x, y, format);
1149 template <
typename Numeric>
void text(Numeric x, Numeric y,
const std::string &s =
"") {
1150 PyObject *
args = PyTuple_New(3);
1151 PyTuple_SetItem(
args, 0, PyFloat_FromDouble(x));
1152 PyTuple_SetItem(
args, 1, PyFloat_FromDouble(y));
1153 PyTuple_SetItem(
args, 2, PyString_FromString(
s.c_str()));
1157 throw std::runtime_error(
"Call to text() failed.");
1173 PyObject *
args = PyTuple_New(1);
1174 PyTuple_SetItem(
args, 0, PyLong_FromLong(number));
1180 throw std::runtime_error(
"Call to figure() failed.");
1182 PyObject *num = PyObject_GetAttrString(res,
"number");
1184 throw std::runtime_error(
"Could not get number attribute of figure object");
1185 const long figureNumber = PyLong_AsLong(num);
1190 return figureNumber;
1197 PyObject *
args = PyTuple_New(1);
1198 PyTuple_SetItem(
args, 0, PyLong_FromLong(number));
1201 throw std::runtime_error(
"Call to fignum_exists() failed.");
1203 bool ret = PyObject_IsTrue(res);
1214 const size_t dpi = 100;
1215 PyObject *size = PyTuple_New(2);
1216 PyTuple_SetItem(size, 0, PyFloat_FromDouble((
double)w / dpi));
1217 PyTuple_SetItem(size, 1, PyFloat_FromDouble((
double)h / dpi));
1219 PyObject *kwargs = PyDict_New();
1220 PyDict_SetItemString(kwargs,
"figsize", size);
1221 PyDict_SetItemString(kwargs,
"dpi", PyLong_FromSize_t(dpi));
1229 throw std::runtime_error(
"Call to figure_size() failed.");
1237 throw std::runtime_error(
"Call to legend() failed.");
1242 template <
typename Numeric>
void ylim(Numeric left, Numeric right) {
1243 PyObject *list = PyList_New(2);
1244 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1245 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1247 PyObject *
args = PyTuple_New(1);
1248 PyTuple_SetItem(
args, 0, list);
1252 throw std::runtime_error(
"Call to ylim() failed.");
1258 template <
typename Numeric>
void xlim(Numeric left, Numeric right) {
1259 PyObject *list = PyList_New(2);
1260 PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1261 PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1263 PyObject *
args = PyTuple_New(1);
1264 PyTuple_SetItem(
args, 0, list);
1268 throw std::runtime_error(
"Call to xlim() failed.");
1275 PyObject *
args = PyTuple_New(0);
1277 PyObject *left = PyTuple_GetItem(res, 0);
1278 PyObject *right = PyTuple_GetItem(res, 1);
1280 double *arr =
new double[2];
1281 arr[0] = PyFloat_AsDouble(left);
1282 arr[1] = PyFloat_AsDouble(right);
1285 throw std::runtime_error(
"Call to xlim() failed.");
1292 PyObject *
args = PyTuple_New(0);
1294 PyObject *left = PyTuple_GetItem(res, 0);
1295 PyObject *right = PyTuple_GetItem(res, 1);
1297 double *arr =
new double[2];
1298 arr[0] = PyFloat_AsDouble(left);
1299 arr[1] = PyFloat_AsDouble(right);
1302 throw std::runtime_error(
"Call to ylim() failed.");
1308 template <
typename Numeric>
1309 inline void xticks(
const std::vector<Numeric> &ticks,
const std::vector<std::string> &labels = {},
1310 const std::map<std::string, std::string> &keywords = {}) {
1311 assert(labels.size() == 0 || ticks.size() == labels.size());
1314 PyObject *ticksarray =
get_array(ticks);
1317 if (labels.size() == 0) {
1319 args = PyTuple_New(1);
1320 PyTuple_SetItem(
args, 0, ticksarray);
1323 PyObject *labelstuple = PyTuple_New(labels.size());
1324 for (
size_t i = 0; i < labels.size(); i++)
1328 args = PyTuple_New(2);
1329 PyTuple_SetItem(
args, 0, ticksarray);
1330 PyTuple_SetItem(
args, 1, labelstuple);
1334 PyObject *kwargs = PyDict_New();
1335 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
1336 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1344 throw std::runtime_error(
"Call to xticks() failed");
1349 template <
typename Numeric>
inline void xticks(
const std::vector<Numeric> &ticks,
const std::map<std::string, std::string> &keywords) {
1350 xticks(ticks, {}, keywords);
1353 template <
typename Numeric>
1354 inline void yticks(
const std::vector<Numeric> &ticks,
const std::vector<std::string> &labels = {},
1355 const std::map<std::string, std::string> &keywords = {}) {
1356 assert(labels.size() == 0 || ticks.size() == labels.size());
1359 PyObject *ticksarray =
get_array(ticks);
1362 if (labels.size() == 0) {
1364 args = PyTuple_New(1);
1365 PyTuple_SetItem(
args, 0, ticksarray);
1368 PyObject *labelstuple = PyTuple_New(labels.size());
1369 for (
size_t i = 0; i < labels.size(); i++)
1373 args = PyTuple_New(2);
1374 PyTuple_SetItem(
args, 0, ticksarray);
1375 PyTuple_SetItem(
args, 1, labelstuple);
1379 PyObject *kwargs = PyDict_New();
1380 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
1381 PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1389 throw std::runtime_error(
"Call to yticks() failed");
1394 template <
typename Numeric>
inline void yticks(
const std::vector<Numeric> &ticks,
const std::map<std::string, std::string> &keywords) {
1395 yticks(ticks, {}, keywords);
1398 inline void subplot(
long nrows,
long ncols,
long plot_number) {
1400 PyObject *
args = PyTuple_New(3);
1401 PyTuple_SetItem(
args, 0, PyLong_FromLong(nrows));
1402 PyTuple_SetItem(
args, 1, PyLong_FromLong(ncols));
1403 PyTuple_SetItem(
args, 2, PyLong_FromLong(plot_number));
1407 throw std::runtime_error(
"Call to subplot() failed.");
1413 inline void title(
const std::string &titlestr,
const std::map<std::string, std::string> &keywords = {}) {
1414 PyObject *pytitlestr = PyString_FromString(titlestr.c_str());
1415 PyObject *
args = PyTuple_New(1);
1416 PyTuple_SetItem(
args, 0, pytitlestr);
1418 PyObject *kwargs = PyDict_New();
1419 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1425 throw std::runtime_error(
"Call to title() failed.");
1432 inline void suptitle(
const std::string &suptitlestr,
const std::map<std::string, std::string> &keywords = {}) {
1433 PyObject *pysuptitlestr = PyString_FromString(suptitlestr.c_str());
1434 PyObject *
args = PyTuple_New(1);
1435 PyTuple_SetItem(
args, 0, pysuptitlestr);
1437 PyObject *kwargs = PyDict_New();
1438 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1444 throw std::runtime_error(
"Call to suptitle() failed.");
1451 inline void axis(
const std::string &axisstr) {
1452 PyObject *str = PyString_FromString(axisstr.c_str());
1453 PyObject *
args = PyTuple_New(1);
1454 PyTuple_SetItem(
args, 0, str);
1458 throw std::runtime_error(
"Call to title() failed.");
1464 inline void xlabel(
const std::string &str,
const std::map<std::string, std::string> &keywords = {}) {
1465 PyObject *pystr = PyString_FromString(str.c_str());
1466 PyObject *
args = PyTuple_New(1);
1467 PyTuple_SetItem(
args, 0, pystr);
1469 PyObject *kwargs = PyDict_New();
1470 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1476 throw std::runtime_error(
"Call to xlabel() failed.");
1483 inline void ylabel(
const std::string &str,
const std::map<std::string, std::string> &keywords = {}) {
1484 PyObject *pystr = PyString_FromString(str.c_str());
1485 PyObject *
args = PyTuple_New(1);
1486 PyTuple_SetItem(
args, 0, pystr);
1488 PyObject *kwargs = PyDict_New();
1489 for (
auto it = keywords.begin(); it != keywords.end(); ++it) {
1495 throw std::runtime_error(
"Call to ylabel() failed.");
1503 PyObject *pyflag = flag ? Py_True : Py_False;
1506 PyObject *
args = PyTuple_New(1);
1507 PyTuple_SetItem(
args, 0, pyflag);
1511 throw std::runtime_error(
"Call to grid() failed.");
1517 inline void show(
const bool block =
true) {
1522 PyObject *kwargs = PyDict_New();
1523 PyDict_SetItemString(kwargs,
"block", Py_False);
1529 throw std::runtime_error(
"Call to show() failed.");
1539 throw std::runtime_error(
"Call to close() failed.");
1546 PyObject *kwargs = PyDict_New();
1553 throw std::runtime_error(
"Call to show() failed.");
1562 throw std::runtime_error(
"Call to draw() failed.");
1567 template <
typename Numeric>
inline void pause(Numeric interval) {
1568 PyObject *
args = PyTuple_New(1);
1569 PyTuple_SetItem(
args, 0, PyFloat_FromDouble(interval));
1573 throw std::runtime_error(
"Call to pause() failed.");
1579 inline void save(
const std::string &filename) {
1580 PyObject *pyfilename = PyString_FromString(filename.c_str());
1582 PyObject *
args = PyTuple_New(1);
1583 PyTuple_SetItem(
args, 0, pyfilename);
1587 throw std::runtime_error(
"Call to save() failed.");
1597 throw std::runtime_error(
"Call to clf() failed.");
1606 throw std::runtime_error(
"Call to ion() failed.");
1611 inline std::vector<std::array<double, 2>>
ginput(
const int numClicks = 1,
const std::map<std::string, std::string> &keywords = {}) {
1612 PyObject *
args = PyTuple_New(1);
1613 PyTuple_SetItem(
args, 0, PyLong_FromLong(numClicks));
1616 PyObject *kwargs = PyDict_New();
1617 for (std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
1626 throw std::runtime_error(
"Call to ginput() failed.");
1628 const size_t len = PyList_Size(res);
1629 std::vector<std::array<double, 2>> out;
1631 for (
size_t i = 0; i < len; i++) {
1632 PyObject *current = PyList_GetItem(res, i);
1633 std::array<double, 2> position;
1634 position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0));
1635 position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1));
1636 out.push_back(position);
1649 throw std::runtime_error(
"Call to tight_layout() failed.");
1658 template <
typename T>
using is_function =
typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
1668 struct Derived : T, Fallback {};
1670 template <
typename U, U>
struct Check;
1672 template <
typename U>
1673 static std::true_type
test(...);
1675 template <
typename U>
static std::false_type
test(Check<
void (Fallback::*)(), &U::operator()> *);
1678 typedef decltype(test<Derived>(
nullptr)) type;
1679 typedef decltype(&Fallback::operator()) dtype;
1680 static constexpr
bool value = type::value;
1691 template <
typename IterableX,
typename IterableY>
bool operator()(
const IterableX &x,
const IterableY &y,
const std::string &format) {
1694 using std::distance;
1697 auto xs = distance(begin(x), end(x));
1698 auto ys = distance(begin(y), end(y));
1699 assert(xs == ys &&
"x and y data must have the same number of elements!");
1701 PyObject *xlist = PyList_New(xs);
1702 PyObject *ylist = PyList_New(ys);
1703 PyObject *pystring = PyString_FromString(format.c_str());
1705 auto itx = begin(x), ity = begin(y);
1706 for (
size_t i = 0; i < xs; ++i) {
1707 PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
1708 PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
1711 PyObject *plot_args = PyTuple_New(3);
1712 PyTuple_SetItem(plot_args, 0, xlist);
1713 PyTuple_SetItem(plot_args, 1, ylist);
1714 PyTuple_SetItem(plot_args, 2, pystring);
1718 Py_DECREF(plot_args);
1727 template <
typename Iterable,
typename Callable>
bool operator()(
const Iterable &ticks,
const Callable &f,
const std::string &format) {
1728 if (begin(ticks) == end(ticks))
1733 std::vector<double> y;
1734 for (
auto x : ticks)
1743 template <
typename... Args>
bool plot() {
return true; }
1745 template <
typename A,
typename B,
typename... Args>
bool plot(
const A &a,
const B &b,
const std::string &format, Args...
args) {
1753 inline bool plot(
const std::vector<double> &x,
const std::vector<double> &y,
const std::string &format =
"") {
1754 return plot<double, double>(x, y, format);
1757 inline bool plot(
const std::vector<double> &y,
const std::string &format =
"") {
return plot<double>(y, format); }
1759 inline bool plot(
const std::vector<double> &x,
const std::vector<double> &y,
const std::map<std::string, std::string> &keywords) {
1760 return plot<double>(x, y, keywords);
1770 template <
typename Numeric>
1771 Plot(
const std::string &name,
const std::vector<Numeric> &x,
const std::vector<Numeric> &y,
const std::string &format =
"") {
1773 assert(x.size() == y.size());
1775 PyObject *kwargs = PyDict_New();
1777 PyDict_SetItemString(kwargs,
"label", PyString_FromString(name.c_str()));
1782 PyObject *pystring = PyString_FromString(format.c_str());
1784 PyObject *plot_args = PyTuple_New(3);
1785 PyTuple_SetItem(plot_args, 0, xarray);
1786 PyTuple_SetItem(plot_args, 1, yarray);
1787 PyTuple_SetItem(plot_args, 2, pystring);
1792 Py_DECREF(plot_args);
1795 line = PyList_GetItem(res, 0);
1798 set_data_fct = PyObject_GetAttrString(line,
"set_data");
1807 Plot(
const std::string &name =
"",
const std::string &format =
"") :
Plot(name,
std::vector<double>(),
std::vector<double>(), format) {}
1809 template <
typename Numeric>
bool update(
const std::vector<Numeric> &x,
const std::vector<Numeric> &y) {
1810 assert(x.size() == y.size());
1815 PyObject *plot_args = PyTuple_New(2);
1816 PyTuple_SetItem(plot_args, 0, xarray);
1817 PyTuple_SetItem(plot_args, 1, yarray);
1819 PyObject *res = PyObject_CallObject(set_data_fct, plot_args);
1828 bool clear() {
return update(std::vector<double>(), std::vector<double>()); }
1833 auto remove_fct = PyObject_GetAttrString(line,
"remove");
1834 PyObject *
args = PyTuple_New(0);
1835 PyObject *res = PyObject_CallObject(remove_fct,
args);
1849 Py_DECREF(set_data_fct);
1852 PyObject *line =
nullptr;
1853 PyObject *set_data_fct =
nullptr;