From e2292d56b5568eac6fbe90415cc7223c9194fb6a Mon Sep 17 00:00:00 2001 From: yjchen Date: Tue, 7 Feb 2023 21:47:42 +0800 Subject: [PATCH 01/12] Add 2d and 3d vector support to quiver interface. - Add new functions to library header. - Modify quiver example. --- .gitignore | 3 + CMakeLists.txt | 4 ++ examples/quiver.cpp | 46 ++++++++++--- matplotlibcpp.h | 162 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1c4a1b0a..bd72326a 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ # vim temp files *.sw* + +.vscode +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index bb2decd8..6b554138 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,10 @@ add_executable(lines3d examples/lines3d.cpp) target_link_libraries(lines3d PRIVATE matplotlib_cpp) set_target_properties(lines3d PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +add_executable(quiver examples/quiver.cpp) +target_link_libraries(quiver PRIVATE matplotlib_cpp) +set_target_properties(quiver PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + if(Python3_NumPy_FOUND) add_executable(surface examples/surface.cpp) target_link_libraries(surface PRIVATE matplotlib_cpp) diff --git a/examples/quiver.cpp b/examples/quiver.cpp index ea3c3eca..26bc40f0 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -1,20 +1,46 @@ +#include +#include + #include "../matplotlibcpp.h" namespace plt = matplotlibcpp; -int main() -{ +int main() { // u and v are respectively the x and y components of the arrows we're plotting - std::vector x, y, u, v; - for (int i = -5; i <= 5; i++) { - for (int j = -5; j <= 5; j++) { - x.push_back(i); - u.push_back(-i); - y.push_back(j); - v.push_back(-j); + int n0 = 11; + int n1 = 11; + int n2 = 11; + + int *x, *y, *z, *u, *v, *w; + x = new int[n0 * n1 * n2]; + y = new int[n0 * n1 * n2]; + z = new int[n0 * n1 * n2]; + u = new int[n0 * n1 * n2]; + v = new int[n0 * n1 * n2]; + w = new int[n0 * n1 * n2]; + + for (int i = 0; i < n0; i++) { + for (int j = 0; j < n1; j++) { + for (int k = 0; k < n2; k++) { + int idx = k + n2 * (j + n1 * i); + x[idx] = k - 5; + y[idx] = j - 5; + z[idx] = i - 5; + u[idx] = k - 5; + v[idx] = j - 5; + w[idx] = i - 5; + } } } - plt::quiver(x, y, u, v); + std::map kwargs = {{"normalize", "True"}}; + plt::quiver(x, y, z, u, v, w, n0, n1, n2, kwargs); plt::show(); + + delete[] x; + delete[] y; + delete[] z; + delete[] u; + delete[] v; + delete[] w; } \ No newline at end of file diff --git a/matplotlibcpp.h b/matplotlibcpp.h index d95d46ad..2a17f4c1 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -374,6 +374,51 @@ PyObject* get_array(const std::vector& v) return varray; } +template +PyObject* get_2darray(const Numeric* vp, const size_t& n0, const size_t& n1) +{ + npy_intp dims[2]; + dims[0] = n0; + dims[1] = n1; + NPY_TYPES type = select_npy_type::type; + if (type == NPY_NOTYPE) { + size_t arrsize = n0*n1; + size_t memsize = arrsize*sizeof(double); + double* dp = static_cast(::malloc(memsize)); + for (size_t i=0; i(varray), NPY_ARRAY_OWNDATA); + return varray; + } + + PyObject* varray = PyArray_SimpleNewFromData(2, dims, type, (void*)(vp)); + return varray; +} + +template +PyObject* get_3darray(const Numeric* vp, const size_t& n0, const size_t& n1, const size_t& n2) +{ + npy_intp dims[3]; + dims[0] = n0; + dims[1] = n1; + dims[2] = n2; + NPY_TYPES type = select_npy_type::type; + if (type == NPY_NOTYPE) { + size_t arrsize = n0*n1*n2; + size_t memsize = arrsize*sizeof(double); + double* dp = static_cast(::malloc(memsize)); + for (size_t i=0; i(varray), NPY_ARRAY_OWNDATA); + return varray; + } + + PyObject* varray = PyArray_SimpleNewFromData(3, dims, type, (void*)(vp)); + return varray; +} + template PyObject* get_2darray(const std::vector<::std::vector>& v) @@ -1448,6 +1493,40 @@ bool quiver(const std::vector& x, const std::vector& y, cons return res; } +template +bool quiver(const NumericX* x, const NumericY* y, const NumericU* u, const NumericW* w, const size_t& n0, const size_t& n1, const std::map& keywords = {}) +{ + detail::_interpreter::get(); + + PyObject* xarray = detail::get_2darray(x, n0, n1); + PyObject* yarray = detail::get_2darray(y, n0, n1); + PyObject* uarray = detail::get_2darray(u, n0, n1); + PyObject* warray = detail::get_2darray(w, n0, n1); + + PyObject* plot_args = PyTuple_New(4); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, uarray); + PyTuple_SetItem(plot_args, 3, warray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } + + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); + + return res; +} + template bool quiver(const std::vector& x, const std::vector& y, const std::vector& z, const std::vector& u, const std::vector& w, const std::vector& v, const std::map& keywords = {}) { @@ -1534,6 +1613,89 @@ bool quiver(const std::vector& x, const std::vector& y, cons return res; } +template +bool quiver(const NumericX* x, const NumericY* y, const NumericZ* z, const NumericU* u, const NumericW* w, const NumericV* v, const size_t& n0, const size_t& n1, const size_t& n2, const std::map& keywords = {}) +{ + //set up 3d axes stuff + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + detail::_interpreter::get(); + + PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } + } + + //set up parameters + detail::_interpreter::get(); + + PyObject* xarray = detail::get_3darray(x, n0, n1, n2); + PyObject* yarray = detail::get_3darray(y, n0, n1, n2); + PyObject* zarray = detail::get_3darray(z, n0, n1, n2); + PyObject* uarray = detail::get_3darray(u, n0, n1, n2); + PyObject* warray = detail::get_3darray(w, n0, n1, n2); + PyObject* varray = detail::get_3darray(v, n0, n1, n2); + + PyObject* plot_args = PyTuple_New(6); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, zarray); + PyTuple_SetItem(plot_args, 3, uarray); + PyTuple_SetItem(plot_args, 4, warray); + PyTuple_SetItem(plot_args, 5, varray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } + + //get figure gca to enable 3d projection + PyObject *fig = + PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + if (!fig) throw std::runtime_error("Call to figure() failed."); + + PyObject *gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject *gca = PyObject_GetAttrString(fig, "add_subplot"); + if (!gca) throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject *axis = PyObject_Call( + gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + //plot our boys bravely, plot them strongly, plot them with a wink and clap + PyObject *plot3 = PyObject_GetAttrString(axis, "quiver"); + if (!plot3) throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject* res = PyObject_Call( + plot3, plot_args, kwargs); + if (!res) throw std::runtime_error("Failed 3D plot"); + Py_DECREF(plot3); + Py_DECREF(axis); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); + + return res; +} + template bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") { From c20513c7f9d06ccc07c36e66d8cb488e4e6060ac Mon Sep 17 00:00:00 2001 From: yjchen Date: Wed, 8 Feb 2023 00:43:41 +0800 Subject: [PATCH 02/12] Add float value support in keyword args. --- examples/quiver.cpp | 20 ++++++++++---------- matplotlibcpp.h | 22 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/examples/quiver.cpp b/examples/quiver.cpp index 26bc40f0..55a562bd 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -7,9 +7,9 @@ namespace plt = matplotlibcpp; int main() { // u and v are respectively the x and y components of the arrows we're plotting - int n0 = 11; - int n1 = 11; - int n2 = 11; + int n0 = 5; + int n1 = 5; + int n2 = 5; int *x, *y, *z, *u, *v, *w; x = new int[n0 * n1 * n2]; @@ -23,17 +23,17 @@ int main() { for (int j = 0; j < n1; j++) { for (int k = 0; k < n2; k++) { int idx = k + n2 * (j + n1 * i); - x[idx] = k - 5; - y[idx] = j - 5; - z[idx] = i - 5; - u[idx] = k - 5; - v[idx] = j - 5; - w[idx] = i - 5; + x[idx] = k - 2; + y[idx] = j - 2; + z[idx] = i - 2; + u[idx] = k - 2; + v[idx] = j - 2; + w[idx] = i - 2; } } } - std::map kwargs = {{"normalize", "True"}}; + std::map kwargs = {{"normalize", "True"}, {"length", "0.3"}}; plt::quiver(x, y, z, u, v, w, n0, n1, n2, kwargs); plt::show(); diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 2a17f4c1..d17eb4f2 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -14,6 +14,7 @@ #include // requires c++11 support #include #include // std::stod +#include #ifndef WITHOUT_NUMPY # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION @@ -1457,6 +1458,14 @@ bool contour(const std::vector& x, const std::vector& y, return res; } +bool isFloat(std::string s) { + std::istringstream iss(s); + float f; + iss >> std::noskipws >> f; // noskipws considers leading whitespace invalid + // Check the entire string was consumed and if either failbit or badbit is set + return iss.eof() && !iss.fail(); +} + template bool quiver(const std::vector& x, const std::vector& y, const std::vector& u, const std::vector& w, const std::map& keywords = {}) { @@ -1513,7 +1522,12 @@ bool quiver(const NumericX* x, const NumericY* y, const NumericU* u, const Numer PyObject* kwargs = PyDict_New(); for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + if(isFloat(it->second)) { + PyObject *float_str = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromString(float_str)); + } else { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } } PyObject* res = PyObject_Call( @@ -1656,7 +1670,13 @@ bool quiver(const NumericX* x, const NumericY* y, const NumericZ* z, const Numer PyObject* kwargs = PyDict_New(); for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { + if(isFloat(it->second)) { + PyObject *float_str = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromString(float_str)); + } + else { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } } //get figure gca to enable 3d projection From 0f87c41eb24ad814e93f9afacffc0954ba754d49 Mon Sep 17 00:00:00 2001 From: yjchen Date: Thu, 9 Feb 2023 10:17:40 +0800 Subject: [PATCH 03/12] Beautify the code. --- matplotlibcpp.h | 2709 ++++++++++++++++++++++++----------------------- 1 file changed, 1357 insertions(+), 1352 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index d17eb4f2..fb8bd48f 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -4,43 +4,42 @@ // they define _POSIX_C_SOURCE #include -#include -#include -#include -#include #include -#include -#include -#include // requires c++11 support +#include +#include // requires c++11 support #include -#include // std::stod +#include +#include +#include #include +#include +#include // std::stod +#include #ifndef WITHOUT_NUMPY -# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -# include +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include -# ifdef WITH_OPENCV -# include -# endif // WITH_OPENCV +#ifdef WITH_OPENCV +#include +#endif // WITH_OPENCV /* * A bunch of constants were removed in OpenCV 4 in favour of enum classes, so * define the ones we need here. */ -# if CV_MAJOR_VERSION > 3 -# define CV_BGR2RGB cv::COLOR_BGR2RGB -# define CV_BGRA2RGBA cv::COLOR_BGRA2RGBA -# endif -#endif // WITHOUT_NUMPY +#if CV_MAJOR_VERSION > 3 +#define CV_BGR2RGB cv::COLOR_BGR2RGB +#define CV_BGRA2RGBA cv::COLOR_BGRA2RGBA +#endif +#endif // WITHOUT_NUMPY #if PY_MAJOR_VERSION >= 3 -# define PyString_FromString PyUnicode_FromString -# define PyInt_FromLong PyLong_FromLong -# define PyString_FromString PyUnicode_FromString +#define PyString_FromString PyUnicode_FromString +#define PyInt_FromLong PyLong_FromLong +#define PyString_FromString PyUnicode_FromString #endif - namespace matplotlibcpp { namespace detail { @@ -48,62 +47,62 @@ static std::string s_backend; struct _interpreter { PyObject* s_python_function_arrow; - PyObject *s_python_function_show; - PyObject *s_python_function_close; - PyObject *s_python_function_draw; - PyObject *s_python_function_pause; - PyObject *s_python_function_save; - PyObject *s_python_function_figure; - PyObject *s_python_function_fignum_exists; - PyObject *s_python_function_plot; - PyObject *s_python_function_quiver; + PyObject* s_python_function_show; + PyObject* s_python_function_close; + PyObject* s_python_function_draw; + PyObject* s_python_function_pause; + PyObject* s_python_function_save; + PyObject* s_python_function_figure; + PyObject* s_python_function_fignum_exists; + PyObject* s_python_function_plot; + PyObject* s_python_function_quiver; PyObject* s_python_function_contour; - PyObject *s_python_function_semilogx; - PyObject *s_python_function_semilogy; - PyObject *s_python_function_loglog; - PyObject *s_python_function_fill; - PyObject *s_python_function_fill_between; - PyObject *s_python_function_hist; - PyObject *s_python_function_imshow; - PyObject *s_python_function_scatter; - PyObject *s_python_function_boxplot; - PyObject *s_python_function_subplot; - PyObject *s_python_function_subplot2grid; - PyObject *s_python_function_legend; - PyObject *s_python_function_xlim; - PyObject *s_python_function_ion; - PyObject *s_python_function_ginput; - PyObject *s_python_function_ylim; - PyObject *s_python_function_title; - PyObject *s_python_function_axis; - PyObject *s_python_function_axhline; - PyObject *s_python_function_axvline; - PyObject *s_python_function_axvspan; - PyObject *s_python_function_xlabel; - PyObject *s_python_function_ylabel; - PyObject *s_python_function_gca; - PyObject *s_python_function_xticks; - PyObject *s_python_function_yticks; + PyObject* s_python_function_semilogx; + PyObject* s_python_function_semilogy; + PyObject* s_python_function_loglog; + PyObject* s_python_function_fill; + PyObject* s_python_function_fill_between; + PyObject* s_python_function_hist; + PyObject* s_python_function_imshow; + PyObject* s_python_function_scatter; + PyObject* s_python_function_boxplot; + PyObject* s_python_function_subplot; + PyObject* s_python_function_subplot2grid; + PyObject* s_python_function_legend; + PyObject* s_python_function_xlim; + PyObject* s_python_function_ion; + PyObject* s_python_function_ginput; + PyObject* s_python_function_ylim; + PyObject* s_python_function_title; + PyObject* s_python_function_axis; + PyObject* s_python_function_axhline; + PyObject* s_python_function_axvline; + PyObject* s_python_function_axvspan; + PyObject* s_python_function_xlabel; + PyObject* s_python_function_ylabel; + PyObject* s_python_function_gca; + PyObject* s_python_function_xticks; + PyObject* s_python_function_yticks; PyObject* s_python_function_margins; - PyObject *s_python_function_tick_params; - PyObject *s_python_function_grid; + PyObject* s_python_function_tick_params; + PyObject* s_python_function_grid; PyObject* s_python_function_cla; - PyObject *s_python_function_clf; - PyObject *s_python_function_errorbar; - PyObject *s_python_function_annotate; - PyObject *s_python_function_tight_layout; - PyObject *s_python_colormap; - PyObject *s_python_empty_tuple; - PyObject *s_python_function_stem; - PyObject *s_python_function_xkcd; - PyObject *s_python_function_text; - PyObject *s_python_function_suptitle; - PyObject *s_python_function_bar; - PyObject *s_python_function_barh; - PyObject *s_python_function_colorbar; - PyObject *s_python_function_subplots_adjust; - PyObject *s_python_function_rcparams; - PyObject *s_python_function_spy; + PyObject* s_python_function_clf; + PyObject* s_python_function_errorbar; + PyObject* s_python_function_annotate; + PyObject* s_python_function_tight_layout; + PyObject* s_python_colormap; + PyObject* s_python_empty_tuple; + PyObject* s_python_function_stem; + PyObject* s_python_function_xkcd; + PyObject* s_python_function_text; + PyObject* s_python_function_suptitle; + PyObject* s_python_function_bar; + PyObject* s_python_function_barh; + PyObject* s_python_function_colorbar; + PyObject* s_python_function_subplots_adjust; + PyObject* s_python_function_rcparams; + PyObject* s_python_function_spy; /* For now, _interpreter is implemented as a singleton since its currently not possible to have multiple independent embedded python interpreters without patching the python source code @@ -113,31 +112,26 @@ struct _interpreter { users can manually ensure that the interpreter is constructed and destroyed within the same thread. - 1: http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program + 1: + http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program 2: https://github.com/lava/matplotlib-cpp/pull/202#issue-436220256 */ - static _interpreter& get() { - return interkeeper(false); - } + static _interpreter& get() { return interkeeper(false); } - static _interpreter& kill() { - return interkeeper(true); - } + static _interpreter& kill() { return interkeeper(true); } // Stores the actual singleton object referenced by `get()` and `kill()`. static _interpreter& interkeeper(bool should_kill) { static _interpreter ctx; - if (should_kill) - ctx.~_interpreter(); + if (should_kill) ctx.~_interpreter(); return ctx; } PyObject* safe_import(PyObject* module, std::string fname) { PyObject* fn = PyObject_GetAttrString(module, fname.c_str()); - if (!fn) - throw std::runtime_error(std::string("Couldn't find required function: ") + fname); + if (!fn) throw std::runtime_error(std::string("Couldn't find required function: ") + fname); if (!PyFunction_Check(fn)) throw std::runtime_error(fname + std::string(" is unexpectedly not a PyFunction.")); @@ -145,27 +139,25 @@ struct _interpreter { return fn; } -private: - + private: #ifndef WITHOUT_NUMPY -# if PY_MAJOR_VERSION >= 3 +#if PY_MAJOR_VERSION >= 3 - void *import_numpy() { - import_array(); // initialize C-API + void* import_numpy() { + import_array(); // initialize C-API return NULL; } -# else +#else void import_numpy() { - import_array(); // initialize C-API + import_array(); // initialize C-API } -# endif +#endif #endif _interpreter() { - // optional but recommended #if PY_MAJOR_VERSION >= 3 wchar_t name[] = L"plotting"; @@ -175,24 +167,25 @@ struct _interpreter { Py_SetProgramName(name); Py_Initialize(); - wchar_t const *dummy_args[] = {L"Python", NULL}; // const is needed because literals must not be modified - wchar_t const **argv = dummy_args; - int argc = sizeof(dummy_args)/sizeof(dummy_args[0])-1; + wchar_t const* dummy_args[] = { + L"Python", NULL}; // const is needed because literals must not be modified + wchar_t const** argv = dummy_args; + int argc = sizeof(dummy_args) / sizeof(dummy_args[0]) - 1; #if PY_MAJOR_VERSION >= 3 - PySys_SetArgv(argc, const_cast(argv)); + PySys_SetArgv(argc, const_cast(argv)); #else - PySys_SetArgv(argc, (char **)(argv)); + PySys_SetArgv(argc, (char**)(argv)); #endif #ifndef WITHOUT_NUMPY - import_numpy(); // initialize numpy C-API + import_numpy(); // initialize numpy C-API #endif PyObject* matplotlibname = PyString_FromString("matplotlib"); PyObject* pyplotname = PyString_FromString("matplotlib.pyplot"); - PyObject* cmname = PyString_FromString("matplotlib.cm"); - PyObject* pylabname = PyString_FromString("pylab"); + PyObject* cmname = PyString_FromString("matplotlib.cm"); + PyObject* pylabname = PyString_FromString("pylab"); if (!pyplotname || !pylabname || !matplotlibname || !cmname) { throw std::runtime_error("couldnt create string"); } @@ -208,22 +201,27 @@ struct _interpreter { // matplotlib.use() must be called *before* pylab, matplotlib.pyplot, // or matplotlib.backends is imported for the first time if (!s_backend.empty()) { - PyObject_CallMethod(matplotlib, const_cast("use"), const_cast("s"), s_backend.c_str()); + PyObject_CallMethod(matplotlib, const_cast("use"), const_cast("s"), + s_backend.c_str()); } - - PyObject* pymod = PyImport_Import(pyplotname); Py_DECREF(pyplotname); - if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } + if (!pymod) { + throw std::runtime_error("Error loading module matplotlib.pyplot!"); + } s_python_colormap = PyImport_Import(cmname); Py_DECREF(cmname); - if (!s_python_colormap) { throw std::runtime_error("Error loading module matplotlib.cm!"); } + if (!s_python_colormap) { + throw std::runtime_error("Error loading module matplotlib.cm!"); + } PyObject* pylabmod = PyImport_Import(pylabname); Py_DECREF(pylabname); - if (!pylabmod) { throw std::runtime_error("Error loading module pylab!"); } + if (!pylabmod) { + throw std::runtime_error("Error loading module pylab!"); + } s_python_function_arrow = safe_import(pymod, "arrow"); s_python_function_show = safe_import(pymod, "show"); @@ -240,9 +238,9 @@ struct _interpreter { s_python_function_loglog = safe_import(pymod, "loglog"); s_python_function_fill = safe_import(pymod, "fill"); s_python_function_fill_between = safe_import(pymod, "fill_between"); - s_python_function_hist = safe_import(pymod,"hist"); - s_python_function_scatter = safe_import(pymod,"scatter"); - s_python_function_boxplot = safe_import(pymod,"boxplot"); + s_python_function_hist = safe_import(pymod, "hist"); + s_python_function_scatter = safe_import(pymod, "scatter"); + s_python_function_boxplot = safe_import(pymod, "boxplot"); s_python_function_subplot = safe_import(pymod, "subplot"); s_python_function_subplot2grid = safe_import(pymod, "subplot2grid"); s_python_function_legend = safe_import(pymod, "legend"); @@ -264,7 +262,7 @@ struct _interpreter { s_python_function_ion = safe_import(pymod, "ion"); s_python_function_ginput = safe_import(pymod, "ginput"); s_python_function_save = safe_import(pylabmod, "savefig"); - s_python_function_annotate = safe_import(pymod,"annotate"); + s_python_function_annotate = safe_import(pymod, "annotate"); s_python_function_cla = safe_import(pymod, "cla"); s_python_function_clf = safe_import(pymod, "clf"); s_python_function_errorbar = safe_import(pymod, "errorbar"); @@ -273,24 +271,22 @@ struct _interpreter { s_python_function_xkcd = safe_import(pymod, "xkcd"); s_python_function_text = safe_import(pymod, "text"); s_python_function_suptitle = safe_import(pymod, "suptitle"); - s_python_function_bar = safe_import(pymod,"bar"); + s_python_function_bar = safe_import(pymod, "bar"); s_python_function_barh = safe_import(pymod, "barh"); s_python_function_colorbar = PyObject_GetAttrString(pymod, "colorbar"); - s_python_function_subplots_adjust = safe_import(pymod,"subplots_adjust"); + s_python_function_subplots_adjust = safe_import(pymod, "subplots_adjust"); s_python_function_rcparams = PyObject_GetAttrString(pymod, "rcParams"); - s_python_function_spy = PyObject_GetAttrString(pymod, "spy"); + s_python_function_spy = PyObject_GetAttrString(pymod, "spy"); #ifndef WITHOUT_NUMPY s_python_function_imshow = safe_import(pymod, "imshow"); #endif s_python_empty_tuple = PyTuple_New(0); } - ~_interpreter() { - Py_Finalize(); - } + ~_interpreter() { Py_Finalize(); } }; -} // end namespace detail +} // end namespace detail /// Select the backend /// @@ -301,20 +297,16 @@ struct _interpreter { /// matplotlibcpp in headless mode, for example on a machine with no display. /// /// See also: https://matplotlib.org/2.0.2/api/matplotlib_configuration_api.html#matplotlib.use -inline void backend(const std::string& name) -{ - detail::s_backend = name; -} +inline void backend(const std::string& name) { detail::s_backend = name; } -inline bool annotate(std::string annotation, double x, double y) -{ +inline bool annotate(std::string annotation, double x, double y) { detail::_interpreter::get(); - PyObject * xy = PyTuple_New(2); - PyObject * str = PyString_FromString(annotation.c_str()); + PyObject* xy = PyTuple_New(2); + PyObject* str = PyString_FromString(annotation.c_str()); - PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); - PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); + PyTuple_SetItem(xy, 0, PyFloat_FromDouble(x)); + PyTuple_SetItem(xy, 1, PyFloat_FromDouble(y)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "xy", xy); @@ -322,12 +314,13 @@ inline bool annotate(std::string annotation, double x, double y) PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, str); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -336,36 +329,76 @@ namespace detail { #ifndef WITHOUT_NUMPY // Type selector for numpy array conversion -template struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default -template <> struct select_npy_type { const static NPY_TYPES type = NPY_DOUBLE; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_FLOAT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_BOOL; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT8; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_SHORT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT64; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT8; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_USHORT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_ULONG; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; +template +struct select_npy_type { + const static NPY_TYPES type = NPY_NOTYPE; +}; // Default +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_DOUBLE; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_FLOAT; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_BOOL; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_INT8; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_SHORT; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_INT; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_INT64; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_UINT8; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_USHORT; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_ULONG; +}; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_UINT64; +}; // Sanity checks; comment them out or change the numpy type below if you're compiling on // a platform where they don't apply static_assert(sizeof(long long) == 8); -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT64; }; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_INT64; +}; static_assert(sizeof(unsigned long long) == 8); -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; +template <> +struct select_npy_type { + const static NPY_TYPES type = NPY_UINT64; +}; -template -PyObject* get_array(const std::vector& v) -{ +template +PyObject* get_array(const std::vector& v) { npy_intp vsize = v.size(); NPY_TYPES type = select_npy_type::type; if (type == NPY_NOTYPE) { - size_t memsize = v.size()*sizeof(double); + size_t memsize = v.size() * sizeof(double); double* dp = static_cast(::malloc(memsize)); - for (size_t i=0; i(varray), NPY_ARRAY_OWNDATA); return varray; @@ -375,19 +408,17 @@ PyObject* get_array(const std::vector& v) return varray; } -template -PyObject* get_2darray(const Numeric* vp, const size_t& n0, const size_t& n1) -{ +template +PyObject* get_2darray(const Numeric* vp, const size_t& n0, const size_t& n1) { npy_intp dims[2]; dims[0] = n0; dims[1] = n1; NPY_TYPES type = select_npy_type::type; if (type == NPY_NOTYPE) { - size_t arrsize = n0*n1; - size_t memsize = arrsize*sizeof(double); + size_t arrsize = n0 * n1; + size_t memsize = arrsize * sizeof(double); double* dp = static_cast(::malloc(memsize)); - for (size_t i=0; i(varray), NPY_ARRAY_OWNDATA); return varray; @@ -397,20 +428,18 @@ PyObject* get_2darray(const Numeric* vp, const size_t& n0, const size_t& n1) return varray; } -template -PyObject* get_3darray(const Numeric* vp, const size_t& n0, const size_t& n1, const size_t& n2) -{ +template +PyObject* get_3darray(const Numeric* vp, const size_t& n0, const size_t& n1, const size_t& n2) { npy_intp dims[3]; dims[0] = n0; dims[1] = n1; dims[2] = n2; NPY_TYPES type = select_npy_type::type; if (type == NPY_NOTYPE) { - size_t arrsize = n0*n1*n2; - size_t memsize = arrsize*sizeof(double); + size_t arrsize = n0 * n1 * n2; + size_t memsize = arrsize * sizeof(double); double* dp = static_cast(::malloc(memsize)); - for (size_t i=0; i(varray), NPY_ARRAY_OWNDATA); return varray; @@ -420,73 +449,66 @@ PyObject* get_3darray(const Numeric* vp, const size_t& n0, const size_t& n1, con return varray; } - -template -PyObject* get_2darray(const std::vector<::std::vector>& v) -{ +template +PyObject* get_2darray(const std::vector<::std::vector>& v) { if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); - npy_intp vsize[2] = {static_cast(v.size()), - static_cast(v[0].size())}; + npy_intp vsize[2] = {static_cast(v.size()), static_cast(v[0].size())}; - PyArrayObject *varray = - (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); + PyArrayObject* varray = (PyArrayObject*)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - double *vd_begin = static_cast(PyArray_DATA(varray)); + double* vd_begin = static_cast(PyArray_DATA(varray)); - for (const ::std::vector &v_row : v) { - if (v_row.size() != static_cast(vsize[1])) - throw std::runtime_error("Missmatched array size"); - std::copy(v_row.begin(), v_row.end(), vd_begin); - vd_begin += vsize[1]; + for (const ::std::vector& v_row : v) { + if (v_row.size() != static_cast(vsize[1])) + throw std::runtime_error("Missmatched array size"); + std::copy(v_row.begin(), v_row.end(), vd_begin); + vd_begin += vsize[1]; } - return reinterpret_cast(varray); + return reinterpret_cast(varray); } -#else // fallback if we don't have numpy: copy every element of the given vector +#else // fallback if we don't have numpy: copy every element of the given vector -template -PyObject* get_array(const std::vector& v) -{ +template +PyObject* get_array(const std::vector& v) { PyObject* list = PyList_New(v.size()); - for(size_t i = 0; i < v.size(); ++i) { + for (size_t i = 0; i < v.size(); ++i) { PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); } return list; } -#endif // WITHOUT_NUMPY +#endif // WITHOUT_NUMPY // sometimes, for labels and such, we need string arrays -inline PyObject * get_array(const std::vector& strings) -{ - PyObject* list = PyList_New(strings.size()); - for (std::size_t i = 0; i < strings.size(); ++i) { - PyList_SetItem(list, i, PyString_FromString(strings[i].c_str())); - } - return list; +inline PyObject* get_array(const std::vector& strings) { + PyObject* list = PyList_New(strings.size()); + for (std::size_t i = 0; i < strings.size(); ++i) { + PyList_SetItem(list, i, PyString_FromString(strings[i].c_str())); + } + return list; } // not all matplotlib need 2d arrays, some prefer lists of lists -template -PyObject* get_listlist(const std::vector>& ll) -{ - PyObject* listlist = PyList_New(ll.size()); - for (std::size_t i = 0; i < ll.size(); ++i) { - PyList_SetItem(listlist, i, get_array(ll[i])); - } - return listlist; +template +PyObject* get_listlist(const std::vector>& ll) { + PyObject* listlist = PyList_New(ll.size()); + for (std::size_t i = 0; i < ll.size(); ++i) { + PyList_SetItem(listlist, i, get_array(ll[i])); + } + return listlist; } -} // namespace detail +} // namespace detail /// Plot a line through the given x and y data points.. /// /// See: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.plot.html -template -bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) -{ +template +bool plot(const std::vector& x, const std::vector& y, + const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -502,8 +524,8 @@ bool plot(const std::vector &x, const std::vector &y, const st // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } @@ -511,7 +533,7 @@ bool plot(const std::vector &x, const std::vector &y, const st Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -520,286 +542,285 @@ bool plot(const std::vector &x, const std::vector &y, const st // a non-numpy alternative for `detail::get_2darray()`. #ifndef WITHOUT_NUMPY template -void plot_surface(const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - const std::map &keywords = - std::map(), - const long fig_number=0) -{ - detail::_interpreter::get(); - - // We lazily load the modules here the first time this function is called - // because I'm not sure that we can assume "matplotlib installed" implies - // "mpl_toolkits installed" on all platforms, and we don't want to require - // it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - // using numpy arrays - PyObject *xarray = detail::get_2darray(x); - PyObject *yarray = detail::get_2darray(y); - PyObject *zarray = detail::get_2darray(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); - PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); - - PyObject *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); - - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - if (it->first == "linewidth" || it->first == "alpha") { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(std::stod(it->second))); +void plot_surface( + const std::vector<::std::vector>& x, const std::vector<::std::vector>& y, + const std::vector<::std::vector>& z, + const std::map& keywords = std::map(), + const long fig_number = 0) { + detail::_interpreter::get(); + + // We lazily load the modules here the first time this function is called + // because I'm not sure that we can assume "matplotlib installed" implies + // "mpl_toolkits installed" on all platforms, and we don't want to require + // it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + detail::_interpreter::get(); + + PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } + + assert(x.size() == y.size()); + assert(y.size() == z.size()); + + // using numpy arrays + PyObject* xarray = detail::get_2darray(x); + PyObject* yarray = detail::get_2darray(y); + PyObject* zarray = detail::get_2darray(z); + + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); + + // Build up the kw args. + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); + PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); + + PyObject* python_colormap_coolwarm = + PyObject_GetAttrString(detail::_interpreter::get().s_python_colormap, "coolwarm"); + + PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); + + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + if (it->first == "linewidth" || it->first == "alpha") { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyFloat_FromDouble(std::stod(it->second))); + } else { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } + } + + PyObject* fig_args = PyTuple_New(1); + PyObject* fig = nullptr; + PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); + PyObject* fig_exists = + PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); + if (!PyObject_IsTrue(fig_exists)) { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - } - - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject( - detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - Py_DECREF(fig_exists); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface"); - if (!plot_surface) throw std::runtime_error("No surface"); - Py_INCREF(plot_surface); - PyObject *res = PyObject_Call(plot_surface, args, kwargs); - if (!res) throw std::runtime_error("failed surface"); - Py_DECREF(plot_surface); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, fig_args); + } + Py_DECREF(fig_exists); + if (!fig) throw std::runtime_error("Call to figure() failed."); + + PyObject* gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject* gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject* axis = + PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); + + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + PyObject* plot_surface = PyObject_GetAttrString(axis, "plot_surface"); + if (!plot_surface) throw std::runtime_error("No surface"); + Py_INCREF(plot_surface); + PyObject* res = PyObject_Call(plot_surface, args, kwargs); + if (!res) throw std::runtime_error("failed surface"); + Py_DECREF(plot_surface); + + Py_DECREF(axis); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); } template -void contour(const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - const std::map &keywords = {}) -{ - detail::_interpreter::get(); +void contour(const std::vector<::std::vector>& x, + const std::vector<::std::vector>& y, + const std::vector<::std::vector>& z, + const std::map& keywords = {}) { + detail::_interpreter::get(); - // using numpy arrays - PyObject *xarray = detail::get_2darray(x); - PyObject *yarray = detail::get_2darray(y); - PyObject *zarray = detail::get_2darray(z); + // using numpy arrays + PyObject* xarray = detail::get_2darray(x); + PyObject* yarray = detail::get_2darray(y); + PyObject* zarray = detail::get_2darray(z); - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); - // Build up the kw args. - PyObject *kwargs = PyDict_New(); + // Build up the kw args. + PyObject* kwargs = PyDict_New(); - PyObject *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); + PyObject* python_colormap_coolwarm = + PyObject_GetAttrString(detail::_interpreter::get().s_python_colormap, "coolwarm"); - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); + PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_contour, args, kwargs); - if (!res) - throw std::runtime_error("failed contour"); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_contour, args, kwargs); + if (!res) throw std::runtime_error("failed contour"); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); } template -void spy(const std::vector<::std::vector> &x, +void spy(const std::vector<::std::vector>& x, const double markersize = -1, // -1 for default matplotlib size - const std::map &keywords = {}) -{ - detail::_interpreter::get(); + const std::map& keywords = {}) { + detail::_interpreter::get(); + + PyObject* xarray = detail::get_2darray(x); + + PyObject* kwargs = PyDict_New(); + if (markersize != -1) { + PyDict_SetItemString(kwargs, "markersize", PyFloat_FromDouble(markersize)); + } + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } + + PyObject* plot_args = PyTuple_New(1); + PyTuple_SetItem(plot_args, 0, xarray); + + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_spy, plot_args, kwargs); + + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); +} +#endif // WITHOUT_NUMPY + +template +void plot3( + const std::vector& x, const std::vector& y, const std::vector& z, + const std::map& keywords = std::map(), + const long fig_number = 0) { + detail::_interpreter::get(); + + // Same as with plot_surface: We lazily load the modules here the first time + // this function is called because I'm not sure that we can assume "matplotlib + // installed" implies "mpl_toolkits installed" on all platforms, and we don't + // want to require it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + detail::_interpreter::get(); + + PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } + + assert(x.size() == y.size()); + assert(y.size() == z.size()); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + PyObject* zarray = detail::get_array(z); + + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); + + // Build up the kw args. + PyObject* kwargs = PyDict_New(); + + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } + + PyObject* fig_args = PyTuple_New(1); + PyObject* fig = nullptr; + PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); + PyObject* fig_exists = + PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); + if (!PyObject_IsTrue(fig_exists)) { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + } else { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, fig_args); + } + if (!fig) throw std::runtime_error("Call to figure() failed."); + + PyObject* gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - PyObject *xarray = detail::get_2darray(x); + PyObject* gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject* axis = + PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - PyObject *kwargs = PyDict_New(); - if (markersize != -1) { - PyDict_SetItemString(kwargs, "markersize", PyFloat_FromDouble(markersize)); - } - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); - PyObject *plot_args = PyTuple_New(1); - PyTuple_SetItem(plot_args, 0, xarray); + Py_DECREF(gca); + Py_DECREF(gca_kwargs); - PyObject *res = PyObject_Call( - detail::_interpreter::get().s_python_function_spy, plot_args, kwargs); + PyObject* plot3 = PyObject_GetAttrString(axis, "plot"); + if (!plot3) throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject* res = PyObject_Call(plot3, args, kwargs); + if (!res) throw std::runtime_error("Failed 3D line plot"); + Py_DECREF(plot3); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + Py_DECREF(axis); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); } -#endif // WITHOUT_NUMPY template -void plot3(const std::vector &x, - const std::vector &y, - const std::vector &z, - const std::map &keywords = - std::map(), - const long fig_number=0) -{ - detail::_interpreter::get(); - - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - PyObject *zarray = detail::get_array(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot3 = PyObject_GetAttrString(axis, "plot"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject *res = PyObject_Call(plot3, args, kwargs); - if (!res) throw std::runtime_error("Failed 3D line plot"); - Py_DECREF(plot3); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -template -bool stem(const std::vector &x, const std::vector &y, const std::map& keywords) -{ +bool stem(const std::vector& x, const std::vector& y, + const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -815,26 +836,23 @@ bool stem(const std::vector &x, const std::vector &y, const st // construct keyword args PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_stem, args, kwargs); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_stem, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template< typename Numeric > -bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -{ +template +bool fill(const std::vector& x, const std::vector& y, + const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -864,9 +882,10 @@ bool fill(const std::vector& x, const std::vector& y, const st return res; } -template< typename Numeric > -bool fill_between(const std::vector& x, const std::vector& y1, const std::vector& y2, const std::map& keywords) -{ +template +bool fill_between(const std::vector& x, const std::vector& y1, + const std::vector& y2, + const std::map& keywords) { assert(x.size() == y1.size()); assert(x.size() == y2.size()); @@ -885,15 +904,17 @@ bool fill_between(const std::vector& x, const std::vector& y1, // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -919,20 +940,18 @@ bool arrow(Numeric x, Numeric y, Numeric end_x, Numeric end_y, const std::string PyTuple_SetItem(plot_args, 3, obj_end_y); PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); + PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template< typename Numeric> -bool hist(const std::vector& y, long bins=10,std::string color="b", - double alpha=1.0, bool cumulative=false) -{ +template +bool hist(const std::vector& y, long bins = 10, std::string color = "b", + double alpha = 1.0, bool cumulative = false) { detail::_interpreter::get(); PyObject* yarray = detail::get_array(y); @@ -947,13 +966,12 @@ bool hist(const std::vector& y, long bins=10,std::string color="b", PyTuple_SetItem(plot_args, 0, yarray); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); - + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -961,86 +979,86 @@ bool hist(const std::vector& y, long bins=10,std::string color="b", #ifndef WITHOUT_NUMPY namespace detail { -inline void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors, const std::map &keywords, PyObject** out) -{ +inline void imshow(void* ptr, const NPY_TYPES type, const int rows, const int columns, + const int colors, const std::map& keywords, + PyObject** out) { assert(type == NPY_UINT8 || type == NPY_FLOAT); assert(colors == 1 || colors == 3 || colors == 4); detail::_interpreter::get(); // construct args - npy_intp dims[3] = { rows, columns, colors }; - PyObject *args = PyTuple_New(1); + npy_intp dims[3] = {rows, columns, colors}; + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr)); // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if (!res) - throw std::runtime_error("Call to imshow() failed"); + if (!res) throw std::runtime_error("Call to imshow() failed"); if (out) *out = res; else Py_DECREF(res); } -} // namespace detail +} // namespace detail -inline void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject** out = nullptr) -{ - detail::imshow((void *) ptr, NPY_UINT8, rows, columns, colors, keywords, out); +inline void imshow(const unsigned char* ptr, const int rows, const int columns, const int colors, + const std::map& keywords = {}, + PyObject** out = nullptr) { + detail::imshow((void*)ptr, NPY_UINT8, rows, columns, colors, keywords, out); } -inline void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject** out = nullptr) -{ - detail::imshow((void *) ptr, NPY_FLOAT, rows, columns, colors, keywords, out); +inline void imshow(const float* ptr, const int rows, const int columns, const int colors, + const std::map& keywords = {}, + PyObject** out = nullptr) { + detail::imshow((void*)ptr, NPY_FLOAT, rows, columns, colors, keywords, out); } #ifdef WITH_OPENCV -void imshow(const cv::Mat &image, const std::map &keywords = {}) -{ +void imshow(const cv::Mat& image, const std::map& keywords = {}) { // Convert underlying type of matrix, if needed cv::Mat image2; NPY_TYPES npy_type = NPY_UINT8; switch (image.type() & CV_MAT_DEPTH_MASK) { - case CV_8U: - image2 = image; - break; - case CV_32F: - image2 = image; - npy_type = NPY_FLOAT; - break; - default: - image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels())); + case CV_8U: + image2 = image; + break; + case CV_32F: + image2 = image; + npy_type = NPY_FLOAT; + break; + default: + image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels())); } // If color image, convert from BGR to RGB switch (image2.channels()) { - case 3: - cv::cvtColor(image2, image2, CV_BGR2RGB); - break; - case 4: - cv::cvtColor(image2, image2, CV_BGRA2RGBA); + case 3: + cv::cvtColor(image2, image2, CV_BGR2RGB); + break; + case 4: + cv::cvtColor(image2, image2, CV_BGRA2RGBA); } detail::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords); } -#endif // WITH_OPENCV -#endif // WITHOUT_NUMPY +#endif // WITH_OPENCV +#endif // WITHOUT_NUMPY -template -bool scatter(const std::vector& x, - const std::vector& y, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}) -{ +template +bool scatter(const std::vector& x, const std::vector& y, + const double s = 1.0, // The marker size in points**2 + const std::map& keywords = {}) { detail::_interpreter::get(); assert(x.size() == y.size()); @@ -1050,8 +1068,7 @@ bool scatter(const std::vector& x, PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - for (const auto& it : keywords) - { + for (const auto& it : keywords) { PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); } @@ -1059,155 +1076,153 @@ bool scatter(const std::vector& x, PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template - bool scatter_colored(const std::vector& x, - const std::vector& y, - const std::vector& colors, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}) - { - detail::_interpreter::get(); +template +bool scatter_colored(const std::vector& x, const std::vector& y, + const std::vector& colors, + const double s = 1.0, // The marker size in points**2 + const std::map& keywords = {}) { + detail::_interpreter::get(); - assert(x.size() == y.size()); + assert(x.size() == y.size()); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* colors_array = detail::get_array(colors); + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + PyObject* colors_array = detail::get_array(colors); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - PyDict_SetItemString(kwargs, "c", colors_array); + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); + PyDict_SetItemString(kwargs, "c", colors_array); + + for (const auto& it : keywords) { + PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + } + + PyObject* plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); + + return res; +} + +template +bool scatter(const std::vector& x, const std::vector& y, + const std::vector& z, + const double s = 1.0, // The marker size in points**2 + const std::map& keywords = {}, const long fig_number = 0) { + detail::_interpreter::get(); + + // Same as with plot_surface: We lazily load the modules here the first time + // this function is called because I'm not sure that we can assume "matplotlib + // installed" implies "mpl_toolkits installed" on all platforms, and we don't + // want to require it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + detail::_interpreter::get(); + + PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) { + throw std::runtime_error("couldnt create string"); } - PyObject* plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); + assert(x.size() == y.size()); + assert(y.size() == z.size()); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + PyObject* zarray = detail::get_array(z); - return res; + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); + + // Build up the kw args. + PyObject* kwargs = PyDict_New(); + + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } + PyObject* fig_args = PyTuple_New(1); + PyObject* fig = nullptr; + PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); + PyObject* fig_exists = + PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); + if (!PyObject_IsTrue(fig_exists)) { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + } else { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, fig_args); } - + Py_DECREF(fig_exists); + if (!fig) throw std::runtime_error("Call to figure() failed."); -template -bool scatter(const std::vector& x, - const std::vector& y, - const std::vector& z, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}, - const long fig_number=0) { - detail::_interpreter::get(); - - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - PyObject *zarray = detail::get_array(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - Py_DECREF(fig_exists); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot3 = PyObject_GetAttrString(axis, "scatter"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject *res = PyObject_Call(plot3, args, kwargs); - if (!res) throw std::runtime_error("Failed 3D line plot"); - Py_DECREF(plot3); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(fig); - if (res) Py_DECREF(res); - return res; - -} - -template + PyObject* gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject* gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject* axis = + PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); + + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + PyObject* plot3 = PyObject_GetAttrString(axis, "scatter"); + if (!plot3) throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject* res = PyObject_Call(plot3, args, kwargs); + if (!res) throw std::runtime_error("Failed 3D line plot"); + Py_DECREF(plot3); + + Py_DECREF(axis); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(fig); + if (res) Py_DECREF(res); + return res; +} + +template bool boxplot(const std::vector>& data, const std::vector& labels = {}, - const std::map & keywords = {}) -{ + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* listlist = detail::get_listlist(data); @@ -1222,25 +1237,24 @@ bool boxplot(const std::vector>& data, } // take care of the remaining keywords - for (const auto& it : keywords) - { + for (const auto& it : keywords) { PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template +template bool boxplot(const std::vector& data, - const std::map & keywords = {}) -{ + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* vector = detail::get_array(data); @@ -1248,100 +1262,94 @@ bool boxplot(const std::vector& data, PyTuple_SetItem(args, 0, vector); PyObject* kwargs = PyDict_New(); - for (const auto& it : keywords) - { + for (const auto& it : keywords) { PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } template -bool bar(const std::vector & x, - const std::vector & y, - std::string ec = "black", - std::string ls = "-", - double lw = 1.0, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); +bool bar(const std::vector& x, const std::vector& y, std::string ec = "black", + std::string ls = "-", double lw = 1.0, + const std::map& keywords = {}) { + detail::_interpreter::get(); - PyObject * xarray = detail::get_array(x); - PyObject * yarray = detail::get_array(y); + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); - PyObject * kwargs = PyDict_New(); + PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); - PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); - PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); + PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); + PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); + PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); - for (std::map::const_iterator it = - keywords.begin(); - it != keywords.end(); - ++it) { - PyDict_SetItemString( - kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject * plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + PyObject* plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); - PyObject * res = PyObject_Call( - detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); - return res; + return res; } template -bool bar(const std::vector & y, - std::string ec = "black", - std::string ls = "-", - double lw = 1.0, - const std::map & keywords = {}) -{ - using T = typename std::remove_reference::type::value_type; +bool bar(const std::vector& y, std::string ec = "black", std::string ls = "-", + double lw = 1.0, const std::map& keywords = {}) { + using T = typename std::remove_reference::type::value_type; - detail::_interpreter::get(); + detail::_interpreter::get(); - std::vector x; - for (std::size_t i = 0; i < y.size(); i++) { x.push_back(i); } + std::vector x; + for (std::size_t i = 0; i < y.size(); i++) { + x.push_back(i); + } - return bar(x, y, ec, ls, lw, keywords); + return bar(x, y, ec, ls, lw, keywords); } +template +bool barh(const std::vector& x, const std::vector& y, std::string ec = "black", + std::string ls = "-", double lw = 1.0, + const std::map& keywords = {}) { + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); -template -bool barh(const std::vector &x, const std::vector &y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map &keywords = { }) { - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - - PyObject *kwargs = PyDict_New(); + PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject *plot_args = PyTuple_New(2); + PyObject* plot_args = PyTuple_New(2); PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_barh, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_barh, plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); @@ -1350,33 +1358,30 @@ bool barh(const std::vector &x, const std::vector &y, std::str return res; } - -inline bool subplots_adjust(const std::map& keywords = {}) -{ +inline bool subplots_adjust(const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(it->second)); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); + ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second)); } - PyObject* plot_args = PyTuple_New(0); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, + plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template< typename Numeric> -bool named_hist(std::string label,const std::vector& y, long bins=10, std::string color="b", double alpha=1.0) -{ +template +bool named_hist(std::string label, const std::vector& y, long bins = 10, + std::string color = "b", double alpha = 1.0) { detail::_interpreter::get(); PyObject* yarray = detail::get_array(y); @@ -1387,22 +1392,22 @@ bool named_hist(std::string label,const std::vector& y, long bins=10, s PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); - PyObject* plot_args = PyTuple_New(1); PyTuple_SetItem(plot_args, 0, yarray); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template -bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool plot(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1417,10 +1422,11 @@ bool plot(const std::vector& x, const std::vector& y, const PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); Py_DECREF(plot_args); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -1448,12 +1454,11 @@ bool contour(const std::vector& x, const std::vector& y, } PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_contour, plot_args, kwargs); + PyObject_Call(detail::_interpreter::get().s_python_function_contour, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -1461,14 +1466,15 @@ bool contour(const std::vector& x, const std::vector& y, bool isFloat(std::string s) { std::istringstream iss(s); float f; - iss >> std::noskipws >> f; // noskipws considers leading whitespace invalid + iss >> std::noskipws >> f; // noskipws considers leading whitespace invalid // Check the entire string was consumed and if either failbit or badbit is set - return iss.eof() && !iss.fail(); + return iss.eof() && !iss.fail(); } -template -bool quiver(const std::vector& x, const std::vector& y, const std::vector& u, const std::vector& w, const std::map& keywords = {}) -{ +template +bool quiver(const std::vector& x, const std::vector& y, + const std::vector& u, const std::vector& w, + const std::map& keywords = {}) { assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); detail::_interpreter::get(); @@ -1486,25 +1492,25 @@ bool quiver(const std::vector& x, const std::vector& y, cons // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template -bool quiver(const NumericX* x, const NumericY* y, const NumericU* u, const NumericW* w, const size_t& n0, const size_t& n1, const std::map& keywords = {}) -{ +template +bool quiver(const NumericX* x, const NumericY* y, const NumericU* u, const NumericW* w, + const size_t& n0, const size_t& n1, + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* xarray = detail::get_2darray(x, n0, n1); @@ -1520,205 +1526,217 @@ bool quiver(const NumericX* x, const NumericY* y, const NumericU* u, const Numer // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - if(isFloat(it->second)) { - PyObject *float_str = PyUnicode_FromString(it->second.c_str()); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + if (isFloat(it->second)) { + PyObject* float_str = PyUnicode_FromString(it->second.c_str()); PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromString(float_str)); } else { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), + PyUnicode_FromString(it->second.c_str())); } } - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template -bool quiver(const std::vector& x, const std::vector& y, const std::vector& z, const std::vector& u, const std::vector& w, const std::vector& v, const std::map& keywords = {}) -{ - //set up 3d axes stuff - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - //assert sizes match up - assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size() && x.size() == z.size() && x.size() == v.size() && u.size() == v.size()); - - //set up parameters - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* zarray = detail::get_array(z); - PyObject* uarray = detail::get_array(u); - PyObject* warray = detail::get_array(w); - PyObject* varray = detail::get_array(v); - - PyObject* plot_args = PyTuple_New(6); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, zarray); - PyTuple_SetItem(plot_args, 3, uarray); - PyTuple_SetItem(plot_args, 4, warray); - PyTuple_SetItem(plot_args, 5, varray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - //get figure gca to enable 3d projection - PyObject *fig = - PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - //plot our boys bravely, plot them strongly, plot them with a wink and clap - PyObject *plot3 = PyObject_GetAttrString(axis, "quiver"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject* res = PyObject_Call( - plot3, plot_args, kwargs); - if (!res) throw std::runtime_error("Failed 3D plot"); - Py_DECREF(plot3); - Py_DECREF(axis); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - - return res; -} - -template -bool quiver(const NumericX* x, const NumericY* y, const NumericZ* z, const NumericU* u, const NumericW* w, const NumericV* v, const size_t& n0, const size_t& n1, const size_t& n2, const std::map& keywords = {}) -{ - //set up 3d axes stuff - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - //set up parameters - detail::_interpreter::get(); - - PyObject* xarray = detail::get_3darray(x, n0, n1, n2); - PyObject* yarray = detail::get_3darray(y, n0, n1, n2); - PyObject* zarray = detail::get_3darray(z, n0, n1, n2); - PyObject* uarray = detail::get_3darray(u, n0, n1, n2); - PyObject* warray = detail::get_3darray(w, n0, n1, n2); - PyObject* varray = detail::get_3darray(v, n0, n1, n2); - - PyObject* plot_args = PyTuple_New(6); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, zarray); - PyTuple_SetItem(plot_args, 3, uarray); - PyTuple_SetItem(plot_args, 4, warray); - PyTuple_SetItem(plot_args, 5, varray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - if(isFloat(it->second)) { - PyObject *float_str = PyUnicode_FromString(it->second.c_str()); - PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromString(float_str)); +template +bool quiver(const std::vector& x, const std::vector& y, + const std::vector& z, const std::vector& u, + const std::vector& w, const std::vector& v, + const std::map& keywords = {}) { + // set up 3d axes stuff + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + detail::_interpreter::get(); + + PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } } - else { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - } - - //get figure gca to enable 3d projection - PyObject *fig = - PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "add_subplot"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - //plot our boys bravely, plot them strongly, plot them with a wink and clap - PyObject *plot3 = PyObject_GetAttrString(axis, "quiver"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject* res = PyObject_Call( - plot3, plot_args, kwargs); - if (!res) throw std::runtime_error("Failed 3D plot"); - Py_DECREF(plot3); - Py_DECREF(axis); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - - return res; -} - -template -bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") -{ + + // assert sizes match up + assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size() && + x.size() == z.size() && x.size() == v.size() && u.size() == v.size()); + + // set up parameters + detail::_interpreter::get(); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + PyObject* zarray = detail::get_array(z); + PyObject* uarray = detail::get_array(u); + PyObject* warray = detail::get_array(w); + PyObject* varray = detail::get_array(v); + + PyObject* plot_args = PyTuple_New(6); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, zarray); + PyTuple_SetItem(plot_args, 3, uarray); + PyTuple_SetItem(plot_args, 4, warray); + PyTuple_SetItem(plot_args, 5, varray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } + + // get figure gca to enable 3d projection + PyObject* fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + if (!fig) throw std::runtime_error("Call to figure() failed."); + + PyObject* gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject* gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject* axis = + PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + // plot our boys bravely, plot them strongly, plot them with a wink and clap + PyObject* plot3 = PyObject_GetAttrString(axis, "quiver"); + if (!plot3) throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject* res = PyObject_Call(plot3, plot_args, kwargs); + if (!res) throw std::runtime_error("Failed 3D plot"); + Py_DECREF(plot3); + Py_DECREF(axis); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; +} + +template +bool quiver(const NumericX* x, const NumericY* y, const NumericZ* z, const NumericU* u, + const NumericW* w, const NumericV* v, const size_t& n0, const size_t& n1, + const size_t& n2, const std::map& keywords = {}) { + // set up 3d axes stuff + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + detail::_interpreter::get(); + + PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } + + // set up parameters + detail::_interpreter::get(); + + PyObject* xarray = detail::get_3darray(x, n0, n1, n2); + PyObject* yarray = detail::get_3darray(y, n0, n1, n2); + PyObject* zarray = detail::get_3darray(z, n0, n1, n2); + PyObject* uarray = detail::get_3darray(u, n0, n1, n2); + PyObject* warray = detail::get_3darray(w, n0, n1, n2); + PyObject* varray = detail::get_3darray(v, n0, n1, n2); + + PyObject* plot_args = PyTuple_New(6); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, zarray); + PyTuple_SetItem(plot_args, 3, uarray); + PyTuple_SetItem(plot_args, 4, warray); + PyTuple_SetItem(plot_args, 5, varray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + if (isFloat(it->second)) { + PyObject* float_str = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromString(float_str)); + } else { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyUnicode_FromString(it->second.c_str())); + } + } + + // get figure gca to enable 3d projection + PyObject* fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + if (!fig) throw std::runtime_error("Call to figure() failed."); + + PyObject* gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject* gca = PyObject_GetAttrString(fig, "add_subplot"); + if (!gca) throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject* axis = + PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + // plot our boys bravely, plot them strongly, plot them with a wink and clap + PyObject* plot3 = PyObject_GetAttrString(axis, "quiver"); + if (!plot3) throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject* res = PyObject_Call(plot3, plot_args, kwargs); + if (!res) throw std::runtime_error("Failed 3D plot"); + Py_DECREF(plot3); + Py_DECREF(axis); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; +} + +template +bool stem(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1733,19 +1751,18 @@ bool stem(const std::vector& x, const std::vector& y, const PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_stem, plot_args); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_stem, plot_args); Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template -bool semilogx(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool semilogx(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1760,17 +1777,18 @@ bool semilogx(const std::vector& x, const std::vector& y, co PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args); Py_DECREF(plot_args); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template -bool semilogy(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool semilogy(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1785,17 +1803,18 @@ bool semilogy(const std::vector& x, const std::vector& y, co PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args); Py_DECREF(plot_args); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template -bool loglog(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool loglog(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1810,17 +1829,19 @@ bool loglog(const std::vector& x, const std::vector& y, cons PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args); Py_DECREF(plot_args); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template -bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::map &keywords = {}) -{ +template +bool errorbar(const std::vector& x, const std::vector& y, + const std::vector& yerr, + const std::map& keywords = {}) { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1831,18 +1852,19 @@ bool errorbar(const std::vector &x, const std::vector &y, co // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } PyDict_SetItemString(kwargs, "yerr", yerrarray); - PyObject *plot_args = PyTuple_New(2); + PyObject* plot_args = PyTuple_New(2); PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); @@ -1855,9 +1877,9 @@ bool errorbar(const std::vector &x, const std::vector &y, co return res; } -template -bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -{ +template +bool named_plot(const std::string& name, const std::vector& y, + const std::string& format = "") { detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); @@ -1872,7 +1894,8 @@ bool named_plot(const std::string& name, const std::vector& y, const st PyTuple_SetItem(plot_args, 0, yarray); PyTuple_SetItem(plot_args, 1, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); @@ -1881,9 +1904,9 @@ bool named_plot(const std::string& name, const std::vector& y, const st return res; } -template -bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +template +bool named_plot(const std::string& name, const std::vector& x, + const std::vector& y, const std::string& format = "") { detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); @@ -1899,7 +1922,8 @@ bool named_plot(const std::string& name, const std::vector& x, const s PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); @@ -1908,9 +1932,9 @@ bool named_plot(const std::string& name, const std::vector& x, const s return res; } -template -bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +template +bool named_semilogx(const std::string& name, const std::vector& x, + const std::vector& y, const std::string& format = "") { detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); @@ -1926,7 +1950,8 @@ bool named_semilogx(const std::string& name, const std::vector& x, con PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); @@ -1935,9 +1960,9 @@ bool named_semilogx(const std::string& name, const std::vector& x, con return res; } -template -bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +template +bool named_semilogy(const std::string& name, const std::vector& x, + const std::vector& y, const std::string& format = "") { detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); @@ -1953,7 +1978,8 @@ bool named_semilogy(const std::string& name, const std::vector& x, con PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); @@ -1962,9 +1988,9 @@ bool named_semilogy(const std::string& name, const std::vector& x, con return res; } -template -bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +template +bool named_loglog(const std::string& name, const std::vector& x, + const std::vector& y, const std::string& format = "") { detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); @@ -1979,7 +2005,8 @@ bool named_loglog(const std::string& name, const std::vector& x, const PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); @@ -1988,33 +2015,29 @@ bool named_loglog(const std::string& name, const std::vector& x, const return res; } -template -bool plot(const std::vector& y, const std::string& format = "") -{ +template +bool plot(const std::vector& y, const std::string& format = "") { std::vector x(y.size()); - for(size_t i=0; i -bool plot(const std::vector& y, const std::map& keywords) -{ +template +bool plot(const std::vector& y, const std::map& keywords) { std::vector x(y.size()); - for(size_t i=0; i -bool stem(const std::vector& y, const std::string& format = "") -{ +template +bool stem(const std::vector& y, const std::string& format = "") { std::vector x(y.size()); for (size_t i = 0; i < x.size(); ++i) x.at(i) = i; return stem(x, y, format); } -template -void text(Numeric x, Numeric y, const std::string& s = "") -{ +template +void text(Numeric x, Numeric y, const std::string& s = "") { detail::_interpreter::get(); PyObject* args = PyTuple_New(3); @@ -2023,16 +2046,16 @@ void text(Numeric x, Numeric y, const std::string& s = "") PyTuple_SetItem(args, 2, PyString_FromString(s.c_str())); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); - if(!res) throw std::runtime_error("Call to text() failed."); + if (!res) throw std::runtime_error("Call to text() failed."); Py_DECREF(args); Py_DECREF(res); } -inline void colorbar(PyObject* mappable = NULL, const std::map& keywords = {}) -{ +inline void colorbar(PyObject* mappable = NULL, const std::map& keywords = {}) { if (mappable == NULL) - throw std::runtime_error("Must call colorbar with PyObject* returned from an image, contour, surface, etc."); + throw std::runtime_error( + "Must call colorbar with PyObject* returned from an image, contour, surface, etc."); detail::_interpreter::get(); @@ -2040,40 +2063,40 @@ inline void colorbar(PyObject* mappable = NULL, const std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); + ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second)); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); - if(!res) throw std::runtime_error("Call to colorbar() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); + if (!res) throw std::runtime_error("Call to colorbar() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } - -inline long figure(long number = -1) -{ +inline long figure(long number = -1) { detail::_interpreter::get(); - PyObject *res; + PyObject* res; if (number == -1) - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); + res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); else { assert(number > 0); // Make sure interpreter is initialised detail::_interpreter::get(); - PyObject *args = PyTuple_New(1); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyLong_FromLong(number)); res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args); Py_DECREF(args); } - if(!res) throw std::runtime_error("Call to figure() failed."); + if (!res) throw std::runtime_error("Call to figure() failed."); PyObject* num = PyObject_GetAttrString(res, "number"); if (!num) throw std::runtime_error("Could not get number attribute of figure object"); @@ -2085,14 +2108,14 @@ inline long figure(long number = -1) return figureNumber; } -inline bool fignum_exists(long number) -{ +inline bool fignum_exists(long number) { detail::_interpreter::get(); - PyObject *args = PyTuple_New(1); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyLong_FromLong(number)); - PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, args); - if(!res) throw std::runtime_error("Call to fignum_exists() failed."); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, args); + if (!res) throw std::runtime_error("Call to fignum_exists() failed."); bool ret = PyObject_IsTrue(res); Py_DECREF(res); @@ -2101,8 +2124,7 @@ inline bool fignum_exists(long number) return ret; } -inline void figure_size(size_t w, size_t h) -{ +inline void figure_size(size_t w, size_t h) { detail::_interpreter::get(); const size_t dpi = 100; @@ -2115,62 +2137,60 @@ inline void figure_size(size_t w, size_t h) PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + detail::_interpreter::get().s_python_empty_tuple, kwargs); Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to figure_size() failed."); + if (!res) throw std::runtime_error("Call to figure_size() failed."); Py_DECREF(res); } -inline void legend() -{ +inline void legend() { detail::_interpreter::get(); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple); - if(!res) throw std::runtime_error("Call to legend() failed."); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, + detail::_interpreter::get().s_python_empty_tuple); + if (!res) throw std::runtime_error("Call to legend() failed."); Py_DECREF(res); } -inline void legend(const std::map& keywords) -{ - detail::_interpreter::get(); +inline void legend(const std::map& keywords) { + detail::_interpreter::get(); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple, kwargs); - if(!res) throw std::runtime_error("Call to legend() failed."); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, + detail::_interpreter::get().s_python_empty_tuple, kwargs); + if (!res) throw std::runtime_error("Call to legend() failed."); - Py_DECREF(kwargs); - Py_DECREF(res); + Py_DECREF(kwargs); + Py_DECREF(res); } -template -inline void set_aspect(Numeric ratio) -{ +template +inline void set_aspect(Numeric ratio) { detail::_interpreter::get(); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyFloat_FromDouble(ratio)); PyObject* kwargs = PyDict_New(); - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* ax = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); if (!ax) throw std::runtime_error("Call to gca() failed."); Py_INCREF(ax); - PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); + PyObject* set_aspect = PyObject_GetAttrString(ax, "set_aspect"); if (!set_aspect) throw std::runtime_error("Attribute set_aspect not found."); Py_INCREF(set_aspect); - PyObject *res = PyObject_Call(set_aspect, args, kwargs); + PyObject* res = PyObject_Call(set_aspect, args, kwargs); if (!res) throw std::runtime_error("Call to set_aspect() failed."); Py_DECREF(set_aspect); @@ -2179,8 +2199,7 @@ inline void set_aspect(Numeric ratio) Py_DECREF(kwargs); } -inline void set_aspect_equal() -{ +inline void set_aspect_equal() { // expect ratio == "equal". Leaving error handling to matplotlib. detail::_interpreter::get(); @@ -2188,17 +2207,16 @@ inline void set_aspect_equal() PyTuple_SetItem(args, 0, PyString_FromString("equal")); PyObject* kwargs = PyDict_New(); - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* ax = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); if (!ax) throw std::runtime_error("Call to gca() failed."); Py_INCREF(ax); - PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); + PyObject* set_aspect = PyObject_GetAttrString(ax, "set_aspect"); if (!set_aspect) throw std::runtime_error("Attribute set_aspect not found."); Py_INCREF(set_aspect); - PyObject *res = PyObject_Call(set_aspect, args, kwargs); + PyObject* res = PyObject_Call(set_aspect, args, kwargs); if (!res) throw std::runtime_error("Call to set_aspect() failed."); Py_DECREF(set_aspect); @@ -2207,9 +2225,8 @@ inline void set_aspect_equal() Py_DECREF(kwargs); } -template -void ylim(Numeric left, Numeric right) -{ +template +void ylim(Numeric left, Numeric right) { detail::_interpreter::get(); PyObject* list = PyList_New(2); @@ -2220,15 +2237,14 @@ void ylim(Numeric left, Numeric right) PyTuple_SetItem(args, 0, list); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - if(!res) throw std::runtime_error("Call to ylim() failed."); + if (!res) throw std::runtime_error("Call to ylim() failed."); Py_DECREF(args); Py_DECREF(res); } -template -void xlim(Numeric left, Numeric right) -{ +template +void xlim(Numeric left, Numeric right) { detail::_interpreter::get(); PyObject* list = PyList_New(2); @@ -2239,45 +2255,41 @@ void xlim(Numeric left, Numeric right) PyTuple_SetItem(args, 0, list); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - if(!res) throw std::runtime_error("Call to xlim() failed."); + if (!res) throw std::runtime_error("Call to xlim() failed."); Py_DECREF(args); Py_DECREF(res); } - -inline std::array xlim() -{ +inline std::array xlim() { PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - if(!res) throw std::runtime_error("Call to xlim() failed."); + if (!res) throw std::runtime_error("Call to xlim() failed."); Py_DECREF(res); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; + PyObject* left = PyTuple_GetItem(res, 0); + PyObject* right = PyTuple_GetItem(res, 1); + return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; } - -inline std::array ylim() -{ +inline std::array ylim() { PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - if(!res) throw std::runtime_error("Call to ylim() failed."); + if (!res) throw std::runtime_error("Call to ylim() failed."); Py_DECREF(res); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; + PyObject* left = PyTuple_GetItem(res, 0); + PyObject* right = PyTuple_GetItem(res, 1); + return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; } -template -inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ +template +inline void xticks(const std::vector& ticks, const std::vector& labels = {}, + const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); detail::_interpreter::get(); @@ -2286,7 +2298,7 @@ inline void xticks(const std::vector &ticks, const std::vector &ticks, const std::vector::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to xticks() failed"); + if (!res) throw std::runtime_error("Call to xticks() failed"); Py_DECREF(res); } -template -inline void xticks(const std::vector &ticks, const std::map& keywords) -{ +template +inline void xticks(const std::vector& ticks, + const std::map& keywords) { xticks(ticks, {}, keywords); } -template -inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ +template +inline void yticks(const std::vector& ticks, const std::vector& labels = {}, + const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); detail::_interpreter::get(); @@ -2335,7 +2348,7 @@ inline void yticks(const std::vector &ticks, const std::vector &ticks, const std::vector::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to yticks() failed"); + if (!res) throw std::runtime_error("Call to yticks() failed"); Py_DECREF(res); } -template -inline void yticks(const std::vector &ticks, const std::map& keywords) -{ +template +inline void yticks(const std::vector& ticks, + const std::map& keywords) { yticks(ticks, {}, keywords); } -template inline void margins(Numeric margin) -{ +template +inline void margins(Numeric margin) { // construct positional args PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); + PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); + if (!res) throw std::runtime_error("Call to margins() failed."); Py_DECREF(args); Py_DECREF(res); } -template inline void margins(Numeric margin_x, Numeric margin_y) -{ +template +inline void margins(Numeric margin_x, Numeric margin_y) { // construct positional args PyObject* args = PyTuple_New(2); PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin_x)); PyTuple_SetItem(args, 1, PyFloat_FromDouble(margin_y)); PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); + PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); + if (!res) throw std::runtime_error("Call to margins() failed."); Py_DECREF(args); Py_DECREF(res); } +inline void tick_params(const std::map& keywords, + const std::string axis = "both") { + detail::_interpreter::get(); -inline void tick_params(const std::map& keywords, const std::string axis = "both") -{ - detail::_interpreter::get(); - - // construct positional args - PyObject* args; - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyString_FromString(axis.c_str())); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } + // construct positional args + PyObject* args; + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyString_FromString(axis.c_str())); + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - if (!res) throw std::runtime_error("Call to tick_params() failed"); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) throw std::runtime_error("Call to tick_params() failed"); - Py_DECREF(res); + Py_DECREF(res); } -inline void subplot(long nrows, long ncols, long plot_number) -{ +inline void subplot(long nrows, long ncols, long plot_number) { detail::_interpreter::get(); // construct positional args @@ -2441,15 +2451,16 @@ inline void subplot(long nrows, long ncols, long plot_number) PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); - if(!res) throw std::runtime_error("Call to subplot() failed."); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); + if (!res) throw std::runtime_error("Call to subplot() failed."); Py_DECREF(args); Py_DECREF(res); } -inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) -{ +inline void subplot2grid(long nrows, long ncols, long rowid = 0, long colid = 0, long rowspan = 1, + long colspan = 1) { detail::_interpreter::get(); PyObject* shape = PyTuple_New(2); @@ -2466,8 +2477,9 @@ inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, lon PyTuple_SetItem(args, 2, PyLong_FromLong(rowspan)); PyTuple_SetItem(args, 3, PyLong_FromLong(colspan)); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot2grid, args); - if(!res) throw std::runtime_error("Call to subplot2grid() failed."); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot2grid, args); + if (!res) throw std::runtime_error("Call to subplot2grid() failed."); Py_DECREF(shape); Py_DECREF(loc); @@ -2475,8 +2487,8 @@ inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, lon Py_DECREF(res); } -inline void title(const std::string &titlestr, const std::map &keywords = {}) -{ +inline void title(const std::string& titlestr, + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); @@ -2488,16 +2500,17 @@ inline void title(const std::string &titlestr, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); - if(!res) throw std::runtime_error("Call to title() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); + if (!res) throw std::runtime_error("Call to title() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } -inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -{ +inline void suptitle(const std::string& suptitlestr, + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); @@ -2509,16 +2522,16 @@ inline void suptitle(const std::string &suptitlestr, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); - if(!res) throw std::runtime_error("Call to suptitle() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); + if (!res) throw std::runtime_error("Call to suptitle() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } -inline void axis(const std::string &axisstr) -{ +inline void axis(const std::string& axisstr) { detail::_interpreter::get(); PyObject* str = PyString_FromString(axisstr.c_str()); @@ -2526,14 +2539,15 @@ inline void axis(const std::string &axisstr) PyTuple_SetItem(args, 0, str); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); - if(!res) throw std::runtime_error("Call to title() failed."); + if (!res) throw std::runtime_error("Call to title() failed."); Py_DECREF(args); Py_DECREF(res); } -inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) -{ +inline void axhline( + double y, double xmin = 0., double xmax = 1., + const std::map& keywords = std::map()) { detail::_interpreter::get(); // construct positional args @@ -2544,21 +2558,23 @@ inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axhline, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_axhline, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); } -inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ +inline void axvline( + double x, double ymin = 0., double ymax = 1., + const std::map& keywords = std::map()) { detail::_interpreter::get(); // construct positional args @@ -2569,21 +2585,23 @@ inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axvline, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_axvline, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); } -inline void axvspan(double xmin, double xmax, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ +inline void axvspan( + double xmin, double xmax, double ymin = 0., double ymax = 1., + const std::map& keywords = std::map()) { // construct positional args PyObject* args = PyTuple_New(4); PyTuple_SetItem(args, 0, PyFloat_FromDouble(xmin)); @@ -2594,24 +2612,25 @@ inline void axvspan(double xmin, double xmax, double ymin = 0., double ymax = 1. // construct keyword args PyObject* kwargs = PyDict_New(); for (auto it = keywords.begin(); it != keywords.end(); ++it) { - if (it->first == "linewidth" || it->first == "alpha") { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(std::stod(it->second))); - } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } + if (it->first == "linewidth" || it->first == "alpha") { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyFloat_FromDouble(std::stod(it->second))); + } else { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axvspan, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_axvspan, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); } -inline void xlabel(const std::string &str, const std::map &keywords = {}) -{ +inline void xlabel(const std::string& str, + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* pystr = PyString_FromString(str.c_str()); @@ -2623,16 +2642,17 @@ inline void xlabel(const std::string &str, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); - if(!res) throw std::runtime_error("Call to xlabel() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); + if (!res) throw std::runtime_error("Call to xlabel() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } -inline void ylabel(const std::string &str, const std::map& keywords = {}) -{ +inline void ylabel(const std::string& str, + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* pystr = PyString_FromString(str.c_str()); @@ -2644,16 +2664,17 @@ inline void ylabel(const std::string &str, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); - if(!res) throw std::runtime_error("Call to ylabel() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); + if (!res) throw std::runtime_error("Call to ylabel() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } -inline void set_zlabel(const std::string &str, const std::map& keywords = {}) -{ +inline void set_zlabel(const std::string& str, + const std::map& keywords = {}) { detail::_interpreter::get(); // Same as with plot_surface: We lazily load the modules here the first time @@ -2664,15 +2685,21 @@ inline void set_zlabel(const std::string &str, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* ax = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); if (!ax) throw std::runtime_error("Call to gca() failed."); Py_INCREF(ax); - PyObject *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); + PyObject* zlabel = PyObject_GetAttrString(ax, "set_zlabel"); if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); Py_INCREF(zlabel); - PyObject *res = PyObject_Call(zlabel, args, kwargs); + PyObject* res = PyObject_Call(zlabel, args, kwargs); if (!res) throw std::runtime_error("Call to set_zlabel() failed."); Py_DECREF(zlabel); @@ -2704,8 +2730,7 @@ inline void set_zlabel(const std::string &str, const std::map -inline void pause(Numeric interval) -{ +template +inline void pause(Numeric interval) { detail::_interpreter::get(); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); - if(!res) throw std::runtime_error("Call to pause() failed."); + if (!res) throw std::runtime_error("Call to pause() failed."); Py_DECREF(args); Py_DECREF(res); } -inline void save(const std::string& filename, const int dpi=0) -{ +inline void save(const std::string& filename, const int dpi = 0) { detail::_interpreter::get(); PyObject* pyfilename = PyString_FromString(filename.c_str()); @@ -2815,8 +2828,7 @@ inline void save(const std::string& filename, const int dpi=0) PyObject* kwargs = PyDict_New(); - if(dpi > 0) - { + if (dpi > 0) { PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); } @@ -2834,13 +2846,17 @@ inline void rcparams(const std::map& keywords = {}) { PyObject* kwargs = PyDict_New(); for (auto it = keywords.begin(); it != keywords.end(); ++it) { if ("text.usetex" == it->first) - PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); - else PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), + PyLong_FromLong(std::stoi(it->second.c_str()))); + else + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); } - - PyObject * update = PyObject_GetAttrString(detail::_interpreter::get().s_python_function_rcparams, "update"); - PyObject * res = PyObject_Call(update, args, kwargs); - if(!res) throw std::runtime_error("Call to rcParams.update() failed."); + + PyObject* update = + PyObject_GetAttrString(detail::_interpreter::get().s_python_function_rcparams, "update"); + PyObject* res = PyObject_Call(update, args, kwargs); + if (!res) throw std::runtime_error("Call to rcParams.update() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(update); @@ -2850,9 +2866,8 @@ inline void rcparams(const std::map& keywords = {}) { inline void clf() { detail::_interpreter::get(); - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_clf, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_clf, + detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to clf() failed."); @@ -2865,8 +2880,7 @@ inline void cla() { PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, detail::_interpreter::get().s_python_empty_tuple); - if (!res) - throw std::runtime_error("Call to cla() failed."); + if (!res) throw std::runtime_error("Call to cla() failed."); Py_DECREF(res); } @@ -2874,31 +2888,30 @@ inline void cla() { inline void ion() { detail::_interpreter::get(); - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ion, + detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to ion() failed."); Py_DECREF(res); } -inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -{ +inline std::vector> ginput( + const int numClicks = 1, const std::map& keywords = {}) { detail::_interpreter::get(); - PyObject *args = PyTuple_New(1); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_ginput, args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_ginput, args, kwargs); Py_DECREF(kwargs); Py_DECREF(args); @@ -2908,7 +2921,7 @@ inline std::vector> ginput(const int numClicks = 1, const std::vector> out; out.reserve(len); for (size_t i = 0; i < len; i++) { - PyObject *current = PyList_GetItem(res, i); + PyObject* current = PyList_GetItem(res, i); std::array position; position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0)); position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1)); @@ -2923,9 +2936,8 @@ inline std::vector> ginput(const int numClicks = 1, const inline void tight_layout() { detail::_interpreter::get(); - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_tight_layout, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_tight_layout, + detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to tight_layout() failed."); @@ -2936,59 +2948,59 @@ inline void tight_layout() { namespace detail { -template +template using is_function = typename std::is_function>>::type; -template +template struct is_callable_impl; -template -struct is_callable_impl -{ +template +struct is_callable_impl { typedef is_function type; -}; // a non-object is callable iff it is a function +}; // a non-object is callable iff it is a function -template -struct is_callable_impl -{ - struct Fallback { void operator()(); }; - struct Derived : T, Fallback { }; +template +struct is_callable_impl { + struct Fallback { + void operator()(); + }; + struct Derived : T, Fallback {}; - template struct Check; + template + struct Check; - template - static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match + template + static std::true_type test(...); // use a variadic function to make sure (1) it accepts + // everything and (2) its always the worst match - template - static std::false_type test( Check* ); + template + static std::false_type test(Check*); -public: + public: typedef decltype(test(nullptr)) type; typedef decltype(&Fallback::operator()) dtype; static constexpr bool value = type::value; -}; // an object is callable iff it defines operator() +}; // an object is callable iff it defines operator() -template -struct is_callable -{ - // dispatch to is_callable_impl or is_callable_impl depending on whether T is of class type or not +template +struct is_callable { + // dispatch to is_callable_impl or is_callable_impl depending on whether T is + // of class type or not typedef typename is_callable_impl::value, T>::type type; }; -template -struct plot_impl { }; +template +struct plot_impl {}; -template<> -struct plot_impl -{ - template - bool operator()(const IterableX& x, const IterableY& y, const std::string& format) - { +template <> +struct plot_impl { + template + bool operator()(const IterableX& x, const IterableY& y, const std::string& format) { detail::_interpreter::get(); // 2-phase lookup for distance, begin, end - using std::distance; using std::begin; + using std::distance; using std::end; auto xs = distance(begin(x), end(x)); @@ -3000,7 +3012,7 @@ struct plot_impl PyObject* pystring = PyString_FromString(format.c_str()); auto itx = begin(x), ity = begin(y); - for(size_t i = 0; i < xs; ++i) { + for (size_t i = 0; i < xs; ++i) { PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); } @@ -3010,75 +3022,77 @@ struct plot_impl PyTuple_SetItem(plot_args, 1, ylist); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); Py_DECREF(plot_args); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } }; -template<> -struct plot_impl -{ - template - bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) - { - if(begin(ticks) == end(ticks)) return true; +template <> +struct plot_impl { + template + bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) { + if (begin(ticks) == end(ticks)) return true; // We could use additional meta-programming to deduce the correct element type of y, // but all values have to be convertible to double anyways std::vector y; - for(auto x : ticks) y.push_back(f(x)); - return plot_impl()(ticks,y,format); + for (auto x : ticks) y.push_back(f(x)); + return plot_impl()(ticks, y, format); } }; -} // end namespace detail +} // end namespace detail // recursion stop for the above -template -bool plot() { return true; } +template +bool plot() { + return true; +} -template -bool plot(const A& a, const B& b, const std::string& format, Args... args) -{ - return detail::plot_impl::type>()(a,b,format) && plot(args...); +template +bool plot(const A& a, const B& b, const std::string& format, Args... args) { + return detail::plot_impl::type>()(a, b, format) && + plot(args...); } /* * This group of plot() functions is needed to support initializer lists, i.e. calling * plot( {1,2,3,4} ) */ -inline bool plot(const std::vector& x, const std::vector& y, const std::string& format = "") { - return plot(x,y,format); +inline bool plot(const std::vector& x, const std::vector& y, + const std::string& format = "") { + return plot(x, y, format); } inline bool plot(const std::vector& y, const std::string& format = "") { - return plot(y,format); + return plot(y, format); } -inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(x,y,keywords); +inline bool plot(const std::vector& x, const std::vector& y, + const std::map& keywords) { + return plot(x, y, keywords); } /* * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting */ -class Plot -{ -public: +class Plot { + public: // default initialization with plot label, some data and format - template - Plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") { + template + Plot(const std::string& name, const std::vector& x, const std::vector& y, + const std::string& format = "") { detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* kwargs = PyDict_New(); - if(name != "") - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + if (name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); PyObject* xarray = detail::get_array(x); PyObject* yarray = detail::get_array(y); @@ -3090,17 +3104,17 @@ class Plot PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if(res) - { - line= PyList_GetItem(res, 0); + if (res) { + line = PyList_GetItem(res, 0); - if(line) - set_data_fct = PyObject_GetAttrString(line,"set_data"); + if (line) + set_data_fct = PyObject_GetAttrString(line, "set_data"); else Py_DECREF(line); Py_DECREF(res); @@ -3112,11 +3126,10 @@ class Plot Plot(const std::string& name = "", const std::string& format = "") : Plot(name, std::vector(), std::vector(), format) {} - template + template bool update(const std::vector& x, const std::vector& y) { assert(x.size() == y.size()); - if(set_data_fct) - { + if (set_data_fct) { PyObject* xarray = detail::get_array(x); PyObject* yarray = detail::get_array(y); @@ -3132,15 +3145,12 @@ class Plot } // clears the plot but keep it available - bool clear() { - return update(std::vector(), std::vector()); - } + bool clear() { return update(std::vector(), std::vector()); } // definitely remove this line void remove() { - if(line) - { - auto remove_fct = PyObject_GetAttrString(line,"remove"); + if (line) { + auto remove_fct = PyObject_GetAttrString(line, "remove"); PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(remove_fct, args); if (res) Py_DECREF(res); @@ -3148,21 +3158,16 @@ class Plot decref(); } - ~Plot() { - decref(); - } -private: + ~Plot() { decref(); } + private: void decref() { - if(line) - Py_DECREF(line); - if(set_data_fct) - Py_DECREF(set_data_fct); + if (line) Py_DECREF(line); + if (set_data_fct) Py_DECREF(set_data_fct); } - PyObject* line = nullptr; PyObject* set_data_fct = nullptr; }; -} // end namespace matplotlibcpp +} // end namespace matplotlibcpp From 601b5b3b3831303e0804e9897ed0fa7170b66acb Mon Sep 17 00:00:00 2001 From: yjchen Date: Thu, 9 Feb 2023 13:00:48 +0800 Subject: [PATCH 04/12] Update behavior - Add kwargs to subplot - Remove creating new figure when use 3d scatter and quiver - Add kwargs support to scatter and quiver --- matplotlibcpp.h | 144 ++++++++++++++++++++++++------------------------ 1 file changed, 71 insertions(+), 73 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index fb8bd48f..ad57926f 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -503,6 +503,14 @@ PyObject* get_listlist(const std::vector>& ll) { } // namespace detail +bool isDouble(std::string s) { + std::istringstream iss(s); + double f; + iss >> std::noskipws >> f; // noskipws considers leading whitespace invalid + // Check the entire string was consumed and if either failbit or badbit is set + return iss.eof() && !iss.fail(); +} + /// Plot a line through the given x and y data points.. /// /// See: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.plot.html @@ -1057,7 +1065,6 @@ void imshow(const cv::Mat& image, const std::map& keyw template bool scatter(const std::vector& x, const std::vector& y, - const double s = 1.0, // The marker size in points**2 const std::map& keywords = {}) { detail::_interpreter::get(); @@ -1066,10 +1073,19 @@ bool scatter(const std::vector& x, const std::vector& y, PyObject* xarray = detail::get_array(x); PyObject* yarray = detail::get_array(y); + // construct keyword args PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - for (const auto& it : keywords) { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyObject* pobj_second; + if (isDouble(it->second)) { + pobj_second = PyFloat_FromDouble(std::stod(it->second)); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); + } else { + pobj_second = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); + } + Py_DECREF(pobj_second); } PyObject* plot_args = PyTuple_New(2); @@ -1124,8 +1140,7 @@ bool scatter_colored(const std::vector& x, const std::vector template bool scatter(const std::vector& x, const std::vector& y, const std::vector& z, - const double s = 1.0, // The marker size in points**2 - const std::map& keywords = {}, const long fig_number = 0) { + const std::map& keywords = {}) { detail::_interpreter::get(); // Same as with plot_surface: We lazily load the modules here the first time @@ -1168,42 +1183,26 @@ bool scatter(const std::vector& x, const std::vector& y, PyTuple_SetItem(args, 1, yarray); PyTuple_SetItem(args, 2, zarray); - // Build up the kw args. + // construct keyword args PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - PyObject* fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject* fig_exists = - PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, fig_args); + PyObject* pobj_second; + if (isDouble(it->second)) { + pobj_second = PyFloat_FromDouble(std::stod(it->second)); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); + } else { + pobj_second = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); + } + Py_DECREF(pobj_second); } - Py_DECREF(fig_exists); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject* gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject* gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject* axis = - PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + PyObject* axis = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); if (!axis) throw std::runtime_error("No axis"); Py_INCREF(axis); - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - PyObject* plot3 = PyObject_GetAttrString(axis, "scatter"); if (!plot3) throw std::runtime_error("No 3D line plot"); Py_INCREF(plot3); @@ -1214,7 +1213,6 @@ bool scatter(const std::vector& x, const std::vector& y, Py_DECREF(axis); Py_DECREF(args); Py_DECREF(kwargs); - Py_DECREF(fig); if (res) Py_DECREF(res); return res; } @@ -1463,14 +1461,6 @@ bool contour(const std::vector& x, const std::vector& y, return res; } -bool isFloat(std::string s) { - std::istringstream iss(s); - float f; - iss >> std::noskipws >> f; // noskipws considers leading whitespace invalid - // Check the entire string was consumed and if either failbit or badbit is set - return iss.eof() && !iss.fail(); -} - template bool quiver(const std::vector& x, const std::vector& y, const std::vector& u, const std::vector& w, @@ -1528,13 +1518,15 @@ bool quiver(const NumericX* x, const NumericY* y, const NumericU* u, const Numer PyObject* kwargs = PyDict_New(); for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - if (isFloat(it->second)) { - PyObject* float_str = PyUnicode_FromString(it->second.c_str()); - PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromString(float_str)); + PyObject* pobj_second; + if (isDouble(it->second)) { + pobj_second = PyFloat_FromDouble(std::stod(it->second)); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyUnicode_FromString(it->second.c_str())); + pobj_second = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); } + Py_DECREF(pobj_second); } PyObject* res = @@ -1691,33 +1683,22 @@ bool quiver(const NumericX* x, const NumericY* y, const NumericZ* z, const Numer PyObject* kwargs = PyDict_New(); for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - if (isFloat(it->second)) { - PyObject* float_str = PyUnicode_FromString(it->second.c_str()); - PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromString(float_str)); + PyObject* pobj_second; + if (isDouble(it->second)) { + pobj_second = PyFloat_FromDouble(std::stod(it->second)); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyUnicode_FromString(it->second.c_str())); + pobj_second = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); } + Py_DECREF(pobj_second); } // get figure gca to enable 3d projection - PyObject* fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject* gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject* gca = PyObject_GetAttrString(fig, "add_subplot"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject* axis = - PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - + PyObject* axis = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); if (!axis) throw std::runtime_error("No axis"); Py_INCREF(axis); - Py_DECREF(gca); - Py_DECREF(gca_kwargs); // plot our boys bravely, plot them strongly, plot them with a wink and clap PyObject* plot3 = PyObject_GetAttrString(axis, "quiver"); @@ -2442,21 +2423,38 @@ inline void tick_params(const std::map& keywords, Py_DECREF(res); } -inline void subplot(long nrows, long ncols, long plot_number) { +inline void subplot(long nrows, long ncols, long plot_number, + const std::map& keywords = {}) { detail::_interpreter::get(); // construct positional args PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); + PyTuple_SetItem(args, 0, PyLong_FromLong(nrows)); + PyTuple_SetItem(args, 1, PyLong_FromLong(ncols)); + PyTuple_SetItem(args, 2, PyLong_FromLong(plot_number)); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyObject* pobj_second; + if (isDouble(it->second)) { + pobj_second = PyFloat_FromDouble(std::stod(it->second)); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); + } else { + pobj_second = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(kwargs, it->first.c_str(), pobj_second); + } + Py_DECREF(pobj_second); + } PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); + PyObject_Call(detail::_interpreter::get().s_python_function_subplot, args, kwargs); if (!res) throw std::runtime_error("Call to subplot() failed."); Py_DECREF(args); Py_DECREF(res); + Py_DECREF(kwargs); } inline void subplot2grid(long nrows, long ncols, long rowid = 0, long colid = 0, long rowspan = 1, From 1d0a2c40fe81d47fc80cc8520224917ea3dde96e Mon Sep 17 00:00:00 2001 From: yjchen Date: Thu, 9 Feb 2023 13:01:02 +0800 Subject: [PATCH 05/12] Update quiver example. --- examples/quiver.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/quiver.cpp b/examples/quiver.cpp index 55a562bd..9d43139c 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -33,8 +33,10 @@ int main() { } } - std::map kwargs = {{"normalize", "True"}, {"length", "0.3"}}; - plt::quiver(x, y, z, u, v, w, n0, n1, n2, kwargs); + std::map subplot_kwargs = {{"projection", "3d"}}; + plt::subplot(1, 1, 1, subplot_kwargs); + std::map quiver_kwargs = {{"normalize", "True"}, {"length", "0.3"}}; + plt::quiver(x, y, z, u, v, w, n0, n1, n2, quiver_kwargs); plt::show(); delete[] x; From 87201569f2b81e420c3b87f02dd812cfc2be5aaf Mon Sep 17 00:00:00 2001 From: yjchen Date: Mon, 13 Feb 2023 11:11:20 +0800 Subject: [PATCH 06/12] Modify figsize interface --- matplotlibcpp.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index ad57926f..42d05cbf 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -2105,21 +2105,27 @@ inline bool fignum_exists(long number) { return ret; } -inline void figure_size(size_t w, size_t h) { +inline void figure_size(long number, double w, double h) { detail::_interpreter::get(); - const size_t dpi = 100; + assert(number > 0); + // Make sure interpreter is initialised + detail::_interpreter::get(); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromLong(number)); + PyObject* size = PyTuple_New(2); - PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); - PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi)); + PyTuple_SetItem(size, 0, PyFloat_FromDouble(w)); + PyTuple_SetItem(size, 1, PyFloat_FromDouble(h)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "figsize", size); - PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_figure, args, kwargs); + Py_DECREF(args); + Py_DECREF(size); Py_DECREF(kwargs); if (!res) throw std::runtime_error("Call to figure_size() failed."); From e2e6b44c442cda896a7f575e1715f5769aa010a5 Mon Sep 17 00:00:00 2001 From: yjchen Date: Mon, 13 Feb 2023 17:12:45 +0800 Subject: [PATCH 07/12] update basic example --- examples/basic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/basic.cpp b/examples/basic.cpp index 2dc34c74..1401949d 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -17,7 +17,7 @@ int main() } // Set the size of output image = 1200x780 pixels - plt::figure_size(1200, 780); + // plt::figure_size(1200, 780); // Plot line from given x and y data. Color is selected automatically. plt::plot(x, y); From 1d5620821184a96f736be276be6fb02fb9f43e45 Mon Sep 17 00:00:00 2001 From: yjchen Date: Thu, 16 Feb 2023 09:10:17 +0800 Subject: [PATCH 08/12] Remove basic target --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b554138..336bae64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,9 +41,9 @@ add_executable(minimal examples/minimal.cpp) target_link_libraries(minimal PRIVATE matplotlib_cpp) set_target_properties(minimal PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -add_executable(basic examples/basic.cpp) -target_link_libraries(basic PRIVATE matplotlib_cpp) -set_target_properties(basic PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +# add_executable(basic examples/basic.cpp) +# target_link_libraries(basic PRIVATE matplotlib_cpp) +# set_target_properties(basic PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") add_executable(modern examples/modern.cpp) target_link_libraries(modern PRIVATE matplotlib_cpp) From 929684f2ab8490331b012bd46e9b1cde72f5446e Mon Sep 17 00:00:00 2001 From: yjchen Date: Wed, 15 Mar 2023 18:55:54 +0800 Subject: [PATCH 09/12] Update build environment setting. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 336bae64..ea328c9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ target_compile_features(matplotlib_cpp INTERFACE cxx_std_11 ) # TODO: Use `Development.Embed` component when requiring cmake >= 3.18 -find_package(Python3 COMPONENTS Interpreter Development REQUIRED) +find_package(Python3 3.8 COMPONENTS Interpreter Development REQUIRED) target_link_libraries(matplotlib_cpp INTERFACE Python3::Python Python3::Module From c69518423814f19b47687c27df908e430d2d8b95 Mon Sep 17 00:00:00 2001 From: yjchen Date: Fri, 28 Apr 2023 00:51:17 +0800 Subject: [PATCH 10/12] Add way to plot rectangle in 3d space. --- examples/quiver.cpp | 2 + matplotlibcpp.h | 116 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/examples/quiver.cpp b/examples/quiver.cpp index 9d43139c..cc45cf56 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -37,6 +37,8 @@ int main() { plt::subplot(1, 1, 1, subplot_kwargs); std::map quiver_kwargs = {{"normalize", "True"}, {"length", "0.3"}}; plt::quiver(x, y, z, u, v, w, n0, n1, n2, quiver_kwargs); + std::map rect_kwargs = {{"angle", "30"}, {"fill", "0"}, {"rotation_point", "center"}}; + plt::rectangle3d(0, 0, 1, 2, 3, rect_kwargs); plt::show(); delete[] x; diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 42d05cbf..c0ef82c3 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -1715,6 +1715,122 @@ bool quiver(const NumericX* x, const NumericY* y, const NumericZ* z, const Numer return res; } +bool rectangle3d(const double& x, const double& y, const double& z, const double& width, + const double& height, const std::map& keywords = {}) { + // set up 3d axes stuff + static PyObject *mpl_toolkitsmod = nullptr, *art3dmod = nullptr, *patchesmod = nullptr; + if (!mpl_toolkitsmod) { + detail::_interpreter::get(); + + PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject* art3d = PyString_FromString("mpl_toolkits.mplot3d.art3d"); + if (!mpl_toolkits || !art3d) { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + art3dmod = PyImport_Import(art3d); + Py_DECREF(art3d); + if (!art3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d.art3d!"); + } + } + + // set up patches + if (!patchesmod) { + PyObject* patches = PyString_FromString("matplotlib.patches"); + if (!patches) { + throw std::runtime_error("couldnt create string"); + } + + patchesmod = PyImport_Import(patches); + Py_DECREF(patches); + if (!patchesmod) { + throw std::runtime_error("Error loading module matplotlib.patches!"); + } + } + + // construct plot_args for rectangle + PyObject* xy = PyTuple_New(2); + PyTuple_SetItem(xy, 0, PyFloat_FromDouble(x)); + PyTuple_SetItem(xy, 1, PyFloat_FromDouble(y)); + PyObject* rect_plot_args = PyTuple_New(3); + PyTuple_SetItem(rect_plot_args, 0, xy); + PyTuple_SetItem(rect_plot_args, 1, PyFloat_FromDouble(width)); + PyTuple_SetItem(rect_plot_args, 2, PyFloat_FromDouble(height)); + + // construct keyword args for rectangle + PyObject* rect_kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyObject* pobj_second; + if (isDouble(it->second)) { + pobj_second = PyFloat_FromDouble(std::stod(it->second)); + PyDict_SetItemString(rect_kwargs, it->first.c_str(), pobj_second); + } else { + pobj_second = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(rect_kwargs, it->first.c_str(), pobj_second); + } + Py_DECREF(pobj_second); + } + + // create rectangle + PyObject* rectangle_func = PyObject_GetAttrString(patchesmod, "Rectangle"); + if (!rectangle_func) throw std::runtime_error("No Rectangle"); + Py_INCREF(rectangle_func); + PyObject* rect = PyObject_Call(rectangle_func, rect_plot_args, rect_kwargs); + if (!rect) throw std::runtime_error("Failed creating rectangle"); + Py_DECREF(rectangle_func); + Py_DECREF(rect_kwargs); + Py_DECREF(rect_plot_args); + + // construct plot_args for pathpatch_2d_to_3d + PyObject* path_plot_args = PyTuple_New(1); + PyTuple_SetItem(path_plot_args, 0, rect); + + // add patch + PyObject* axis = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); + PyObject* add_patch_func = PyObject_GetAttrString(axis, "add_patch"); + if (!add_patch_func) throw std::runtime_error("No add_patch"); + Py_INCREF(add_patch_func); + PyObject* res = PyObject_CallObject(add_patch_func, path_plot_args); + if (!res) throw std::runtime_error("Failed add_patch"); + Py_DECREF(add_patch_func); + Py_DECREF(axis); + if (res) Py_DECREF(res); + + // construct keyword args for pathpatch_2d_to_3d + PyObject* path_kwargs = PyDict_New(); + PyObject* pobj_second; + pobj_second = PyFloat_FromDouble(z); + PyDict_SetItemString(path_kwargs, "z", pobj_second); + Py_DECREF(pobj_second); + pobj_second = PyUnicode_FromString("z"); + PyDict_SetItemString(path_kwargs, "zdir", pobj_second); + Py_DECREF(pobj_second); + + // convert patch from 2d to 3d + PyObject* path_2d_to_3d_func = PyObject_GetAttrString(art3dmod, "pathpatch_2d_to_3d"); + if (!path_2d_to_3d_func) throw std::runtime_error("No pathpatch_2d_to_3d"); + Py_INCREF(path_2d_to_3d_func); + res = PyObject_Call(path_2d_to_3d_func, path_plot_args, path_kwargs); + if (!res) throw std::runtime_error("Failed to execute pathpatch_2d_to_3d"); + Py_DECREF(path_2d_to_3d_func); + Py_DECREF(path_plot_args); + Py_DECREF(path_kwargs); + if (res) Py_DECREF(res); + + return res; +} + template bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") { From 577147ee6c0b67f604b3e4aa8ae6e247646cf8a1 Mon Sep 17 00:00:00 2001 From: yjchen Date: Thu, 4 May 2023 21:32:23 +0800 Subject: [PATCH 11/12] Add zlim interface --- matplotlibcpp.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index c0ef82c3..4c2866f7 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -2364,6 +2364,36 @@ void xlim(Numeric left, Numeric right) { Py_DECREF(res); } +template +void zlim(Numeric left, Numeric right) { + detail::_interpreter::get(); + + PyObject* list = PyList_New(2); + PyList_SetItem(list, 0, PyFloat_FromDouble(left)); + PyList_SetItem(list, 1, PyFloat_FromDouble(right)); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, list); + + // Get axis from python + PyObject* ax = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); + if (!ax) throw std::runtime_error("No axis"); + Py_INCREF(ax); + // Get zlim function from axis + PyObject* set_zlim = PyObject_GetAttrString(ax, "set_zlim"); + if (!set_zlim) throw std::runtime_error("No set_zlim"); + Py_INCREF(set_zlim); + // call set_zlim + PyObject* res = PyObject_CallObject(set_zlim, args); + if (!res) throw std::runtime_error("Call to set_zlim() failed."); + Py_DECREF(set_zlim); + Py_DECREF(ax); + + Py_DECREF(args); + Py_DECREF(res); +} + inline std::array xlim() { PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); From 3d8d85006dcd6c3ad82ece090a91fb690ca38939 Mon Sep 17 00:00:00 2001 From: yjchen Date: Sat, 6 May 2023 17:56:11 +0800 Subject: [PATCH 12/12] Add rectangle2d --- matplotlibcpp.h | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 4c2866f7..8e471b4d 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -1715,6 +1715,78 @@ bool quiver(const NumericX* x, const NumericY* y, const NumericZ* z, const Numer return res; } +bool rectangle2d(const double& x, const double& y, const double& width, const double& height, + const std::map& keywords = {}) { + // set up patches + static PyObject* patchesmod = nullptr; + if (!patchesmod) { + PyObject* patches = PyString_FromString("matplotlib.patches"); + if (!patches) { + throw std::runtime_error("couldnt create string"); + } + + patchesmod = PyImport_Import(patches); + Py_DECREF(patches); + if (!patchesmod) { + throw std::runtime_error("Error loading module matplotlib.patches!"); + } + } + + // construct plot_args for rectangle + PyObject* xy = PyTuple_New(2); + PyTuple_SetItem(xy, 0, PyFloat_FromDouble(x)); + PyTuple_SetItem(xy, 1, PyFloat_FromDouble(y)); + PyObject* rect_plot_args = PyTuple_New(3); + PyTuple_SetItem(rect_plot_args, 0, xy); + PyTuple_SetItem(rect_plot_args, 1, PyFloat_FromDouble(width)); + PyTuple_SetItem(rect_plot_args, 2, PyFloat_FromDouble(height)); + + // construct keyword args for rectangle + PyObject* rect_kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + PyObject* pobj_second; + if (isDouble(it->second)) { + pobj_second = PyFloat_FromDouble(std::stod(it->second)); + PyDict_SetItemString(rect_kwargs, it->first.c_str(), pobj_second); + } else { + pobj_second = PyUnicode_FromString(it->second.c_str()); + PyDict_SetItemString(rect_kwargs, it->first.c_str(), pobj_second); + } + Py_DECREF(pobj_second); + } + + // create rectangle + PyObject* rectangle_func = PyObject_GetAttrString(patchesmod, "Rectangle"); + if (!rectangle_func) throw std::runtime_error("No Rectangle"); + Py_INCREF(rectangle_func); + PyObject* rect = PyObject_Call(rectangle_func, rect_plot_args, rect_kwargs); + if (!rect) throw std::runtime_error("Failed creating rectangle"); + Py_DECREF(rectangle_func); + Py_DECREF(rect_kwargs); + Py_DECREF(rect_plot_args); + + // construct plot_args + PyObject* path_plot_args = PyTuple_New(1); + PyTuple_SetItem(path_plot_args, 0, rect); + + // add patch + PyObject* axis = PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); + if (!axis) throw std::runtime_error("No axis"); + Py_INCREF(axis); + PyObject* add_patch_func = PyObject_GetAttrString(axis, "add_patch"); + if (!add_patch_func) throw std::runtime_error("No add_patch"); + Py_INCREF(add_patch_func); + PyObject* res = PyObject_CallObject(add_patch_func, path_plot_args); + if (!res) throw std::runtime_error("Failed add_patch"); + Py_DECREF(add_patch_func); + Py_DECREF(axis); + if (res) Py_DECREF(res); + + return res; +} + bool rectangle3d(const double& x, const double& y, const double& z, const double& width, const double& height, const std::map& keywords = {}) { // set up 3d axes stuff