From 0f382b372da331e12e40dad5584dbde727c33d71 Mon Sep 17 00:00:00 2001 From: Christoph Jenzen Date: Fri, 22 Jun 2018 16:19:39 +0200 Subject: [PATCH 01/12] Added Eventplot + Reformatting --- Makefile | 9 +- examples/eventplot.cpp | 34 ++++++ matplotlibcpp.h | 267 +++++++++++++++++++++++++++-------------- 3 files changed, 214 insertions(+), 96 deletions(-) create mode 100644 examples/eventplot.cpp diff --git a/Makefile b/Makefile index e75d1343..abb5a6ce 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ -examples: minimal basic modern animation nonblock xkcd +examples: minimal basic eventplot modern animation nonblock xkcd minimal: examples/minimal.cpp matplotlibcpp.h cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python2.7 -lpython2.7 -o minimal -std=c++11 basic: examples/basic.cpp matplotlibcpp.h - cd examples && g++ basic.cpp -I/usr/include/python2.7 -lpython2.7 -o basic + cd examples && g++ basic.cpp -I/usr/include/python2.7 -lpython2.7 -o basic -std=c++11 + +eventplot: examples/eventplot.cpp matplotlibcpp.h + cd examples && g++ eventplot.cpp -I/usr/include/python2.7 -lpython2.7 -o eventplot -std=c++11 -g modern: examples/modern.cpp matplotlibcpp.h cd examples && g++ modern.cpp -I/usr/include/python2.7 -lpython2.7 -o modern -std=c++11 @@ -19,4 +22,4 @@ xkcd: examples/xkcd.cpp matplotlibcpp.h cd examples && g++ xkcd.cpp -I/usr/include/python2.7 -lpython2.7 -o xkcd -std=c++11 clean: - rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd} + rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,eventplot} diff --git a/examples/eventplot.cpp b/examples/eventplot.cpp new file mode 100644 index 00000000..210b9637 --- /dev/null +++ b/examples/eventplot.cpp @@ -0,0 +1,34 @@ +#define _USE_MATH_DEFINES +#include +#include +#include "../matplotlibcpp.h" + +namespace plt = matplotlibcpp; + +int main() +{ + // Prepare data. + std::vector> events; + events.push_back({2,5,10,25}); + events.push_back({20,21,22,24}); + events.push_back({4,8,12,14,16,17,18}); + events.push_back({10,11,12,13.5}); + + + + // Set the size of output image = 1200x780 pixels + plt::figure_size(1200, 780); + + plt::eventplot(events); + + // Add graph title + plt::title("Event plot"); + plt::xlabel("Time in ms"); + plt::ylabel("Neuron ID"); + + plt::show(); + // save figure + const char* filename = "./events.png"; + std::cout << "Saving result to " << filename << std::endl;; + plt::save(filename); +} diff --git a/matplotlibcpp.h b/matplotlibcpp.h index f9f7026b..9cfd75c6 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -37,6 +37,7 @@ struct _interpreter { PyObject *s_python_function_save; PyObject *s_python_function_figure; PyObject *s_python_function_plot; + PyObject *s_python_function_eventplot; PyObject *s_python_function_semilogx; PyObject *s_python_function_semilogy; PyObject *s_python_function_loglog; @@ -114,7 +115,9 @@ struct _interpreter { PyObject* matplotlib = PyImport_Import(matplotlibname); Py_DECREF(matplotlibname); - if (!matplotlib) { throw std::runtime_error("Error loading module matplotlib!"); } + if (!matplotlib) { + throw std::runtime_error("Error loading module matplotlib!"); + } // matplotlib.use() must be called *before* pylab, matplotlib.pyplot, // or matplotlib.backends is imported for the first time @@ -124,12 +127,16 @@ struct _interpreter { 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!"); + } 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_show = PyObject_GetAttrString(pymod, "show"); s_python_function_close = PyObject_GetAttrString(pymod, "close"); @@ -137,6 +144,7 @@ struct _interpreter { s_python_function_pause = PyObject_GetAttrString(pymod, "pause"); s_python_function_figure = PyObject_GetAttrString(pymod, "figure"); s_python_function_plot = PyObject_GetAttrString(pymod, "plot"); + s_python_function_eventplot = PyObject_GetAttrString(pymod, "eventplot"); s_python_function_semilogx = PyObject_GetAttrString(pymod, "semilogx"); s_python_function_semilogy = PyObject_GetAttrString(pymod, "semilogy"); s_python_function_loglog = PyObject_GetAttrString(pymod, "loglog"); @@ -161,63 +169,69 @@ struct _interpreter { s_python_function_xkcd = PyObject_GetAttrString(pymod, "xkcd"); if( !s_python_function_show - || !s_python_function_close - || !s_python_function_draw - || !s_python_function_pause - || !s_python_function_figure - || !s_python_function_plot - || !s_python_function_semilogx - || !s_python_function_semilogy - || !s_python_function_loglog - || !s_python_function_fill_between - || !s_python_function_subplot - || !s_python_function_legend - || !s_python_function_ylim - || !s_python_function_title - || !s_python_function_axis - || !s_python_function_xlabel - || !s_python_function_ylabel - || !s_python_function_grid - || !s_python_function_xlim - || !s_python_function_ion - || !s_python_function_save - || !s_python_function_clf - || !s_python_function_annotate - || !s_python_function_errorbar - || !s_python_function_errorbar - || !s_python_function_tight_layout - || !s_python_function_stem - || !s_python_function_xkcd - ) { throw std::runtime_error("Couldn't find required function!"); } + || !s_python_function_close + || !s_python_function_draw + || !s_python_function_pause + || !s_python_function_figure + || !s_python_function_plot + || !s_python_function_eventplot + || !s_python_function_semilogx + || !s_python_function_semilogy + || !s_python_function_loglog + || !s_python_function_fill_between + || !s_python_function_subplot + || !s_python_function_legend + || !s_python_function_ylim + || !s_python_function_title + || !s_python_function_axis + || !s_python_function_xlabel + || !s_python_function_ylabel + || !s_python_function_grid + || !s_python_function_xlim + || !s_python_function_ion + || !s_python_function_save + || !s_python_function_clf + || !s_python_function_annotate + || !s_python_function_errorbar + || !s_python_function_errorbar + || !s_python_function_tight_layout + || !s_python_function_stem + || !s_python_function_xkcd + ) { + throw std::runtime_error("Couldn't find required function!"); + } if ( !PyFunction_Check(s_python_function_show) - || !PyFunction_Check(s_python_function_close) - || !PyFunction_Check(s_python_function_draw) - || !PyFunction_Check(s_python_function_pause) - || !PyFunction_Check(s_python_function_figure) - || !PyFunction_Check(s_python_function_plot) - || !PyFunction_Check(s_python_function_semilogx) - || !PyFunction_Check(s_python_function_semilogy) - || !PyFunction_Check(s_python_function_loglog) - || !PyFunction_Check(s_python_function_fill_between) - || !PyFunction_Check(s_python_function_subplot) - || !PyFunction_Check(s_python_function_legend) - || !PyFunction_Check(s_python_function_annotate) - || !PyFunction_Check(s_python_function_ylim) - || !PyFunction_Check(s_python_function_title) - || !PyFunction_Check(s_python_function_axis) - || !PyFunction_Check(s_python_function_xlabel) - || !PyFunction_Check(s_python_function_ylabel) - || !PyFunction_Check(s_python_function_grid) - || !PyFunction_Check(s_python_function_xlim) - || !PyFunction_Check(s_python_function_ion) - || !PyFunction_Check(s_python_function_save) - || !PyFunction_Check(s_python_function_clf) - || !PyFunction_Check(s_python_function_tight_layout) - || !PyFunction_Check(s_python_function_errorbar) - || !PyFunction_Check(s_python_function_stem) - || !PyFunction_Check(s_python_function_xkcd) - ) { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); } + || !PyFunction_Check(s_python_function_close) + || !PyFunction_Check(s_python_function_draw) + || !PyFunction_Check(s_python_function_pause) + || !PyFunction_Check(s_python_function_figure) + || !PyFunction_Check(s_python_function_plot) + || !PyFunction_Check(s_python_function_eventplot) + || !PyFunction_Check(s_python_function_semilogx) + || !PyFunction_Check(s_python_function_semilogy) + || !PyFunction_Check(s_python_function_loglog) + || !PyFunction_Check(s_python_function_fill_between) + || !PyFunction_Check(s_python_function_subplot) + || !PyFunction_Check(s_python_function_legend) + || !PyFunction_Check(s_python_function_annotate) + || !PyFunction_Check(s_python_function_ylim) + || !PyFunction_Check(s_python_function_title) + || !PyFunction_Check(s_python_function_axis) + || !PyFunction_Check(s_python_function_xlabel) + || !PyFunction_Check(s_python_function_ylabel) + || !PyFunction_Check(s_python_function_grid) + || !PyFunction_Check(s_python_function_xlim) + || !PyFunction_Check(s_python_function_ion) + || !PyFunction_Check(s_python_function_save) + || !PyFunction_Check(s_python_function_clf) + || !PyFunction_Check(s_python_function_tight_layout) + || !PyFunction_Check(s_python_function_errorbar) + || !PyFunction_Check(s_python_function_stem) + || !PyFunction_Check(s_python_function_xkcd) + ) { + throw std::runtime_error("Python object is unexpectedly not a PyFunction."); + } s_python_empty_tuple = PyTuple_New(0); } @@ -261,18 +275,42 @@ inline bool annotate(std::string annotation, double x, double y) #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; +}; template PyObject* get_array(const std::vector& v) @@ -337,6 +375,45 @@ bool plot(const std::vector &x, const std::vector &y, const st return res; } +template +bool eventplot(const std::vector> &events, const std::map& keywords = std::map()) +{ + PyObject* list = PyList_New(events.size()); + // using numpy arrays + for(size_t i = 0; i < events.size(); i++) { + PyList_SetItem(list, i, get_array(events[i])); + } + + PyObject* res; + // construct positional args + if(keywords.size()>0) { + PyObject* args = PyTuple_New(2); + PyTuple_SetItem(args, 0, list); + + // 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())); + } + + res = PyObject_CallObject(detail::_interpreter::get().s_python_function_eventplot, args); + Py_DECREF(kwargs); + Py_DECREF(args); + } + else { + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, list); + + res = PyObject_CallObject(detail::_interpreter::get().s_python_function_eventplot, args); + + Py_DECREF(args); + } + + if(res) Py_DECREF(res); + return res; +} + template bool stem(const std::vector &x, const std::vector &y, const std::map& keywords) { @@ -354,13 +431,13 @@ 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) { + keywords.begin(); it != keywords.end(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); + PyString_FromString(it->second.c_str())); } PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_stem, args, kwargs); + detail::_interpreter::get().s_python_function_stem, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); @@ -493,7 +570,7 @@ bool stem(const std::vector& x, const std::vector& y, const PyTuple_SetItem(plot_args, 2, pystring); PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_stem, plot_args); + detail::_interpreter::get().s_python_function_stem, plot_args); Py_DECREF(plot_args); if (res) @@ -762,8 +839,8 @@ inline void figure_size(size_t w, size_t h) 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, + detail::_interpreter::get().s_python_empty_tuple, kwargs); Py_DECREF(kwargs); @@ -937,15 +1014,15 @@ inline void show(const bool block = true) if(block) { res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_show, - detail::_interpreter::get().s_python_empty_tuple); + detail::_interpreter::get().s_python_function_show, + detail::_interpreter::get().s_python_empty_tuple); } else { PyObject *kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "block", Py_False); res = PyObject_Call( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs); - Py_DECREF(kwargs); + Py_DECREF(kwargs); } @@ -957,8 +1034,8 @@ inline void show(const bool block = true) inline void close() { PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_close, - detail::_interpreter::get().s_python_empty_tuple); + detail::_interpreter::get().s_python_function_close, + detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to close() failed."); @@ -970,7 +1047,7 @@ inline void xkcd() { PyObject *kwargs = PyDict_New(); res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + detail::_interpreter::get().s_python_empty_tuple, kwargs); Py_DECREF(kwargs); @@ -983,8 +1060,8 @@ inline void xkcd() { inline void draw() { PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_draw, - detail::_interpreter::get().s_python_empty_tuple); + detail::_interpreter::get().s_python_function_draw, + detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to draw() failed."); @@ -1020,18 +1097,18 @@ inline void save(const std::string& filename) inline void clf() { PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_clf, - detail::_interpreter::get().s_python_empty_tuple); + detail::_interpreter::get().s_python_function_clf, + detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to clf() failed."); Py_DECREF(res); } - inline void ion() { +inline void ion() { PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - detail::_interpreter::get().s_python_empty_tuple); + detail::_interpreter::get().s_python_function_ion, + detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to ion() failed."); @@ -1041,8 +1118,8 @@ inline void clf() { // Actually, is there any reason not to call this automatically for every plot? inline void tight_layout() { PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_tight_layout, - detail::_interpreter::get().s_python_empty_tuple); + 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."); @@ -1069,7 +1146,9 @@ struct is_callable_impl template struct is_callable_impl { - struct Fallback { void operator()(); }; + struct Fallback { + void operator()(); + }; struct Derived : T, Fallback { }; template struct Check; @@ -1155,7 +1234,9 @@ struct plot_impl // recursion stop for the above template -bool plot() { return true; } +bool plot() { + return true; +} template bool plot(const A& a, const B& b, const std::string& format, Args... args) From 3a90a0d248bcdf9708e56bd4eadd36bd31b46ef9 Mon Sep 17 00:00:00 2001 From: Christoph Jenzen Date: Mon, 25 Jun 2018 16:20:18 +0200 Subject: [PATCH 02/12] add in_between to the makefile --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index abb5a6ce..a7f7ef8d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -examples: minimal basic eventplot modern animation nonblock xkcd +examples: minimal basic eventplot fill_inbetween modern animation nonblock xkcd minimal: examples/minimal.cpp matplotlibcpp.h cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python2.7 -lpython2.7 -o minimal -std=c++11 @@ -8,6 +8,9 @@ basic: examples/basic.cpp matplotlibcpp.h eventplot: examples/eventplot.cpp matplotlibcpp.h cd examples && g++ eventplot.cpp -I/usr/include/python2.7 -lpython2.7 -o eventplot -std=c++11 -g + +fill_inbetween: examples/fill_inbetween.cpp matplotlibcpp.h + cd examples && g++ fill_inbetween.cpp -I/usr/include/python2.7 -lpython2.7 -o fill_inbetween -std=c++11 -g modern: examples/modern.cpp matplotlibcpp.h cd examples && g++ modern.cpp -I/usr/include/python2.7 -lpython2.7 -o modern -std=c++11 @@ -22,4 +25,4 @@ xkcd: examples/xkcd.cpp matplotlibcpp.h cd examples && g++ xkcd.cpp -I/usr/include/python2.7 -lpython2.7 -o xkcd -std=c++11 clean: - rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,eventplot} + rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,eventplot,fill_inbetween} From 1815f40bfe96250a53f33b1859ef471fa1562ec3 Mon Sep 17 00:00:00 2001 From: Christoph Jenzen Date: Mon, 25 Jun 2018 16:21:01 +0200 Subject: [PATCH 03/12] Repair eventplots in case of keyword args beeing numbers --- examples/eventplot.cpp | 6 +++-- matplotlibcpp.h | 54 ++++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/examples/eventplot.cpp b/examples/eventplot.cpp index 210b9637..417650f2 100644 --- a/examples/eventplot.cpp +++ b/examples/eventplot.cpp @@ -18,8 +18,10 @@ int main() // Set the size of output image = 1200x780 pixels plt::figure_size(1200, 780); - - plt::eventplot(events); + std::map keywords; + keywords["linewidths"] = "0.5"; + keywords["colors"] = "black"; + plt::eventplot(events, keywords); // Add graph title plt::title("Event plot"); diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 9cfd75c6..51197b9d 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -378,39 +378,53 @@ bool plot(const std::vector &x, const std::vector &y, const st template bool eventplot(const std::vector> &events, const std::map& keywords = std::map()) { - PyObject* list = PyList_New(events.size()); + PyObject *list = PyList_New(events.size()); // using numpy arrays - for(size_t i = 0; i < events.size(); i++) { + for (size_t i = 0; i < events.size(); i++) { PyList_SetItem(list, i, get_array(events[i])); } - PyObject* res; + PyObject *res; // construct positional args - if(keywords.size()>0) { - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, list); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, list); + if (keywords.size() > 0) { // 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 *kwargs = PyDict_New(); + for (std::map::const_iterator it = + keywords.begin(); + it != keywords.end(); ++it) { + bool is_number = false; + double value = 0.0; + try { + value = std::stod(it->second.c_str()); + is_number = true; + } + catch( ... ) {} + if(is_number) { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyFloat_FromDouble(value)); + } + else { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } } - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_eventplot, args); + res = PyObject_Call( + detail::_interpreter::get().s_python_function_eventplot, args, + kwargs); Py_DECREF(kwargs); - Py_DECREF(args); } else { - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, list); - - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_eventplot, args); - - Py_DECREF(args); + res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_eventplot, args); } - if(res) Py_DECREF(res); + Py_DECREF(args); + if (res) + Py_DECREF(res); return res; } @@ -545,7 +559,7 @@ bool plot(const std::vector& x, const std::vector& y, const PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - + std::cout << "hey"< Date: Mon, 25 Jun 2018 16:32:48 +0200 Subject: [PATCH 04/12] remove "hey" --- matplotlibcpp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 51197b9d..29a4d26a 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -559,7 +559,6 @@ bool plot(const std::vector& x, const std::vector& y, const PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - std::cout << "hey"< Date: Wed, 27 Jun 2018 09:44:47 +0200 Subject: [PATCH 05/12] Remove unnecessary string --- matplotlibcpp.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 29a4d26a..ac03c495 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -662,7 +662,7 @@ bool loglog(const std::vector& x, const std::vector& y, cons } template -bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::string &s = "") +bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr) { assert(x.size() == y.size()); @@ -674,8 +674,6 @@ bool errorbar(const std::vector &x, const std::vector &y, co PyDict_SetItemString(kwargs, "yerr", yerrarray); - PyObject *pystring = PyString_FromString(s.c_str()); - PyObject *plot_args = PyTuple_New(2); PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); From 789e09b84adcd095079f932bc90bbcb679cbb467 Mon Sep 17 00:00:00 2001 From: Christoph Ostrau Date: Fri, 15 Nov 2019 15:30:53 +0100 Subject: [PATCH 06/12] inline of subplot2grid to avoid multiple copies while linking --- matplotlibcpp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 4a351ec0..6e0ae4c7 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -1560,7 +1560,7 @@ inline void subplot(long nrows, long ncols, long plot_number) Py_DECREF(res); } -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) { PyObject* shape = PyTuple_New(2); PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); From ee86b1e43d57b42d855c780061769a726d345886 Mon Sep 17 00:00:00 2001 From: Christoph Ostrau Date: Thu, 12 Dec 2019 09:44:40 +0100 Subject: [PATCH 07/12] Make sure that the python interpreter is initialized --- matplotlibcpp.h | 60 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 6e0ae4c7..f9d557e4 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -339,6 +339,8 @@ inline void backend(const std::string& name) 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()); @@ -448,6 +450,7 @@ PyObject* get_2darray(const std::vector<::std::vector>& v) template PyObject* get_array(const std::vector& v) { + detail::_interpreter::get(); PyObject* list = PyList_New(v.size()); for(size_t i = 0; i < v.size(); ++i) { PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); @@ -460,6 +463,7 @@ PyObject* get_array(const std::vector& v) template bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) { + detail::_interpreter::get(); assert(x.size() == y.size()); // using numpy arrays @@ -497,6 +501,7 @@ void plot_surface(const std::vector<::std::vector> &x, const std::map &keywords = std::map()) { + 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 @@ -587,6 +592,7 @@ void plot_surface(const std::vector<::std::vector> &x, template bool eventplot(const std::vector> &events, const std::map& keywords = std::map()) { + detail::_interpreter::get(); PyObject *list = PyList_New(events.size()); // using numpy arrays for (size_t i = 0; i < events.size(); i++) { @@ -640,6 +646,7 @@ bool eventplot(const std::vector> &events, const std::map bool stem(const std::vector &x, const std::vector &y, const std::map& keywords) { + detail::_interpreter::get(); assert(x.size() == y.size()); // using numpy arrays @@ -673,6 +680,7 @@ bool stem(const std::vector &x, const std::vector &y, const st template< typename Numeric > bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) { + detail::_interpreter::get(); assert(x.size() == y.size()); // using numpy arrays @@ -703,6 +711,7 @@ bool fill(const std::vector& x, const std::vector& y, const st template< typename Numeric > bool fill_between(const std::vector& x, const std::vector& y1, const std::vector& y2, const std::map& keywords) { + detail::_interpreter::get(); assert(x.size() == y1.size()); assert(x.size() == y2.size()); @@ -736,7 +745,7 @@ template< typename Numeric> 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 = get_array(y); PyObject* kwargs = PyDict_New(); @@ -803,6 +812,7 @@ bool hist(const std::vector& y, long bins=10,std::string color="b", #ifdef WITH_OPENCV void imshow(const cv::Mat &image, const std::map &keywords = {}) { + detail::_interpreter::get(); // Convert underlying type of matrix, if needed cv::Mat image2; NPY_TYPES npy_type = NPY_UINT8; @@ -837,6 +847,7 @@ bool scatter(const std::vector& x, const std::vector& y, const double s=1.0) // The marker size in points**2 { + detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* xarray = get_array(x); @@ -865,6 +876,7 @@ bool bar(const std::vector & x, std::string ls = "-", double lw = 1.0, const std::map & keywords = {}) { + detail::_interpreter::get(); PyObject * xarray = get_array(x); PyObject * yarray = get_array(y); @@ -902,6 +914,7 @@ bool bar(const std::vector & y, std::string ls = "-", double lw = 1.0, const std::map & keywords = {}) { + detail::_interpreter::get(); using T = typename std::remove_reference::type::value_type; std::vector x; @@ -912,7 +925,7 @@ bool bar(const std::vector & y, 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) { @@ -935,6 +948,7 @@ inline bool subplots_adjust(const std::map& keywords = {}) template< typename Numeric> 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 = get_array(y); PyObject* kwargs = PyDict_New(); @@ -959,6 +973,7 @@ bool named_hist(std::string label,const std::vector& y, long bins=10, s template bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") { + detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* xarray = get_array(x); @@ -981,6 +996,7 @@ bool plot(const std::vector& x, const std::vector& y, const template bool quiver(const std::vector& x, const std::vector& y, const std::vector& u, const std::vector& w, const std::map& keywords = {}) { + detail::_interpreter::get(); assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); PyObject* xarray = get_array(x); @@ -1015,6 +1031,7 @@ bool quiver(const std::vector& x, const std::vector& y, cons template bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") { + detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* xarray = get_array(x); @@ -1040,6 +1057,7 @@ bool stem(const std::vector& x, const std::vector& y, const template bool semilogx(const std::vector& x, const std::vector& y, const std::string& s = "") { + detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* xarray = get_array(x); @@ -1063,6 +1081,7 @@ bool semilogx(const std::vector& x, const std::vector& y, co template bool semilogy(const std::vector& x, const std::vector& y, const std::string& s = "") { + detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* xarray = get_array(x); @@ -1086,6 +1105,7 @@ bool semilogy(const std::vector& x, const std::vector& y, co template bool loglog(const std::vector& x, const std::vector& y, const std::string& s = "") { + detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* xarray = get_array(x); @@ -1109,6 +1129,7 @@ bool loglog(const std::vector& x, const std::vector& y, cons template bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::map &keywords = {}) { + detail::_interpreter::get(); assert(x.size() == y.size()); PyObject* xarray = get_array(x); @@ -1144,6 +1165,7 @@ bool errorbar(const std::vector &x, const std::vector &y, co template bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") { + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1168,6 +1190,7 @@ bool named_plot(const std::string& name, const std::vector& y, const st 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(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1193,6 +1216,7 @@ bool named_plot(const std::string& name, const std::vector& x, const st 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(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1218,6 +1242,7 @@ bool named_semilogx(const std::string& name, const std::vector& x, cons 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(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1243,6 +1268,7 @@ bool named_semilogy(const std::string& name, const std::vector& x, cons 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(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1291,6 +1317,7 @@ bool stem(const std::vector& y, const std::string& format = "") template void text(Numeric x, Numeric y, const std::string& s = "") { + detail::_interpreter::get(); PyObject* args = PyTuple_New(3); PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); @@ -1306,6 +1333,7 @@ void text(Numeric x, Numeric y, const std::string& s = "") inline long figure(long number = -1) { + detail::_interpreter::get(); PyObject *res; if (number == -1) res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); @@ -1384,6 +1412,7 @@ inline void legend() template void ylim(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)); @@ -1401,6 +1430,7 @@ void ylim(Numeric left, Numeric right) template void xlim(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)); @@ -1418,6 +1448,7 @@ void xlim(Numeric left, Numeric right) inline double* xlim() { + detail::_interpreter::get(); PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); PyObject* left = PyTuple_GetItem(res,0); @@ -1436,6 +1467,7 @@ inline double* xlim() inline double* ylim() { + detail::_interpreter::get(); PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); PyObject* left = PyTuple_GetItem(res,0); @@ -1455,6 +1487,7 @@ 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(); // using numpy array PyObject* ticksarray = get_array(ticks); @@ -1502,6 +1535,7 @@ 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(); // using numpy array PyObject* ticksarray = get_array(ticks); @@ -1547,6 +1581,7 @@ inline void yticks(const std::vector &ticks, const std::map &keywords = {}) { + detail::_interpreter::get(); PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pytitlestr); @@ -1606,6 +1643,7 @@ inline void title(const std::string &titlestr, const std::map &keywords = {}) { + detail::_interpreter::get(); PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pysuptitlestr); @@ -1625,6 +1663,7 @@ inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) { + detail::_interpreter::get(); PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); @@ -1657,6 +1697,7 @@ inline void xlabel(const std::string &str, const std::map& keywords = {}) { + detail::_interpreter::get(); PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); @@ -1676,6 +1717,7 @@ inline void ylabel(const std::string &str, const std::map inline void pause(Numeric interval) { + detail::_interpreter::get(); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); @@ -1764,6 +1810,7 @@ inline void pause(Numeric interval) inline void save(const std::string& filename) { + detail::_interpreter::get(); PyObject* pyfilename = PyString_FromString(filename.c_str()); PyObject* args = PyTuple_New(1); @@ -1798,6 +1845,7 @@ inline void ion() { inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) { + detail::_interpreter::get(); PyObject *args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); @@ -1832,6 +1880,7 @@ inline std::vector> ginput(const int numClicks = 1, const // Actually, is there any reason not to call this automatically for every plot? 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); @@ -1899,6 +1948,7 @@ struct plot_impl using std::distance; using std::begin; using std::end; + detail::_interpreter::get(); auto xs = distance(begin(x), end(x)); auto ys = distance(begin(y), end(y)); @@ -1986,7 +2036,7 @@ class Plot Plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") { assert(x.size() == y.size()); - + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); if(name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -2021,7 +2071,9 @@ class Plot // shorter initialization with name or format only // basically calls line, = plot([], []) Plot(const std::string& name = "", const std::string& format = "") - : Plot(name, std::vector(), std::vector(), format) {} + : Plot(name, std::vector(), std::vector(), format) { + detail::_interpreter::get(); + } template bool update(const std::vector& x, const std::vector& y) { From c5a4b7dae1dce8c18d341d532cc0fc54b480d794 Mon Sep 17 00:00:00 2001 From: Christoph Ostrau Date: Thu, 2 Jul 2020 15:41:42 +0200 Subject: [PATCH 08/12] Fix two bugs I had (Interpreter shutdown, and kwargs with double values are not working) --- examples/fill_inbetween.cpp | 2 +- matplotlibcpp.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/fill_inbetween.cpp b/examples/fill_inbetween.cpp index 788d0086..a388c1c7 100644 --- a/examples/fill_inbetween.cpp +++ b/examples/fill_inbetween.cpp @@ -19,7 +19,7 @@ int main() { // Prepare keywords to pass to PolyCollection. See // https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.fill_between.html std::map keywords; - keywords["alpha"] = "0.4"; + //keywords["alpha"] = 0.4; keywords["color"] = "grey"; keywords["hatch"] = "-"; diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 8fe93829..8746a04e 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -253,7 +253,7 @@ struct _interpreter { } ~_interpreter() { - Py_Finalize(); + //Py_Finalize(); } }; @@ -777,7 +777,6 @@ bool fill_between(const std::vector& x, const std::vector& y1, assert(x.size() == y1.size()); assert(x.size() == y2.size()); - detail::_interpreter::get(); // using numpy arrays PyObject* xarray = detail::get_array(x); From 295544917d2cf2b345032dacb6ce8e1be6a5f69f Mon Sep 17 00:00:00 2001 From: Christoph Ostrau Date: Thu, 2 Jul 2020 15:48:02 +0200 Subject: [PATCH 09/12] Remove static assert warnings with c++17 --- matplotlibcpp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 8746a04e..54cdf08a 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -341,9 +341,9 @@ template <> struct select_npy_type { // 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); +static_assert(sizeof(long long) == 8, "Sanity check, see source code!"); template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT64; }; -static_assert(sizeof(unsigned long long) == 8); +static_assert(sizeof(unsigned long long) == 8, "Sanity check, see source code!"); template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; // TODO: add int, long, etc. From c45f8c8e4a8a4db358c98118f08d1add358461ba Mon Sep 17 00:00:00 2001 From: Christoph Ostrau Date: Fri, 4 Dec 2020 15:27:04 +0100 Subject: [PATCH 10/12] Fix potential segfaults --- matplotlibcpp.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 54cdf08a..94a232ff 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -350,6 +350,7 @@ template <> struct select_npy_type { const static NPY_TYPES template PyObject* get_array(const std::vector& v) { + detail::_interpreter::get(); npy_intp vsize = v.size(); NPY_TYPES type = select_npy_type::type; if (type == NPY_NOTYPE) { @@ -371,7 +372,7 @@ template PyObject* get_2darray(const std::vector<::std::vector>& v) { if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); - + detail::_interpreter::get(); npy_intp vsize[2] = {static_cast(v.size()), static_cast(v[0].size())}; @@ -408,6 +409,7 @@ PyObject* get_array(const std::vector& v) // sometimes, for labels and such, we need string arrays inline PyObject * get_array(const std::vector& strings) { + detail::_interpreter::get(); 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())); @@ -419,6 +421,7 @@ inline PyObject * get_array(const std::vector& strings) template PyObject* get_listlist(const std::vector>& ll) { + detail::_interpreter::get(); PyObject* listlist = PyList_New(ll.size()); for (std::size_t i = 0; i < ll.size(); ++i) { PyList_SetItem(listlist, i, get_array(ll[i])); From d8d93c9f7c96313a8b604d231a65878d1cbc0f87 Mon Sep 17 00:00:00 2001 From: Christoph Ostrau Date: Fri, 4 Dec 2020 15:27:25 +0100 Subject: [PATCH 11/12] Remove deprecated warning fom double to int conversion --- matplotlibcpp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 94a232ff..df4ebb3e 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -1905,9 +1905,9 @@ inline void subplot(long nrows, long ncols, long plot_number) 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)); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); if(!res) throw std::runtime_error("Call to subplot() failed."); From aafe492528d3c05c87d47ec4e4709f191375009f Mon Sep 17 00:00:00 2001 From: Christoph Ostrau Date: Wed, 9 Dec 2020 21:02:09 +0100 Subject: [PATCH 12/12] Magically solve another potential segfault (using -O3) --- matplotlibcpp.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index df4ebb3e..b397a2b5 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -109,6 +109,9 @@ struct _interpreter { static _interpreter& get() { static _interpreter ctx; +#ifndef WITHOUT_NUMPY + ctx.import_numpy(); +#endif return ctx; }