From bf49327bfaddbd70659f4c47c58f5036de19d0e7 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Thu, 25 Apr 2019 16:23:41 +0100 Subject: [PATCH 01/21] Added xtensor functionality to matplotlibcpp header. Half of the examples are updated - must complete this --- .gitignore | 2 + examples/animation.cpp | 11 +- examples/bar.cpp | 8 +- examples/basic.cpp | 25 +-- examples/fill.cpp | 7 +- examples/fill_inbetween.cpp | 36 +++-- examples/minimal.cpp | 3 + examples/modern.cpp | 13 +- examples/nonblock.cpp | 15 +- examples/quiver.cpp | 6 +- matplotlibcpp.h | 311 ++++++++++++++++++------------------ 11 files changed, 230 insertions(+), 207 deletions(-) diff --git a/.gitignore b/.gitignore index 7622be7..b0a5e1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.ycm_extra_conf.py + # Compiled Object files *.slo *.lo diff --git a/examples/animation.cpp b/examples/animation.cpp index d979430..f5a9b43 100644 --- a/examples/animation.cpp +++ b/examples/animation.cpp @@ -2,17 +2,20 @@ #include #include "../matplotlibcpp.h" +#include +#include + namespace plt = matplotlibcpp; int main() { int n = 1000; - std::vector x, y, z; + xt::xtensor x, y, z; for(int i=0; i{i*i})); + x = xt::concatenate(xt::xtuple(x, xt::xtensor{sin(2*M_PI*i/360.0)})); + x = xt::concatenate(xt::xtuple(x, xt::xtensor{log(i)})); if (i % 10 == 0) { // Clear previous plot diff --git a/examples/bar.cpp b/examples/bar.cpp index 86423ad..0e1843c 100644 --- a/examples/bar.cpp +++ b/examples/bar.cpp @@ -5,11 +5,11 @@ #include "../matplotlibcpp.h" namespace plt = matplotlibcpp; +#include +#include + int main(int argc, char **argv) { - std::vector test_data; - for (int i = 0; i < 20; i++) { - test_data.push_back(i); - } + xt::xtensor test_data = xt::arange(20); plt::bar(test_data); plt::show(); diff --git a/examples/basic.cpp b/examples/basic.cpp index 2dc34c7..5e6b277 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -3,21 +3,25 @@ #include #include "../matplotlibcpp.h" +#include +#include + namespace plt = matplotlibcpp; int main() { // Prepare data. int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i i = xt::linspace(0, (n-1), n); + std::array shape{static_cast(n)}; + xt::xtensor w(shape); + w.fill(2.0); + xt::xtensor x = xt::square(i); + xt::xtensor y = xt::sin(2 * xt::numeric_constants::PI * i / 360.0); + xt::xtensor z = xt::log(i); // 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); @@ -37,8 +41,9 @@ int main() // Enable legend. plt::legend(); + plt::show(); // save figure - const char* filename = "./basic.png"; - std::cout << "Saving result to " << filename << std::endl;; - plt::save(filename); + //const char* filename = "./basic.png"; + //std::cout << "Saving result to " << filename << std::endl;; + //plt::save(filename); } diff --git a/examples/fill.cpp b/examples/fill.cpp index 6059b47..5680e57 100644 --- a/examples/fill.cpp +++ b/examples/fill.cpp @@ -5,13 +5,14 @@ using namespace std; namespace plt = matplotlibcpp; +#include +#include + // Example fill plot taken from: // https://matplotlib.org/gallery/misc/fill_spiral.html int main() { // Prepare data. - vector theta; - for (double d = 0; d < 8 * M_PI; d += 0.1) - theta.push_back(d); + xt::xtensor theta = xt::arange(0, 8*xt::numeric_constants::PI, 0.1); const int a = 1; const double b = 0.2; diff --git a/examples/fill_inbetween.cpp b/examples/fill_inbetween.cpp index 788d008..4192125 100644 --- a/examples/fill_inbetween.cpp +++ b/examples/fill_inbetween.cpp @@ -6,23 +6,27 @@ using namespace std; namespace plt = matplotlibcpp; +#include +#include + int main() { - // Prepare data. - int n = 5000; - std::vector x(n), y(n), z(n), w(n, 2); - for (int i = 0; i < n; ++i) { - x.at(i) = i * i; - y.at(i) = sin(2 * M_PI * i / 360.0); - z.at(i) = log(i); - } + // Prepare data. + int n = 5000; + xt::xtensor i = xt::linspace(0, (n-1), n); + std::array shape{static_cast(n)}; + xt::xtensor w(shape); + w.fill(2.0); + xt::xtensor x = xt::square(i); + xt::xtensor y = xt::sin(2 * xt::numeric_constants::PI * i / 360.0); + xt::xtensor z = xt::log(i); - // 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["color"] = "grey"; - keywords["hatch"] = "-"; + // 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["color"] = "grey"; + keywords["hatch"] = "-"; - plt::fill_between(x, y, z, keywords); - plt::show(); + plt::fill_between(x, y, z, keywords); + plt::show(); } diff --git a/examples/minimal.cpp b/examples/minimal.cpp index fbe1e1c..e16cc60 100644 --- a/examples/minimal.cpp +++ b/examples/minimal.cpp @@ -2,6 +2,9 @@ namespace plt = matplotlibcpp; +#include +#include + int main() { plt::plot({1,3,2,4}); plt::show(); diff --git a/examples/modern.cpp b/examples/modern.cpp index a8aa0c7..7977707 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -5,6 +5,9 @@ using namespace std; namespace plt = matplotlibcpp; +#include +#include + int main() { // plot(y) - the x-coordinates are implicitly set to [0,1,...,n) @@ -12,12 +15,10 @@ int main() // Prepare data for parametric plot. int n = 5000; // number of data points - vector x(n),y(n); - for(int i=0; i i = xt::linspace(0, (n-1), n); + xt::xtensor t = 2 * xt::numeric_constants::PI * i / n; + xt::xtensor x = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); + xt::xtensor y = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); // plot() takes an arbitrary number of (x,y,format)-triples. // x must be iterable (that is, anything providing begin(x) and end(x)), diff --git a/examples/nonblock.cpp b/examples/nonblock.cpp index 327d96c..6260df5 100644 --- a/examples/nonblock.cpp +++ b/examples/nonblock.cpp @@ -4,6 +4,8 @@ namespace plt = matplotlibcpp; +#include +#include using namespace matplotlibcpp; using namespace std; @@ -12,12 +14,13 @@ int main() { // Prepare data. int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i i = xt::linspace(0, (n-1), n); + std::array shape{static_cast(n)}; + xt::xtensor w(shape); + w.fill(2.0); + xt::xtensor x = xt::square(i); + xt::xtensor y = xt::sin(2 * xt::numeric_constants::PI * i / 360.0); + xt::xtensor z = xt::log(i); // Plot line from given x and y data. Color is selected automatically. plt::subplot(2,2,1); diff --git a/examples/quiver.cpp b/examples/quiver.cpp index ea3c3ec..5bcd0e6 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -1,10 +1,14 @@ #include "../matplotlibcpp.h" +#include +#include + namespace plt = matplotlibcpp; int main() { // u and v are respectively the x and y components of the arrows we're plotting + std::array shape{121}; std::vector x, y, u, v; for (int i = -5; i <= 5; i++) { for (int j = -5; j <= 5; j++) { @@ -17,4 +21,4 @@ int main() plt::quiver(x, y, u, v); plt::show(); -} \ No newline at end of file +} diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 2797295..429f082 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -23,6 +23,10 @@ # define PyString_FromString PyUnicode_FromString #endif +#include +#include +#include +#include namespace matplotlibcpp { namespace detail { @@ -321,53 +325,53 @@ template <> struct select_npy_type { const static NPY_TYPES type = NPY 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) +template +PyObject* get_array(E&& v) { + assert(v.dimension() <= 2); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - NPY_TYPES type = select_npy_type::type; - if (type == NPY_NOTYPE) - { - std::vector vd(v.size()); + + if (v.dimension() == 1) { + NPY_TYPES type = select_npy_type::value_type>::type; + if (type == NPY_NOTYPE) + { + std::vector vd(v.size()); + npy_intp vsize = v.size(); + std::copy(v.begin(),v.end(),vd.begin()); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); + return varray; + } + npy_intp vsize = v.size(); - std::copy(v.begin(),v.end(),vd.begin()); - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); return varray; - } + } else { + if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); - npy_intp vsize = v.size(); - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); - return varray; -} + npy_intp vsize[2] = {static_cast(v.shape()[0]), + static_cast(v.shape()[1])}; -template -PyObject* get_2darray(const std::vector<::std::vector>& v) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); + PyArrayObject *varray = + (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - npy_intp vsize[2] = {static_cast(v.size()), - static_cast(v[0].size())}; + double *vd_begin = static_cast(PyArray_DATA(varray)); - PyArrayObject *varray = - (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - - double *vd_begin = static_cast(PyArray_DATA(varray)); + for (const std::size_t v_row_num : xt::arange(v.shape()[0])) { + auto v_row = xt::view(v, v_row_num); + 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 -template -PyObject* get_array(const std::vector& v) +template +PyObject* get_array(E&& v) { PyObject* list = PyList_New(v.size()); for(size_t i = 0; i < v.size(); ++i) { @@ -378,14 +382,14 @@ PyObject* get_array(const std::vector& v) #endif // WITHOUT_NUMPY -template -bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) +template +bool plot(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); // construct positional args PyObject* args = PyTuple_New(2); @@ -408,10 +412,8 @@ bool plot(const std::vector &x, const std::vector &y, const st return res; } -template -void plot_surface(const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, +template +void plot_surface(E1&& x, E2&& y, E3&& z, const std::map &keywords = std::map()) { @@ -440,9 +442,9 @@ void plot_surface(const std::vector<::std::vector> &x, assert(y.size() == z.size()); // using numpy arrays - PyObject *xarray = get_2darray(x); - PyObject *yarray = get_2darray(y); - PyObject *zarray = get_2darray(z); + PyObject *xarray = get_array(std::forward(x)); + PyObject *yarray = get_array(std::forward(y)); + PyObject *zarray = get_array(std::forward(z)); // construct positional args PyObject *args = PyTuple_New(3); @@ -500,14 +502,14 @@ void plot_surface(const std::vector<::std::vector> &x, if (res) Py_DECREF(res); } -template -bool stem(const std::vector &x, const std::vector &y, const std::map& keywords) +template +bool stem(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); // construct positional args PyObject* args = PyTuple_New(2); @@ -533,14 +535,14 @@ bool stem(const std::vector &x, const std::vector &y, const st return res; } -template< typename Numeric > -bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) +template +bool fill(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); // construct positional args PyObject* args = PyTuple_New(2); @@ -563,16 +565,16 @@ 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(E1&& x, E2&& y1, E3&& y2, const std::map& keywords) { assert(x.size() == y1.size()); assert(x.size() == y2.size()); // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* y1array = get_array(y1); - PyObject* y2array = get_array(y2); + PyObject* xarray = get_array(std::forward(x)); + PyObject* y1array = get_array(std::forward(y1)); + PyObject* y2array = get_array(std::forward(y2)); // construct positional args PyObject* args = PyTuple_New(3); @@ -595,12 +597,12 @@ bool fill_between(const std::vector& x, const std::vector& y1, return res; } -template< typename Numeric> -bool hist(const std::vector& y, long bins=10,std::string color="b", +template +bool hist(E&& y, long bins=10, std::string color="b", double alpha=1.0, bool cumulative=false) { - PyObject* yarray = get_array(y); + PyObject* yarray = get_array(std::forward(y)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); @@ -623,15 +625,14 @@ bool hist(const std::vector& y, long bins=10,std::string color="b", return res; } -template -bool scatter(const std::vector& x, - const std::vector& y, +template +bool scatter(E1&& x, E2&& y, const double s=1.0) // The marker size in points**2 { assert(x.size() == y.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); @@ -649,11 +650,11 @@ bool scatter(const std::vector& x, return res; } -template< typename Numeric> -bool bar(const std::vector& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, +template +bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map& keywords = {}) { - PyObject* yarray = get_array(y); + PyObject* yarray = get_array(std::forward(y)); std::vector x; for (int i = 0; i < y.size(); i++) @@ -702,10 +703,10 @@ inline bool subplots_adjust(const std::map& keywords = {}) 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, E&& y, long bins=10, std::string color="b", double alpha=1.0) { - PyObject* yarray = get_array(y); + PyObject* yarray = get_array(std::forward(y)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str())); @@ -726,13 +727,13 @@ bool named_hist(std::string label,const std::vector& y, long bins=10, s return res; } -template -bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") +template +bool plot(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -749,15 +750,15 @@ bool plot(const std::vector& x, const std::vector& y, const return res; } -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(E1&& x, E2&& y, E3&& u, E4&& w, const std::map& keywords = {}) { assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); - PyObject* uarray = get_array(u); - PyObject* warray = get_array(w); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); + PyObject* uarray = get_array(std::forward(u)); + PyObject* warray = get_array(std::forward(w)); PyObject* plot_args = PyTuple_New(4); PyTuple_SetItem(plot_args, 0, xarray); @@ -783,13 +784,13 @@ bool quiver(const std::vector& x, const std::vector& y, cons return res; } -template -bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") +template +bool stem(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -808,13 +809,13 @@ bool stem(const std::vector& x, const std::vector& y, const return res; } -template -bool semilogx(const std::vector& x, const std::vector& y, const std::string& s = "") +template +bool semilogx(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -831,13 +832,13 @@ bool semilogx(const std::vector& x, const std::vector& y, co return res; } -template -bool semilogy(const std::vector& x, const std::vector& y, const std::string& s = "") +template +bool semilogy(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -854,13 +855,13 @@ bool semilogy(const std::vector& x, const std::vector& y, co return res; } -template -bool loglog(const std::vector& x, const std::vector& y, const std::string& s = "") +template +bool loglog(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -877,14 +878,14 @@ bool loglog(const std::vector& x, const std::vector& y, cons return res; } -template -bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::map &keywords = {}) +template +bool errorbar(E1&& x, E2&& y, E3&& yerr, const std::map &keywords = {}) { assert(x.size() == y.size()); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); - PyObject* yerrarray = get_array(yerr); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); + PyObject* yerrarray = get_array(std::forward(yerr)); // construct keyword args PyObject* kwargs = PyDict_New(); @@ -912,13 +913,13 @@ 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, E&& y, const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* yarray = get_array(y); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -936,14 +937,14 @@ 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, E1&& x, E2&& y, const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -961,14 +962,14 @@ bool named_plot(const std::string& name, const std::vector& x, const st 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, E1&& x, E2&& y, const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -986,14 +987,14 @@ bool named_semilogx(const std::string& name, const std::vector& x, cons 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, E1&& x, E2& y, const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1011,14 +1012,14 @@ bool named_semilogy(const std::string& name, const std::vector& x, cons 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, E1&& x, E2&& y, const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1036,20 +1037,16 @@ 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(E&& y, const std::string& format = "") { - std::vector x(y.size()); - for(size_t i=0; i -bool stem(const std::vector& y, const std::string& format = "") +template +bool stem(E&& 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); + return stem(xt::arange(y.size()),y,format); } template @@ -1212,13 +1209,13 @@ inline double* ylim() return arr; } -template -inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +template +inline void xticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); // using numpy array - PyObject* ticksarray = get_array(ticks); + PyObject* ticksarray = get_array(std::forward(ticks)); PyObject* args; if(labels.size() == 0) { @@ -1253,19 +1250,19 @@ inline void xticks(const std::vector &ticks, const std::vector -inline void xticks(const std::vector &ticks, const std::map& keywords) +template +inline void xticks(E&& ticks, const std::map& keywords) { - xticks(ticks, {}, keywords); + xticks(std::forward(ticks), {}, keywords); } -template -inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +template +inline void yticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); // using numpy array - PyObject* ticksarray = get_array(ticks); + PyObject* ticksarray = get_array(std::forward(ticks)); PyObject* args; if(labels.size() == 0) { @@ -1300,10 +1297,10 @@ inline void yticks(const std::vector &ticks, const std::vector -inline void yticks(const std::vector &ticks, const std::map& keywords) +template +inline void yticks(E&& ticks, const std::map& keywords) { - yticks(ticks, {}, keywords); + yticks(std::forward(ticks), {}, keywords); } inline void subplot(long nrows, long ncols, long plot_number) @@ -1522,7 +1519,7 @@ inline void clf() { 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); @@ -1695,15 +1692,15 @@ bool plot(const A& a, const B& b, const std::string& format, Args... args) * 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); + return plot(xt::adapt(x),xt::adapt(y),format); } inline bool plot(const std::vector& y, const std::string& format = "") { - return plot(y,format); + return plot(xt::adapt(y),format); } inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(x,y,keywords); + return plot(xt::adapt(x),xt::adapt(y),keywords); } /* @@ -1714,8 +1711,8 @@ 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, E1&& x, E2&& y, const std::string& format = "") { assert(x.size() == y.size()); @@ -1723,8 +1720,8 @@ class Plot if(name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1753,15 +1750,15 @@ 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, xt::xtensor(), xt::xtensor(), format) {} - template - bool update(const std::vector& x, const std::vector& y) { + template + bool update(E1&& x, E2&& y) { assert(x.size() == y.size()); if(set_data_fct) { - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* plot_args = PyTuple_New(2); PyTuple_SetItem(plot_args, 0, xarray); @@ -1776,7 +1773,7 @@ class Plot // clears the plot but keep it available bool clear() { - return update(std::vector(), std::vector()); + return update(xt::xtensor(), xt::xtensor()); } // definitely remove this line From d98f8933d4df4b7006ca489e19a6101f7adc46b3 Mon Sep 17 00:00:00 2001 From: Kenneth Hanley Date: Sat, 27 Apr 2019 16:04:22 +0100 Subject: [PATCH 02/21] Updated more examples --- Makefile | 29 +++++++++++++++-------------- examples/animation.cpp | 6 +++--- examples/basic.cpp | 2 +- examples/fill.cpp | 15 ++++++++++----- examples/nonblock.cpp | 10 ++++------ examples/quiver.cpp | 12 +++++++----- examples/subplot.cpp | 16 ++++++++++------ examples/xkcd.cpp | 11 +++-------- matplotlibcpp.h | 28 ++++++++++++++++++---------- 9 files changed, 71 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index 1df85e6..71b4b72 100644 --- a/Makefile +++ b/Makefile @@ -1,40 +1,41 @@ -examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update +#examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update +examples: minimal basic animation nonblock xkcd quiver bar fill_inbetween 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 + cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python3.7m -lpython3.7m -o minimal -std=c++17 basic: examples/basic.cpp matplotlibcpp.h - cd examples && g++ basic.cpp -I/usr/include/python2.7 -lpython2.7 -o basic -std=c++11 + cd examples && g++ basic.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o basic -std=c++17 -modern: examples/modern.cpp matplotlibcpp.h - cd examples && g++ modern.cpp -I/usr/include/python2.7 -lpython2.7 -o modern -std=c++11 +#modern: examples/modern.cpp matplotlibcpp.h +# cd examples && g++ modern.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o modern -std=c++17 animation: examples/animation.cpp matplotlibcpp.h - cd examples && g++ animation.cpp -I/usr/include/python2.7 -lpython2.7 -o animation -std=c++11 + cd examples && g++ animation.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o animation -std=c++17 nonblock: examples/nonblock.cpp matplotlibcpp.h - cd examples && g++ nonblock.cpp -I/usr/include/python2.7 -lpython2.7 -o nonblock -std=c++11 + cd examples && g++ nonblock.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o nonblock -std=c++17 quiver: examples/quiver.cpp matplotlibcpp.h - cd examples && g++ quiver.cpp -I/usr/include/python2.7 -lpython2.7 -o quiver -std=c++11 + cd examples && g++ quiver.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o quiver -std=c++17 xkcd: examples/xkcd.cpp matplotlibcpp.h - cd examples && g++ xkcd.cpp -I/usr/include/python2.7 -lpython2.7 -o xkcd -std=c++11 + cd examples && g++ xkcd.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o xkcd -std=c++17 bar: examples/bar.cpp matplotlibcpp.h - cd examples && g++ bar.cpp -I/usr/include/python2.7 -lpython2.7 -o bar -std=c++11 + cd examples && g++ bar.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o bar -std=c++17 surface: examples/surface.cpp matplotlibcpp.h - cd examples && g++ surface.cpp -I/usr/include/python2.7 -lpython2.7 -o surface -std=c++11 + cd examples && g++ surface.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o surface -std=c++17 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 + cd examples && g++ fill_inbetween.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o fill_inbetween -std=c++17 fill: examples/fill.cpp matplotlibcpp.h - cd examples && g++ fill.cpp -I/usr/include/python2.7 -lpython2.7 -o fill -std=c++11 + cd examples && g++ fill.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o fill -std=c++17 update: examples/update.cpp matplotlibcpp.h - cd examples && g++ update.cpp -I/usr/include/python2.7 -lpython2.7 -o update -std=c++11 + cd examples && g++ update.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o update -std=c++17 clean: rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,quiver,bar,surface,fill_inbetween,fill,update} diff --git a/examples/animation.cpp b/examples/animation.cpp index f5a9b43..5ddb0cd 100644 --- a/examples/animation.cpp +++ b/examples/animation.cpp @@ -13,9 +13,9 @@ int main() xt::xtensor x, y, z; for(int i=0; i{i*i})); - x = xt::concatenate(xt::xtuple(x, xt::xtensor{sin(2*M_PI*i/360.0)})); - x = xt::concatenate(xt::xtuple(x, xt::xtensor{log(i)})); + x = xt::concatenate(xt::xtuple(x, xt::xtensor{static_cast(i*i)})); + y = xt::concatenate(xt::xtuple(y, xt::xtensor{sin(2*M_PI*i/360.0)})); + z = xt::concatenate(xt::xtuple(z, xt::xtensor{log(i)})); if (i % 10 == 0) { // Clear previous plot diff --git a/examples/basic.cpp b/examples/basic.cpp index 5e6b277..1fe2239 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -21,7 +21,7 @@ int main() xt::xtensor z = xt::log(i); // 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); diff --git a/examples/fill.cpp b/examples/fill.cpp index 5680e57..b2a72a8 100644 --- a/examples/fill.cpp +++ b/examples/fill.cpp @@ -18,14 +18,19 @@ int main() { const double b = 0.2; for (double dt = 0; dt < 2 * M_PI; dt += M_PI/2.0) { - vector x1, y1, x2, y2; + xt::xtensor x1 = xt::zeros_like(theta); + xt::xtensor y1 = xt::zeros_like(theta); + xt::xtensor x2 = xt::zeros_like(theta); + xt::xtensor y2 = xt::zeros_like(theta); + std::size_t idx = 0; for (double th : theta) { - x1.push_back( a*cos(th + dt) * exp(b*th) ); - y1.push_back( a*sin(th + dt) * exp(b*th) ); + x1[idx] = a*cos(th + dt) * exp(b*th); + y1[idx] = a*sin(th + dt) * exp(b*th); - x2.push_back( a*cos(th + dt + M_PI/4.0) * exp(b*th) ); - y2.push_back( a*sin(th + dt + M_PI/4.0) * exp(b*th) ); + x2[idx] = a*cos(th + dt + M_PI/4.0) * exp(b*th); + y2[idx] = a*sin(th + dt + M_PI/4.0) * exp(b*th); } + //xt::xtensor x1 = a*xt::cos(theta + dt) * xt::exp(b*theta); x1.insert(x1.end(), x2.rbegin(), x2.rend()); y1.insert(y1.end(), y2.rbegin(), y2.rend()); diff --git a/examples/nonblock.cpp b/examples/nonblock.cpp index 6260df5..1e38aba 100644 --- a/examples/nonblock.cpp +++ b/examples/nonblock.cpp @@ -1,14 +1,12 @@ #define _USE_MATH_DEFINES +#include #include #include "../matplotlibcpp.h" -namespace plt = matplotlibcpp; - #include #include -using namespace matplotlibcpp; -using namespace std; +namespace plt = matplotlibcpp; int main() { @@ -44,6 +42,6 @@ int main() plt::show(false); - cout << "matplotlibcpp::show() is working in an non-blocking mode" << endl; - getchar(); + std::cout << "matplotlibcpp::show() is working in an non-blocking mode" << std::endl; + std::getchar(); } diff --git a/examples/quiver.cpp b/examples/quiver.cpp index 5bcd0e6..7870946 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -9,13 +9,15 @@ int main() { // u and v are respectively the x and y components of the arrows we're plotting std::array shape{121}; - std::vector x, y, u, v; + xt::xtensor x(shape), y(shape), u(shape), v(shape); + std::size_t idx = 0; 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); + x[idx] = (i); + u[idx] = (-i); + y[idx] = (j); + v[idx] = (-j); + ++idx; } } diff --git a/examples/subplot.cpp b/examples/subplot.cpp index bee322e..76928bc 100644 --- a/examples/subplot.cpp +++ b/examples/subplot.cpp @@ -2,6 +2,9 @@ #include #include "../matplotlibcpp.h" +#include +#include + using namespace std; namespace plt = matplotlibcpp; @@ -9,12 +12,13 @@ int main() { // Prepare data int n = 500; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i i = xt::linspace(0, (n-1), n); + std::array shape{static_cast(n)}; + xt::xtensor w(shape); + w.fill(2.0); + xt::xtensor x = xt::square(i); + xt::xtensor y = xt::sin(2 * xt::numeric_constants::PI * i / 360.0); + xt::xtensor z = xt::log(i); // Set the "super title" plt::suptitle("My plot"); diff --git a/examples/xkcd.cpp b/examples/xkcd.cpp index fa41cfc..9526b7e 100644 --- a/examples/xkcd.cpp +++ b/examples/xkcd.cpp @@ -6,16 +6,11 @@ namespace plt = matplotlibcpp; int main() { - std::vector t(1000); - std::vector x(t.size()); - - for(size_t i = 0; i < t.size(); i++) { - t[i] = i / 100.0; - x[i] = sin(2.0 * M_PI * 1.0 * t[i]); - } + xt::xtensor t = xt::linspace(0, 10, 1000); + xt::xtensor y = xt::sin(2.0 * xt::numeric_constants::PI * t); plt::xkcd(); - plt::plot(t, x); + plt::plot(t, y); plt::title("AN ORDINARY SIN WAVE"); plt::show(); } diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 429f082..f81f5ff 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -656,9 +656,7 @@ bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, { PyObject* yarray = get_array(std::forward(y)); - std::vector x; - for (int i = 0; i < y.size(); i++) - x.push_back(i); + xt::xtensor x = xt::arange(y.size()); PyObject* xarray = get_array(x); @@ -1040,7 +1038,8 @@ bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& fo template bool plot(E&& y, const std::string& format = "") { - return plot(xt::arange(y.size()),y,format); + xt::xtensor x = xt::arange(y.size()); + return plot(x, y, format); } template @@ -1113,6 +1112,8 @@ inline bool fignum_exists(long number) inline void figure_size(size_t w, size_t h) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + const size_t dpi = 100; PyObject* size = PyTuple_New(2); PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); @@ -1305,6 +1306,8 @@ inline void yticks(E&& ticks, const std::map& keywords inline void subplot(long nrows, long ncols, long plot_number) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + // construct positional args PyObject* args = PyTuple_New(3); PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); @@ -1691,16 +1694,21 @@ bool plot(const A& a, const B& b, const std::string& format, Args... 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(xt::adapt(x),xt::adapt(y),format); +inline bool plot(std::vector x, std::vector y, const std::string& format = "") { + xt::xtensor x_adapt = xt::adapt(x); + xt::xtensor y_adapt = xt::adapt(y); + return plot(std::move(x_adapt), std::move(y_adapt), format); } -inline bool plot(const std::vector& y, const std::string& format = "") { - return plot(xt::adapt(y),format); +inline bool plot(std::vector y, const std::string& format = "") { + xt::xtensor y_adapt = xt::adapt(y); + return plot(std::move(y_adapt), format); } -inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(xt::adapt(x),xt::adapt(y),keywords); +inline bool plot(std::vector x, std::vector y, const std::map& keywords) { + xt::xtensor x_adapt = xt::adapt(x); + xt::xtensor y_adapt = xt::adapt(y); + return plot(std::move(x_adapt), std::move(y_adapt), keywords); } /* From 65599467e4575f60e6831ceb5cfba5f33e1f1f0c Mon Sep 17 00:00:00 2001 From: Kenneth Hanley Date: Sat, 27 Apr 2019 16:04:37 +0100 Subject: [PATCH 03/21] Added compile_commands --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index b0a5e1d..f0df7de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ .ycm_extra_conf.py +.ccls-cache/ +compile_commands.json + # Compiled Object files *.slo From ab0bfb199c3d69effa390c5408d156897f52c6bb Mon Sep 17 00:00:00 2001 From: Kenneth Hanley Date: Tue, 30 Apr 2019 10:19:31 +0100 Subject: [PATCH 04/21] Fixed update and fill. Modern needs more work and I need to put some time into working with rvalues --- Makefile | 7 ++-- examples/fill.cpp | 27 ++++-------- examples/modern.cpp | 14 ++++++- examples/update.cpp | 18 ++++---- matplotlibcpp.h | 100 ++++++++++++++++++++++++++++++++++++++------ 5 files changed, 123 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index 71b4b72..0351219 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ #examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update -examples: minimal basic animation nonblock xkcd quiver bar fill_inbetween +examples: minimal basic animation nonblock xkcd quiver bar surface fill_inbetween fill update minimal: examples/minimal.cpp matplotlibcpp.h cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python3.7m -lpython3.7m -o minimal -std=c++17 basic: examples/basic.cpp matplotlibcpp.h +#all: examples/basic.cpp matplotlibcpp.h cd examples && g++ basic.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o basic -std=c++17 -#modern: examples/modern.cpp matplotlibcpp.h -# cd examples && g++ modern.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o modern -std=c++17 +modern: examples/modern.cpp matplotlibcpp.h + cd examples && g++ modern.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o modern -std=c++17 animation: examples/animation.cpp matplotlibcpp.h cd examples && g++ animation.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o animation -std=c++17 diff --git a/examples/fill.cpp b/examples/fill.cpp index b2a72a8..daebcff 100644 --- a/examples/fill.cpp +++ b/examples/fill.cpp @@ -2,12 +2,12 @@ #include "../matplotlibcpp.h" #include -using namespace std; -namespace plt = matplotlibcpp; - #include #include +using namespace xt::placeholders; +namespace plt = matplotlibcpp; + // Example fill plot taken from: // https://matplotlib.org/gallery/misc/fill_spiral.html int main() { @@ -18,22 +18,13 @@ int main() { const double b = 0.2; for (double dt = 0; dt < 2 * M_PI; dt += M_PI/2.0) { - xt::xtensor x1 = xt::zeros_like(theta); - xt::xtensor y1 = xt::zeros_like(theta); - xt::xtensor x2 = xt::zeros_like(theta); - xt::xtensor y2 = xt::zeros_like(theta); - std::size_t idx = 0; - for (double th : theta) { - x1[idx] = a*cos(th + dt) * exp(b*th); - y1[idx] = a*sin(th + dt) * exp(b*th); - - x2[idx] = a*cos(th + dt + M_PI/4.0) * exp(b*th); - y2[idx] = a*sin(th + dt + M_PI/4.0) * exp(b*th); - } - //xt::xtensor x1 = a*xt::cos(theta + dt) * xt::exp(b*theta); + xt::xtensor x1 = a*xt::cos(theta + dt) * xt::exp(b*theta); + xt::xtensor y1 = a*xt::sin(theta + dt) * xt::exp(b*theta); + xt::xtensor x2 = a*xt::cos(theta + dt + M_PI/4.0) * xt::exp(b*theta); + xt::xtensor y2 = a*xt::sin(theta + dt + M_PI/4.0) * xt::exp(b*theta); - x1.insert(x1.end(), x2.rbegin(), x2.rend()); - y1.insert(y1.end(), y2.rbegin(), y2.rend()); + x1 = xt::concatenate(xt::xtuple(x1, xt::view(x2, xt::range(x2.size(), _, -1)))); + y1 = xt::concatenate(xt::xtuple(y1, xt::view(y2, xt::range(y2.size(), _, -1)))); plt::fill(x1, y1, {}); } diff --git a/examples/modern.cpp b/examples/modern.cpp index 7977707..1d5a608 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -20,10 +20,22 @@ int main() xt::xtensor x = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); xt::xtensor y = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); + + + xt::xtensor x2 = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); + xt::xtensor x3 = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); + xt::xtensor y2 = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); + xt::xtensor y3 = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); + // plot() takes an arbitrary number of (x,y,format)-triples. // x must be iterable (that is, anything providing begin(x) and end(x)), // y must either be callable (providing operator() const) or iterable. - plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); + //plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); + //plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-", x, y+1.0, "r-."); + //plt::plot(x, y, "r-", x2, xt::eval(y2+0.5), "b-.", xt::eval(x3+1.0), xt::eval(y3+1.0), "g."); + plt::plot(x, y+1.0, "r-"); + //plt::plot(x, y, "r-"); + //plt::plot(x, y, "r-", x, y2, "b.."); // show plots diff --git a/examples/update.cpp b/examples/update.cpp index 64f4906..113a526 100644 --- a/examples/update.cpp +++ b/examples/update.cpp @@ -3,10 +3,14 @@ #include "../matplotlibcpp.h" #include +#include +#include + namespace plt = matplotlibcpp; +template void update_window(const double x, const double y, const double t, - std::vector &xt, std::vector &yt) + E1& xt, E2& yt) { const double target_length = 300; const double half_win = (target_length/(2.*sqrt(1.+t*t))); @@ -21,20 +25,18 @@ void update_window(const double x, const double y, const double t, int main() { size_t n = 1000; - std::vector x, y; const double w = 0.05; const double a = n/2; - for (size_t i=0; i x = xt::linspace(0, n-1, n); + xt::xtensor y = a * xt::sin(w * x); - std::vector xt(2), yt(2); + xt::xtensor xt{0,0}; + xt::xtensor yt{0,0}; plt::title("Tangent of a sine curve"); - plt::xlim(x.front(), x.back()); + plt::xlim(*(x.begin()), *(x.end()-1)); plt::ylim(-a, a); plt::axis("equal"); diff --git a/matplotlibcpp.h b/matplotlibcpp.h index f81f5ff..e269935 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -288,6 +289,8 @@ inline void backend(const std::string& name) inline bool annotate(std::string annotation, double x, double y) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject * xy = PyTuple_New(2); PyObject * str = PyString_FromString(annotation.c_str()); @@ -329,7 +332,6 @@ template PyObject* get_array(E&& v) { assert(v.dimension() <= 2); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work if (v.dimension() == 1) { NPY_TYPES type = select_npy_type::value_type>::type; @@ -342,6 +344,9 @@ PyObject* get_array(E&& v) return varray; } + //auto ev = xt::make_xshared(std::move(xt::eval(v))); + //npy_intp vsize = ev.size(); + //PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(ev.data())); npy_intp vsize = v.size(); PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); return varray; @@ -386,10 +391,15 @@ template bool plot(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + //PyObject* xarray = get_array(std::forward(x)); + //PyObject* yarray = get_array(std::forward(y)); + xt::common_tensor_type_t ex = x; + xt::common_tensor_type_t ey = y; + PyObject* xarray = get_array(xt::detail::shared_forward(ex)); + PyObject* yarray = get_array(xt::detail::shared_forward(ey)); // construct positional args PyObject* args = PyTuple_New(2); @@ -421,10 +431,10 @@ void plot_surface(E1&& x, E2&& y, E3&& z, // 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. + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + 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"); } @@ -506,6 +516,7 @@ template bool stem(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays PyObject* xarray = get_array(std::forward(x)); @@ -539,6 +550,7 @@ template bool fill(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays PyObject* xarray = get_array(std::forward(x)); @@ -570,6 +582,7 @@ bool fill_between(E1&& x, E2&& y1, E3&& y2, const std::map(x)); @@ -601,6 +614,7 @@ template bool hist(E&& y, long bins=10, std::string color="b", double alpha=1.0, bool cumulative=false) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* yarray = get_array(std::forward(y)); @@ -630,6 +644,7 @@ bool scatter(E1&& x, E2&& y, const double s=1.0) // The marker size in points**2 { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -654,6 +669,8 @@ template bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map& keywords = {}) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* yarray = get_array(std::forward(y)); xt::xtensor x = xt::arange(y.size()); @@ -681,6 +698,7 @@ bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, inline bool subplots_adjust(const std::map& keywords = {}) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); for (std::map::const_iterator it = @@ -704,6 +722,8 @@ inline bool subplots_adjust(const std::map& keywords = {}) template bool named_hist(std::string label, E&& y, long bins=10, std::string color="b", double alpha=1.0) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* yarray = get_array(std::forward(y)); PyObject* kwargs = PyDict_New(); @@ -729,6 +749,7 @@ template bool plot(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -752,6 +773,7 @@ template bool quiver(E1&& x, E2&& y, E3&& u, E4&& w, const std::map& keywords = {}) { assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -786,6 +808,7 @@ template bool stem(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -811,6 +834,7 @@ template bool semilogx(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -834,6 +858,7 @@ template bool semilogy(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -857,6 +882,7 @@ template bool loglog(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -880,6 +906,7 @@ template bool errorbar(E1&& x, E2&& y, E3&& yerr, const std::map &keywords = {}) { assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -914,6 +941,8 @@ bool errorbar(E1&& x, E2&& y, E3&& yerr, const std::map bool named_plot(const std::string& name, E&& y, const std::string& format = "") { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -938,6 +967,8 @@ bool named_plot(const std::string& name, E&& y, const std::string& format = "") template bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -963,6 +994,8 @@ bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& form template bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -988,6 +1021,8 @@ bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& template bool named_semilogy(const std::string& name, E1&& x, E2& y, const std::string& format = "") { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1013,6 +1048,8 @@ bool named_semilogy(const std::string& name, E1&& x, E2& y, const std::string& f template bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1051,6 +1088,8 @@ bool stem(E&& y, const std::string& format = "") template void text(Numeric x, Numeric y, const std::string& s = "") { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* args = PyTuple_New(3); PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); @@ -1143,6 +1182,8 @@ inline void legend() template void ylim(Numeric left, Numeric right) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* list = PyList_New(2); PyList_SetItem(list, 0, PyFloat_FromDouble(left)); PyList_SetItem(list, 1, PyFloat_FromDouble(right)); @@ -1160,6 +1201,8 @@ void ylim(Numeric left, Numeric right) template void xlim(Numeric left, Numeric right) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* list = PyList_New(2); PyList_SetItem(list, 0, PyFloat_FromDouble(left)); PyList_SetItem(list, 1, PyFloat_FromDouble(right)); @@ -1177,6 +1220,8 @@ void xlim(Numeric left, Numeric right) inline double* xlim() { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); PyObject* left = PyTuple_GetItem(res,0); @@ -1195,6 +1240,8 @@ inline double* xlim() inline double* ylim() { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); PyObject* left = PyTuple_GetItem(res,0); @@ -1214,6 +1261,7 @@ template inline void xticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy array PyObject* ticksarray = get_array(std::forward(ticks)); @@ -1261,6 +1309,7 @@ template inline void yticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy array PyObject* ticksarray = get_array(std::forward(ticks)); @@ -1323,6 +1372,8 @@ inline void subplot(long nrows, long ncols, long plot_number) inline void title(const std::string &titlestr, const std::map &keywords = {}) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pytitlestr); @@ -1342,6 +1393,8 @@ inline void title(const std::string &titlestr, const std::map &keywords = {}) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pysuptitlestr); @@ -1361,6 +1414,8 @@ inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); @@ -1393,6 +1450,8 @@ inline void xlabel(const std::string &str, const std::map& keywords = {}) { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); @@ -1412,6 +1471,8 @@ inline void ylabel(const std::string &str, const std::map struct plot_impl { template - bool operator()(const IterableX& x, const IterableY& y, const std::string& format) + bool operator()(IterableX&& x, IterableY&& y, const std::string& format) { // 2-phase lookup for distance, begin, end using std::distance; @@ -1638,6 +1701,8 @@ struct plot_impl auto ys = distance(begin(y), end(y)); assert(xs == ys && "x and y data must have the same number of elements!"); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* xlist = PyList_New(xs); PyObject* ylist = PyList_New(ys); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1666,15 +1731,20 @@ template<> struct plot_impl { template - bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) + bool operator()(Iterable&& ticks, 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); + std::size_t size = std::distance(begin(ticks), end(ticks)); + std::array shape{size}; + xt::xtensor y(shape); + //for(auto x : ticks) y.push_back(f(x)); + std::size_t idx = 0; + for(auto x : ticks) y[idx++] = f(x); + //for (auto i = 0ul; i < size; ++i) y[i] = f(ticks[i]); + return plot_impl()(std::forward(ticks), std::move(y), format); } }; @@ -1684,10 +1754,14 @@ struct plot_impl template bool plot() { return true; } -template -bool plot(const A& a, const B& b, const std::string& format, Args... args) +template +bool plot(E1&& a, E2&& b, const std::string& format, Args... args) { - return detail::plot_impl::type>()(a,b,format) && plot(args...); + //return detail::plot_impl>::type>()( + //std::forward(a), std::forward(b), format + //) && plot(args...); + //return plot(std::forward(a), std::forward(b), format) && plot(args...); + return plot(std::forward(a), std::forward(b), format) && plot(std::forward(args)...); } /* From 084a32ca4aeb38ae4970097df1110f928e3d099a Mon Sep 17 00:00:00 2001 From: khanley6 Date: Tue, 30 Apr 2019 17:14:01 +0100 Subject: [PATCH 05/21] Added cmake support --- .gitignore | 2 + CMakeLists.txt | 18 ++ Makefile | 42 ---- cmake/FindNumpy.cmake | 89 +++++++++ cmake/FindPythonLibs.cmake | 399 +++++++++++++++++++++++++++++++++++++ cmake/xtensorConfig.cmake | 56 ++++++ examples/CMakeLists.txt | 15 ++ examples/animation.gif | Bin 33288 -> 0 bytes examples/bar.png | Bin 11952 -> 0 bytes examples/basic.png | Bin 37402 -> 0 bytes examples/fill.png | Bin 62995 -> 0 bytes examples/fill_between.png | Bin 24970 -> 0 bytes examples/minimal.png | Bin 20174 -> 0 bytes examples/modern.png | Bin 30389 -> 0 bytes examples/quiver.png | Bin 39752 -> 0 bytes examples/surface.png | Bin 106199 -> 0 bytes examples/xkcd.png | Bin 79452 -> 0 bytes 17 files changed, 579 insertions(+), 42 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 Makefile create mode 100644 cmake/FindNumpy.cmake create mode 100644 cmake/FindPythonLibs.cmake create mode 100644 cmake/xtensorConfig.cmake create mode 100644 examples/CMakeLists.txt delete mode 100644 examples/animation.gif delete mode 100644 examples/bar.png delete mode 100644 examples/basic.png delete mode 100644 examples/fill.png delete mode 100644 examples/fill_between.png delete mode 100644 examples/minimal.png delete mode 100644 examples/modern.png delete mode 100644 examples/quiver.png delete mode 100644 examples/surface.png delete mode 100644 examples/xkcd.png diff --git a/.gitignore b/.gitignore index f0df7de..561c987 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +build + .ycm_extra_conf.py .ccls-cache/ compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..09b6f75 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +## +## PROJECT +## name and version +## +project(matplotlibcpp_xt VERSION 0.1.0 LANGUAGES CXX) + +find_package(PythonLibs REQUIRED) +find_package(xtensor REQUIRED) + +## +## TARGET +## create target and add include path +## +add_library(matplotlibcpp INTERFACE) + +add_subdirectory(examples) diff --git a/Makefile b/Makefile deleted file mode 100644 index 0351219..0000000 --- a/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -#examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update -examples: minimal basic animation nonblock xkcd quiver bar surface fill_inbetween fill update - -minimal: examples/minimal.cpp matplotlibcpp.h - cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python3.7m -lpython3.7m -o minimal -std=c++17 - -basic: examples/basic.cpp matplotlibcpp.h -#all: examples/basic.cpp matplotlibcpp.h - cd examples && g++ basic.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o basic -std=c++17 - -modern: examples/modern.cpp matplotlibcpp.h - cd examples && g++ modern.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o modern -std=c++17 - -animation: examples/animation.cpp matplotlibcpp.h - cd examples && g++ animation.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o animation -std=c++17 - -nonblock: examples/nonblock.cpp matplotlibcpp.h - cd examples && g++ nonblock.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o nonblock -std=c++17 - -quiver: examples/quiver.cpp matplotlibcpp.h - cd examples && g++ quiver.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o quiver -std=c++17 - -xkcd: examples/xkcd.cpp matplotlibcpp.h - cd examples && g++ xkcd.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o xkcd -std=c++17 - -bar: examples/bar.cpp matplotlibcpp.h - cd examples && g++ bar.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o bar -std=c++17 - -surface: examples/surface.cpp matplotlibcpp.h - cd examples && g++ surface.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o surface -std=c++17 - -fill_inbetween: examples/fill_inbetween.cpp matplotlibcpp.h - cd examples && g++ fill_inbetween.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o fill_inbetween -std=c++17 - -fill: examples/fill.cpp matplotlibcpp.h - cd examples && g++ fill.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o fill -std=c++17 - -update: examples/update.cpp matplotlibcpp.h - cd examples && g++ update.cpp -I/usr/include/python3.7m -I/usr/lib/python3.7/site-packages/numpy/core/include -lpython3.7m -o update -std=c++17 - -clean: - rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,quiver,bar,surface,fill_inbetween,fill,update} diff --git a/cmake/FindNumpy.cmake b/cmake/FindNumpy.cmake new file mode 100644 index 0000000..48a1046 --- /dev/null +++ b/cmake/FindNumpy.cmake @@ -0,0 +1,89 @@ +# - Find the NumPy libraries +# This module finds if NumPy is installed, and sets the following variables +# indicating where it is. +# +# TODO: Update to provide the libraries and paths for linking npymath lib. +# +# NUMPY_FOUND - was NumPy found +# NUMPY_VERSION - the version of NumPy found as a string +# NUMPY_VERSION_MAJOR - the major version number of NumPy +# NUMPY_VERSION_MINOR - the minor version number of NumPy +# NUMPY_VERSION_PATCH - the patch version number of NumPy +# NUMPY_VERSION_DECIMAL - e.g. version 1.6.1 is 10601 +# NUMPY_INCLUDE_DIRS - path to the NumPy include files + +#============================================================================ +# Copyright 2012 Continuum Analytics, Inc. +# +# MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#============================================================================ + +# Finding NumPy involves calling the Python interpreter +if(NumPy_FIND_REQUIRED) + find_package(PythonInterp REQUIRED) +else() + find_package(PythonInterp) +endif() + +if(NOT PYTHONINTERP_FOUND) + set(NUMPY_FOUND FALSE) +endif() + +execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" + "import numpy as n; print(n.__version__); print(n.get_include());" + RESULT_VARIABLE _NUMPY_SEARCH_SUCCESS + OUTPUT_VARIABLE _NUMPY_VALUES + ERROR_VARIABLE _NUMPY_ERROR_VALUE + OUTPUT_STRIP_TRAILING_WHITESPACE) + +if(NOT _NUMPY_SEARCH_SUCCESS MATCHES 0) + if(NumPy_FIND_REQUIRED) + message(FATAL_ERROR + "NumPy import failure:\n${_NUMPY_ERROR_VALUE}") + endif() + set(NUMPY_FOUND FALSE) +endif() + +# Convert the process output into a list +string(REGEX REPLACE ";" "\\\\;" _NUMPY_VALUES ${_NUMPY_VALUES}) +string(REGEX REPLACE "\n" ";" _NUMPY_VALUES ${_NUMPY_VALUES}) +list(GET _NUMPY_VALUES 0 NUMPY_VERSION) +list(GET _NUMPY_VALUES 1 NUMPY_INCLUDE_DIRS) + +# Make sure all directory separators are '/' +string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIRS ${NUMPY_INCLUDE_DIRS}) + +# Get the major and minor version numbers +string(REGEX REPLACE "\\." ";" _NUMPY_VERSION_LIST ${NUMPY_VERSION}) +list(GET _NUMPY_VERSION_LIST 0 NUMPY_VERSION_MAJOR) +list(GET _NUMPY_VERSION_LIST 1 NUMPY_VERSION_MINOR) +list(GET _NUMPY_VERSION_LIST 2 NUMPY_VERSION_PATCH) +string(REGEX MATCH "[0-9]*" NUMPY_VERSION_PATCH ${NUMPY_VERSION_PATCH}) +math(EXPR NUMPY_VERSION_DECIMAL + "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}") + +find_package_message(NUMPY + "Found NumPy: version \"${NUMPY_VERSION}\" ${NUMPY_INCLUDE_DIRS}" + "${NUMPY_INCLUDE_DIRS}${NUMPY_VERSION}") + +set(NUMPY_FOUND TRUE) diff --git a/cmake/FindPythonLibs.cmake b/cmake/FindPythonLibs.cmake new file mode 100644 index 0000000..1d62ac4 --- /dev/null +++ b/cmake/FindPythonLibs.cmake @@ -0,0 +1,399 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPythonLibs +-------------- + +.. deprecated:: 3.12 + + Use :module:`FindPython3`, :module:`FindPython2` or :module:`FindPython` instead. + +Find python libraries + +This module finds if Python is installed and determines where the +include files and libraries are. It also determines what the name of +the library is. This code sets the following variables: + +:: + + PYTHONLIBS_FOUND - have the Python libs been found + PYTHON_LIBRARIES - path to the python library + PYTHON_INCLUDE_PATH - path to where Python.h is found (deprecated) + PYTHON_INCLUDE_DIRS - path to where Python.h is found + PYTHON_DEBUG_LIBRARIES - path to the debug library (deprecated) + PYTHONLIBS_VERSION_STRING - version of the Python libs found (since CMake 2.8.8) + + + +The Python_ADDITIONAL_VERSIONS variable can be used to specify a list +of version numbers that should be taken into account when searching +for Python. You need to set this variable before calling +find_package(PythonLibs). + +If you'd like to specify the installation of Python to use, you should +modify the following cache variables: + +:: + + PYTHON_LIBRARY - path to the python library + PYTHON_INCLUDE_DIR - path to where Python.h is found + +If calling both ``find_package(PythonInterp)`` and +``find_package(PythonLibs)``, call ``find_package(PythonInterp)`` first to +get the currently active Python version by default with a consistent version +of PYTHON_LIBRARIES. +#]=======================================================================] + +# Use the executable's path as a hint +set(_Python_LIBRARY_PATH_HINT) +if(IS_ABSOLUTE "${PYTHON_EXECUTABLE}") + if(WIN32) + get_filename_component(_Python_PREFIX "${PYTHON_EXECUTABLE}" PATH) + if(_Python_PREFIX) + set(_Python_LIBRARY_PATH_HINT ${_Python_PREFIX}/libs) + endif() + unset(_Python_PREFIX) + else() + get_filename_component(_Python_PREFIX "${PYTHON_EXECUTABLE}" PATH) + get_filename_component(_Python_PREFIX "${_Python_PREFIX}" PATH) + if(_Python_PREFIX) + set(_Python_LIBRARY_PATH_HINT ${_Python_PREFIX}/lib) + endif() + unset(_Python_PREFIX) + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/CMakeFindFrameworks.cmake) +# Search for the python framework on Apple. +CMAKE_FIND_FRAMEWORKS(Python) + +# Save CMAKE_FIND_FRAMEWORK +if(DEFINED CMAKE_FIND_FRAMEWORK) + set(_PythonLibs_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) +else() + unset(_PythonLibs_CMAKE_FIND_FRAMEWORK) +endif() +# To avoid picking up the system Python.h pre-maturely. +set(CMAKE_FIND_FRAMEWORK LAST) + +set(_PYTHON1_VERSIONS 1.6 1.5) +set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) +set(_PYTHON3_VERSIONS 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0) + +if(PythonLibs_FIND_VERSION) + if(PythonLibs_FIND_VERSION_COUNT GREATER 1) + set(_PYTHON_FIND_MAJ_MIN "${PythonLibs_FIND_VERSION_MAJOR}.${PythonLibs_FIND_VERSION_MINOR}") + unset(_PYTHON_FIND_OTHER_VERSIONS) + if(PythonLibs_FIND_VERSION_EXACT) + if(_PYTHON_FIND_MAJ_MIN STREQUAL PythonLibs_FIND_VERSION) + set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}") + else() + set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}" "${_PYTHON_FIND_MAJ_MIN}") + endif() + else() + foreach(_PYTHON_V ${_PYTHON${PythonLibs_FIND_VERSION_MAJOR}_VERSIONS}) + if(NOT _PYTHON_V VERSION_LESS _PYTHON_FIND_MAJ_MIN) + list(APPEND _PYTHON_FIND_OTHER_VERSIONS ${_PYTHON_V}) + endif() + endforeach() + endif() + unset(_PYTHON_FIND_MAJ_MIN) + else() + set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON${PythonLibs_FIND_VERSION_MAJOR}_VERSIONS}) + endif() +else() + set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS} ${_PYTHON2_VERSIONS} ${_PYTHON1_VERSIONS}) +endif() + +# Set up the versions we know about, in the order we will search. Always add +# the user supplied additional versions to the front. +# If FindPythonInterp has already found the major and minor version, +# insert that version between the user supplied versions and the stock +# version list. +set(_Python_VERSIONS ${Python_ADDITIONAL_VERSIONS}) +if(DEFINED PYTHON_VERSION_MAJOR AND DEFINED PYTHON_VERSION_MINOR) + list(APPEND _Python_VERSIONS ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}) +endif() +list(APPEND _Python_VERSIONS ${_PYTHON_FIND_OTHER_VERSIONS}) + +unset(_PYTHON_FIND_OTHER_VERSIONS) +unset(_PYTHON1_VERSIONS) +unset(_PYTHON2_VERSIONS) +unset(_PYTHON3_VERSIONS) + +# Python distribution: define which architectures can be used +if (CMAKE_SIZEOF_VOID_P) + # In this case, search only for 64bit or 32bit + math (EXPR _PYTHON_ARCH "${CMAKE_SIZEOF_VOID_P} * 8") + set (_PYTHON_ARCH2 _PYTHON_PREFIX_ARCH}) +else() + if (PYTHON_EXECUTABLE) + # determine interpreter architecture + execute_process (COMMAND "${PYTHON_EXECUTABLE}" -c "import sys; print(sys.maxsize > 2**32)" + RESULT_VARIABLE _PYTHON_RESULT + OUTPUT_VARIABLE _PYTHON_IS64BIT + ERROR_VARIABLE _PYTHON_IS64BIT) + if (NOT _PYTHON_RESULT) + if (_PYTHON_IS64BIT) + set (_PYTHON_ARCH 64) + set (_PYTHON_ARCH2 64) + else() + set (_PYTHON_ARCH 32) + set (_PYTHON_ARCH2 32) + endif() + endif() + else() + # architecture unknown, search for both 64bit and 32bit + set (_PYTHON_ARCH 64) + set (_PYTHON_ARCH2 32) + endif() +endif() + +foreach(_CURRENT_VERSION ${_Python_VERSIONS}) + string(REPLACE "." "" _CURRENT_VERSION_NO_DOTS ${_CURRENT_VERSION}) + if(WIN32) + find_library(PYTHON_DEBUG_LIBRARY + NAMES python${_CURRENT_VERSION_NO_DOTS}_d python + NAMES_PER_DIR + HINTS ${_Python_LIBRARY_PATH_HINT} + PATHS + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs/Debug + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs/Debug + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs/Debug + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs/Debug + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs + ) + endif() + + set(PYTHON_FRAMEWORK_LIBRARIES) + if(Python_FRAMEWORKS AND NOT PYTHON_LIBRARY) + foreach(dir ${Python_FRAMEWORKS}) + list(APPEND PYTHON_FRAMEWORK_LIBRARIES + ${dir}/Versions/${_CURRENT_VERSION}/lib) + endforeach() + endif() + find_library(PYTHON_LIBRARY + NAMES + python${_CURRENT_VERSION_NO_DOTS} + python${_CURRENT_VERSION}mu + python${_CURRENT_VERSION}m + python${_CURRENT_VERSION}u + python${_CURRENT_VERSION} + NAMES_PER_DIR + HINTS + ${_Python_LIBRARY_PATH_HINT} + PATHS + ${PYTHON_FRAMEWORK_LIBRARIES} + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs + ) + # Look for the static library in the Python config directory + find_library(PYTHON_LIBRARY + NAMES python${_CURRENT_VERSION_NO_DOTS} python${_CURRENT_VERSION} + NAMES_PER_DIR + # This is where the static library is usually located + PATH_SUFFIXES python${_CURRENT_VERSION}/config + ) + + # Don't search for include dir until library location is known + if(PYTHON_LIBRARY) + + # Use the library's install prefix as a hint + set(_Python_INCLUDE_PATH_HINT) + # PYTHON_LIBRARY may contain a list because of SelectLibraryConfigurations + # which may have been run previously. If it is the case, the list can be: + # optimized;;debug; + foreach(lib ${PYTHON_LIBRARY} ${PYTHON_DEBUG_LIBRARY}) + if(IS_ABSOLUTE "${lib}") + get_filename_component(_Python_PREFIX "${lib}" PATH) + get_filename_component(_Python_PREFIX "${_Python_PREFIX}" PATH) + if(_Python_PREFIX) + list(APPEND _Python_INCLUDE_PATH_HINT ${_Python_PREFIX}/include) + endif() + unset(_Python_PREFIX) + endif() + endforeach() + + # Add framework directories to the search paths + set(PYTHON_FRAMEWORK_INCLUDES) + if(Python_FRAMEWORKS AND NOT PYTHON_INCLUDE_DIR) + foreach(dir ${Python_FRAMEWORKS}) + list(APPEND PYTHON_FRAMEWORK_INCLUDES + ${dir}/Versions/${_CURRENT_VERSION}/include) + endforeach() + endif() + + find_path(PYTHON_INCLUDE_DIR + NAMES Python.h + HINTS + ${_Python_INCLUDE_PATH_HINT} + PATHS + ${PYTHON_FRAMEWORK_INCLUDES} + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/include + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/include + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/include + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/include + PATH_SUFFIXES + python${_CURRENT_VERSION}mu + python${_CURRENT_VERSION}m + python${_CURRENT_VERSION}u + python${_CURRENT_VERSION} + ) + endif() + + # For backward compatibility, set PYTHON_INCLUDE_PATH. + set(PYTHON_INCLUDE_PATH "${PYTHON_INCLUDE_DIR}") + + if(PYTHON_INCLUDE_DIR AND EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h") + file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str + REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") + string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1" + PYTHONLIBS_VERSION_STRING "${python_version_str}") + unset(python_version_str) + endif() + + if(PYTHON_LIBRARY AND PYTHON_INCLUDE_DIR) + break() + endif() +endforeach() + +unset(_Python_INCLUDE_PATH_HINT) +unset(_Python_LIBRARY_PATH_HINT) + +mark_as_advanced( + PYTHON_DEBUG_LIBRARY + PYTHON_LIBRARY + PYTHON_INCLUDE_DIR +) + +# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the +# cache entries because they are meant to specify the location of a single +# library. We now set the variables listed by the documentation for this +# module. +set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") +set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") + +# These variables have been historically named in this module different from +# what SELECT_LIBRARY_CONFIGURATIONS() expects. +set(PYTHON_LIBRARY_DEBUG "${PYTHON_DEBUG_LIBRARY}") +set(PYTHON_LIBRARY_RELEASE "${PYTHON_LIBRARY}") +include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) +SELECT_LIBRARY_CONFIGURATIONS(PYTHON) +# SELECT_LIBRARY_CONFIGURATIONS() sets ${PREFIX}_FOUND if it has a library. +# Unset this, this prefix doesn't match the module prefix, they are different +# for historical reasons. +unset(PYTHON_FOUND) + +# Restore CMAKE_FIND_FRAMEWORK +if(DEFINED _PythonLibs_CMAKE_FIND_FRAMEWORK) + set(CMAKE_FIND_FRAMEWORK ${_PythonLibs_CMAKE_FIND_FRAMEWORK}) + unset(_PythonLibs_CMAKE_FIND_FRAMEWORK) +else() + unset(CMAKE_FIND_FRAMEWORK) +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibs + REQUIRED_VARS PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS + VERSION_VAR PYTHONLIBS_VERSION_STRING) + +# PYTHON_ADD_MODULE( src1 src2 ... srcN) is used to build modules for python. +# PYTHON_WRITE_MODULES_HEADER() writes a header file you can include +# in your sources to initialize the static python modules +function(PYTHON_ADD_MODULE _NAME ) + get_property(_TARGET_SUPPORTS_SHARED_LIBS + GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) + option(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE) + option(PYTHON_MODULE_${_NAME}_BUILD_SHARED + "Add module ${_NAME} shared" ${_TARGET_SUPPORTS_SHARED_LIBS}) + + # Mark these options as advanced + mark_as_advanced(PYTHON_ENABLE_MODULE_${_NAME} + PYTHON_MODULE_${_NAME}_BUILD_SHARED) + + if(PYTHON_ENABLE_MODULE_${_NAME}) + if(PYTHON_MODULE_${_NAME}_BUILD_SHARED) + set(PY_MODULE_TYPE MODULE) + else() + set(PY_MODULE_TYPE STATIC) + set_property(GLOBAL APPEND PROPERTY PY_STATIC_MODULES_LIST ${_NAME}) + endif() + + set_property(GLOBAL APPEND PROPERTY PY_MODULES_LIST ${_NAME}) + add_library(${_NAME} ${PY_MODULE_TYPE} ${ARGN}) +# target_link_libraries(${_NAME} ${PYTHON_LIBRARIES}) + + if(PYTHON_MODULE_${_NAME}_BUILD_SHARED) + set_target_properties(${_NAME} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") + if(WIN32 AND NOT CYGWIN) + set_target_properties(${_NAME} PROPERTIES SUFFIX ".pyd") + endif() + endif() + + endif() +endfunction() + +function(PYTHON_WRITE_MODULES_HEADER _filename) + + get_property(PY_STATIC_MODULES_LIST GLOBAL PROPERTY PY_STATIC_MODULES_LIST) + + get_filename_component(_name "${_filename}" NAME) + string(REPLACE "." "_" _name "${_name}") + string(TOUPPER ${_name} _nameUpper) + set(_filename ${CMAKE_CURRENT_BINARY_DIR}/${_filename}) + + set(_filenameTmp "${_filename}.in") + file(WRITE ${_filenameTmp} "/*Created by cmake, do not edit, changes will be lost*/\n") + file(APPEND ${_filenameTmp} +"#ifndef ${_nameUpper} +#define ${_nameUpper} + +#include + +#ifdef __cplusplus +extern \"C\" { +#endif /* __cplusplus */ + +") + + foreach(_currentModule ${PY_STATIC_MODULES_LIST}) + file(APPEND ${_filenameTmp} "extern void init${PYTHON_MODULE_PREFIX}${_currentModule}(void);\n\n") + endforeach() + + file(APPEND ${_filenameTmp} +"#ifdef __cplusplus +} +#endif /* __cplusplus */ + +") + + + foreach(_currentModule ${PY_STATIC_MODULES_LIST}) + file(APPEND ${_filenameTmp} "int ${_name}_${_currentModule}(void) \n{\n static char name[]=\"${PYTHON_MODULE_PREFIX}${_currentModule}\"; return PyImport_AppendInittab(name, init${PYTHON_MODULE_PREFIX}${_currentModule});\n}\n\n") + endforeach() + + file(APPEND ${_filenameTmp} "void ${_name}_LoadAllPythonModules(void)\n{\n") + foreach(_currentModule ${PY_STATIC_MODULES_LIST}) + file(APPEND ${_filenameTmp} " ${_name}_${_currentModule}();\n") + endforeach() + file(APPEND ${_filenameTmp} "}\n\n") + file(APPEND ${_filenameTmp} "#ifndef EXCLUDE_LOAD_ALL_FUNCTION\nvoid CMakeLoadAllPythonModules(void)\n{\n ${_name}_LoadAllPythonModules();\n}\n#endif\n\n#endif\n") + +# with configure_file() cmake complains that you may not use a file created using file(WRITE) as input file for configure_file() + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_filenameTmp}" "${_filename}" OUTPUT_QUIET ERROR_QUIET) + +endfunction() diff --git a/cmake/xtensorConfig.cmake b/cmake/xtensorConfig.cmake new file mode 100644 index 0000000..69ee380 --- /dev/null +++ b/cmake/xtensorConfig.cmake @@ -0,0 +1,56 @@ +############################################################################ +# Copyright (c) 2016, Johan Mabille and Sylvain Corlay # +# # +# Distributed under the terms of the BSD 3-Clause License. # +# # +# The full license is in the file LICENSE, distributed with this software. # +############################################################################ + +# xtensor cmake module +# This module sets the following variables in your project:: +# +# xtensor_FOUND - true if xtensor found on the system +# xtensor_INCLUDE_DIRS - the directory containing xtensor headers +# xtensor_LIBRARY - empty + + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was xtensorConfig.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +include(CMakeFindDependencyMacro) +find_dependency(xtl 0.5.3) + +if(XTENSOR_USE_XSIMD) + find_dependency(xsimd ) +endif() + +if(XTENSOR_USE_TBB) + find_dependency(TBB) +endif() + +if(NOT TARGET xtensor) + include("${CMAKE_CURRENT_LIST_DIR}/xtensorTargets.cmake") + get_target_property(xtensor_INCLUDE_DIRS xtensor INTERFACE_INCLUDE_DIRECTORIES) +endif() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..adea40b --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,15 @@ +file(GLOB files "*.cpp") +foreach(file ${files}) + get_filename_component(file_basename ${file} NAME_WE) + + add_executable(${file_basename} ${file}) + target_include_directories(${file_basename} PRIVATE + ${PYTHON_INCLUDE_DIRS} + ${xtensor_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR} + ) + target_link_libraries(${file_basename} + ${PYTHON_LIBRARIES} + ) +endforeach() + diff --git a/examples/animation.gif b/examples/animation.gif deleted file mode 100644 index ef8eb5ad30980a5cfa69ff94e128198fb07e9025..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33288 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
BP>FuN0d=u+s++oOQ=aYxW zfQMhX(>Q!`CNJt@=IdWU(a>sEeEqf8@)X0VXu`cq%)R^d2ga_9*L!)3=vS2uKwqv* zrMeAfHHY;xH1wxjfXov0xY(>385VFOvGM8fZPfhy#ZF=TSs~TFd_@emEh;1CD9=c; zj5})&%417+aL6^H2dN9U2Zn;7)LO6Np;G1|8~+2;hKuA1nAo;5?A{EwNvW)J^q#)H zQ@-Q9ck9c=v)q}Pq9f?_ycGxWQogjlQaWp((Wo>J>IiXwEPpN>RV@p5Q&10Dx#{6j zo04V1G8KHRq<~JnMT-OCXYI9e1k7ST^B8SGpM|9}O9+7?hjkXA11nflnLO1c3w!pk zG9r*=ProZh@baz6Jk;B6`h-UZMzKOeAHy6xa z&n7%rH^uOKBNHFB;C;X$tHAp>tD;a2AQ@N?>EI+#l*G?`IfoAdeJIBNO~y3!J&etD z{@9HCni>bvZx)3GoF8T!6#@uLUd{Zs|wb(qk&lci{{-lJK%>)wk=OyJPUWO9#&% ze0qsRroNv)jB|tcfXCcFCu8tM?Y66|Tt}5P_4oktfkz5FU)sBFpNAHSM#BkHlkYyh z4C-Ft!Q>vOQr4|JBqD1zM^+C2v4zk8AfVfrfuv}w*nnRm%f7L?BiAGdcwGS1(k<>X z3JF`N3s^4!|=fsFp+Vw3^3%O^(TKaZ1F5ND zyx!5@-Sf~WMRd=}2m8bAsWWvpHfag?@!slgRbMWFJcu}3S7Qq%CtKeN`sZ3k>z#|& zBJr)eUv2K_6ch(^uFYydRTKPR_D3Q} zy)-csv(g}Ll%%M`GRQeIVktjfSXHJ!fSQg#*@@yeD@SB4Xq$ua-}esCICeIB1Lp?9 z^>&*qmH1Pq(T{8D>_g@6uQ?%gr+-V`O8WbZl+)7l{psipQ;3Gt3fp!H{2w?rvp|6< zxj67+(%jAdfb0MGfuI=`Yy)uHLt>u7ZSNl@MjFIt)%BIWwPMS0;E^Daxb9fnl4CnQ&R2Bw)*mht;NwmV79lZ5 z*QJRDI}jJWJa>LPGgNco-NT}60gyS{a6J$@;F?^M;FETkvlG zzV5(Fg>O}f8$pXM%ZSVo) z-`a*PY+Jbl_7&tCtd0y}>qVs7v;28*47GG4)Tzs2S!{o^0iMgQ&HdBGmOseY&w@Ko z9o`?HOzRk1Izz4XOIfDk-#WDgZ{HuMZ`gNO&%8Mu z`pZqyd~RYa-DRuc)rwcTNva_uyK)q>Dq*k`LBVwynG2kbeJ&Z%)<+T}TlqjEaTwUH zlOZ2AP>q?qsNu|0G^t;~KUJ@w_2IpVp<{pj`W!g5b$9F{IJI@|@z1mOZvFK27hizS zc^eBLHE})5lu8`QMy&^@wk)^HMtJDdiIH4;9&wb9FXoQs5$j~5 z0_T>A(GOg@h-3Ng-*U$edW_4)3f4TB7(3*rOHv2}E#ee~bjJpTXf0W(C}L4bH^h=F@ZQRWxd&V1XR_=eG zyjhj5>og(Bwuqmo<~zzKj^>jmCu)RLC#6)pK3-W{x?QfUt4N(x)=PL!lQJoo*K3f~ z$tUH8CEe(|lsiG#g!xmeG)&9s@lD-C%5xiBBZL;1n!vFxSiz7M|m%yRYdZ{Ij;Hvb04I z7+6?d0r>*LO}}xmM0&2%lrWrJ;G|7g7sX?;i=2({z7| z@rUjS*DTo_aQ3$^tQqblIh6PB(=H|4xov{eQl`EKUFb diff --git a/examples/bar.png b/examples/bar.png deleted file mode 100644 index be6af0fa449d932fd42ca9cadd8a83851e52d488..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11952 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%0AEFGg;{EZPhaF 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 G{eJ)oR^-kA diff --git a/examples/fill_between.png b/examples/fill_between.png deleted file mode 100644 index a199423bdf0c0cea0010ffdfd0bf995395893683..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24970 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 diff --git a/examples/modern.png b/examples/modern.png deleted file mode 100644 index 0c51555f0979ac59744a276d4cf315eaf8d66d25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30389 zcmeFZWmJ`2_ddEoPy`WFLTM}-3_?03rMtVkr7=JS=~B8j2-4k%fTSQ@QX;wOZqD4k zzxVvdiE%!i^X)ui`0T;nYpr{&HP@Q+n%A83{-7Wyfsadui$Eaor6k3a5Qt062n41H z&Sm&!XB$ZmA6U*JQYtv`pEr)ld-(gRgQTW20zqJi{)h2JFxwJ=pg~B939GzJT%Ght z4B5N5*jgMtctF&twI8Vv{eY2?(L{z`Ag1g+fvs4|J`r(#dcd!@xH;isD$-j>$>H}O zNqCL#I2TM)7p6QmXErwL;od+cdi=JpbmmQb>YTKg_}RJV#I?TiS?>-X2F$>pVBUce zJ`o7Hz}ML5FYFbI(0^{S;F6#}8=f~|!pFBtdJXiSha}i|=+EhN19bNpZ6a7C0^uF} z|9Ad>dBa33b{2jzs^xtmVb&mY@oEmlkGUriI>#DJ%H|eL1bhDedbQ4#_rwXDw*5ou z`uX)<2bU+QaIngZT5+WmWI2`avO{UDgHcVM*G*!AMR*CL)4~jgLSGMKdX9ee8^8nBx&wG4A*Ilw`3kjg*d2$q>gsJKgD} zJ57H37Hg%mf2l<~Aj_li00?FBC$^I0jRN-=v=0 zymd=8S0(3`ufB-L>k7Nc`0e^Ph4#dusMktI{sN#uc?PtZnZ~NdT+b z{p7G8;OPqot58OG>u;|EYEf>#f%&t=L}zxZLHY-DbhV-06wt@;JC znK;(v^J^e#MQ`sqzFud_qh}o*9UzzJ&RCX&^;a&lo;H}a8jzGOH{rSKd_wm6-A#7z$sJDpV>E@e)`u%Yizd-R2GD|qp z1#`*2&d*NvmNLQ^?WgLpPwzO*cOu)Uyk3B0;K6SfekNo?TjWV?)k^Ny-MKKqnozvN z#4FR9B_cDEh~SaBuZMw0u%@bwn&$yU_>w9`i9%1-i9~=hvj9r1T2)>gD1e z%O~^c!KCCp8}D!I^a{EkKYf|J$f8rV8GQ#-%sMf%#%AV$`_iu_UWXa~ffU-ukNZ%A zIRjEpN$3^6G3nJEGWhk_H=YeI_s)1Ea~c2msBFfpRrV#0O}`;(YP#0lexp6&o}6DG zs0)vu@f^ICKVDnRkMT82%75sjX%n#4)M&OcWWu8Axf`;j?dfe}nGlr+X6D z3ne4&>V;Bp%N=vv6aVONcJC!>r0}3KhRMBi`uXhl0C`WpBp%l~+lh+m^T$S)ZEJp| z8f?*?SBV-=)p@kl-WJ)(LH+_WM22 z=y$=;2pjPdZsE3c94qB+y=*-D)^#er+iANGX=!JxL^2JV1E)$%yZXuMycUz(LrOBZ15Qx@R+sV!BxDl#Afe z->5kB}aYFW#kKLYna!RX`C*JOWj7}g}_@&d7GhJRpBsA*e>RzYH}_+ zonKouZfj)w;=(k9n|3wJS*dN5g1+8aVU?~ZwL<9_M&Y)TwaRIcPlqiH7w0FbZ8pEF z9J9QxUwY-wWiwioI=8nmE!grQEG|0wF9+QIB}en_PZ7&=`TC9LRi)>C=SSu^w^ByI zrcmvES{pCl0UiI;HSh0V6MN9cv|feJbWaX84tn?xey6sbEhN}K@u@2dS>yBAe#z^; ze$DXDEplGBRY$t=$jHbiu6dc6_ctmg?C^M|;N*xT9=?PhH=P!HD0iy_FHW6d+6GOp zQ;k)>D9{f0rKHM|G7>Qhv{1V*U}0hudL66_Q@>1Gy&*MW{M2=2Fr1RNe7-A=+C7#{ zU4vS^jz$ZWYDZWqzC#vM?aJSJ^Z z6}Aa+PtALxjSrUk?wPd7*-kh32;+CTt&Iol{%yM@&v#>&;_UongO=CL3c7gyntSV{ zF?qa)dK1cT(jJZ;%PU529OdI9X4fv!8C@zuzWjy*bk)9CoYI(A6@y zeMH}n-=wWa?th&eM=MJ&Gi#D#bo#3>ozXJFN*Rx@v zH-);yIQuLdPyN#HPF<>a6Z$CiUzPye^oH!|>^7*lcdOkNT9(1919!+G@4OQFRy!L= zu0*w%m0*WERvZ->S*L`QMpB%NnWx~76%R;znQ=$=j{NP2dJ}pECo*t#G>4MMr5%l^ zI_IuYJbMJYQ)#dNtCz567CDe5i#M^u;q}!wu9r*Q&gE)096p9WB{eIus`4h~RRToiVHN<##E^xqC<8-@=jh253 z)R$=V?jV)VZeMg;-O)lqsdwGr4*U19c6k=tt#Xf@1!hWnSfOxRa0?-A@6PMMNIrmm zngUZHTvMN%>avqP8L_SoRDx7f7wtgTX!7Wd8?khePmG1di%`uSkGr~D7tN9AX~nL zT9B+S3lATcg!)eyuaBkIeH}R*zT=a~zeD-jT%!01gG>W2K0TuS$RN)G${0?OY)52- zp-v87GQiq*rgGiO@!Za4(y`Ymc}$kPlnE^3dEM_8K&LO_D0@4Ha$)Tr54Q$E&cws zN2Jb2>lWOOsW|Lv-(JXp`Eivf6BwV(ydjV~Iq4_iyExsEzpb3CwL&`z5Mn1XDk{nJ z!{z@ayz)Wp*Qmg6ik9S@*`>^uE5vSheMnAC01FujR&*kQ=$tm;DX!>2Z@sIEWyqC zPpfjPp~Q{qIgep4Qc}{mNG6?N+!oAnmo(v~KcZuMVO|?k^~=7WvIMMoJ$ILIvUvG( z+H&p3O6K3{M^z}gfd_+=%~w8nD@=aRFy2#hLSEqL{_Cp)q&Qfw_m`iIecqzvb<6aY z%~3*n_Yq36?2R5M6Vsvr!X-`oKkMQp#L2AN0!QnjifeO_x1LR} zZd9>zm;ZFLnStByaQ0p53E1jCDDg4H9KjcCHB0Gp>l?qTojcFq#yN&>?j|xWf~HYk zcYdrt?~<=q&$HD1a%JQ>4Iz$J$+Ld)1T(P}BLUkUw#L)`k&u!M5*DrK$ekg8va zXS4O&RJ|7^lCQk1)q8yYhcanLhIoim^b;Sr74jXRwd^lX##Kn}Pe`R@^e^zaEGhgt zv#;9{??g9nhj#W2M+;J3M9`5`$Kh4RTRYPcPTenxMTZJ*=X2MwFojQO?>~I#3A%$x zzrkCDy)!f@EKG16pU>5JarPax8>oUS1XS0KAIVBfZ)3jlSI>I!IeOx5{e-t!-EO}O zgU4d`=Q$5O2jfL>lwF~q6M| z-Xm0D<7>~Abi)^ZwQg%lPYQKwhj;jTy;gFvmF%30-%E)j^Q#o$C7y@?7!;P zR?NN4&Ia4q=F@-_5GKu0y;pj7Z*gMMeR|D9Z&Tz7oFJFPUrDRKv+y4LQxp?;<1UZJ z$xJ2A06Q{ND{llp0tGnIC#MaD5`1fi@6!R)Kgv=H2APVH>k;p>klayGQEy^RWG9su zE7NSUx7TYovP{@iz9@7y0 zoW;CFA}uq%C9uh&M3Mt zbOVoVlc79KWq^VWDEiM8mIDv@ce6PdL(DliUxiGvkH^1K|SmF-wgx!!8FJ4SI8274BC~ZS@?gZ+tgS`Fc2-D zgoMT$bdPuBEm3L=w8G=n1FW@fl(nl9bd&-V-cr($P7Bda^SBK}^fbf_cZpf7MxF;r zwg$_XCq0N^Fpld-A|oFl>GfiXH_QK;EEhIr{!CaauQz^IKkUBx%x$bupXcS~==?W~ z<@Ot1x>*f>yDbY*A_1@2T7$+=$K6lYoQ5^s7*wT$f}PKS074>U8(d#NnDNNT4_ z+sGt%-7gEu73e4(ZTD9%O2;rw?7_#-R~gl><7WuD^=}wn{Dpe9anrt0z88~vUfPx8 z)=$cfS~H*agiA*kjl4_~*}w2U$~-+<<56er*jX+2*>(E+KKhdd9qayD)cK+4c3*L z73L$`m#!4UIQ-ILP?G1wrZ$?z8g{T*ot}cnBqZT2R;|sX)$@Vlz5at~nOk&P#*!tk zzlh`KxY;hh#>?b!&6Hs+J{58+vrQ;-$=UV0FdylP)pT@n@v6A_Ak%6n@38UIiMPXH zSE(Y8_~9%g(f&r<`S}Fv)vNtkvaz;v;>#2E$g8*VzD2CINR(Tt)g}5hs1zoHFv;yb*Qv?^yW;evofpSH58sop(Euo}v@tb|rbcQ_b=5BOG5xCQV`HW?<1dqmmrBi~^nFa} zsQ1^)lYhvtM%dL4k!_RenuzA5ZP4v`) zP1KG2R)b$7@grExd>eIsQI3Y9)sVE+zz;GWkL@Zs+{DqIq<&I;jff{+6?>^f^ah2f zEZO{Gy~c*0S32Y(BUeqjPmkO*tA2TE;1QQZ-OSgP8PT(*GxaCT08;Fq(u<2N<0?-s_5tT6^*5WJ5cx#HSWNscQBzc{Z>j`@CK8#L4E)`ml{%kq?G(Y$ml< z#)mu&UJBe`n5dMAqLWe1(okg4+|Yk_owIE<(K+!)FwaD#cG%!z$^^wHN?sd!i)=Z! z9OZX^us@3@u(E$@#%#guEe!-_O@`Xrpjo(wUwvh$%M**W;Zw)o&%~tWc=&?_Eckbf zP841w+w{7g><an(?BATNFxhA&)xK9_ERi7D z;FiDJ{Z#4AWg@0Dm4ZZe1ApT8jpvM$?kOBj@f@Yo&B1Krn%Xp9hx4PTUVihGEvS{# zDi!x!=brfFI?TMhKf$0T!r*R4&d6)_k>!NXs{%iT^6~drJGkXcWMQmv*J9_=`%~>)n|*!@M;X5xWEON?}yYOEX-=jH4T< zgK1mWibU@G%37o6%Q@LL{Q~~s5PLecIdaO8A=NHk$gj-g-6$jIIGC<{dT{M%yOM%? z^~I68{+KsfC%rB;dY^UM#0gJ8ELXX}+YDbD_8L z0Psb=dASHSuVJz4SJYdfZcw(T7RyQ#c&T!f6WtCiING0Asu%O(u=}#@bgkbP=-UV1 zy>{oWYOaas@&1N;()EblgX!U?p6k_|uTIWSY*SL=^o*qbSg6)ktDS4*-Z^|x5GLd3#EnB0R;CG;TS-y- zb>|utFKil;Z>v_9uz2`v)N}5lA|x`u2k2&tJ|kjbmuD}3E#wRq*w*&TCp`T5*|?rrXzNdZY47;e zT(h5<7pHBpITs7$BOM6+3CZs@RqY_adIF7dOVRInUx~Pd!JLJeKaqR%cw?pSdt%M%j2tuIcVml9~JT8vn<5 z;0buoLp83}faPBRz8?hMvtY8;omcw9dtQfcKMF?*Y-RL(_dm1y)PxvcmYdHjwdp=N zJ?dYdtnmD;EMJ^aF}*r!Xx>>^CBmpX9_V+r;kO%q*C&K*Y$bf7&Y0g3wj^15_Y0;l zJlO=;Evvrtfc>n`VwKh-thx|S7;o^YefZ*2YMSV~6$nJAWy>W|Ja{g~qG1rw*&Z?M zuUY*4NBN~Yjz{yHFIJnbKo}#6wSMqCc4jJ1lk+!fF3grX^k@f3#-Wof!rl=fx-vH4 zIXh8STx|`O`T|2T-Js)1@6IlGH@Of1J3g59n@4Jf?gFp%3nCf2K+-J(uP}gKH~gj# zG*BN9)hK$7?{=W|lD+cMJcczZ@U~}~lp4GXqG+||e_Gcw1(RqN0#VJG`G|YWwPcmy zai88C*kQbf0BP`lQh4XxjgpQnJM&oRDJQ3YzdecM7sFW{AW54tSFd}8rt9R zJw2RTPvQ5fi08D;z4<^o^Y?K2b39^J9SxwCJnm=QRe~{|7R>#SDy%cAXCBI}mJ85u z+-mKQd{Cj#Jk!)4qb}`tzRaV#4;ldAR>k*$uZ3D{U1R38=!PF37hU`}7oe4xQ{VO* zLR+>(>efWz)%G9s8YN#u0&vk`sz3tj0-%qm-7j)gzp4NMk~-nE(47NhxFw6dQ1SdP zTJjQr5iII;Mgg{jZFkh)YBhLQ#I=Eb6we^lvvAHJ)Jrz+>f^M!Pt0J{yt`igPHGRQ z-uo!;itDV%a*7`yTAO(x&Y0(%&t({cgGkv5fa6czJ%_{g6+$j;lX}2kuZ@+`CH4_Y zHJ+L6;EI1NB7VKl9l@yPl7w5lzTIW}`T!X>?n@1KYb`hQ*F?EY&6YSXYO*k8cha3x zm<%Ty6!pkqekB$8>%)WT0%eRF5=}SFEEmf%W8Xa8=K)D(okI)LfluAfI0Co_NVYr#t!v_zg z-KQ92KN*a$HP92&&+rhJWK=zycv~iX35ESdUH*7el$SR+?+%w7fEcxt1YY%Al@8at zCh8+P#`P>*(>6Og$uC97o`v5s5x7ZBU3hqSm^uOMz&yRIO`5^gQmdg{N-p&W+}xTF z-B1DgNbaZ}f>#QYHLlHf2tJp)MWDA zI9y^X;{*I4`c5g^od8#b-i30Tv3|oRCgZ!yN@vIYO>a1{J{n>BD%F(jVf}V|w|6?} z#U?{-KA6nkkI$u1xZEDm|LHLi(`HyAH?oa7uHo=|;Co%~;@zEI5TD_55TE;`Yuxr? zZy~Tn7UN}>=)nG9xwSeRQE7ZKb_Ys=JF_1BQS#EZ6XQxHg69@pq?dfb``*K;JIZ3W ziXJRTD)VbZsq`7niEFpaOxWA@eDgUd#=U*IoclF1#WymDxO6r}IlD#<>n%RE%==d4 zkpYutNhUf*8u>sb*LtLYjPGR;kNbL_RMbOm>GvR3&6O-C?%91H%&!$=T`7W7h?|bD|raL1bNn9+QY)p|* zZf4rSJk6&MQVf=!LvV`Syoch-2f~}+jG2G&JC+Ixi?geNV=%L;>y^JY|0_3UuqbVh zZ1Br0Ps~Mkf_Z(mYOZ98A8V3F7E0{fGJ}RfJbMR8;O!?Zv15J*x`B`HX8mf$Ozd14 z;*9WE)6(vbHp1@vB1egOOs^toH9pA6*YY@uZUXlOKKVE*5q^8fDo4hr5&z`*@u4xV zaIse}1L%*%-I?WqdXWTg_3R^-5ANu=$ErpgG5L z!(sg8i1_~Aq?%1Gi8UP^VJW>vIDftlgRXm$OUHwXC$~dx3o+_y#dF9Uqu3JO`)#J8#57B76Mp^# zmlzZxNk8I#j)_#l0Gj$?xj09`F0kT~m273FgO~~{L zvhknf?M`_W3?S&lnqIHY)*r0m9|e%wVBbe9cSVSj2~IuCue7xmWjwPv^F%$jos2JS z6%xO8+rW!x(jy!H#wBlHQi|=5oV;!|ta0Yp>yKFaFDZQqhv;s_pW!6;WA~fBM(Hkd zAr+YYhg+-Vm?mO6iMz+B{-ebS)ccs`nWuFb_bS$=SX`HAhQ83&A2Zf!U;3wkINCVPsVv~s;(C_`8yn9kZc&r;K=49R zIjhL~aX4`juZ;VoX+YEVe8B)#!jtEoC$`Hm>Z{it`*$t5V1<}2HVp z$Is8VqN0!&rxJh@f=CdveGT>ac&G_=X-S8q%VW1;!`fb58g}&=GgZ1chhtNmFM_>{ zjLR%Gz9-0T^H*~D9kq>V(dp5>lTjhJr%svCbYU(Blh^RyJSAd&Pbn{G%XB&9PIH!{ z(EZazL8YjN6~DKd-b8qG@1bl(Hhm7pG7S*3s_AcS8M$ra**!{7?Cn_=L$sWy+rhF} zRP61sy4Zxij*k6b6#IXK^#4kOp1x<9O2}0#Z2xwP=_yXb^?`S)%`+g`bbT6{y%p11 z#}mUGRT|zLO=Ztb;pH)N+u~q{<6Y(2y4^^XB7>LIctS-H_iUH;F3uNuu9nc^l87~4 zy_LDqSoyTxW2Z*$l8GQlF3CAmwi`e0&6Tx77A;AxsoM>07!F3JUBEz$TUU(SAryw? z*`4fb7D~5;Dh*`8&WtIap8}K9zdF{Rr#b8Kakd%xGXWW=Z}vv=TTFwGEnAk?hAF1N z-JsXleYQ&qmTlLUj}~?5FiI*bY}YcI&JHH7@1{kE8;JIR*~wKWSS!XzZ1`PmJ1`o6 zhm?xa0a=PPy2#>@dVUvAV~E7j2MSWwFW)zquLDi+{@IqivUbE8=qEW7Q&)>-hOZ2^UBQBfV>Pj zr=)%TJZ#NX*qUq(>&$~G@InJ{tK}}ue4$H;c3X?o^Wk7`Bj+1^crxWIZxMQh2E|$> z1W3kHP}J24^BFd}V;fbe_=`flf+&P!zPAUkQb@z*On$Etw>+c_l0g|XQ{47Eo~!^O zZL8&01zlHrL_rh{d8&c%u4b_aSVZ0(>3f$qQ-t5F=AoDhP1c^t3$i4+Cnt4a&#)0Q zO1l3xbRJnU75=1HM03n{R#vaLzq-tG)&CavA_eNqdluXBV7;5tcwTxL{JK!B0-dy< zS7_MLe3??)N5>?r$Dtqw(>ZbSyH5=K;n1Sk5prfTLY5c4mb**cJ{P6E((|2twU~#R z0k~*m>GbCp?T95|Grb0(uK36BAQGfI_GWE~DKf#nB7`a`^2vTZY~0pX{~H1)Bh1ZO zP!bh(XXPwajS(0fi}#wud_lz0_0Q2$2kV z>g5rA^ox+QvUg4v)f!| z$$5Uu1Q!z;w`OX;*r$8^lPJzD}}m6LR#h0H3w7eCYK0#CTnG| zaYuEOX?ennLUJy-Tpi7t)9v>yn1mt$cruhc zqo~A=1N5T~r!%G0zPO+kK)~J4P|P{93CbxRla15+8a4AIaxV~lxnAy;XP%aQcSocM zjnPj5NtBQLqj8|iN}ni%8!TIcZcPii=E_zy&d0w00Z)n3w~zlQQL@(R zaJB~ry*-G}!)C8gDk_wEy1_YncSv1nvB$0i11AY+r4e?o5}LO#HGAbO$q`*TV#dF) zn!J_Ynp(ALS`B=M`|^V2vW637j!}3*OF%iR=2-;KBWQtZx{#I(k7Z7~aj7MUsW2M6 zj3dSz*(62|3z{UKiUc?|bgVrBm4ZiahrSa&A!6Pv{QPt+WMkzkC>KIpG$*SiS!zyQ zyY>yka+sN%^)d}-ndQB+qwFLXED?WL!rsxM+i1x!L7*?0~6mF$!nI4HtRn10gIkqw6;R+HndHxX$rKRGyGnDkJbT>P$9%286v z*RpelHS1KPG5uqF8Z1~eq})n+9gJ_@Kon=#XfB`b`jS zZ?+%=XlLZ{NTsoHC0$W9a+oxOthL>4-=|6?j+g0}G!QMZOa(=KH>Z6-cN-x3LECQv-|6-mjv8ggA|HAhR8QD^kw6qnWg`R-+SzQY%NeKMXw zIkEl)VG@NRv2Q?BMAOMrmD^A2aUU7TO_!Lu=@uqWP$0hFW9{)&^*vRr*%Sc{@mA*S zm{Z+$l809j!{p|?9TqdBu!EnPuEDL_6)OdNc584g?2ZlqR@6?9bHXK|Lkj+_!vT3a zXEcfX?@2_Yq}dRb&Q(YgVN^_i>v^!A?{l(W9l9Xj6({4mQYD8$lNdx)Y>i7o;|3u+ z$oGcuAnN{mC&&Va2st`yAJRYM)+Q=P@-$0#+wX0LcYFTYEexZ{ zhQj8xJ0WJUn;X{x)n+1{f<<-(&x$3iTuP#LbvXD;N^^*8_JFRBSHv3=? zwN~R~TFH%gtG=_)AInmpjKHbPRYm?aIq@!3Y<7(=;^~u`M@Q|bz9yU9an|_0I@9!~ zW~Yaj1M+!NC+KA3GZVR;lZy@>XipRgGipT>e}^&&?8Rj3k;aR4&MWC;{LF@G)lR0a z8&kTy{0E8K3qQYJ#wS}!uy5#t)X1-p*}B9RD1bdt)a0rD=Z_8@lsRas)|B~V(cQ0- zdrdFibQ1#-#L>IV?zXDI4~eXd>II3(o+}KKkmXpAanxI3t29;uGe`I~c6?A(D1w$=? zPfWq_dI0)`6kUg7Bm+$I`XopzNU`XfU?@c~SJ}-6|K^vbR8>^wUWg)kZv?Hw07TUY zVZbILgq9SFXo5ic$9bo9` zoCN_My3nT>vK`RoQHUtR;FTW)id}mW?Vw@_@r?^TaJBP zzwiIo7gzY9Jg6nP`CXXLk4vA0K)XI0Z+1E?LbsrC0mzLEdG#V4hNkd&YV6Da3vHXK zS4tE4??Sg1D<6coue&5cRmxjje&+VO@D$h!bk$MIO>ir3z+?lU_Q-#9`(PUM;s12h zmyQlUKO1p{>JdW5t5+c~_TL{mW1=c-9FrjT;%(<}{y$m$+f#ku+|Li2|MkH2I*>j& z7-)XYoM!NE1CyZ?zi|$j1txkHN81$xXZn8Caxhkj)tXjqfl{mObukX~ zZ%Apkdb^~5t3(awMZiQQZ>i=USxp>(DcDYI5%r(4NQxQG4)yxKhi!K$Bdu%Fm>+yu-r`UYE5 z90bFlt;VxRfj(^MV-W1E{f=w+Z?}~pGzz;d_Vup`SbR|b@Q_O|lsrDUwBXr&N`Y0L zs|ZB<7k%Fd0IRHxztM&T_COi%j!}9U5GnUT))@`wTAc|8qjf4Yc<9cgy7!5h9{L<1 z|NHBBP>lDH4xR9|RD)N7^W6;K4}!1u@7H^gQAljO+t&lbK^%U%9?0FZgZ>7ee>*r( z{<65trxvUt7!GlTqHm2_W#OR|h8nkFTmBBnBX2(V)cE>eN7bCW-~`L2!0sUs&va9K z9s)myzj67WRUWR$XEzSqD}$5lH&Lgl)d1ua*xMFDSc&#T1?Tns+KqqLZ5iV8oiQ>s z$5yZpqOcVEJ(P@TrzDz*1flisG+j~ZidEYB1M>-l`Aj?g4Ii(JdnjLFdJ_ZTFK9c( z>~oUuG9U}T|A5~wYFwi#>|z#r-O(p3vHNdFMXgT)=YM}?trp|i;IsUW1#kiJt;2is zm23r@QVY!NHq1<4CvmUDdp9Eb6S&L>gd{3XA5D$gHH<+68Z>IOo6M~DLRt>|o4aNG zSp^hYL9R$GKntKGmK@frl}gRP;rq9lgV(8|e*k+~ui6>a=1TT&gs|H6ND|g)wSs?l zkb=WDzRdU?FwW@h25-Q#%$6z1m82d{$YIA)pVHh9rE;tP{`R-S*xY`~OMbkv*Od%` zDDtjmw@-H2sE6MJp>NIZifJpZ4874u>PU}0;tivl_>W2K&!nMAmF3P*Jb)2d5(>IQB*3>fgm90>D%CjFAb!=aygps zckY!+UPN!sm^|do9HSt%j26xS%@3FX5C35*oKP0$YY4<$>s<@&&X?a1BU0h`pgDQq zbhw-!L3|G_SfPEV&D7n~9i@YHrTI?ij&`10f`X%{Jj8$t(<*C6udpPnays_>ScZ(f z-Swu)EtsWV5|1WZS4P->#&B2)XLtEBhzwRi27&Ya5O9*oaGqwaeq#eJ3G){y@v?%# zwSs%k8!5QaK3l`7l2*|-^vFijyc?2!=av~1{y1p{AN)5OPUN_LJG_Aq0us`&bD>_q z^KXO%q%!nYg_4|&mq)SINRmByOWce=;AH!ptcn>{+9`#Qp=aJP&m-iv3HgR!A+kos zWtVtA2Ws)8rKQ2;7af9BIf!%hI)0}oAvL#8=K4+JvlRfo5O8V;!UR2U#qnxo&uxIO z;Xi*h-!y}$ML(qN=abvlJzm=1Uz@Oo0s*b|k~&QY000Hie|8|#(E%Pig3#;yT$_xu z+pWA%p~;oZ1UL)B3d82hlu#iBIfVE%XLUP0QTOv9%kp{N=uJ{{b04+5qGBjUqbW=F zR_gq$O!n*-Y^x}`A4DOglp^jve{IL6Q&n`|5<+q}dWoV|Mk*hdzqumgbpYG~LTFW^ zUJC-;K`~$}!J`)gD5A%6tI7HAj5^_yUcP&4W5!)9n4pJu_<&u5ka6v03InJQBxcc4 zi7ey#sdH-SFwzBwy6>!2{2OXM@ z*j>IEjFqGW)nb3<=HA%x^7LQU6om&bCVLg2Lvv7Qi9PANdx0(hT0RK9{a6IP!MASs zw6odV@3k?O`3+o?BNkZo+;xg@U?&Qy#cR$zM=ZTJ#OPuGhvh;g1-CR2@9i)mGsx3c zhT!a8p9D4bQR=Dyte^RJHcL9ikuKCv}2`28-Q(N{8BKH$tsYFCPM141oQh*lolg{7 z?qurKXFf5_q!k5M`BU>v2B=z6ov5(YZEF``R4d~eqZPHOp5t)^auz|uQ@0Ze3S+mG zlyi{G;Ug7EO995E%y@6Foq_EY^@LUal4ZL2yo$kcvgAO|6d>4>&h;NMo$L*|ajoqR9o5Z*zEe%a? zkSjyTWd1v3ml5AS+`lgg0l;!=I;e8u!6yU*Ud(2%M^3iC(|Zm75`u=MH_EONZ4Nwl zWcPJmZGhVFg18_VyQJrztIH=F{~jSI9#(-5nT!AiJ6*|Uo)Iy(3j|(^U~SM?8CM-I z1x1TM{MN4Q;e59`B!jj(WHaEohWq^OVF8NrY$q)LHRvC=*y#JN8+PPkC5*Sd0V<5i z%y$BrAhl6X*V+aQHNu}4&OI1p*-tcRZx`P|2_EDN)}_WJ!t)@O)6OO7GQz(-fm_-0 z+(Y|g78r6%e`R1j_HU8W)o%snKb|hma9IjRiNQ(fN%51e{0+I#raS70lniL3Quc-2 zG>FCZbo%1o)iR;rHp;lRy%6&wB+BU*(c6nH^`OR zUu7%+vuFDWNvXA4;>&68K-5n_7W4{2$4mDhB{oNbfPv5<2?yc-YphhlYD5lzjOD5Z zujUo88@MDwk-2IyVAcfAHPCtsJ+BZUp_)B4UIs4Pc$KOmi1dItLP(Tb8qaxBdv$y2 zps`jjpK(BE%Lg~7>+eON&>G=w`io{cPT$7o7_<~?-7nX>0HMrRRF?ZBkQZn2HS0XE zpD!}rVN0^G%6TqQ=4f#&2a;ztUbvwr_EEb;48*eAK_Pg({ zL!b=tZF!>PIb3weA|0i;`S?|%!HigEOliSxE6wPvFQ|im?*#}3_V`^4DD^(WX#plR zr^SjW`=g!O{{-3`p2X>zF}(vz$!_uYv)7n1C2#>}LH=p%Q(0D{LYI+n#5y;kFga?$IJ)3FPUi{KFYheI}uoJ3Ee zl6Rd-eGM@yIVXf;5dLtj!4|uDtS~^EBFMFpQ*V0RZ=NC*fGY)gZBVBPt=fBHnIj-~ zs5i4O!&VGI_y(r`@!8G`-UQdpR4_{Y1-fXvRFbiW%5Q5lleOG7(f)D!y&@5_kT_5} z&%0t-`dvq)K79DsDoXGo8sK3NNx5nhE(rugahSjze`+-xEpYMs;f(td4I0hfKmhr$ zNDX0To8B0<#%SpnCuqqFElbJR!?Wbd2|jAumlHre^>@<|)`Y?m=WL(-XtoWW8-zFD zxoTw=v><^H>h(!&2pEGRYf1Mx$+Rwv0rw&ZJV*HIZeYm0S9vSHgwf~3Ts~p61P30c?>*&{d&5=)0AD^%^NF)&Eg%v}c`d&2fpIyNF)^&P=PR%@Pv0#QecL3w?n!NMe?QY5V48h<3q=7h;#v z&MUK;=eaQh@ifBgmo97cJ#k3gE8;t*=Vt+-QYMu`1}wX6eEzk|CeAQK72j#mUyuG& z;r=wyYXp}NiQ{RaYI)vU0mMurIuMp}vGDiL;%^Bw<AFe} zHW1hp&T9r2zOcoJh}|~o3hT2_%Kq2bL`*_F@bU~&yDH&-NKvw8h4JJU9E*l>>wFC< zxmbYLR)e6vHu-T$zQq8Icl%q7E6||*DSl|xhm&pEm8Zd=@GU5&Ge(yVGaVBfZ$_!! zv!82vl<_fSY<=ber1M!&zvk3wInmkX_9!}s2ulnc@^8RmW!g8!Y%j)Bkp?5;R7&$JZtN4 z`alL!x}{0=nagb$d`=-uj_~i^=3Dl=C=GeDQ7a$+=#}Xz+NZ}j&2%uFSgx|w&Jn!= zX{ay&!elVw9^`=c-;$Svv_DWK^Qj%!CM4t%n7&b5g}dh`oGYQehIlEIW zl~2Mmm#`6BeDaW5Y&j#8qs_IPUun}vgrJ37sDGWIeBI@$ZcBUa)7~=ONc#p&Fc#X3 zrSjAatUa*&c7e#qOt1BbA0Hvq6hY;ecwk8L@%Bv;3<*3En)|pUWwH-W4l0RT)~nkD z;MFg)mF8hdk30`_Yx%aYT5$=@09D6+`t$`}24MyHN4d(`p=fptT#}UlQauMs{61!L zIoO=;+qGqOERe&*LyTyt2q8y`huFMa&(mBj#uUSWw}zm3UuwV8EvXGQNXf?~X1w3K zQ)V~G^N%ajtE+-C_pB?_-U?7LJ*X_tPu$ehRHnGV~e z2<3y)!%ZkDkaVAXFzNZV%(Hy=Z zm26QcM`=2qoVx$KZ=+W+eN-6y4fKmupzbUmJj5I*6lSQDk7t*HbWxQDoS#JK=R1tO zFjNXzA)gmbQYSe0VU?B&|?UFGF*Yq+r`9CG!6W3pV6nUHV#6`V{mUbj56 zpYcd2Cbx!H6?ks7lIpgJGNT>gmqPIZy79atKXeN9H(-m!-q|;nANil`kNx!wBL2pW z8~cb!A=SU(c!dd)&6L2~P=vC&GI;-tY>I#`I0EpFlH%24lOt6{A%VZT9m?ShX_)lYf`P zJ8XI!%u7E@62Vpr@c%BAfQ+%uxXPq!h}EM%csV{^%e$7#%>>AYvNm*>;n?d%2y7`x z?sqDIoCcN3f;+625!ih|2ZWGG0rAA^rl5u(&45O-^_~lHJ0V=svI+5~VHl~Y&)j?R zGDkDsfnh%)%vO3Zk%Q2=9Dq&#{`>b#*@SMkRRN#w)7WXhO0bsO!^Or*sA02v?RTDL zLJa)wbDL~T2kdS`4BXrqgVK(_li9JPf}E}j~ayOpjx0b*k``8LK&k60>`2F_!si_okIw8CJ7tX~g2RZ}Nlo<7?U;iHj_F#p<;O87a6HN;-j!Rn z*74wOD_vFL}#bs zLak9UvW6;=5pt`sxwOoiu-Zd9MVa&YdCE*;HD+(tQo9e~xW7tPEOXC{*~sy_f8C4{ zJ@xGln>5<~y?DHYX}jgyVD+dy2n5fbZ60_{u1>^tT!PUXG5L7e-j}n{%sZ`dvvwuo z2g(L3BA^lUEOX1!%7~aA2qX`{4LJ4)jmSFwfSwl}^=m2_7#N9h&`PN&-?uG2{o=PF zwVE|$+8GO(ixD%g3!0JjPy&u{>+j;Bt@uzE=h1(`tX5^DT{Y>XvdLQ|n@%P9Rq~y_ z6R$UFB%MU@lM=d|c!J_`l%U%hKK4f!bc%%SXeJ70&$H;5P7jbZMu?q$dRb8X6Tth$lrxxKgw7Q~Bw)V^q z*IW9Jv|~Lq{agI4>4`H0T2WuFyqG^;;OpzuZq^}6O^vbUSrZZ|x2*M}yTeN<2l(cv z;m{jPgqtq$`BQ08$ELASy>#0PxN}%Z2wN$a(qDgv|%F2`(1>zm|jq5boS-J ztTuUvU4Gm;1>4b1E|(wsmKXad;gvz`q)Y`CzoxBZm*JSAj*u5R2%wkU&-F~CS^Q$7 z<&7*qD!iE07gN8NOUoI^D@b&w7|Q0=x+I;XJpBCbK84kqSlKOf+GEZ*kKtl42jyJl z&9&skI)FR(n@>*z_zYNIKy)peszz_Duk1lqWHcw=^j7}GtJ80HP|jh&ba>W{VQomf zciZUoGM3{GnS6VUY!-Bumwy#)Wlyw(xay;mCsiOHZ*EZ{ zt%))F*=MAW5Gf2r-WRSq9lfE(K~j0h9fxcf zjg>a8+bm$zJK8n*BZIUPWP|HsAV&doY^WL7yr6(A1bvS*gUG0LN zu@T&@>3gedy43!fW34%mF%DGXSgO|qof)0qISA2wN;#9AZso>)_`wTfNI4W!$B_@Gdd8yDX_Il*& zHLGufq=l`b5A7mp@=+5@3O+91L(m;O-DyRpmsKO9Tc?T2q0dwfg;y*)t$WK5*s7?i z+-Bnk1Q@5~h8?-^Lh0&Nid{H51(Bi3y(cY5d@L=}V+W9{zIf%$ahT6>`{jLY8Qn6|nIEkTYu_z6gD*=BiTZO&N;j)szXsvWzFlc+>`xR}VnwKg!Zx7Qhf2j+ z9EyzKo*Ctnoq5m^{C)X%3hD%~`57mTC;S1-AS*SKS7f5%yI#0tT)K3LnT;*|`t`r? z8d#ZokYpyIeRTGEj~~McfGd!ijRG6HG<+!gnb~nk)vZ|ud_sDAPRDRxaJq**3fapX zVW4#SbStQ9(g3eWw;!m|^Qi~plvb&$4d~p?G&MEdzIU%R+xRs}trI8b-C1*s#^9`i z-$9RjwymId>ad=?BZ4L7+Wpjb>WM#W79r^K>j-v)Q-@cuWWQanOnrj95je<@#JTo$ z$yl!i6b!sbN0Dqu_GO?wKnrv-*kZidSSwpEcQoJqy>Y$x>o;2kv*Xqlmq8fKe*rI> zdOD?1E(|@}kj8i7464F!-n{t^7>Ea4Cb4i9=3b z*vQDJi5N}`G>^3_v4b_is-c;SuMhu587FLCoRq_!NM)L@B~<|_?o)NmHEZZqjJ&yo zj2gb071v~5&DQ}GyZw6)-GGlnc_An{9)IYRJyV4y$` zV{O#d)yAK5EiEnUYDAVw=2&doH*(16a;ZFcXa5Xv88oAw&&;EFclE~l`sNyTX%(~r zIt@q58W2X(Zfe`1|5jQvA`hAeIsYucouljgQhlcYwV!o0!gmXgjGfV)JOlPLmTlXf z0EJ{GJ~~PVQnxyD>L*3i^r8=kbD0cCS1j#8Xlc{U zTmR5_R`>lSJ#V5syfyFx;&m-#AOyKS$ZrdK5XitP{0yPICAO0-2$X*Yj~_oK%a|#q zgd>-fE_zp~tvV^~hGGJ@*<~%ISs465Fz};Y(ruwFOETuD20Tb7<_H-HkLkFLpc-;nn6>~kOC3S$ zgu`LN{iy~Q-yyvpE$>G=M6Dk>-)dje{}fHO9qB&Pmr;4hOP=+OcuVi+@2~uu=wA;q z4xsD`tW<%}{u zY+nJAjAK~g#Yx>c>`=9i2JsVbCA4k7&7U;6vU$TpmN*H!!nn07zy*rw49#}ce_iOZ z&4Z?U2Ai&6SUgXG`US^HeN3bKlr@ikSDd`v*hkrwV)tj~dBXY4;M3|V8q@fdY2+q% z2n-GcrYLgUzp=qgR4&)`%XMZZliArQaaH(Yd^asp3C;sl4#bPVE+X}O|Ngg6Q?j0Q zrb}O{ZFsJo-zmk}<6ANPNu9Ey>6{PeuAd)~f?pYo)3v{mh;MFt-h9DLdGR+yR`PRU zeVx<7Pf4+o_*~jQ{%EC6Vp9E%mOkG|npe*7w644Wu*K47PB^ z$Et|RLWJ3ya(;FppijO=Z^Pp+iOh{2TZ03>_W=u0%#UT-U-KM0pvsXTW!(F5tlL6* zbJ>8Mub9A9UmSpHtml128qqcQXdr_f8HWoq~E^I?S z$wfY?totx(@MBp?OX2hBw)2Hd1C}Xis*SQdIQE0~kD?;Al5dimR774SiQT(3j{3Kh z7P$jitag3$uxHznWDGo3iPI<@F|0!h{*aK-0X6KfX34O zIuvFVC&MTE%P-$O53t4#b9y4giu_dq!HOOeC&W&TqT=eidLE86KZ0G+rKU!CRhZ0D zw-}Z_uq@!FPOc}{+*5fKkSvWX!{(->X1H59mkKop{81G7emU>JSH)e*1y-aJGtXec zNL21}re4xszxb6Y@2|=GdkdM4gwBrM-!2}i78hD*{rDO2C;0WNxZK-a7d%%ZUzb~B zz2Bl8esNOcNM;zyflm#4Aaw5{$sJHf(;09^pVI1MhL#s?c=#Vm*dC-4-Bb189RmyU zFn(TlaOx}E_#mSHqNe`Jid)w$hKTEbrMpf$r^K$$%719bT=CHkS69BNE$6bNj(v$s(((557UIC*25|+<<8Ms9W z>kyT2Q8#@wp~k%{l3O*ned|7AJtt4vHMn1YGI#_-B8=F~NXpc3%Hmj<&vL8lp1#j0 zeYdLIzI$+o<=^zAloTTcMKEiH^DB?EDa$XLYHyVG?sQEon+f)PXl!q6j0;1#vXiKs z!TmoIa^ht4OT9vyFpn8gH-pI}Bj0fSq6k{rx;Su0k?%ESB7f`)gwoY_>Nlmoy2e$L z6ZfvvXY~TiV7Ic$sRx-Ay%49$b4WQ6bs^b$d3D^kHPbrP24#cxBKPs&!9MtE;+CJu zrKub#1aQ$H(MaBj_0pTQD3<4a&8oO_FMO-u{*0^Wwvt{?aMB~LLN4#KZn}vg%A^*< zYF!qN<^xAzVS$K4)gKp#ID}Y~Skh7Ob5GjE##dk?usoGe$TU=k%5PF|^o7v`&j#1+ zgn}^6lwbplQ277w=x^l<)ccE!-3Cw`Br$A=pV*j_|<)gl&odrLloVW@QsNQ^0lTv(P`t>dmzK=bhN2-efXiEmZB_xagnSi zO%RY2BIITW3vs_aWw1-O)4KROg^4G+lpkhB+^Q3(jX&{u|0IewW2Ndp+D=2DFo4T+#gpFN4=jW8}Bm(xTo zcb)+!WpDQQF)Hq;Ore#GQhswstgHZxW5D%?k5QV_U*orQL&p`cww7mn^>G3(XCgW> zs@LDxD7nKx_&hi15@7!~l6%(C4r>W$5;7~Ev!Cm80pfE?MS)kVqPz!tC3DPpA{0Ed z0-SdqueGqSU|6?KOF=>5h9baOg2{goB3Fi3NE`(Ht_Nxfg<%6A8B_NSJ?s|o_lEp1 z8ls;G7vU>C+5Zkw&!P91B!@s4{oY}xkY4Wbfq?Vyz*JmFe4QRgz=$(?R77B-pLr`N73@Wv-F)<~r zq2KTwu&nyrXG*ErS7bO&C@N-LZc5}o_w)hD0v^Vrz91z;T#2gLyF4V)T;lXiP1R7u zB{qV>z1;qc@7|8cB41XbQheK%h=Bb3gVi-PMw9c|+4~WB90ePB$!Mdpx_Uc_ynFPB z^K`t79vHZr0KXHr?UwSMs+RrRU_T1y=<}c?cD=mKP%>r z@@w&quWsbtKB{AU=#q@ zlF7D&Nfio_ovMmH9|ot$p|R4G$)T64Zq|La-|Eo&=R8&4yE;!0?TOi@yJchys8njn z${`vW8q4Nn<3((@X;9~>xHAI#N>Sm%EWNt6`%W3n* zXs)|ft)VwI%#1buO^E1~UC9B%ZtTG4iNPA7l=nuwg6;rK9@EdG+#?C^QF1hp@i7+9 z5jFc@FuMqf=f@yrAGSD2{JIULiL}yKPYN>X5;kSO^LW%FT*o6^M??JQ3g{~1au?3H zgNB+cex@9srw<#O`bhnhhQR>x^>NaYuP4xZz`uY0{@PLz_)SP->F4j?aVRy#eb{`g zV{i4_=yR_uTPGVD|03pC4|c z)oHZ=S*ZFkRQJrkn0TM#z_e&V|a&Xbg+=9Ut!9Q2%Mb{3p!Gfw@v(~fa!~I9lHARgwM{mfa z#4ZRvse;_iM|G)b3Aw(JToT&++NZXQ?o&5`(x-=>3vt`Cm&}O&!<6Y2Ih2+Fs*ndK z@9s~*s0n1c2=|{zOrOaLU=&$(LE}AI!DhzC(ZxknC_sOIef~}fid|DlxL~F|$E0~A zOI2NFcfj>I^3|=RDJYXPy_xS>)KMZQkVlCc3Z~yMZ6i$hjr{rUEM+EYkaXS25MSr9 zSTybfpR85*Y&?&KFd&`4cb@+Sa<*~#c1CZ9fjZd09t!fVu=Pa0CAoEW&Oc1KTSfFA zOw8fUEYC(n6$lfvF&~)Rje-E+y~s30YY(7mG}>IZxU+;gi^-Ic)^Zy&q5}IxVS;XPkYeq(GEY4@ETtj zsh6(}&x--(+vAT5!0>4E-sCR3$US>)&}~z^6O{m>+^t@m;%-6^ndA)u?!5pjOH$#-Me=)Y~0wMtQ;oD zMNS!7VuTe0MgCLpWoxR-FXw}!7ku7*hU!R0f~?7Y!U~g0o<4lI4W^8L_wFMgg#q?I z=^(7;o%d5&)!MxRVJ5*Cr%hqtd!C}lX$SKk(R{HZ%NNG!*46csJcg&7 z{(N6)>_FMj&SBxsW_B!!0&h+9yYUJhB57bRgY+IfcgJrG0%k$>V}ZRp35@NA=8f^^kXRM-I(_{3 z^?eqgf0nByrx(p7ady#k^9l)_#y^Pkk`omCWAdCqNoS<(=$K1sh~-m0?6Xw7kK~xD z{pIpMlZI92@1t?X&+ArIXaI6lPr&^f=~a$niDIb5TE&6-AY03>p~#VZDkEU|tU~3G zojp1GA?B9DE7+?7C-|@jmbU!+(_g#S9%{Jo?=HK|ToD=O+Tb_@Hm3%dGxp$`!D-M6 z9r9gSsvgE{7^|AW2`K@c%(`E)*a;^Yj$ou=V+DP`fq^R)OvSzT-&_M3uFMsnx?czH zf@kp333gG&TRytaA&`r;Azn5E%vqL0AHugEc7F2Z%NJ1@qXNrwaEmMf*=GwfnsWjn zZthYE;Qxq{rJX^DUG~og>{kM>QF+;iND({f8%9%74J>bk213D&p6b@;tpf_@_Aqt1 zsG;`bCr(fSCGW)FRGW}Q-n~}_*CR))^y<~C^4ov*oqa6(>qj^gwtkk6|0{H7>d7gSb1Q_C#7r3g7ytAeWq)E&i96l3s;j>kIyuxl{ z#bdcVTwEuR*o7xpXJ3YeM{Fr!ZP#k}b=cJfLnt1h-<5LZHE-0*5$?q!^*}+t-YBkX7+&@w@!upTubZ0 z>{w3*NS6(LR~P#V&>NCj+MQbvFSA+f~iXq6OWn{IS9tz-#-?v66t$Jl~bT8)R0(q8tXp9_)m|3^l;FK zuqTJtuOsNr7|UUQEn5E1lNG3{?5I3nGPvVMV`NH$!9U|r0`+0cSC~w_ygXvRcuoB7jFy#0Z58% zo=MGy%u<6dCTx-a2c`F6`qs(+UE^hD)Wt}uPYpMc?ZF2xe|#j!dK9JZv!7*>>iDoXUf>NxGkj~`bG#i@?umDw`=cU1K4MBCs5@8QGx zbIctC{D(`xyGVrNafGLG&eVs)MRAh9geRC4vs9n*>oQ4YBC74;vc@kUK@|T zqqCUGqGMoS5HaQHI^G*cU0_5E3N^>LG~<@y6d4+th~fx2XM~iy+su545X0}K7WhX`x+iU**r2l`9P3$D*6p%xN zrt2m9P(I_UE!nYBcYZjN)6mWLL7bBwRMDZJB%BhTgoHMvPQS!4g{1d0@|iyY)0?=F zsdNW~kNHh|PAtRv_2({M{?3)KI@4|>cEL9kimZv&cliRf+k1W}^032~>ljZ(jw+#o z4ZQ_#ZAn&U!og<8EUtb=<&j%G{uz`_2F6JlxFMJE-UKY&XJH{l=Dkqr6J?2r5;M2_ zoNfH0_hl(0Y@c#unUnnypIGOpFef)YxB(1|jHOpR3mpdE;=eS}e^ubK?15wYAQ074 z^}l{rR7eOpAC7D_WA*JI>oZ`A)Id!JKP`Spv>RS)Bog_WbUM~iYNzr11d1} zcG!Bv^oi^4l>(`W>`4m@pQu+~fIK=HU#Gb*zlVKC-(uEC!s?RwjX~^Q=)Q11&9^57 zD=J+gWx+OC@~ti^j4IWxOEJ(q^m^ps?{2i0MtxfsEAMMajznqiGmAyhka4Tv$Fu~W zXle=a37JQtQto+9e}9aI z+XEZG{eij3p<0&h+drfgMLM7=hO<>iWLj_U1;zm^ziv`fb(?`(hm)~c-02tzGpTae z`hdW|45){Q(2|XR%*QubRHey=!$$d4uZhoC!vpA<@82)qdEYI>%Zo(wU9uBRY-eAI zQ`+o!Ulv&X&Z~Ue;5%PybP(x67i#l~9TL{XQX=ED&_(~62uM6>BFJFhx~s4rz4_{* zGMI!nC>1p5g((H%wMs^}Ne2-8O-$d=QdQUH@#@ z;0kZK-|N>a`UXrc=>LnJUK*9Z|Cs#ZvCL5zb0@%%w*sib&;a%TD&|uh#w~HCrKOEU zIlpUyR8Zzu*h@VypXft=B&gXGS&IO+C(7#W>_yd6$XOFMtcsvTxE4xnZ!+%s2<^a!PTcjJ3Y#vE@| zeW3-E*cGqeiEIIN^QKMxJ2A56OFQ?zeNt#OboRe?Ee>aT7<}uw)nCV^su)E~OXde4 zCUKuX>yl$-)Zn+r;SL@GthylN<4brqI|E0Ar8n%78^xfm_H;N^n#K0UX^?~l&+(V$ z(h*h;r!UAF)@1gg6ddd4=eN%81$&JH>8z$fSvFu&&Il$PHc{y(}AiG(7VB10sJGG)k+C{02_GG;3CP?RDv4orzjv+QUBA25J?orPJs!{A&)%QU`~8~UJ6P+a1_K=j9YGKbM~|p! z69lCXK~VJ5(%==T)}C+pW1Xw&QC(X6$BXtt5dOWv>4oGM&)#A&;p*v}HzqkXJF zyQ#%35O~jZZM9$K3Hy6?<(r;~Lp@1j za%bg|z2py$D9kA|va|B>F{#q-xW$xjRv|~=PgPopJtD*g@^4KWS$)VCc31__DgS%Z z{zKHfxe^T9~MRA1ub#tqyguuVw-mgn+Cf^*-{{Mf>|K`_5FOy369xv_W z{FKF0?KHZlx+3k))YKCv@)04H{O@JR4aSB!Rmd&hEs_O6ogM}s)nm~A{G`s z1qH?6)4piIW98l551d7YCf77p?}{2w5=47@J9&a0OTP=*g{~dWeW4tinbN0nD=={P zMFB0QbzE|8PvhqvUin(_>z7@7ZpiG+51mZIf@iWW>|3@}$!Q1cWf=-44*mFu>#ZZ= zKGx2vVd&{lC8x)x}o+1qhl_t}4uoZ`aOx$mB^xu&{0h~HLBOf3HX{daQO zxq12dxwaqE2M=tQw%gXxk=Rpj;^E=pzoNiFq4tx^Nq@~1rO`5t> z4%0U^H(PQy3hS_W2k8=gZ7kw*#aAX?JpEyM?%cV~f=g^g#l@6Fd3)Bm*L^Je%&Tc_ zy7B}GBH`fm`%4Tv&OFn-SzfM82=`QY^_NrB25YvLc)Ct?Xm*D`UAH)*yJqy~;@av; zWK7IDg1C9}rdFCJYi)2yq3y?=vaZ7$3F4()*X965p7*k+r?!e2(RRPGry_{6XU~#H z?)>s)-$_Bn@Z(FDC%!&(&O6J)>O+_OlJ7%fBYkCMW%;{zSWcxYf6vYTX;ET-vhRIm zCFR|{CYwZJ@w%^{-ws8^htAIif3%BH5}CL)X3=e}CVhv;h{mMV17|7?d#<;!f>FIC0d5@h?`K{p&1wkI>@~=*c&(F_VCunYG^$yGB_R*Er zVcfCXUT%IQ$$M)))(GoF&uc7~T=m=A_YAN6e4dR`6qTKwUBo#x-uotVh-J5;;(3Ka zp6fHr*m~MuSe!auoUbVGfDmBQr!p0RA7Cxd-Xi*zx#{ES9%6JcRha?rT zI^DQ8lb^lD{L5LM6BHjg%J-RJ#ptdRvDc~p_~cY;P0e8mPSu!K>}p3jRbq4r5qqkj zXlZX@+o8Z{>FYUSt4tXLxzLX5OYsV_-hBP~btmq7jUCP&*HKAK;M zl*i3HnqTHmyM5GXyu0Uh?@Yy^slX%DynObQrv(JFHoPn-@P86{zn|8A zUBOXs;8o{m;4B?hn$I_7zSeblYf{((G2X-qqrl7W;GO4}E*GW))0VzOO%n zVpkfiZd*Fj3d4@9bA`jwPoky$gf01lwCR+|&Acy}AA9Yxq{6Yig)N5yH%njV%~}}R z&gzrRl*V!sYvycqdSnWx>dq7Q1srHwFBU|iChSY3c-_o`d4l_O`x_E+g-`xn!MqH?i-#W-eBsZCMV#1q z0ZwJNk^2P|e(Q(IZ&FSD{oUQ;u&V#sMNrJ7l#6+xcYdml$2+J|&ZBqcQQwnEh2PI_ zcdT~DJS9Y_5;?V;51XQAe=YM)a#sD39*HY%e)+PrLr)R&xmR`#a*0nz10t!`Z!(P) zIU~-?>*Fp-wfI2gtJj|s>xf@%Y4l_IK|$L%I6~ZieyZ48I!_7sQN`^0OZa$E+k*Ama5rwN0M zQ4_1(y5tx7${CrevV#3`5g-I5A#K}stNR2` zRR9D2%PH~<8>DPani?omc>}{!8|KbJM-yj(v7euxXAbQ!A2_Mr8?L|BZ^p56=T4eJ zhu)B5abkz%<>imodao`7x~qB3Pwvoru6N=U@8sm9Dfg+Dmpa6{!b(^&g8Wl26}K9% z3;{iir01x{?0rEHS0=tT%iXW6|Bzkz}&;a&{VAro-znp%wr4_l4>4|M$ zd0e)vb_Km>5KvcN1BTBm)$?KXXnVfPsd3>}hUueuGC}@7P zl|Mn!Hd=s(@pfp@wK=i&=Vx0+pEB*e<|ICk% z8#lA6s?CqTnJEAGam!XwecpwudU{*!dW&OK^1QJj=}#sdw08?kbCB72$-es)>y@4# zA8jNje|7Dr34W|A!rGLiWHMb09N;He+wfcWoBdo$&w&R@-latr4+~ztl>Bh9Ai4tw zrNd4&i#+nKv!FZEV8873MafUk&NRNf8Pb_&Nq@o8@~E*%jwyx5)vJ|P`mWc_Y+%Gv z3YeU9Y8X>dQTdQ|jEyF^p5Eg8O%e8q3Ep)o<$$yUW7%a6GY`cW8D+n|vgeeOmv0>Y zGdpW}|Af%~{afTO{}OH(862$qO#7fmuKZHRi`)n+<-!BXSB^iFi**;E`tjojO=<@A z>)<#?(muq}|$=JKAa9v<7?>d%e$ zHp=Zh=rymUy=^oCP#OD3Z7Fh{>>XRjWO;dsKhx9y zmT7(ck*;fIBkv!+j$iG~x4zxFT3uB|g=XK_JX9NYS``b|hHjqK+R~DmUnAlcFnVQ) z=b!S1hNIJpI_bwL!quyId&?9Q6$frBt@^O;*7JGz@L@#<&&&PV)YRam%;& zyBnw9q##7jzS#KY@^9Y`6Yuk0dr+j!_;#6?m_R9E@}3wTt`!e2!LqDhz0bBdlIaaK zVrZyJJUr&cgKI=6O#NKS)%hVt za%0Cli&Rg&xl1Sgi18H{7hgd4islD0X5Z?g2K`ny)ajp1)=aOy!gMO>U`_BAAx&xj z%yWei?vkgyyc8A}7J|v$T^-mnt<1D8LF&@o_}g*Kl8X`C@;k*UO^V%ijmd7Fnwl~% z4GN-dcNTEyEf!o|`dWJZfjd|59idYp4@4ZkmNdvkR0HBOB~P;7E(urW=WsBNSG*>D zRwtHRS*N%r|NN-}v1`v&D_dQBuF_{_Vc}O%QDLMgpDP*D=^ZCSR=5TR;T=0D0ylAs z99(;c9q8)fqF=X}m4&6BQE8d?MNOMxR+13V8T|*;3f^P>cB@GSDU=TCEzDCq63SXwt>wO2k zR}4Ek;??U6}ZJ*^Akp!dS)Ug)f;3s80h8s@j@`{5xWs+TTZ>Ur%dG$y|qy*s{8YL=ymgySJt%G?Z$WSD6d_+CKkFFH}!0`Z?E60AB3{5E=#6C zK26Enw+0$!nrYh3=awmmLK$_U|J5N1!a?2~fAOK{FP!{1u+THrGwe~S=UG}e)gu!b zXYp63+`zy<+^Jt#AH_>nUOqpty#Y>zG38mPD1?+ZB1m#3I~dv>O{6{rdY&i@etkjtQrwf4*o2 zpf))^cI6F7d7l>c4Z)~*S zPWv=CIGC()dwWmTl-Nn~Hq6hL_rAGepyBB*(c@Fu1Adt6JXAZl<>$)Eiu3aPlzN#r zSbpBAgL@~=tKsW)K0dl-iv1X;w4HEASsCBsw6sUr*?TDow6Y=GK79=lK!MxUx6fVt z{EYQK9M^4S(cP{yX9p#LLU9)oM{rP(@|7!B9F%4cy(blpv1=gAU`-+8A60sKd#9k( zkm5(2$&FybC!9m7a;zg8w4JZOFg(k!0BQ=Ll*1LXu{X{`G{vu9?@%7lxRjojmJ8tn zJBGpD&W?%r(A~|MpO^P;#rlJo>He?O%l#Ep+mvo7EUzw2q#1A7XZen$zP_I6_Ik$c zx<{n5^ymvNbwKMlUDtAOX=CZ)&)uMKPa~7gZnv|ut3Jhk^!V{xSfQ>;oAnDWo?%)? zK@cEF>w)ns6P{j>y7Ux1Q>VDpp1C17IG7-u2CFx`GBY+Sc6|^ZPb+n) z{Q_q?%XS410;O#?K|D@RSH<_+CM42@?>vB=4B?uVQa8&m);VRcrlzK1X`+nr=+UEu z*1RpZLUxO&u&_^d=^|agCT_Zgg$07pdak$Ua5&R$x-q(#Slr0aQ_niMC)XGYfp$bc z`(58X&3#Mnc?}e_ucnV%`}%n9+_}@ZVjUZYjbqnW`ZoUT2L78U*(3n6`U+hP3YB4z z)1&yayHb4|OBZ(H&K4CV>pi#Rexe4k}S(3E3(Uk)lgnD{jpDZk0nwtpa(J;s|lzKtGrMmLe zNter)x3)}SwUf$NTSysT1*C=I_zqN-%Dyli3Y%J;a#9tk4d>+K`uq29KZ%H_#IF7Q zwIM1hN~`R~bwW5n8g-DtuBRxgiGQI^0*jrNr(4e8dhKKyHsgZ%0%OX_wlF{`4n`IsJFl#m8i!o<$r@cU4w$*#=Z zT8S|)H#`>BDfK&Y>Qr5#;x&$qx7SlsJHK&OvE~1#9lW&Fk#KZ!5+6HKqy0tLR8`g2 z!(nOWN0r>k;23F2lGTNJPV|+v$eqlMkzQou;u1~l27L>8K;!xNag-7^BM>Idb;FiK z#S_we8vH(13e-m1kN5h-yb{y0J)GRuP9YZ*p zArwfbj7EOz43&0Uv2q&gO-)0_r!P+{3uaO2YEwLYJnOB=@!z+Lwl6h2qWlonL5SRo zZl@NpKY>prKb$vd`UESjo-!ET5Wi zN;=!~hxJAzF)Ge3RX0mP5GM98Tr|PP%DjiUm>B~F~z@Q+-o0ds0 znn7EF0>71{`SW`%#wgZr;tFEqId~yq+~lwZ1!O5d)V@J0MSXSkfcYt%#W4bi+jSkW zJmJ08C_7MgaC!1jrb*esO&pR(nhu}|k^i_n-gD1gp%oC+#%Ys^Ky{_} z1n2@ADR%uH?Zdv25Eo}+UN}E@R!hrNy!d&{VD{+MGLbXS`XSL9)TyeKE;{P{BfuOV zX2&{mZ>%g1*6f@+P|3{99M-n-yok?fapp%6x_<43H7TrB3G3&2S>j-tXGB=f9;Qzj z5Kew!K}wD!p^v|F$B!iRpsgIov&JHTj&mY}7Z*m71Q*=u_LePI$|c$?On;B|I`Kfd z2JbTOEp~r>FVC(u#b4#YH|LoNC=MjDlaP=Y99c$RVc#F%F4+n`=Zw<`s&||^`_i#> zO~HgHUz{Cto%L)fne7uL(V2pD^306euh!JSR`;7I`L%$h`%c=H(0Yw!6@KXLeHhBg zk>aM9?BLe_yRdKAJiHgW#}q($jb-EANB;i)6=iSUzE%8VyOn#zwjgEwDV@*YC;RXJ z!F2-vm$vIPm9z%7`o~Mt98jwwn;~b$?Ku}fmVA`{NOv`sbrhUZ7cV&3|9LgOclU1k z-ripFiuP>v7CMrLaqUI%pn$zUYib9PNIyxb840U}$L5 z;ZWrjPA8}E*xNKDc;9dI$trzi$5r zbnv6{TPaD|hz!H??wnz^BLZre2LZj`zIIn>%70 zQWh4r5$I?qCCkCD8CW0aDv1wdQWiaam!0@0%)O=f-IZTwdfxQ=yVx2Ntlk871+|#1 zH;b!)+ma4meN!fA8pk5%9irEYzv>_Ls+=E!y_Uh^4L8M9R2k5kBqh7{J{eN zW5wNE9eO8E z!E`Ja6#ET|*Zy8$4UeH2qtk7OncT!DBg4i9En-P*E?nlT>0(hlq=(=)XTNU(PY`QA zf4ESU<3 zZ~6Q=_RX%$`1oypuKKC!3=ZnI+$bq2H}1nPZ(!t>tCqW4-&y>LhJnLr>ZlaBMQ&Ca9X5U2`BNuAb)3nW?I*KbOa7l46j0L5oJYId1LY8Drdu1${Dr{KJUkkmSY42PhVU+pGaQAG#Oq19SAd(fcvR1Sd(rn24mrY zE+ytJbuBZ0umRp|0}AfHgvZzcU* zoCR6Ns~NXx@uki6eOK`hqWzY3!OF__&Ydk6E?n?Ic3@1_k~9K3;c17l@27co=6S7L z1ceF{uc+uo4oMpVP1TZHgAe)%WOxctPb==jl*~I66cW1YB)H@+Z&HwatDh<9eR%Jj@k?j1pJEzJkeY2mu z6ciGw!huceBX?-Mxoi*l;n$g;WhPr$eJqt3f)H&uz5Qny#r)M!6*4NJD#G>uFeKxm z$+WH$iX!yg_S42k&|QRow?^Y4o-wj2Fw81yy2auj1o~o7=dmM*7Oz|Wiy|b*xrZR7 zkOD4^uLa6ACY&uQLL4Y?=#?X3_WZ&^1quO~F@O)?S5~G(mgcs$HZY4=I7dE(g)+eM z1`^a~pcs%O8Yo3yV;5_KmnZI1$UUJG_p85K$NjuU+5jl)6vV@Xgh>>;O#ax>UtRfd zy%jvf!T9n#|5!-?^FAOi4md~fJbU-QQ#8=5{K~NE^7z! zplH-^NL>uN*W1%0E+iD_E}9Cv#+P3`Onh_+?+L&j|Gt_(n(xD$L5TW=*eU1c=61d~ zFYiZRfn9O-g;6j^czTbwv8OCf9M@B)>5`=-%7oar;-_EUUXwx4Vb?QS?4^|WLTJ`K zBdqHv-jA?tJT0$4{KFKZH=B}*yJ8#y{{rpV-5z9~Gj{A7eftlG^srs?;@d(Jy zFFq`Zv-;=~cY`xHwA9sUPR5Hj$Z{q>{$a9`VM4}LuKg7qJED%m@0R;cUTcIw zhM)ERtUoaas4|EXJ+2*dn&Jqx>Am=3ikjNml(Moi^K}1MX~9f*`<=Rzd6tdagzkvQ zF(iPi!~UuLSBiJGT`Z8jP|u{`Ivn>0z&7MNK!3ia`+|suA~V3Fc(qz? zJ0C|x{Et&qOY`%*L_fq8_Vhb#;YUV8&a9Z+<~k7Vu0REqUP3nR@Dp#(UF+~WxA3d@ zgvQxV6KTids>jY9tx1Yb_cAy!_YQ$2*v@8MJ~5JejPCC;Q(*>Kp#A0)NMwy z|FWe2NwP=edBg<-ZY>mRsxak1X^IY0VD$!s8FVj&RU-Dpiyx+9d;8YZloY1cdAA9G zi}*ez=7k?+1}Vt(cwADhIYI9T%bJ2Px%OLXSbp#K^jq#9<4ahn&CJa59@^>aZyU3T zkBsC!x$utr&6No&?$eK3ZE^s(&{=1T#kv%VS#-nx+KHIl%_n7#q*e)TcQ@L12egkXH11AS(+Fu&oJ5ZMuML&d??!HH{&Tm_jn3 z$^QQRyM(4iLR=i1r2QA&$JW;h{&0j z!b8c85V(X}X!>|3#-3+=mWDjJu1-8=fCO`Ehh$wh_`hl&b? zn0^j{d{R=2z|j90k?2fTp-Nq-z0K1iaPBk~YUJ_P6vX>``vVc?IDPsw zNcoQ8rN7;d1{%>vjvcFlO2bc>qD1P~MY*podronwtE=bXE1*WwYRxC8wsR8SMkmr| zCnuR?)=v%w^4y3tY5{HA@U_U<&s|bYZ5h-j>?<3XtPg-l6~x{B4R^tt;PQ&Ra?Aj~ zCeN0hjxPR!=!TY+!i;~)&p#v&y^3USGjnqqpv0+cWUB4nc=eWb6xjUYF!(Pw_kttc zv)ug?poeB`_jBEh%3fDCvO(-Ie90tFw;kkiBUG(dHm$y}=&+0cX#lIj7sSq3+?R2T zAPGs`<{zWmwZ9^s<*@zui$C8QwoHB0>0j%}n94~!2`r?TcWJYqudld>NXQSHY`y1F z+iLb+?db~5?a5uIJOsJfZQvGUc+gRJITqs zV(F37fBrZ_8t8m-iYHSyV>2ZIk2$tW{`>&|6Np#2NAK*UCCKP!euO|2lsDuOm5Fko z^>*hA)a%zZ!CMD8MQs$ zKq^?F*OE>`E}rjEz%@jwcQ2Y*T-WjNgJ_KKpJ}cK0!iTgKC zs*8f}0!Ka+sP6*zVLfBx?SIEQZo6+xh1uHN?Arg$Yq~+GsiU6b&&N|rW)Q~C`p1GW zUCBY~C~_WBf3f|ZpMH_s6D%|`xiJU?^m?hj2}F=YOsy>~jAh_s3SRT#XUCFFZbdIm zOsA-R>fWwtd<1(|_P_xZ;44` z0s;cc&@2ozqTErK#acKCWo_-vMXz7yM(o%vFV9K%g!Vpj0kKjje2u$7mL()5^CI|g zHx=PN`QUr!M(`mcMhC~?L$Uj%nz<`Pw%*!G9=R3<&D7R4jFB%%i7b8ZR zAFRj1_kkAdgHl1#AXtd{b$nz#JwwatJOLcP8Tf%7cg7F2*cb5vka4YLCJ%CeA@Xb# z9dndBtufNu=Q_1#!1DHR*0a;YGT~ zpw83s_ycJMGBCPp*RIIO$a2^qF0QUB-c19j;W=(Uv;%^Tdl2V;WKwn`narZ?iiO%j z%fLX5*aqsH1xVWFEn9X72&_XrrUISG94aY}ihQfa^|5pKq`t zh36Dd!&%pE?B2cm7wmFm{Addd?O(5DPLru*35YQT&d|Z1l4Mq-9bREg6Mmrvo;n#J z2ewA87$oFFvS82wI41ny5OG(ALiyHKKuPH)1K{Xv38fr!U z0#S$gf%UZwntzuUT$d4atywxuD%0?mo_{U^tIjFh(2jpY79Bq3&N>!YAY+&od9#Hnr~#YCAhS``{Gn8QmpilN$?yUphOF zgftr#TqI3Xuz=hiZ!3fF?TQ>{L}FEp6X{h@ihw4fOX_a($jq1KTepz0!v~RvpMJh* z*YV{AM(<0&&2}6rg!gDWn^Uh{$y%ri0|GV>aG@yL5Fn& zX%AFq7MqwL*Y2(m3~<~aH8MOLK%&Tnk;B;7q<#pwdSi$Zq3rGL?J&;V)z#(k_m_cR z2k^R;))5KrP@_Z`-zQUe&)J2K+XGJp#0p z4&AR9-~nu${&|}QK{ReMD&^qt7vm^#|I(})L^+yA`;?l{sYEpd#Jf(r66IvHidk@- ziZUivj_M)e;;_0hdstnaL$M4ytd`95Fdqi8IYgABhjX%cV?_=PH~U~cXPYP`NLbMD zX=3?KAap#wT<(4*!1&R;fWW}~2*I%jj-^o-3J}?a9^T%%k>&iwN4vGJ{QgqY z{K*k|`7f!K#-}hsroT7VRNgDBWMq~Q6r@JbF9^A+!AlBZe@S~4_rXF(2vLi@pOdV+ ze2g#XPQqqmF?r+mBf24tII&r`3VQrdA0pm{@|Md0@9iedzy}d?7T6X7VXJ#&xmQEuXgb=Z1mzP4= z;toF2EWM|opim^T%tYT}2H_K#T72cbXH&1cJS8OmQ08QM*eVN#)8P(vB=28>nsLuk zN{{v@4;(zJ)syF#);a$y938-LmDd)a6G|kRK8<=VgJRqpzLSpy=NAUl&2jPZ!Y>}}xeC!VDD+w@rU=5n z?loY$5flXQy3gaIZlS~Z7wSvjCfmI8$?2@gb{|a+)=x^MtBaS?b@p~-o5Vfb+Qx0- zHAS7@yr;FbwG)vX^A;1*8Aa2o>8Ac8y?%SjC9j7N9 zdT^1wf0w7kzX$~uu09~M!9F82GnkDrD)EpgT^N3#zV|qam6Z;st*vb*n5(%X7fD#P zA0xHL87FE$Za3v)$Bv~g1Z-rlY-ZSlZ3)oSXy{^~togtLmKFC)|N83Db~5@C zcAH1Zid&-{y|E??Q&auvdwxQmB{eIXI}@c#Vlwh~s8z}VO*!9|0(a%Y*eklw5Y2W& zRm~H_SEyzBzZCPJ)yChwYc*{b6odjjIx*oW*^PDH&}@^$mAK@n^N3{Tj>>F%jbn~8 zvnpbM$6>n88Ht*A3Xz^B{iu$V&p zg=_#?1tAik7=r9Qcdk@~;R3MGt+}h7!u3UAsgL4+y?d338FXsrt19?h{RmVPy<6y8 zTRrQdC@&{xuB=P|Puw#w^VgT%hhE&G-OG;z)rr;q2_#8VKMogHfg*I>|I^k_dXWFQ z5pG~VUcU=EG~G#fuxqw9ZW==@5!UY$D&Q*&0J45SVh77bq@g3%LPPA}BYq_%9>`a| zsKQl{Q+bsK79W6xtbl@ok&)6l_<2 z(6B(@QedtEdM(60C9*Z0%`)^S&ljfpoe_ElhCR-~QR5!?PLsYCZXXY|^I`tNuzJr|!Q;&1m(Fm9@2>VOBtg@wM>o zOM{0?G*{*t2mjCs?tG%1QN(`!j)kplgZM?Vx=RU;#=G2xoQmF>z$474cfGvM)8fO!mHQsbW? zv?~^O6N?GnZZiZ7koK>BIqsQ`IEmhy*T-X0~u#Eeu3;YY&|?X^cy zksA|l@qKLTRD56t#m-;(2s?MgzP(d@Blis3Q-OuM7p$-u-B^~Q|#ay#IK_h z-#K-#0s%)W_Ry=--!^>d>M|n}9)DJ9IUW02(HO1e=8)PA40%)6a*FA-)Fv#gxvg1`Z$apH$r}W2rl62S=I+H5GeA-tj7U!(fy*c<8*&DaHC$R4Cnl-+|0|06@=nacwBx*-uX3tznP!JYLC1P9sPm*qg zAck3EHH)NXdAYJ*2h1L4h}{^%5)nvBfI&5g*gVp>Z>s;$6Z6e7eY%|syR)!yINh`t z15tRlA8@&4TbhC`8vyz#T~Cg*0kqI^h)a*E&2x~c_P{Xs zosmPL39G-sS%V$dT?RlGNaDhFMZKt#bN?B{o|Tz-{L9VKr#(GJFZ1&cp)wCsdpko~ zYHe%NR>&qpbHBR_<1YSe)z`U*xu8D1+*VC0!+%jJ^{cEuwJlG*r(wnC~)=DsUQ5y>sOy0C6QanAykl6QRF#0lS>x z)a-25i$+&7D)o9j@5qA;Eaqx~%LL`aYwnylrx$^M=9c}FoA3x?-+rgwJ7xEoi22Q=74-Dbv zO#zSYY|x7_%&LVRGJsX)j2V1DVn+Ee|{$_$rSa`${KaU&2hBg3LV+3iAl%1<4mpO-)KnVq+H0g8Ohg0CO@f#3VXKP6Xf7 zT%UIpq}fN<7i1pM2IB#p-QD>S)P(=-r2G3U>CnA=va^ z%_~f(#*3R#LO0ojd>Ai!545?^mHkj8{J@fY!oyGaTQxQ{-9kWH1tK6mE#_wnd2KM* zeg4sFcibRhzVI3Ei|SwmP(V;n1%(@b9NpAAhN?@>0N5b8 z+K?B!^?%HWWL(Caf`T-@5FoBCSc=or(?#qnpX*%L>_zZMk;ssWA!-dg8^#Mq)HbP> zSQM81|Jc)Gno0?yTyyGAFV1t?+1o#Yx$lH=*Y>D){=h~cRw`hzynGlnBBL?53FMPQ zSb{;ks?gt5Qd_Z3j%Dc`!b*fP91{w|3cw!YT5UFxPSf9xc9wYV|ChER2bK^E1D)BR zb_>%4`mgNR$vlvA5HsXyhrUv7l97|cNhGlP^2(kb-m5=cqx=XxD@+ojKl4xi{TqPd zeMn1-iR+-(Hh3xq8dQW26kSr`$6nk9GZi~~J%kN|Iy_@QLqo%3ZDp?F^Ji9?OE^_!~`P_o5>%HO+iEcCK{&) z#`yXnYOKcxx90+&bZ)gm^uc=Oxary?RV5 zX@NLUH8jO-CG9ZemSJ#c&W`N=?=wpH24lORlze#qeiMbV0v8uo4o3X2kFOp-dD80c z9t1}f6%`rspg)qsg#UUY++eFN$brza{p@hU^B|Bzcr1zp#*z%A9|8u4bb%ki!5Kh{ zC&S*#9`63XKFKnix#w{%^d;dP1J?HpV(CQM#L-Y*{Vy{VCpoc&5UR%Xvv|v|u z$J5hPcsj=>xLSeeG=8XX4SDQ3hyuf0yah7|Iwa@JXe-sh`F<)VCnrA8A7)h>kH49(Z=VOV=@hi$sF7 z2bApNce5ZDyiYj5Zxwp`w#?#NBu-5&EciXI!$|yq=NP!O?4+esJA62}3q$^PGuP13 zO-2`uL2@^46Yo#UA6Pr}`)A%mj4OAp*1Uf|p5}e`JwS~a2F7qDL*6wttrHS@LieML z)z5aJ;R8@66EWFzZ$C|T%R_m#zN=$5HSfZ*f3d7JS-3}*8&b61|Sun4y_wU@fGhLTlgO`7P+K_GZ z+C0y$mMpx}Xm$h0lprp}%FVrJIE;J*kp@)ACm&i`PPrHZ#pr8PL7g;(wyc$=9s4Y+ zwz@iAw3{>w(a@r!O4$@~T%++W>|f{k$pO4FEr-Vz%(r!6;h>}k!#OZ*E48igrT*>_ zz_8{`G+kTw!L4d*f{5Ipe~`LHMf&l3l#sueyt6qeGHKB&15p-Y7bb!uA_5>;bY-J6 z9^{Oi}!<6U9SmoMLK=HlTYN5RzB znlyN>uOpX^*!kk}OWAMrcHkY(&Nl%ksxY7|fgGkC%hMe?LkemlA|i3w1@s&D|L zM7i*&CB8TBuVBs|Ls7Wos6+u+x5^li!DD!6@tfq#v+!SI0U5a;zkcB&;=7r_y2`QZ z+DAU)r6x++V$2Kk(B$^oJ2O`%ilRqKRi>CUAWJ(fBV!@qi#B&{GHeX)-?!}(a^7?0*lwLI&4Ma3u5WUEYm)7$D4u*hap?N{>kqFT_*gIe01r^YqmM9KeKI*GM@#?J zX6Sp-|H>Trp{(0zh%hn%m^$iWo+^O#x8yZf3<4{ia=$!ym6!)CI00gA@`wA9M zO6nt|%|N=#v9kt-hAiC1uU);0@=MpKm-osQ*Agiozthq}LPAIe(>A7ej4@-@0(y5c zE|ofeskF3ok>{WE9J|{oGppU3GhY$wLS$~1{CO|0J^{|~?42DYyW&+zE^h9DiHX~& z_aYZn#?b`LtgQptj6Eno;xv#07(Eh=>c@dII)tW|gWOup`D(x!aXh_3)VO3D*wUGA z>5R4SQaZ+*XMdg%HGD}6&G)deapLF^b;zc{P&*%?9RUxK(>`h%(baWz7SP)~2K?Df zaWJs3)+hlOv7N>4yO&p124G5}(*;FbxZAemcr54330}3D+cyz~*?1jK-}(f9nQqgj zbl72Sm{B>2f_;1WkEXHOvyVSU=ck4~p&rql`mGlL|MWC$>)rMj3;AG^oq%>zF#k!+ z;+4|6hLyrJeRql@y34$y z;F?SY_BA9uIw@!4h(CNVp(`hdQiZh)p5|H@#T>(g63${Qw8yUn6Kh+Y|g zgh}kKqUOaPwehh7l#%35n%+54)RRB4vMeGlkZ;c4XGH8H-)z7xMzE7_&fLi6^Y3Hy z0{&NhOvX+*;yD*IikOEFPryOZ%{EqirWd}JffG1Wnv%k&dE!JGMj$XznT~Q298rD2 z>5SH4n4hiK>ZdT%k0{(z*z@1U#~o%a!nJI;hUgex6p`wNuV@1;`x_X~a3jp9(IrSN zx);T2w{1a(@*xwIKV~uMoI3H{7(3=MOdb4`h>49o3_PHo4IXf34zX-n;&axyI6i*< z-BN5zb45gE3O+}T%$Fdq=0lAYz5C~`e;*%XXwNRGc zF^B=X=aR@JpJntq8k5MoCD_RaA7mlG2<)&+Nh#^2Vb-sXfWE?upF@zr(q2l8L> z<=-5KH8eh=5DM?y8Gs?qQ>b=ZxSOj{aely_m4x8cdinxh43*>v=UYAh9U)8|Fx;mQ zB~w!4$!BQoF)E6L@t}T6ah8Q#KftNSpsb{%l5<%$mA5v`;2BlXP{?p)qYx&W*|+?4 za*P~%z(Xc>OPzCZ+1H$K;0{JoFyFiLc)T*cRCcv)4PebE;(MvsW2YS)#`(SbYHI_? zxr2+HIc90r7HgY3%kIX;QuC?m>D?U_CVVO@Rnhs)@ZhL;@GyKgIvB)EQC(*t7)oGl z8lB*rLY-d-q;8 z(ih~zMr!h}<6I`Erf!0r-dniX@gm%HE03gbo#vZKz1nj!2u$Hjjyt423kSBvVBPnb|6pVVkK$ zR4OWkDAmTPsH6;SaVnyLaKApzb^U(Vz1H)`^Q`r(`*&aKTG#3-_Wq8a&-?wF-WBsJ zQ6D+__allU1lmmEozKwmv;QO}NL>s@AB!Hw}_TWfTi9= zXKM_u;Nwh#TaQDqXdnYpI>p8s@+mA4K7pID_a|p&E~95`BIyL^^KlzghTh)P$GhA; zG^8QF5zyD;j8$UjpEq+fb0k*bDSB$%%b0i#-!Vyh*ZEq1g@|y1A0FFIS zeoph`{F{ywaXZ;OEVXq|vn9Wh`d_nJsNRfi4NiRC_Xqm!BgjFcVL z_AfI+%cWAE2}R*}Hnu(#)(c02C%vBf@p=*s(_03iZ`tU6L_Et}i)E z0bcN$J?1D}w3}X)IH@C{at=_Jw5~zaXP(bXLqVifG*+X^`-;Rzlv~8LMtcNQn2V%l6uhaHrv! zx4)dM#PmcWm+xOCZ1aB9({B1(?d+%s2z=MyFRWOHATVLdvw^@H!DDI!0n-+%Yu^1R zxJChMtO-`1;nxSAHccgLv(rP)(~t3S4s>SQCvE|Wx?^9lpYNfNN0j4s0nu5r_^3Jf zr!Qk;^^my}qSVoi#XF0ssXjlh84e`G)77e&Kgen?|_fNQM#S?khP@YAA?0>hYXJ zzBXfTgc=P-tVLC?NGK|@hX8ToRfvs^y%O?sKXzex0u9)1e#u}m7f78@+;a_$$rlL8 z&uE@+k%~<3wB6|F7>R}^{T2~6F-%Q8vD2!UZ1ZWkiNfNavxWVKpeL2Ce|t^eQa|Nf zs(H0rT@$Ta$~?A>rDfdE1cFqJy}k3I+R|(wph5>E!g*gDs$AxH1PC^S2~V8k7r{`a#<%K;Q(B3m<%|Mrx(Y51-rT*_O4N= zfLmch!Ioe#@PhK~^S)`T2SOe~dj&id0oq-_YGn-Ql9RjQTOyd$*!cK-@Uk%pbr&VR zzx{>st62K*dCL~S1vh4|R7r~GQD!Qs#})sR)z*L1e!hKp<`C&(3x`?MpMN@R-(J8o zQxO#tBZX;NTG|q@+29FSP13Euf=$=&|rTaX=Zh4g_+P%0)|Niape9f!{xEVVRq21*3413(d;R zw5B|K@+9GT*;X6q4d$nBDtpm}g_1_6XJGeMnf#1e+ZTw1B$fsZH$UtSm3!W<>%4V% z`5VMPA!TSWJtYQ|j6DE0$n-LxCQ+m(#NepM;Th!NQIZ5mj0W8-murhIf`Kd~aD7~4 zYLVIzH4>qBXgWG+(#zc~i4t4BF&f3t&+&14?EgHJ2L-3ygJV8IzC@R%Qb{?u{b{CE zPEJm5PtS&b6;;mTTbD0iUQte6xx44%M-~h!qpcRp?I7jy(~%2)AG5Rw5Q}LUNDA4| z&wYI+Hu}SnNsou9cc-eb(MeE&H8Yr6)OqtxU>iFYt?&~y)M7LSd$=Ju;~zMPFAyRq zVS5Y<3)>qQnAWly(oJ3<{ZzlYRoROk+&GsC?^!nk2l!zWR6LFn2#!C1>YCs+uzu+R zCq=opnl~2AO}2!q^F5m42Ix^um|8^bPY_4k)SUpV$kK_BNg6$NR*ici?m->o{-7g` zJv}+-s<2Mw4aS@1u1AF274N3Gh*Pur@srawumXOij-5I9W{|}zw$%xSV6i3*J~D(f zGC&R=02aTkdORImAmQ4iTQ<70KHbrbLi=JHEP!I)1Z>G8{q-P1eTK!%u%(ZG|Gf3G z*hAc^$Sp~bJnVzd$P%JMs|+2jrULk2;A~sm(TmejR8^(RP|rZAf{QzAxya)V$nByZOisr z1S^X*ZFB`Fi)L>&WTUwu2(PH%`Kq8>7{=aUAq%)`DLv();na@}%|XaP;_malU~tsA zSr26}FlyXoaRvRCMOKJ0+J^f2;nSz{lvHRx9meCLgd=+Q?w#>SD7Frtem6w( zT(e9k79>wyiSZsg6K@P+7-*P#U4{!Io^8m2!?E)^AtknpkFw{KgH5KSr$ z#rP}R*~LW!a^ zbmEYS#@{jq!Id3fZ{xeqKq*QfNewS#X%CqxQ*%&*i-?JBu(M0P5&|yt&zhRhv!T}L zK*|9oYT%2Uem|fJ?CZX@(v*x8dwT02s zJ#@^eBMxa0pt3Tr1fULpoYV+T?Z*m@!$uAPYyYhU=xG#tw3J!cwhay*_8P1B|Nxj8j`y!wc2h z-w*6XQA6Y6;|2EIC?buB+s(*2`e{w-wc<*<^~$4fIs5or_!Jk|ZpsZsgF~Ffz!}By zl)>wEEczL+O+;#K(%-o$>MiQdXK;}CdGDW|nv{OJvGeT89f*+axJ8$K?jsk4?j!x@y9D?`)T}!(t54e!W zzx^$ySO-Z!PTK(C;BSvKt5?*Q^6b_xqg<+_0GIt8MxaE1xA(ic6tDu^!?G|nEGK8N zI(sDUo93p92YE(kVPPSC!0oW^mCCoikaV0TCHAl4NLx9`IhMF`XOWxadMkFYeR3DKL^ssE%$E8G;sU&^2xc? zHi0@yV8L~oTxx<3o-z#0)__Ka0j)>=0s~O}xyA<(s8YuiNR(eIjE2(BaU3;UtePN} zFfCxysc*jGqF}v_;g||lQz~2efq0&fS$jwWcPtK%sTbCtB3SDH(w_(){q9o2H<`*^ zw+8IzrS_0~_Vq97S^+Otypuony6A28`V%k_M4$=L9nF!Q{igZ=^U&W}rKP1D z)6!f&h>y0Hn$JF(7gPb@34a@>!~E>5&0Wh36EeQ@@3hnElmezXXZ zxKUx>#fMv(3P4q&q|;M<;KK@hYwq_nXOWD-18F*H4~4SX(h>WSEX=oO&*$*b9cowk zCSP&aB~SUi+i2W-;4vx#qJEXptT?o9-#x7R`M0<>>wXG~Noz=?mshsdZ^b6^rQN~i znAw`OseIi)&;Tq7pg1L=f2q1Tl~!s-!%s{h(@VXG8&-Gd@o8l`y>m%vZfy1 z1!^7pUctTKoH+uG^dTb;FIjW|lL6esQaBiCS z6eW4eQET@jrW1^mN1L7BEzNK*V*=RrVNQypv~bgEyag%)q~U6{DQwTAHbyABNERn0 zH6z1+G@veJz))G*ky!3gE|9XrhxCk)-vLKhOwXKk$$6)C%KPr_?1vx9`uh8UUJIx@ zUo=9sWk;RK*RK5Sg7uD(FP_!hyYM-w`(Mgmd?2bjf=__KTsd51cdxnmvCyLV5tLZN zRrfnOekLa>5NH};$|y>+qDtXPh)zuszcp<_Hk_KM;Ra$E%?)E+JNkV$s`xExQdfUV)*m8n?X_OmzdfqR2uieb#{S zULaB&CARr)$Gz|BqSzyE-}7IIm5P88ZS^gMf?lGW%r!g!I})HWaXf6(N|O7qV7Wa9Z=J)NQSw(%f&O=K%79j}^l!bCIX#)Bs-tUKBd5x_#*?_H&VIt-lc+4oOZZ@^+;>fw>?sc?5vRXO+g)YKIF(5`-diDwjw z6BTtS^s(;!pV8Ex!5xf=R)us5b@#P~pmb9KPdtuRg{G-#HGcNi zty_0zU|TQtQ#G->Xpn8eL}I9bEz}#5J8F*zd)X ztIhvHfiw2~|AqoXve1eWn?!4+B_}UN{f+(seL^mTihw8K;m2Hw4~)j7{1<}*s5%M! zCMBgzKfVd-a9sIi^pl%d>kh%yr&8m-90?)VAnn0e@nk9>jpSkP%>@7lyd1sVvsfv0 z9*_#;8!e*$epLJhrP3JjS)&l6aRG=FfeUp+Fv!O@w^k!DCJBlQUJ%1^^9_hyjss0= zdh_N2z+SRi&y#;-hMfoeR6ICSYtWe3lZkLQ9tQBKUteu-=dC5Np~VB)QKc(Ptp4BH0h$9q2=oAns0O{d?;bxsv1A7s1yV2z+i}dtf=1t=mA3)eyj>VD;OaUs+@miPSI{vwtG|;Nm zd{_uQQI5($M+rTjm9@+L7ufTowzvF~X2S)+k{W>bfrLgp3sEMa=17NaFWqR<3~pNq zuXs$tcA|}9Ym?OA1SK%xR*MudsAW^&jAs^m{a(ZmJC{nyGt*%{ixwdZAWyY|FqDeM z;C_&HCd=IyhmXnufZBRwGqN*aB9jJA$I0cRfR`3W^_x1l4W&5J(}D@b)p8v;i}r*h zc6XH3GDIo6d-vsM7yDJKr>{vaqo^AV%vObi0Z*0sR|aw6BvAz+F@wnME|m5lMOU2L z18i0LsdI*P;eABpEj_AnJ)lF8o|z1kPEP(Q$TP4`?}6`umZwk&FooimzP~p*Q2hS= z`zDRaW9So(M|XqBCU4a~OE6$A^pp7LyTGU!Ol^{%lKQn8Q1VLz_Xg50@Pd8-$$0EO zA7VT{RM#Nbm}cCP7lXr)Rk1s+leHIn6^_ZB_4$tGG17=_5Fp77?H%c1H4tXjEeiyT zwE>+}^X-Tq6BA-tUE}CQLF6+#LXaPB_t=q%hZMAu!?Y$ znzV;rQ3t5zv#{u7Rlj8s`ovUob!O}jS$BPp`RQ(1G)E@@Hj=t;AGa-v_1}m@YDpF@8VG5XbKr9L5GO2=QhK``fnU1h(*NW8C7lMkTpycfd;-EES)Hwe zW7wOj0@k51*AMz)ol(*^2fya{jaYmMp`!sy(R1 zOqkkuQ@A(wdC_vOU%&o7L5Xr34ZUgOez5W!C0Xv^7<4_ley5k${@{3CK8rQ+wuAWR8y3`}d(*tV1shiG0_y$KK%=2k&N&l4*qZh_+)Z?TgjDte;XIJ1 z@Rwq#$W1NB9@6>(;A!1_13+5{0Hq=!RAqhwIMa8KPS49&4u93w@X1vum(`E%JNm6- zN7U93zD1D1;4w;XL5zDKcQ_8JnTFnz-f&)Xyv`;qsJ8DkQ=>q#_d4&sRA^Tk2qvA5 zYaKBDzDA)Fs1H=&>Pjks2=QXY1GLGJ?R&C7@i^)lvfBKjgQ1JZp*4M5#fXGS1@a@u zpeL=!%yyF_Cs8R(qV}LUlDiNBDy4yZ3b63wMM2D6{{AJ;&I9_FfzsLT$lr5nKSWmfJVAy1g&gNZRc}8RE88=l03=yJd^g@fRy;f8Q6dj%|U>tG>FP_|$-MgJdLz-;Bw;P{2t1JTb z%?G$)igoH`w>d?$duSu%@lm|j)hiJ=D7i@xEXv(CZ{+cvzuD^Fbj6xWE1X*pi9+7$ z@;h>b9cG1*e%rW{*XQp2S0me2!|L$aXuP`_ag()X*4Db?H7RSE+}>Ej>>uySS#n$W zB4A6TmEsMp)bhYWMV4<60nr$aK{B)sHFiV4V8Ya?fTH-S3A z5QGCkR2(IK3gIm!sP4f7%DGmH373*9J4;;r0oWcsqjD3Eft}vS(rcpoC|k}t?d<62 zeaO|N{jT5)^AjB{?3g*=uB^4Xue4IJDzf_h9M!47cnI4qJm_9vllLAtkUFA(a0hs? zus0bKyfsJ#&USSlc?b)lMSwa{+dPQda&0v2{HZRkz&aEQBm2&rlMVxPrRg4x zG7p%%O9kKAbD#chFHXJk!HC^w=TOUXbRI6$$uA6p*iB<{2$5X;sZDMERjsa9mS%;_ z1&;t8rVc~X7|c{4jR@}(M70JVIy+$(1cxBhh*{m_;zo7Sb9n%C07pV%O?1Q-jSpMz z7k|}@!madWad&IGy&!+{`MJ8xf8u#KZFQR|`}tfJr~4cEXM7TBHtZ{1;*Wl%t$1s` z)z7p;m=r}Tdv}6u^4V;4VIW@-<7DHLFZcdJNhNXSBNxQ8q=D3Cgkc#~S(Q z>E*v-tagj9c-PJOwr|sxXV<>B+5K_jfOuiJ%>}wL{fSa>4n-#rIG>4)!0CeCVvjZc zYW#ocD2qp*lkVqF!uwKuQ8@3~fV#Xu>&DWTp1p?gg+qCq55|3(OH?LQsE~&eBZ~d@C?MWi-$4@#* zhAZPved*j;R_yulIs;M#n1-@n`W3aJ_uq@I35HE7Awzr89ziq#Xh^vJa%tK;D)kta z@hz)f=w;s!A^sJ7pb3+9I)%0ky*W|vB{(coZmUE50la%9Y16{%jqeC&cg+vF!9#yti6K+A|-=4UcZ!FFQtPbVKjQg6-UaI$@<^c-MD?B zOULAOIkEu!x4h+{X&_}r$g+LY|3{UIEYwaMr88(cKwVfgb)@~uTbjSaA$VQB{eE5L ztWwsKg5KI=lWXy@Y8o1OP=F>QeUyhv1&sjFtA+k}_b0YCO%NjBp<2VIC$@66yivop zqSzsLIgmtr0eYGIm%7ZnA+PHwR-2LiD!<`5lxk+!*f^L1k&sY8f-90=yaQw`Dk73S zJ@x(0OwIpK|KbU80@5TH$Sl>t05v%+PeITO8v`}WAyC!aT6-SYH4BSJdu`}Zlun2@ z@*aVel4!ob#bU|>pJE*;xf-?XTwJ2D9G{53f(b#uv(bj}GXyVKFQvz77#bQ9 zj0eY#o??;W?eUMLI8#8^Sw;*QEzd|r!}-7RPrLI|-$CJFLbPLgrlf_#x1nanR*o(Y zqBh$=jV5?~X=4lU++y#m1MninF4u2=8E&|nAlw;pwm2$4RZFFuPNH&LZt^Sq+29zN zHV1&&C+#!x6s6@`9>R8E2RAJ3EfFNrQ>egMu|S*u1f`@5LJG{bN%QH{R3)^+kT7BB z2mXtolIR34#kFhQ=wX13q~seP0A9)ufuMHd=HzL_lA8Sl2Y&($e{6zx@1^Tq+Bb!- z`Tr$~is7Vt8Sr~#!+aSX)fr$yY(kt9P_vy%a9QU6@s7F}Da1yF9YM{a`t$;#2-Bz5 znr#-Jx)T-}E~BfVev1N|lhIr1R4NUC$D~n!f_20TD2M4!R4d6@SMAViBP6{m|Z7XC=plBD-Q<9<9YDaWpGpRpKB$q2g zq({V|fy)4;%Olq-5H%G}D=uMcQz?odWZR|jf{1p7E1vT1QA2|;N%6ybC$(nW&3It) zx-wY;SbL0+Ps4jrmNjJVIx^mUVov0C2yPqjw6ydiglTR@*#lI)q#H>MK?x7wmT*OJ zBhXfu2QHb1oZqu{rpgJnMBLT98sH_mCYgjQR4Nz@a+g{^JOW~fVt)iZ__^~>p*3ZI zo92Ny1}t{2X4&uP_0R>*%h&@|m(Mp%bdMXrSwD;Ou?wEwHH$nju5z}JX$;NkEU;RD zmU7mkDzFlO-`)%fJ!okmcdTxN4S?!5L^XJ?%v^K8lvGM}vC%6a%;A>DEm2X)_~Q{7 zD3IW@1ha==0kmI-71ktvguj0E;ggNeF!@JIsZSa8!p>F&wqp_cvN9y+A(jAK;-u59khPoKJ_O~?U%Un4w8>6-4av|oYDu47zzytOsgMKBm7i@iygvp2VTQpSBuYd;iz3>hdf0*KsJ}7=5(S+FwjoOP z@G*BN2BXU1^svomPagK^X}s%b7hID`G;WZT5(OCXd( zMZ0aJ7Ab5s6Q6GJ&z*bB0~0ChRFFmr zSlAe7x9#ZtOP4ZvqK++T!N0*-Q*rsUXHNj?#Oq?J6DM(If~`o#71)OT~+a5dL&yIpp*Z@h|AD zV<36K_K^h1+@7Dfy6T=Z8$Z_HcQi?RVe2Vy6J{-FY4TE^LSKisnjQ9OaIiGm^CtTTpky4dAk@3;RsE$(n&Nw*wRKwcJJ4Nb>;7wKL(L=dy^$fTNi&^x6`@P9)znD{1M;>J|oNOkNiu3zWTFl6B$ABfpq<*`$6_UR99xiSIf~wu&_1T={?| zfm7(eE)~&8=Ra_E8#;JX*v+6+io!In=mcSk>2#)Y*3^0i@w8(ZBW3@wfw+UvHI~(U zlYgl-zT$#2hY%_0jJeg>%b|kMJ3yBnWA0J6vhEP)oSZJu)24s**I{aWm z4tIL@d2!}OwyvmekoDG@U@3fC?B+SXW|}4*>(?Jsd?BQkGc8RXA9UUdRb4jb?T)|L z?%%KDwsDgmr!1IsC_z`eg_r1Phy)v6IBp)koF6gzp+X|*e zs#@WSPL<@bh>_<)v7hd+BNhte+G9ve4wkewXksvp63=HKvW|kkwyYLfx>9Q4LK|$c z1#1s~lAtC7`ILwK8T&f^DZg!iNN5l%Y0O|CvP4owMpch}1TxGth2IE6mjoMgH=|$P zFl_TUpzyBN7p$PPgiaZSmG`~;g5uZ>9UW(hV@Of4`O%|XvdJ;vlW1gM;UgXkilEAaKEksU4_$La!I3iT}NUr^0p zH=V!9M|M7+;QP4Xr$Bqvr#ZH7c?&6|YHrnXu4D2HVmnPKvkhAVFrJUoqo2}g%J)~L zf`si`v+U@D$MpGq`yB2PRRdPy{6+^=jM;e=Y-n_$KCAQjB;QBZiQi<(rX4zWe9Xwb z#{cZgO0oi%#d=*VsEUZV`CNeiqdLE4&9WphBlTqz%!Pu^Idkk@qg^IUi)A!$s4vgCD8l0w#Ns-Us#un|Z~EZRP~74YD|*&UfVJ2H=)1Sz6P zx2{Gq;knJ5H~V4-!K@UM#v^$tRT0>IMw`{kY`1O8;h80R-%!Aarm0@cy3(`jV3p0n z_>-0B*k@TgU27fWM|i6_mO`oXC9!k299w5iXi&Lz=|{KR*vm&koG^-BCG?lg5hkT& za+1C8w`2g*kY$&?zkGuMxiw0nvLDHY8=y3SvUA1wd8<|MSKj>iY4fSr*d$W6o3hzi zS!Fj8X(4G?U!CHd<)E4|ML?HYL5Bs|hw+U}a;U0(=_x74@!1|&Lm&n9y zgSOFS-}K)wZ2dKPm<^k}Iz%A8ofOzY ziy;nfEd`y#V4&A*+dn_t$&T>b8v6NY-A4gH#3XEU-oL+sC$inZ-*IyuWLKvWJP^>C zIeO7V*?y$lVgEUYk?L{$WHRZHHaJ7v>f_@RlWF?pwOTkYf5H=S$ ze@w#SooJXV$tFGn1=yp4q%FhDJIQ(fX7xZjsOidpAlM=?4NMpII`rwAlcS8WlKP^fB%OWzg#{2dB4c6$ z9`Rh1Kx%4WvgHZ+2~uJ`4yqCbaDAAfsQOZ^qc$bNRi6~GT$21FE(8{SOAnBlm}A9* z(~h{rMDEZx0S^J1CwsK*D3^~%e}UjqZ9lV{I8+Vnw#E=NRf0<9gMzsQ#{l_6HukL8 zU)ME{1WnG+EXhtIvrM5+yv9>i!C@1#sbU>|KmW#sHf&^RmyZ&8d3)+2C{{5AZh0U4 zW%8JFo&E4YuU&g*xS=&EapV>}L%&9V(^O{1AL~L~0(F{D$=V@Cjpl|8Je$0>Dd^6& zL0)2C3wRjvI1CP4-wbU#9ZezP&soifM|pPmGpyX^>htY3Ooi+W5oRWAXQ(2%VeB zurmBTcti7_C=*T+RyuhJ8r<>T^C^RGL4hzDQ{Yv6m^aM>0Zq6odZ!_$VQOMu56wdz z5W#G@bs>5O2U?>bUEMZ%^+V>-1jrnht9DGI;Bi1I?reE_8W6j@?+BQ*0lO!0W+)u` z6JIdEl~8sJ)Id}(V(Cp%gb5-)Fac5NEK4s@3ITYMYd5~dr2#6?lCUP2*(Nuin!onHD$c#Zk9i<#1n~fiMCRSPh6JBUJAjk||6YAK*cF2HLD6 z1em?F{2Zgsu$PP3#cC}E%S)yA%xiG75a8Mmr z7ZD!qJQ<)jXjNvqOuKb3s>6PZccnUX;#$)Y&{jw5y&)}2u8{^qB?AOoQhpAK-_@_O z2)+c6#+1la&-mDHnBLM6BzQ$szzC2_KA6+1N`mMk)S&Nm)$5oB0@4OcPZ5fqinVWr z#bu0ux|WArv4`$}c&GwlE6n|l^qhyUUb)$-d4VJ*5FN|XQYRS3k@4em&qCphkobkN zHHDSbyTC1YeWoAt+w6|z~V{7{VX$Qaf;@an`tnzw79FH!SjCSSO7B{iL3&% zE1#N0^BX@5Y=hL1so&X-l#@|WXNNXBx$+S^?dd^-WY)r~i0_1!V_sTA+U9d>5fv1Q zxDWo;Ge}FQ_^=xl9=5i4!h0@aYaMv8jv_gCuCYbB2G!LA&CMB5vQ}ML2&0`u2Z^1; zW7N;h^4Npf>q@d*PbQ&JQd{dd4W~nFf^c@w#x95ftVR%yPQisXz6y>5gO8hr0vkbb zNA|0iBUQg6gcRN#Ihe=eQ}`1b0#K`DEP&^{$w&e8Nv+5XO^xg7>Wb~q0Q3t_>C#s! zc+u793KS1OR@$!HHdr6RxpAC&{7*oxu+7MQSqGl zI{=RkxHLRsrn+9(L`|5f&~kDhQdE&eIt9_maEF(GN>4UOhu4_R^PLN=Pe&Y)K;Svz z1(76u^J~B!u_^K6EN0lFXc3HsG6-Y2T%Rpjwq{xNGGq%0%EgP zF-^O76AT5^LH>ExrdB&o7{5r!38bn9f|b6FkVB*m#qe2Z{^ z%_*o+$q}z9v^=Y*cR_!Z(ii(&JJG&7r|V_GKt;& z5%Lz>23mUJMCe(CbT!%s7}y1uPAt5C;07d{xCiO`@uO}Y+F!|c>#bdDv1UeVlcJG7 z|JZ+kJUGf7HwHF9uRi0CYYP7HC5LN#hM@gGyPNgZVjQmcxE(QRS4IAW^EA z&owJTf zh9uy7U}KFOf0jXE|8XALEr6CT0fNd>&SItP<;)eVvjpCy+Y&;u0TR` zG*n@JI0{gQ8hY&8&`$wuMj#zYkr)LOIm_DH9pNKyFl{b6*6>9&V20!K&LYQ7d0-I! zHc?CaDuVKjcYcvkM^Ah(?`dNEsZ+VQefMG>pTigj4C2a&js}ixhCNW~yqWvJPGWoV zL#K=5I0`I<{IRw1ekeBeO5{r1E55j3euP?n!TZl33r69Cld#+O9K-iUhKH%=S?+KI z;MlCj!|;GRLJWH>rdb+QV(27>vCXm^@r5)ztyWjV)umoWx{bAr5)=2TXxl5N3>5Zl z_~QJ}g;wWG(JS)LJNp4b!o`ahw|*xn5@-(BdnkUrA>t^*-H_z3;xDqvs;$<)bCj=W zN6&BBms=J_1nWjnK4$PcKQfgt+H!6^Wh_91ul*`b(6%9Pg$>_Vxx1oNZUj)MV!t;0 zLj1yro4VnYj~x{LqEd=r`&Fu-?bGcNMg|LvDF=6n@;#V;>|d<>ZX-g*j|GfV+N*{I zY+v-xG1{`gh;-)u9U}ZiJ6DQiXU<-XPm7{>o&sWWWL~s?kzdQg^*8DsN^yXHrwD$s zh5U+yvG+}yH`;uXWs7UtV3KXb`E$`Y9NGR|{@i0y5fH+qJW4oQBOYa#$}h*01$gaYs9tmqo$!lH_*{ZxXZO4Y7k zl=kaC@kzoGMi+##GsuU$`sYKkYpoVX^u_*jp%f7j6;BLgjE^o~nT(nG(rO_#X+;zz z_llbj;dGsL{aU05Ywnqnnae0)Vb^9Vq1e{42z>JKc?PZnvlp}6-Iz=6(0cI{9d}?~ z8qK(i4yX+pxMg}yQpz{^ovt?DK7m;11u)+f#3tXFi>E!Rv{W4h=2AMVI_l3qbD=&a zt_WZPaBmUI1q6OQM4a1`W&uDT3=vA8he)a^(FWk{B-#MdH4Qt2DkC8#5<+qkcZf02 z^W_USBj#c@IORXq>}NTf{Pw95kqa>9 z=lHY#+o4HI)I+KAJ3Kgs-|k%3_SwEY1+plf%yhJMp%Se0TrC+dwVZ~XC-HIYj^CUQ zO z@eo3~9T9_@G}`_F^F-}k7s`MAxaNt(uhTAr54X-5)HwQ2)`!f$vpyOQVY3rs{ORFD ztn*_4zDk^W{t{xxBwqFTvhSMsx+m%P8qdnUxB4ey#Q9`l#Q&SL5GOUDFv$BR=mWAM zsq%%a7%a;0tc-m7Rsg2i9u1G*)UTg2n(mB`WG5i4QCC+c-U2gV$#dn4n>S$=D7rQ< zJM%yaB|@&uLhU6XU)t=3e}T^uh{{c#s^yAhluh~L@b(TsmLw^k%Nj>3V-8y>8g?Ey zy+ZtU8#YiY5D(JwR)4{LZ4M;05RdcCke}KH6GK;ZkPQpp^?dnDtTp@I3tDCBpM8>P zV1Z{D{5k`3Zn9Bp#U?oWV39rsu)Y{CHSEAb-Hmszunxe!l>sN(yWUQ2;0DQQ0w!3G zT~JcKu=yt_%NcMI4Hra$r;6~QqcaE}5JFCi&is_cUgo0}CC-+yy6hnCM0dR9dOkOfK>Nc_^<`|Ty) zzrofb3}=G;8J|1bfg|d4YxY-UCfUIgPBu1t{vv(;ht0e2ydkiqIb;jwr6N{h0}wINOvfZ#Wc3+5 zIf?hc55Na$xgn%Kp55#8Cq}A{D?~IM9U4B16cMOFAR9TuQ*|QI`~=McyZf-K%RTUq zfK`7oWTMif4zoH_zfgD@8Gu==7`^!B>{{ou4S ze7tC>PlX|APEI%A%;*%rN*=U{e1#B>kgeH#|chtHoo z2ZLq8B-q8U#bHFDsiD{N6Jkc+Ue-4@I$(tu4aHX)AOLO@vdfgLtc9RQY&~w4^g&|M zj#67$qqHm!1UDT>7eE}vBPrscCglRp`Up?Og6<;>wEuM3z$Y8zB3i0 zUWg|&Ej?Xj^6{HDTRgN6p2MAt$0&5LHw--L`A8_k>rn`8TTFs;KD3r+!OE`(JGB^_ zm|uMUsZ(NqK@PI_W(nqVH|0G%uy^kwxLB7>UHk(}O>sMXXe7@D7>lLoPKB4#-_c>2 zLxeU8uo!u&GciX%`HbMf|K|hDwhpE&kWKky2!sM6^o4c`7&sX8I=|*mzZ*H- z-A+45OwICeF}b-dn1!#&&Gl&&s<|Co+PW5s8r8B4z!pQHd_TlWcJUmA68sS2{{~Ls z>DkZjj}Tn&UckS1FCl?XpZfe2LF7LlA$$FQKk|Rq<^NB?a9$=af-*u}HThogeYKVZ zeW0->L6G8O){oEAxpV>8g5u`I=N&@NDLap25n5T%L)Qp~PR%^$q}tQXlg<^)l5zsX zz=l#i_Z15%8P>w-wimp5Dw1$9XUpL;C+ZYy?tpn7r+JOHKPZhT1HM7%0;Z9RodvJ{ z*y~`aYa1+Bb+NZ>>08I$gl#wr=evd{f*3!l%a%M&|&GV!u64Rar zO^h6wU-Pfl)BOZTgNQ;Ho}Jmf6$%tvnMRJ03m#cOr{rc%jzOoi)vE+$sX-K6LeQpg zP_KhE>Eh^>2kp~^J3c(Ux+9v}90Vmv&YX3@6nC};@02!Q5N!>n!pzJ*K3#wml&ui5 zn1FC(=L@pj`p=R*o2>W0R#ao8bI)QGGj7gcGHDa(hcECRY#$*6%4^xeZKAWI=hUq-TCe_)JKZ!c`rS7C&r8S+{L{H~-<5%OgMyLA8JX=2a_Qm~X1{ z#X*<7ExZ&-kncG~Fee9R%VO2!`G=Q;VtA`ZG2rSivZ`~G^05)%YOGxauHJk*jB`pq$Z|nK^t{H96nx5#Q4zMbiD76}?2a@dHWsx&yC6J&Bi>*V*}bbl-+n z5K-es9>UiS?=-1DwvFegneHgO&jWj~9h7?H{$f{PFFfs=IP#l2D_yST?&_F(iEIcg)W%a^$X5^8~ISsh^aIws`t1BKx zMn-{)X_!u(9UKTszK`sQ=!r5xF|_iNQ5#Q@`~`fhw-*&Gl}e$iQof2Z#oq32hkZ(< z3N2P;R+)+6npVv18xY4N=pac*#ISbu1VbRx-~t#!rwJ)3>x<1EDZ)N!rfKd--S#eL zjnecwQ-7RwKYaMG6OSyaP>PF(ifCeLN*~`hU89TTFU2F1J9hHhr|m)sZaxAe5bYOD zu;bHdAb>HWU4ED9s&25VL9*ypHwThsWM$v6v9)_F-7emIr?@qq;}RDaN5{b6BxQLX z0KU6+t&JiR-aGWHY^8)AqgkOyNlJ8*KvV-*;7!J!GYT)^hZ<|`pl=fL|5==j>JsEu zBky?^aSdcb2)PqUG3VvM0?fhT<&?Ag!}V6O->h0~qkfM0=+ctBkB`rN1y3Y>tn|6X zO0&l$9bULuagRx*Y;3y@^HlUH_ChJ-pv&KdJ25TI#N0eIH{H9z+Y5wb^G6WtSc)*y zLpeYF)eM(yw_)$L@bK`jQBiBRLh2zMmXcy*XIDmsj-_4MqnHOF%YjS}ZYm@o2%4o?CVzau=*6z!83Y+}j9s<6w;=mx zB?Eq0EnE~oT%xPHTT@SOb3~GSqdgD}xyGr_#(KhP)t$`eI^IW$A=c2?IFR4JpN9I6zi!Vm~0Na1%a5mFzyyw7nDWM^mp(PvE3ZJwx}Af1i5 zF8-LO0>QfFr6H>-8UZ<9yCWv&A}Uo72&xAr|5H$XlRKF4`1Y#JDB)(ZSo>+yIXF5! z7EjY)yupL^DRCw-tmyQ3;pYZ!r<=0U*)Mai0iMwa4+qWN=Bh@ml zS~zht1S$>*B1r3h6{#+ubciB~_}16+>iOI|lXS1tZ>7Q9+^$3-Jru}Pq^g<1zkGp1 zLPFY!=j2MpMMXSVXq3!UfSAq9P$v%@Si0TOsZ2$-^U_>2mbn|2ivN|O0B!5IObUYg z^Ajiy)@s z3=Is}-`_a@q_b$O3^gWAuU*Q*gEY?kJI$b6H=;c2+U>)xa3hEu;{S#n{Qjw2`gF)| zZaS~|*QzkQ6A~I+U8RaMJ|0(=pGc-{ka}EBKH9s*7LT+!`buOcU(8UAz=(xm`FUn-AXDBRxxA5^X;F;?KJX z_c2LUDIYg0E9<$ERl+D=OM8OPjlHmmVKVS}0xFAYJzT#oD!X-uHa|{{FHUWKuXE zX{$YSst$jTGW}2+VY$Qj;cRDlEcg{Qd5s4h3yXUo_vy|J>dMMQ@>SrMBe)kS(ucVB ztsD}Bj-otp{)$?lJ4#`5$W}h}C9P0&%J60YVLHh;nbD&6#4VCGzn};2JH2 zj6T)sjSb_juC6?_!lr#|+qJ!!O6#Fo?OlwT`OUr5i1g;;sk~>XzQOk$tnO*@=|Z~c z$wrkkAnm|aML~z*gl3muBS#j|?@8BwU$P`Xkc%it1+6T(;%B|40Q-kq~T{)J;x8iLJ z(JByE7_IK#9?bUufy{woRsM{Be@}L?D2s0ACb-`w&d=QHh{tggy|n2>x><2UwEN!$ z32!lH|DsLHUPP-{>J`7Ppv~AZR(|S1dEpPLRJjIy5*WG)u&A#IvxGQ!da|)NrB9U zTvi4jt8{8SYNaiy5HkQXwt{-|GdfaW=KG2Xq90g;Y&A&H&`U;|r%e8aQN0F;# z=hV72H8r7DR$ryF+c)~+d0h|YTP{crR3PJ8j)#kaG&D3v0;MhdUG@C7qa`%?OLvxT zw;qZ+W}X`4#yRHShqijQPS5*Rd2&F5V|*&(I*l&Hi&mo=^a3IDSgBNSc9&eO$avv@ zbR(!kI;24E?$+$=Exheu#VmrKCU}Y=92}hfp&`fPRS9O@hN?r%VL1#qTC~}lmZ4Zi z^}i;S=W=R}D|)y3TG~`iyg^>uJznHK{M}GY18y)7Els&OR!XtumX*(Ra>#n$t&wwM zymoDv`Gpgy1o^slrC>v-L5I6z85owed(>PJz+(V5+gpg@do`r-?Q>sIY*tRrKcH&x zc-@>u5(~I|{(6t_t4rbLUsjX@_(mC%Dc^dG2*^l8e5{T8mh`>PmmK#Wqy-hI!zszT z3`Wq1l4a#mcobVbEiA&av)=%eXK88q1OP3n!*&}$Vwda+jjya`;X*oCJ3;64B6^D& zD5hMkK_dGSA~9s4)9Fr&LB{W_Al@cT4nla2W|L0T>Cf% zN-*IpixZQRvox3h3K$YNMF-VNch1p`oASNoz(S*IVnPB%^1#VzI14~MOHQd>rySCs z-q(B6mDC7(({w1F-E=H{Zhst4*YeJI}O46&YDteN?x zKxcP*VGWwIbbef_>?~*Uo;pl?O3_YZOAP?P#Aj~kAUy?NUtgp%`JwUy*ivkx22od6 zCnP4$QelXe&aQLX9!+cTaJAsp{SRDx|$SHuU@E&}!n(tcG=i`zcMfQogx)%(^^ZstsRhhmJ9S|JI~g?k>b;%IbT-O=2P; z4J~cxTAdJbdAU|ydf2ogx^HkbyxYUwHP}eQbZST#tQ04;xp5?d<{L<$&Q1gX$N+5q zvX$wXfAMu0_CY~g7&}JpUB<>s>a+xz&TyODqBz_^a_`0kmGS)DpL$g zr5KgK8V52rQ!qPDfSN^TxK~`8aP@%o@s{!+)%`0!`@e0?yT;0Y7KoKBpDubB&zese z>@z>EoO9F5FLtKuQZU4Y7E<eRsyv;%(YvaII0@&x6i}++bE7VA=AQD z<=VgREsxgw4EBpgD`U;7|L$x(ru<>?@$VgfTNG$KOvIXp^kSmxv=XX?x zuqgCs_q&%~hjr3RXtv$GIknzJk@kpoxj&TZO2T&=zJC2W&VuEaVQv~zUtb@`n<`%GU@u-9U%7+t<$qHd3HX&*$eUA3W1xNrmK8S@ENjXp3pde33y$Q_K9$NqZ$OM{6GKwJP4<5~1Kqb12^E`v>A5RO%BxitUV zS}x{F86sL_qA}YSAZ+imU*-55VkO?TJ_1D|4JNMQ zh@}UK2W#MkXaCpGXs!?e*(y9gq{^i?TE$g&k8UPu|{iQJug4L{%L8f91>GMQw> zH8)}sBggyol}IsXpjf8ydodEgD*TDA85`6a<2d$u6d5$Hb%Yd7Fg&%#{(ifacEmJ~ zgL+a~3*ivdjLD?f*jFw0`?ih;^SmW`&9mha2@|toV@m@vab43zPL3g5ai$?*jNgd! z^fw2X?Y8tiBePk2a1I|li%(2^D@1~;Sl^P1C+2-Yf4I}y<<&&(7)_vmmfatRnjXtO zyx6t-kv=e1X<8FMn`5GW@<_c=?|oyQ%_iG>%j{Ww4(vbJe-cXI-XUC?vYMJ)tqk3x zUi`y;O@51*@a)aKxFc!D5GZkzdKFv+Lz*!#undnd}!R2Hr|F+Sn@RDRcl zq@?x=CcV$w*@G=Bl9ae{Nz811RM9c;t*AMHsB;1N$-*WNCW#<}Q%{Je^5llTK(UK) zM^okNMH%KfkN zuX5zK4qkYQ|CH*h%Ns*i=&F_;+zWzRbCCTaVE<;*>r}F}n)>#AZhY*wT!kescIF7~ zkA@s>;)R;_=YRW;Zqt0TnGyIkJ8k7~vM!ZTJ!ACWL7FUIrNG!UrkP2k1*ga3FVsUP z<^>!e=x&~tLBeu@W5_nwJuMrV&b{Bh^pfz;2?ia2qHN#OuGZbluG7ok9A1H~0FM2BrW$s4wE6zH6 z0`;(*dQ}PHs4h5NTEkmGH*C)P_XVCEX7CH0>lLmd-CmPKnVLsQe~~JhPsElHaa|VI zqNi`HE%^haze>>-<(+KQUN*;Xi;z~_44J@4?Oh*jRrr4fpr)?eoy z*V%bYKd6#+mckzeokW^OYSCZ)7hH>)PWw81JQBuCPXrNiW2+C5YFKa5pjVc|J% zi0k2EwvxGUQ9ZeZbLRd=5bOmULo%{JLAb=?jrx+o{^$LhUZn&tbEmx*@oVSq9@s_h z)Ax9ylvbGLMCjdZJM1B-)<{s!b8NFq{^3o|pFgOa+eK+pTdfmH%C}wH2+PV&s~KP# zVLQKHiSW|!Srxz3<_#~K_Qaf3=-imxCDKgJQ^{oWjv;?AZIymVl|Q*^z3cwPA~^a$ z-T03V9j@bH(#mSe>SYjgtU{~@em%lcmS)AS7PL5Kir{_wx45VfB{%^j5C!5a`B!h? zm0G2v?Y)iMG_+}L)LTJQXG%nsBHMcAu0xS%E<(C|GWzO#}0>pSkBM_BGPf@ z+8db^XyL`@ZT9DA)x*16bz0LWp0U|~Q}%M*JOXQCu4@eHX>8J!3w0#1RbNe9 zvjt_LaLJ3RV5@QucsSwaSpK}Vs)A+7JnJ?7sq}U7#X-J+Vtzm*XSOBx)uM-R`||D5 z0M6qUZP^W$P2{8^5&XfryH?yp%?$PPz(0oN*??avZnxrUG!8sub%o?AfwHQ*DE2&k=x#{4Jjw;At}Q!c>Ynmw?yfK-d{&Cyt@zyGcbnz z<1U!oJdi*lpeJ^9TRS(*Hf*OVh8t9vE{W>ZMEG-|x;ozDEwd3L7@NbPY~Fyu*mxdX z75gdkKI5XHy6x|m)IRL)q_gL`g$y5j_k9n))RQ%gWQbZyl;LFzV_#Pr8;#PppV#}Z zNZa2FiRjQ}F(pr^xAy4^Usm3AZg~f1rh5*>ZB0rwE5Oa?ckSp?X@*yUB>@9KJ8RLQ z)#$XH;oL>$9wcbi0uj)FlB?HvbATJbOzm2p$`|y&`i#N@P@ZmM7hr)2NJ$r*{k!F& zD&y_qia2?=xPqVr0=IjWvW}@l&ROtzS=iP2aMX%v+H2=aH;#VQTG@ji3EyW!np>>G z6W@j0MO>TwmVU)(`VxGEd+HvUX2!5-zw;V&sGU?mhtj|(}{4+>u z`cIW}zT{i-f7d7xJy1zny^ny}kD0fUL?yZmd+(CSzK-#8c=few%JIFGR;Ty0r*@9` znih|irBnGeS1b(Ym7o&>A9@CnuQl66;p1!Chup_7cJdn$$<1HZTRa1Bdq~;1Ggfh+ zbB+UYaxrdzreyb}#0$WZt~=B(>{pCQfC$&N3vl8`atMx zz#AX0+{mOn5?Bt#>c^=nnlj@O*D1-k_pM*L5j<$-{PG}gF|pt&q+iNmTsadN$dwN{NPFT>B>*q$ z zmLi??i=v{TDdlfOvdX%77|kDI2^cLW(uU4+Iha1wbHYWeaWnC)udnj*?i*t4t7jcFZ>K^n zW(g%MWi`Sqqq;-aV9EZX-#n%Dp8cHHyyyKx z7i)Atdo#i>z0_yZ7?EqN92@~#?rv$_{ENq!AaStB@x%Xot_(F#0t5NN;*62CwJecH z>a1dQ6U-F0G~V3@*g^msI+oQoVkAZ!WD^E~q^TF@~=wU?VTCu)!* zh!Z8TA&Q%9*f)+K{p~U+mNhc+c@1TmWx_9Qg{bbem&!qrp(&GHw`p49dIBKt}kl5pkhpN%QbZu4wua!Ru$@@XYo|IED?j6xl zrvskq=`WSu-*d}6Gp1t_yJ3kab8(DzYu@g3>aTevVq7JJC0(sar!`e#I*pVcqlr$+ zsY(=^C@RVLORk~wOO6u^k<^@O2-)+8wc&Yvr?+n`Tie$%Hm+KqtugebGpd6bW$U4= zg%W}Zi)!P-s;+~HmX?+r_r_pNl5P)FL97nF247--FDiFTz)Aw5%x0-2V$1#4*mezn zvXvx*FPLPn;wd7VTs}3l{l*}DWBUtAaB%%h#Bu=WXbFICij_XTJ00SFi<-<6BKUcZ zG}pc-5e=XD2)uZB+hNlxOQB`Cxw%O|PTtKSt5BHQ2Q86n@7Vd*ymvn(%XVPDEPvB$Fc{Vq2+1_oqZ0h^OiA(A zpC>>a{A!{gU9GeDw>RM*&!WSEFk||g!~nCG--V|nSG=SDMp?8@eITiBY#KPSwfauv zY*&FK{Y8DYE;5qyAH;N+>I8Nd2q85uY6>^+rt4^9K|1He>d=6lC;p=liw~E%^VeSs z6~2m}7ROrj`amzimr9c==eXJ#I(y9RT+00R?TR~@ZPPIln2OBuamm&n>aku*j6`d; zmMHH+xP*d}|3m!N`#cK8N@oM=^@;=xSwNPWL0nG&0J@<-*VLA6XsDv-*+ROjFx14} zKKl6B-gD{6DzWvXD|#)hP(!%XsQH`M`@NGy!v0VJ#YL@o?FyjEf7u>p84Y#)3oLht z(fF(DIt6IeJ8BA;tk(X$o^OAsZdtzKV}z}o@!}r7>PhWgjrZEK3S-3#c^zSF!*u;p zO&mS9=9jcsBJofxl#r)hi>`d^A`WhNa5|wz$~eC|2EUEXS=ojCt^Zvj$ws!toV$14 z>|Mt|)dqw(_V2g?Qns^~o0g^QkA7qo)DD$^joAv0_e70D)F-%VgKspLUb@4X%y#a` zzbH}*c_yoYUdBda|AtCK&v13^kyGC5VX3NFA8WM4<9u%EfeTOsU94Z@-pGDuP+m(9 zeuWw}i*3hU7z-MPfWSNl=dW@wp1{Ey3fB{^M>=dh69{ z_}zs5{Y1%Np*kSnb<1Pk=wdopx2(H0Vwn6feAx>Yxn`vqJ%9Mlg&5*bu{>LC38d8E)2$(HXOi7fRC`>fV*|I;f6;RtP0?ZQ)CO4;5@fgQU zAhs>nG*JSh4PGnh58LUhx5WB`c=-74w{uH_EDx(JT)Ky*J{P9f^IJmdkGG2XM`TEV z!0+C#s=TCN^etX{AEat%>OCX(iEbY!0SnY#QKJ55eg#+Y4Ye1a1c|v5 z0j!>8<5sn(Dsap+OD24Dfo;Z7(;*67DV5P+Q)ZPyjQ&}((De}GXM#x4J?^x|_CeFK z(E+%{9^SWb3W=y=`OP-U{)Ez%19P1-=B9-YFJ$K02Q+^nDY;paZM-TqrcVONrBNbV zu=Gdc@GB;_>hsqu1%a)~^|LpDTChgU#U%NgdDiS?w17YeZe3QQ*2GY$DlKEB>bz)t zTNFyT-hK=JyJ*{Yr}e@H>syapCVb6*1ZV1t9MV2<_F?)O79bS$U;4b~&S- zUJFF7Ih{FsfqjHdKL^^)$+ZCa?R59mbhl6!vhbCt_x+Sls=A(g;FP{k>eFLlVgh+_ z@bKZ_@Z|FGVQEXya0xtt#EV*+g{QE|%*?EzG@JlI9C5HUMgiLH=`;hhIl4oJuv1T_OzVvY*C&<8yc*gS&x$5J)h-RM- zrPwBaMA)L? z&eVI;^y;FvwK;3e`=T;^0hIn*KiZ^Ec-=IefgDVN876#-}& z4$Z5R1DTu11Ia}y48S(SE-X9*ixTYm6OLc|;EPc(|LCeOkywByQm}lcsiFCd)W3EV zJ79SEPp7EkRe#FIwc?u}hf`wTTlc>4t$ZWwRnlaJ5zvg>Oqy3SWN6Mo#eWZHbxfQ4 z7f7PH@=W1E_GM1Bvyxq(_lh>xizgQBv$33~b3S-Ahke9`3^*>en~j~C(5-guui+X= zR$xm8K;Lqx;R_U;PJG_7`^=$Rc=1-{J95??e@qwx`ydY6kiH!3ZsA35-0+fhkyh*he7vVK5kQ^8iJ*#`p)(lh30a=#MQ9ZzAyOVFkEW}soN zo0gxZ|6PQOGtODu>JXHCBH>t)ilA8(;Aq-@1Dma0u`XRzZcvmk_uVvxG3-XLxui$1 z|9CwKr#SIC((o%qfw1d?L*jUkP`gs%-|#Xvp-v>%haOw|4ffWhO~Sc)n3x|!77)=tm z{YvRsV$JS3;gtpg ziG{ysN}tdLo%j^bY`;C4T|kAzq3=E*Eo$U|Ypx&nBbF)MVyU%PEEB~(%k5R65Z`cuoNsJ-h+z0$UPMeO z=W*3sI6lP%JbHK0{_04OSTteJ$}N!}*V^ClxP;7wF|sNbLR-BDc}rR2Y%%A-4wes{ z6J<4|b_BJ18sE_`bB4}vJXBMf{M8G7{%F@`f@WK{pLfOW7(VA$-8I5wgiB<9c4dip zSIs6j7|3IC!JfW3;&bd_eK_V%^1l1lWp+R0MYsK!nk%q30^uJpYk*+|Z2O+aR2Eu%KIz} zOW?_T1}r5{_QgiNRy|;A-TTOW0dzfH-ymoiaH|6Tnt+64UfI9fCbD|Y056DASy_3$ z!P!!>qX78@BxdVsfP2Zv#Kc4%O(r;yvj8UCrOjZNLpq-l-m0X%`JNE9V|;zk6oo<0 zddhEObAgvAK1hn7=1c7)QTvbjmS7unMNXQ68@EqrOp0^5olbA}z6SEAbZrC1V6cnT zwWufZqFfhG0f1)bBlTHik)Ia}Ey=+?aB4P1WgIm+bBk{a0`u~k9{yN(g*X14OK?mO zOwM+yopvIAFbwV2tgX?vuc-Tsy}CYn4*6I#6U;Au(Syln zqYwR|7|Y6QtM=Phc#@pnBq+guEWtX0=w`+4=M(C@?kChxg2_wa$hEp`rRkn#$4iE= zp9{#!rRbHl%Oi!lyt!hTlNhb>#mf&X!gs-Uqb&C?pEynT?dE`JhitS(ua zyYoMaoUa!C(&pPk7mEWdZ*p{ho>8OV)LA8(-3n7=`XMVON~oz4F8)-KZN`8rf-8mW zwznfe#i)z*ZS}xh0T|yX3dZ&Np!C1kT3^s%XhR!l)F!DM`93{ZAu%?eYr|aV!u5-= z)dZLtS3ZZGBc{Bv$5l>Xw&AETn=EwO6>ij}E~s+%A}}z1`vVbbzqZ9U`eRGlXy{To zkscfQok=gXS1;vR`>YZd2Dh?q$v58UYyoxR8w_cD3 zYLDwn!;jpLlO>N{GdEwhy(}iu_xsub<(pXV_ONlUrHmsoSQyoe^p3Ffxk zA}TtZ%xo*e4YD@enyfX|KG!DV%cu#EJ>jR*a{V$^T~_cqBKBQ!JDZ5R2?nEeG?7&1 zd<3t*_XsU}Ql>y_d4P;@`PbCy=hC~nBZXvYy;LW!8Ny#F(N7$47c_R+BVkpOjcC4>;jHH{ zx2YkgJI|MaVo-h2D*%Uh$RDq|=N|TU^&da?83UK~j00hT6W;(BCt?LtgY$s#v1Xj7 zHkWwmpt0Uqt6s+h^j_eu05-KwfGZP|lBmqM@e9$=JEkvMIMbHAi4-m>RkiuEl|swQ z-+`gN-t(F*O5g-V|9(gPl7ub(aZi3&50QQ2r&zj%f25&9?u`PH3cfV4Iu~y2bwokh ziiVM#k^QaiPdaMMXFo<02(yemxVY1EnpDuj@?)y6Q+gEwCQwMngVeH=I!-h5-s0|8 zFS5L@ZuuI8KY<6$;i4wKZI~=4;j)6uwe&G;#iQbU*IA8?uMTtSpv0J(PUy?Egenk* zm8~=>(Wcyta`!6LJ!4+XS=sy>{#WR`O_JpEHo|865NR6h-&6BLfl?j5Lcvj#H zwFfpNFYXMd0{Ce+Jt>$>#c5B=#j}S^eQcOviR(U6?6*BL%nl{GIUB7{Lvp!!L8|C| z6s{%Y#@z^k5&Ppm3Y-x=EQ^OSM{-cJU=gugBavObNvsxGFx_NgjmVI&{mWfWrilvE zQcTXELRKZ3a(tYUnjjB$n3c-?s#aU4Z(V^R5}Fwo5x@6v>}*?)#($; zUgM9~sA5VT%-OdaIdg2fm1K}iJk(0siXWTO8MryH?}D)(cJn>6#E(e&=L8|$?j z--1v;`|a0eI#GePv4Y-+6NPP+|fwQ{U)$|%-24Jq;e<6 zX`34v%Q~T(^mf`=zG|^6b|K&Mwj8T*++Cf;u6j}jt4f7-MPQeSbd8*DU7|X>G6$|l z>RuJ574Pj8b}!z#)!kz*?tEAa)j!e-^6LvXMoJS13@gCy2F<%284Vrn$&=p;C;Em$ z4X@DWMAGPC%V+jNXD;pWMLvY)QI3ySrFlWkwI}`d@=!Tn#ZI^O4X(}k28%glW&~CM zyBfS9sgJqU9=;X*PHA8-0E~oKvZDwU>2Ij3Ci@2m!I=LAO3(xxG`2TEi~lH|8Nd+j zKmiAd3mn?{xoLoZ#UZ^do0o^^Xlkw$*Dki73V5&5di#N6Fg5y}Zc*JD*JHx%GW7_b zs&gT+I5#h7n4wVg*e)+pEEE z5$r}ds#JH?c6~>=Rui5U($E~)q7(_8h>!wpVIkl|=})N3LbYx2iZ5d~f;Aw;YPK5d z8SF`F5C*rbkR*^bKrgX3s)Rl)TD&S`kB`znnOJ=NIU{7d`U!P&vy+4rlw94MLks&D;+2^;q4beWOBMA?9*Ec}Kfo znJ&T3L0Vm)m}ro1)C(|*d|L1pmk;7@XPqBQNd&&5C)c?O!+%}pb7`ld>Q6=`;KRSv z)Y4l0U#BDKN%!H;P&i4J1@CZYaHZiNCH{! zH!?f=A?_h(H0flQ-C?5EVH1?r1z3SdH^0w)l6j0(dSL6zmqj&lpIF&VEIW{@QM1^M zvb>C#u;a6Ko>l}jgF0j%Ro0KBDq@{o3m9p8Szr`omZ}d+pB@u^gGIq$K_T_4w ze>x-4ba&DRbQ0u;MgNOuHm2u8j|7aVR3{dcgZuK_0}J6(=|P|v(ptU<9vBL*KraX% zfOeDibG{{1ZlqGdON#f0`2xubZJ zr83;!cOU74cXS+4IFvu^U&gF$$>5^eny-D%hc?z+zQYcFkvNukqt_kUa{3G*5Z-GG ziC%_<`<{s*uB?I?DsG?#?QGll@;PKu3x;tvQCOadZ;+6|5ui#wR<580(+WE?NE&r* z?HDdSC}MkL#s9Jx@e6LfET!;&1jzkgF?&7&?Cj$8IyQ}u_7xnme5oIrkJYOK)8XWt zU9a$|A!OW7LSzgRtYYlLxBuf;1yGiM)~80X_8IVe0tGF{++k;&KJBx`;hg1ur(C^&PqP=%qN_W=aQvRW74obMD)2%2brdz(=#>cb-4>@?!c^2^~UD1 zQ9W~+xu{v=`91^Zw``6vzPmY_-D+zVZf*wg9Lw)~#@KPNCPebwCG*5m4dL8#Ila7r z7c%J%`TbT1@A#J*xXWft4J7e?TNFo&7jAY>+O-WfB4D8D&Uqn$={1BXJBh(9n*2Mj zk6(59ZS_(uhJz_PK?z2L>UhS=k|r)}{q&z~JVv@;m$sn>K$`hC``{t;oDIoKX} z%k-XlFli_EMk*6hD$_^L{aMbF>$@~!x&}fBJ{}%eqt}rz;3VuF9Uc9mLQJj#$ApUt zJZ0s8wFRsX518Ug(x(=Hp1X7>bUce11pC<$(r-qtxMo*m{GCh&)>s|IT#T#eJeF2x z011=)uNNS>z)8!pX@V<)tYIKUqWc#|<@{$|iM|H^b7kon;*PBGgUVFS@(TJ@25sav zS;wRPD$$1#CQIcv=-Qd{Tv63Xro$g3iTG_N3w=WWqV=Q>Ro0Sj2Zc`6rlCoz zp5V)uxxi|+U3pTIUnbC1r{^dqA}axd+!9GSAw8N{p>@mY-|-OH0WH{YL6XVB|^TF&38!4yq_!%{f6N)oGO!Z{gdPkT3+L5d<1!IauV9Qu(YM22~$xAQvL0d?8WHm(jSeyHWbb zDke#Ulg?yJGL@;o%+2|h1F0QIy|3Ak?c}u!1*z>xZ24KHju`7cUGDmD%j+(C37?P2 z-jdU5FPQ)5EaZ?TbNt*G49Mu+;Q-nwSikC3`>&*jq=y zXEjR=bF3bcZgjIG?r1nLh@0PrV-qI~5qH9!Xs~0~yqjRFv5antHE$#A2im2II>V2H z((#T3wT@Pot`D{^>@eou(|^R6A;|ezQTM`VV0`kl$B=XdvoT&`UlfMMLK2Sz%GW(tFjs`l!h^)X9gAXGPn}pU}o&d$Vj9>aHBc= zvEKd5FalD`Jx|QBFsU2(NC;7|`+=JIwfHj|WK~Z!F6MkP-bO_|d&>Xu+E9xv zparIF9pCJhRswPh9H`=NneVqr5@{m$#tNiCr(&wa8?VwN{(QjC{gsWPfa^VOA5{@o z01u+vAoS`41y#2ARCMB^XyMlaVWN3_-l*NJeZWZ=x*(s7LXm=A(Q+|oZgX)^pzM^@ z^I^I4K(;ZrLby3&OGe{NbcxSAvhFR;n)tOt`AaSq6cX;4&fc(#aR@XsKyX~LY<< zOLec4DD(<8RpOn4Rvz@0VDhVk64`a@09}}}B5jckf(_}1I{$k&M#P_Ck`@%=>xgD^ zlqG6qVSQKJGvoiM~cJ*O%|??b;4Xc6Qtgc6Nw{JTJ;7 zUCW26hGueeN_Gx-w(7S_1WN={n$z!_4sV;VI>~dNPBMX`?5aoO^7MPufdi~33)F#2 z<_Kl!M6@iASXwSAwO;=ZVQ(2!sL$8*mJC?X=!fH9?(UW1qQ$OVK$BJ z?Ze>qay0m&#nShsShXJ*b6q|F?xk ze+#pAr>uE3Zkm$qFvmY3B9gCWb#tKuMpzIOao~mr-t{nFu}+)2U>IK4s8rPYK%C2J zR}h8~y@xcS?ca!zv9V)${TBb(1G&I}bF_zFQo2ia84*truM`P1e8RcaEOGqS$WV*d zANl6|yzZUZ6O$O(KIY&)SJ$(-H`P)=s{ZwZ3DMSGI74b`-~77B$r*EV!6Mi@FpbB@ zc~@^=_moqJ)xwy;qTq=fzs$$`^pv2ax>BOnvafiDcdzBE&zTo1X^9y3bC!fg9gD&d zAfBP%&JIGDw7y`RPVaSO&_G(R#OHpgaIfKs`LQ)FQ|S+3cPCv)wG+#|Gx89wCHqO| zLvjZa*E`0tl50&gVf`ZTU%GZ3n6=ZmsiY2^qCMLZgphWU(Zu)UGo6omV?Cphr^lto zjT{WOOTx#*!aDCKbKnB}1Lu7==Sf@VUEBY%g>VS+y|uOV(qX{ukkM8?)juX+=tKjD z>kk~Kr@HAvftx&0uqdMq7{3fPh&5;I&<8BcZ6T5kyKvUSy_STlh`n}yWCyG z#aXR`)FR5}&(FTtA@vRY-3*6%S7l!Fqm@p^@ zD`MF2D5;gM8nxBi&-cF9U};oDYkQ{R9*l3VrRyY40}Y-vw>RrV#VtEo)!McRwmCvT>(!olx$}H^EUDr1p_R_&VH{U964T942qg2VTl=PSAV(bPcTZ z<>!~p{Zzh_jLXTvwrC-Y_qOlz#?>|x=V!W>prT2e)x{8#rtLyTjS7QHsh68ud@#dA zlhix{G`_E%1d6M4!{fs05j(e6O4{fH^d)j*udLZVrq!2l$gqaO3Mgm-e_krYZkH}v zhleH6S$+NdF^wy}C~}&?lqd3O*^ov16eNXC9j)EL55|eOs6a+MRBNhW@0bnF@0ms0-$8!biWV9_c$|>SFE)4X|26iL#I=d!Xq!v1#)0Dih zk=A`P37Z(BSoObU->5L$IYQg!7YIj(iyY0MIkwn>G)QTpBRsGojUSB{W}eJz)>q!g*rBX;0n)p=@};H=o!*6t z_1By^+IRlSRI}1TA0+5_DnBCh)TnpFA=KW5l_dK@W*C{?Knb_h8_-@P>@81Kl1b{P z^bHQm7x<{~Gq(fJY=fSifyPay41!Nt;81zQ?I#2#oQ}pAEr^|>{9@Y33tuP?+3?PoZGc`dv7q%`pW<7; zYsL_259-%`&x`UEo_wEYiCjZx*~*un+Q-rOvMe5yqpAioqd$Z)PY2O*rx&)4A7vg? zrc^sKYb34D=20e!Gwab~OG~X6Ghr7v^L5B;eCr4-n>jTKAh<&j|NXMkX9CS$xBv+9 z(R;ei+bM2iju~2|yZQ?q!kKXc-9=Mp1BpUEBEE9}l>K(0jPNKevR2 zhEgI|Q5AfK>kL3OIGW`{fmd*ML_HhOw}6BSN#;JfI1yk|mO1$3^b)q}j;jJ8Mv_!| zOGZYvuReW*?~#X)GGqaNa}5lZs`qZ}ak_xN3a-}yDJURHz$j$U$KgTv=QVfjTWnJ8 zavCq(?Bkrpa7Q;BK?GsD zm#&TxKNX)h3P;qV*B@bcF`Qxgj|@bhKFT&`JC6t1Yp-6RD@f617vRbvd<#72FhQG1 zkqERv;@O;%5mRZ=Cx{^laDQYfa<>XwEVRlaeMOhK{o0BPVG>)HPMV1Zb+iN754!p< zr`1*l&0)Dca=+F0-@Z{CQ|QQI_gy5uEY#Qv*=gU@=e-k#;0rWK0>3Zao!GJpFVcon zsv7JTL@s}8`d*eBZAw#FuZY8mo7+_s@#a!Hz|-!-n)LeYg=IX~wo(mA*-;mLX#&WFP4wNBNYQ?zu(xU5UKefM3h^UsC z3~27x+SGVc$vO2ghT#RMwrg-sBsGQ_?PxzEBa6$lWniz3B=2i!psbT*#i=?$rIC+e zywky#*43pQ7nqYVf}|1;(LwWmzT1v}BF^(;`DKWj|GwkAk?AC*YS*4SU zcvfqBEyD2KiP9HYHHdeS+Z{^_U$G+T^2uTwYWjUalc4q`wB^6Q)9<|0|Br_T3MIH9 z$#?CU(dyn*`TgIjMZ=&OFs+_NG(+;CYbyPf5$T4f)u;KYC;LIY$YCtyHX560o|# zp8e8$P&z1fM1<@}$K!%9qlpGuHt@s%oUo{=F-seGiIz7$diVQ1Buy#M=#>&)=A7uW zRC}Njubn$+th{{2+1>?2UY(D3onwoOFO%M!U#*Ax)@g_=e@XjRyi$U#AjvcS!k(Fv7+j!CF7 z`5*b*{Z^dpZU$y$h9n%RX0n26ZRB=O-u7t>OW{a$LkP`y3%4n2pgXF^{L`a8BBKrP z6Pc{W8$B&p@U2--tSANO^Qcoo1!clz$KE+~J?tEfpLx@ZyqWjXv$?0A} z>m(aKu9&ZZ3Ngz4hoJ4SU4I!p7FQL|SL+AOiNGZl2GsqC+FKTr*{xRd0p+j<|I!Kc zzKn9w^H3VAvT#VuOEIZ`?)oP6;dMM@D4(oJY|Nn!Egr%;e5ia#eN1cGg&Mkp6S?s$ zV~ifYXp=h?Ph$;-R5i$c8^q@-mVP_=TiW`mo(+AW+rU6}rW{(lRCFp_*y>)sUT>EH zpep$&dC-giPu8Wks1#a8)SA0bstrsUQX-<88LpUtfTr1a)Y+Eyh(d$7Xb<%ayu*X{ z(XB*?AP46|Fnac=dm9VWi;>kzz45=BbPpih#EZ- zd!H%LU4B(%pjT1YbF(pznLXbmj9qWR?Mz{>X<>iCr$4uGI!pX(%=5q^D0TKBP2l{w zysE0&x8=%c{4jda&t1oAD%!BvYGv1aD5C~_K5y7z&O0LQQrby{5FKiyZkL1<`kSl$ z)Z@F{SnZB;g02x$;ezUyA?+j@v-hyKHZD+_g{jUTCYZvMbVqopn9Iss?F@gF~fOPn`J26-Lt;z{EJI zo6=y{=ladhmO#%2Zc7EqY9MxZ7)bKZlxSz&#8oE7=VsEf_ zy{WdVp%1e>g;-$H>)e@iB>5+hiDUnA9Y?4mgA3AK*r}i7H{I|0y3q#hMkWzFK24kj z)S_A6Va+9}UuB>@Wg~ZN^`8~$rX_(+xAqIY_RwsP;9_!ob-Jt9WAZ2HLaZm<{5qZd zrZjdHp~p3+D%Il5QPWJzJHGHv^0GJ~X#6dW*7-Yde=A79f-xZ>pLG>7jIR!l@U1_2`~N!`@Y>gR(EUPAx6KHd|*?|G*7ENJxACnt9@4^jx_>O)T; z0%kQw2sTbt`x6w*ljZ9Uj{(v~eky+tML2H?&+{}f3F-;Qa@iP6m^~y3lY~t#XxQ+N zYmEXg&WEwALM;|Bo}gYGuXLJm4jx})o3ud<{Npt6aS1IM&gcDxv2w>#o!mtex6SGX+xD?OifLV-DU3*bVRN6_zt8X zouU~;?7yfrl)tnO4Wtoi{6xg*45EfGDMgyi7$%qQX3_o|nL)0`{xnQwoAPSt_04c(x9c6iXG6MX zbhABgLx?nc^IHF+?>9n72s>PFX{=S8t+A4yy^*KNvL;C0F-H@E8mn2ykMz48+9nr& zL`YK&7Y!WJ9u6T08xEE65i6oon_TJk9Gi?W@c)3_<&#-H8;8$#XqjH1*5alb^8_0F z2Mre*#(+(+Wb%8kqfP7qv_rpt|29}TMraF%A8P~pBn9|=`yy@0hQB^j(HQhc4$B*$ zKLQ}$EC-!aGZ~T^^VHwgDxGrQ<7@xp%FNCYT!}(_&=70_Yglw_tUdEJmn!1L8zP)d z2u~EEIo}K#jWxwqS|QfKD>TWRyls6C0^3=<{M1Gn_ZOU#QL|q|7N&N*9i9nH#C7pS z(G*|~qR;8l4KN!t$MQU{@d(7;5zBJ_^@0qU^6g%zbwQureoosAH~nrTc|)>uHg2+P z?3ym634+tarZ>iiV}Z-th1~RcFOGjVl=I!?bQEL@8tgA@_NZIE3b|hF>QLsEO<|Yf zx8ky-bo2CRCri!pHFM;Acj>95dsCb%iLm~6dO5Cn28j!^(e5Q5AK~tqX3IUF>@A<7 z6=)+zj83+b<*9LJEj@0J-D!;fa51zKyPr#RoALp&W zOZqKBmx4eVv)ttrk5Q;O82>w2sKNw&zPVD76jR@WbBY*o`Xn{1cY5t*ZPp-{pIz3J%M9(>`a2FehNL-OjoAwTk}rLP zzgp54tdLpe)FOo(*SK#o{4B|6pvbL*UP zomZmGKp=6!Snp4hAHbDZOpQZfp1AZLGp9Ql+#;W5U_9O4$}3O(cU(C72b(b?&#+`I zxu+&|_n}2s3Jo07cB#jQ&gmVf4u|wNa--BdB^%;2o}xWb%9lxdG=cI8&OEQHv7bB1 ziiNL8B4{_I&*K=*xDl<*uHKncnMl_k7;EJu*b_X?dksGsK%rU9?EQsdK8YreY)PY5 zgbXP-n^281XX#7A5|{gy|JT#aExG(n)t^@TPxyQQ&W*xPQG5<~cnXIPfp;kICPh@P zj^eBPeht$2wIAsD1_6hZ1`>0@u&8e@zucR7u@fV`IGf%Q?LoKLo-j3>CF*mu zAsope!~~zTNO5j9WNm*6p~D)dxh-t_*v2*ezGe-oH*e+MBlPg;KlnL0I$Pa4!}x6% z1Je}Ds#Tu}Qu|rrsvkd($TR%3afX=d7AqO|a}K7l=Z%r3oKqH4No`}ZCTNd;Qs7zq z?tira#HIL>xq)SE#65x~Ga#1|hSvD~@bQjxW~-YosN=ZFyKlLQe!qh;FbHdCMlS%Z zDV8z|{qUo!fITk{VksLmXk9=c7Ek?R|I)jB+}z76jrC3C0hIZ-9+p(su@wA5ATw6& zyk>naoYxoiNix04M5R2RpUG3dOq7a1wRU;7*1pBvN6q7OB)~RAFUqTU`V+FRfyNx4 z5|lY6bB{{*DHV5jikq?jl*oR7!|X#+2{A-|)hs4%&8_0YheDUh+5wXuor35Q#FKwM7KviB!y=pZ03^FY3|e4)lQ z@@eY|Y7PsVsVlyBgf&ipIhGV_$aY>~5H2L~Uv`i_O(@9TEYAPojgu^u%cX{}Vga9} zj|9^Tly&*6ZwbxA0ebn~+naRk{Akv;6;C+#C&=M)0uQQeiUmvTh8oxdYRq1uuUCcy z(o~FRfCx+QZsRekIsz7qVrXbjoy6fQ*7*PnLA3Hy?D4^-m$I@s}_o2nx!B@I$v7CJMi)#Teux-la3 zPsHFGnj;dM|WBP6z8jMJ{RqEyBp@~~MI@p(XR~ym(G3@z8 z`AxI;znZy`;;os7)3l;`mum=X5_OK7LkYeaX_x*!LZf{i8HvMIE}2*_Rq%^AB@+3j zrRO)N5#prO%$_l{x6dJe({gAO_|iaDBbfGIH>1KzwOH6|;d#b@ACZcH(hP4pgLcD! zE_CGX+8?HK#qyl3>L1PeEut&~ie4^ngkli2F!?g;4`D_V;L`?KZ#SNn46ue+-CqDP za{+@fcpW*vUEngRel@nVjDUM@4`yrFFMR?wli%E26pI6e9ywfu4G%mlew`g_aK#Cj zv0LDUAY1movqOOUxq&UXzz5@Lb$m<4CkL=HqM??@jUZSYk zi~tq~OhXbkIR_U+3kt492sO6%SU5edO}!ea@&lm zES?y6`Kdw_zado{SxbEwsu-;4bqz|8ice3^(bJ_Vxhjh`&HRH+XJUqB;q+!*f0Sew zf5gRI&P3jZN`v}8uk+`DiTaWu;u3%MJSMT^XWXBh-%358^leuv84f{cWZ&HXq-eW6kA6(mc1qS<6jAIBswYC%-Y{&VT2$Ngmm&+ z<<#XvVN%kTE+52Ca!eE{rO`h1(E`hE=LoPzf9LNw#Q;V`|Bs-5qV&Hp`Oj#7H#b(f z?|ib!8IT5d6u~u;!0!+>7VvQH3%4r*W5-Koz-9r$EX(-H=xoD~%nATg#F1WEgAJbS|x zz2v3l&~W*#&M)J0A|T{UmFR7n@ViDwX|Y635F9%HUB!~QdeHv*Wq%|Bi8&*9LB)d8 zdK7G8%*duiv}Q-j!-z@Qg$?Q^Ez8$NJP9pHJZ|mpv%~fw z^e)C&q0jie@9-D)OWMPN>M#*MQ=r(iT120s1}_{6RGBF32p~=3yHX{jIR_$;APp)L zYVR$5Npr=56IxA^ZotUqsW-(H97pDhVHil&(fV%}UF%Plxw6Xu3NPuL%M?-)gzN(JDEZKL9+i=VFT;2W3!{LhT!vkn3G?p(;QK!s4E9bD_f}}{xd~M3RA;FVT-KJMum?LtV;wnkm`Bj z;&bXHcZwLtr_fAoA6Thm%8Fgh^YO^ID6u(orzL(@D+EDkoo+D4j69PlM+dcy>lqG9 zgNE@ep|>yX@MOhID$@#B2O?@VkA~i3iPO%IZikuKicLoExy;-eny<%} z?h*JA@5;J^s?;CqsQuMIaoCwQP3DamiyvO3E`;fq39{n>xA$7}fot%_GI!beCj??{ zdX8E{=~DNw+Gd+R=xd(IZz-}x`m*M=I~q8GJRt`^weh8lF)-8}uqEiS<=o?2{a2{F z<7elzbpI_xroJ0gE&Q<%KvaR!E(US(TwLEsPq1;NnSq{a4!+Cbi6} zwv22s!i63d7Dh|q@4MoF(+!4f5EoTCWeqMh`5l3b5m~X5bY$vlGQ0XbVgTzRZ}`7=cl)gOP;{p2dI!g;Q=?{ z`jcWOL0Bh~z$Zp7f(?%EI*xll z_NGzivh?6a2OR*eO)0%R#3_RC)dE7;$GCkqsL${5M4JDXZLaNrm5HAsm^ePRJ7s#PW zdkrDAEmlEjh}uHrn|cH5c`QdjkK`4LWl45gL`!aysZgFY_w*Dnb=dGSd@a7@{f+Xp z)Fo%deR7PVBRhs~k3DJ&DXQU(&$v|B`<-iqK2xU!ikQ~1yZ7f+;+Lhb zPYXHyBEhx7{>SVua8K7iJi9d#u1fc@5BEu`7S`~jIQlO3t$ zB7ZqOFUu6l%N@io9=E1DZh;FMxRM}3#Fy@Y;yl)vpl^ELBgf>L9K0(cFg&udm`Ot+ zu0Ka;u-DSKqm*R{J@Z3v3VX|puwHYwVh7^Bc6Kc3#hVuH>_G{phTd%Pcg{@;9U5*T zKfSar{}}7q<0B>?N6UJ6XH*!@t(Z%y^5U6OXKq^{VCh)L`hepGy=O=Lj*yVhTkE_1 z{ciRHbHM#Tz%aZCJA;FzOBRfbjBrI$U0q!Ur`t+L`2$4qt=(`1E;K$ z0dojxlI^y}4w6A5MN$($EwIFoaK)ral6KD=vX9M0P~SznT;S7c)e>Eh{OsfM55n%F zKqK+akouIM3%iJ1Ee2P;C*B-W^-teHQ>1<9YtpBqH%ynIudqW>D7c^C>zN#9cSHYP zck*dsW|Jm(rKD@tTeSm!^qBzb23<1H5wr&Kq!|2M(2-{^_G!-?QaY63Xmg zEdcjGkgO*!j~cfo@psY)t_%r}cfy$@F`X;N5VX+l6j2bsz6Ccq!J~4h{*H(1O?LjB zs;bNozuA2qkS>1TBfbIOu>|;8vZD`RTZ7F^WkcC8%B;wLZ@T0MoIW@c;CW)a5^nt! z0yP%75m+XBj5?PVZ^$>plX3+8J@`IBZddcVj@7^FDeMyv(F~C6=TOKpSPRm4K+Grg zPPkb(R3mEW3n$!<4|e|unBSQYqtPk@+VlnkGCOBtYFl4SRE4HRzgT`qFC{0P(vc=r z{WL6+oT6vgf=k21MleR^6Bk<%PIHjVTL!k_2GmbhSFnpieuIHa+NTvE$n>W(f6mp{ zMWBbu!GG<75)`lAkRvkM(I|4ipTQXPCcvbWj#|cUddvFf{dt6GDkBral_^hUiEo{OcJYxwnj9Ar%a>A<3Stc|gaeOKjQobljcgT7+;1#YB z-2L#5VrIk~?CJ9VCOfVc01H#B_(jJ=qhQTRA6QCbPG_X~Od+1K!o3#ch@AhzQql+zJ()9~aQioiJE4LT5|(ZCY?UonE$dZ3}~Tt8XsVZQ{fJ`j!$ zWCK9$m%YjuaK;D+i9kHI?|~VWnXN6G)C-hZ^8e0BO)^UMek+L0&VsLI0mHcpf%*k& zN_-m4iRfqjSM%RcFZDyG)8T88O10D!4|U7y{by~V&6<%S?gzx-SX9f2kpBt50iigO zig0RDI=i3$J%ZW~^gQ(+<+hBZ_I8Fn2{rNLUh1Jr9wcHYVR#K8h+6)if6Eh2qW`-^ z@SU`tE#-;hzMrW_-|&1IaDcej+HItZU?pLdOi8clC*AVz?;|bJ)ee_`4SAcg?F=@v zBZKT+<7b<0`9ifYR2$ZR?lGcb5LSNEYu2!VoLLTht1Vnb63yy7Nc27Sck5@UR=?>1iV;ifCZ04ZO;I8a&T7L>yQ}*>e)$={` z7cF)gJMN45viWMoTjn@=Ydn=EBcq9I%V-1Hl#=}y3Z43Z|616Cz#}xO>+5@uA0Lii z^79Ym$BF%fCl7(^0I3UTI_PG=#A*25&A@-JIFITd{L30*6gx#l?^z819n^mlC!8Q zRH#8N=Ii<92bHZY(h^T9+)V=V78i7AJ)#h%t$E?Hop<`j-*0L}`^X6Td9+`6J}{F=4!Ul-jEh8htG4WRmXm`MBz&+0Bylf{=;HX_Yj0 zB?|7)er4!I5b8VDj~=g@2G#LsGk5h7*}i!`S50LIvj{U;(r;?pBJpd9%~V*O5&d)a zsJAbS8J0x7BaMJKtcCV>xG`h}?a4x|U)G2>$qJXx8MU@O5-HL+rOn3AIn@w^s}02Y zNJ7Nu4Men{aq4@u(id#c_S|%vAwHPbqFFwXBaK1(AKon~psh!jXFS^XH_y8m1jmZJ zp)1M9eJg@~Alvc5Sm*{SlP}QgQY+x+YqXey-rpo;aUe^K7IHwqhJ61Z?7$Ii2~sQZOG~m#_aZd4obk{2}kaLRvAn~??NJ? z&J-<252nca5NReR-wUItTE$e(#N+uSgvl^dXkQlu9UR@@lvHzVta58G<1yo3<}@+U zs;X$}?$lr*P`SVR=dZhFpaVwL$BX+G#r=yzF$Y(Ki#hnn*4 z&dYLb)=!v<=BoAggtm@EB%YfKo3A9G%>Ic4Q+`61mYBcLr&Qs%j@PKh*hmYb`$-y& zQt>KGg`m>FPEG+94aVivA`+UA5qpNr61U9^#U@2|iiZak3PUA+!9_F-8^)Mg{uOUK zel<2il>VXrL1pt+i0o=~%|SLAkV-}3G0t`dJT_9+s&rOTL%pFn)#NfPA6wm!TeioG zn&#dr!&iBgY8LBNUbfBU!SI{}1Ctd)K_&~Z)YGvnWFCEJL#npw$GCW&xAjNc*D42> zWSpi(GtKu+r$JC7xp_Wqvo`yDU?O)4Q%dCJs!uf;`)K`isv+lGf~3Q#tg-GX7AGtL z680katY_t8fD_@{stfIXEulE*AD1Vu)?1-CVQ%F!_KgGeL8sM%Jkgz$h+2pmmc4@l z-lsZazPvnPG}OeT1I=!Q9=1}{vi+o?OcUpHUkwT7n21g$-wul=K__&VJ)|{e-n~Z7 z9g$}jp~{;d9RsiWG>heeY>w1(zLWSg^a}RcyUwyhlRC83_cVpJx0rnTpOGcOCMs*@ z(9HfR*t>3JOnnr)SNg0HnhuL2VQ+fgsPU8kiuvivpD<8;4C^$g(cJ*@;^tyAV&iT2 zYi&zXx&J~~cnBVg1!mqj@rRo*)%*QitMR=%f7^~6uN#`+Psg_D2z&}LKvACh2k84o z$-97=60UURFfct{{`OVO&wD^wsYx0^_#88iN_;d|I{a@3wS^b*XDLR_2w5ZDOnF+N zD30#)gF zB3^$;gZ|7$I>!&o#QyPZwf?LXgczlV3+%_)IJc|YDspnuWUjd3ldhHF!^xsM^wB!7 zRSHV64}ETDf)=^42fM~~Dng24;h+=7$x#=azh~xY`|z&Cxlo&AzO-yxfO>)}dheq*vu3hstqqAK8+!wca&Y2=r z{c_Rdl#&BDUCP2~%jyJWI(dv(6V({wl#NE;8^{Z0$VmCsh{JXoQF||Jervup|I!zm zph_2P4^Eg!*N$HSI|_6ras!c+56M3j1-kZ_NpE@tA@?k~PK9r|yzV`&nrxoGB;Y69 zH*c6JE4W?~l6>(ANozISiZJclny3yZUV$7!&_PnSW0NDJAgH>X|6!;h|LraTj|FJd z|I@oWPyZPoLwnk-_LVqI!syCT#->CDXZ5A+|GN60a;ip-`-}Z zUc?NZO3t1cp3&@C*IhS5%DWCNvN&FsPs4n{fTG&(xntEMQ?|TcR)Hiar#XFxb3Q|N zE~8vt@5uI4qg>uTr(XG>24}HvQ#QJ7tU)>CR*#Q^S9qc<-Tv_9TA;nwVczLLakYbC z1e+OucWW)q)0C$C^{2*`_{oYU6&H$KkxLW6oTL$~bt@4K4De3m?Z!vAUpfveEGd2-j z#n|%rQ9$Cithv5-sDp^*7+@xWfHI43ztq|XJOBXgd8~|2jge0ixk1>2RnbuT7bRyD zHoONLYr$@##2@rvx6^P@H-4CjTGcfRi!d_KyaPVzO=U=nK7h)X-Nn~NjOmc84XePb z-2)Z}HQK(+C#nkKiEqR!!_E3sYd6k9FCUmeDuoNXIV`Pkvnk2tt~lie{uyox3|HlN zoon?S<)$zAEIaFj_F6g?B9Chal34rdLJkDCw12N{)`vHGhsB z%87JSccenIKeLdkm84wFr$ZU49?ADm&8F+6s#O_=qzJK6qFSX~Ewj7o`nWH{COQjK zg7XhoOv zQvJm}MF<`)?xOOINoFH`P||nTL@nQuKYvVnn_KG!&6{G%8>XK?ZaDhj$DbwyTjb$p zy-iPWVJQnn=Im-DFS5na^&541dRoBeiVX~sC{(`jAYoetZ*mC@(F6AvaGZfw`4)`B zE&H5V{z!lZfGd9iQReFU8Ez;rceXJ!oiFDXSp$+Sc?tPQstBECzQGvNFDZKaH(_`` z4mC*~6Ls;{?M!iJXy|0WNndji6T90I#YhOHUf@bt%&+PII)K8Nsq9JWvzhU*NNv^u z7O$TQk{->U)neTH<<$B##@er5YtROh{vwSi98tHIgoH1S}sqb{I-Wk+`K4I+2hMiMOnZ9o^_=S?zxiVfAAKY>2J#*1 zT3i(_k)W2@N-4}=UgSKMDx#txZ)3Ok6=71ssmaLoNxj@!HbzTokvy&yD;X%WI#t5w z2v2&@T=2-e0)^C|N?m_=1**?Q+mDf)2sJ&P8Rjr)lgYH_o3<$?(jVRrb-C(MiO`;u z4xO06-XgMvP^T#;Dl_Dkn0?9SK23bACkVYfuX#jKGuK_6B*t1A%4O&36PS{ ze~RRjTK%4-%?^Nmitiv{0ZUi`LD=sp7J#rcUyDxB7Qmur4LAgLZIQQIIlw80Z{oYy zQHM)O?KbIj+n=_+{Gd?3kj-oO_hB4q!h59}(v13C<^J^J;JlRUF!wY^*o^+6(y&|* z-=Ch{e@AK)7K3ca=KU`CWkuD%P(|fuZYBM|oOQB7cr+5E%TLY}p9vfPYjJm81$0ifd7PII2 z$*TyKDln)11`Vc3R38qdNZkR1*2(79-N_ldcYZ+0r@Ov4VweH6?Au=ObKeUmZjExX zA+vTo|9;=lV+nIOXKYlpR0%(~0BT0CN(~NSZ=cs>z7D|_UM^zC)KC-|vkCPH4-Y?% zpytQDrt9F z1?>S+4U*av(*`3~IWn8}F{+Y&SuCfyQszrs)b!2He`tv#VHDBH%Ju#9$#GwPnz&y) zYuqbb7U|M@$}+;$BunLo6=p#lDnY`43-x_fT^p#*oTu_k=@wcjFGSd}eVIz<5ys^4 zl93Pdng!_qCEZl|AD&)5*|nwQ2Zcz?z9tjNRB`^0JO@hUX*d7SHxhV z^`rXb^nP3zW5(^RuC6gapWr(gA|oRy<|-Y_nI`)krKgy9e4o_!mwYLSQ#L_GG#Fqc zJ1n=B)}+S^E{kGO)@%A=)yB~cG#xPkmKfOp2p&T)A%0;LW zTVt;rWYrkCU|FiHVQ&h>8nNVVT&?|oDo8(1N7=Cm<5r^Z+h#*y%6%bCtclX)>@9T> z#(c_vg|pZm927+ITOF#L>uGEaN%IjfjeQ5!v1Vr%>%kJ`>1hkNGDhqLlg(J0-_Wc! zINzlUgi$%WPv(-(n!lI2p!)Y;Bpz6(L0B8rf?I6G0^A3jm`h1m7WdK z>5DTz`LCk%*oQj`5lD=k3jokzrqaL+=p*3EFzlG0TJIqZ8%Y^u%94AzF5JyyGMCTn z1Mf>L*iQ$lNOuCA9G`EgYr5nyPkPuQs95xws^@@pIGR;bo%)%}__im#k2i5vQob6} z4Z)_vF-$rNM(=_BS+E*j6Nxai;NTk0LWzs233P(tN2Xe@G{2J^bF5xRlSXfwGA#cf z%w(%n*SalGs=vLkPw%4p&-$$$+1w2~@eib*^?JE#&~LYY;<;^_!(QdR9;J~;ByG@o z8o^jgOTyC1!XGukEyj#w|DL#Ip5Q$ZL{KOU3@PWP^gUe)ub?>+`Ob8MKT5~PG#X>t z8+aCwg@4H$2}c;}2Pum3gk6ccTH!e7*K7@DZ8v-_0ZSZ!zFGF0A!DX$)8~@RMv)dG zw4805sN^e`eyjMas6hnMrFJ72QtdkBA&=mfHcNzW2~L;rR(3$_iW|iJ01MIvJYgIj z1qs$y!ZWDmx#&Sw>;H@ShUcEQpL9P1M9@7V9L&8L2)LI6*~|W6Ad2&GHSI&UPEPjU z-^Dk>AH;fyI&WT4dafcqoM1i1Q{5&|nSgLjwSrm<=r@ulHHaPiI7r_sy|*&~UI;c? zo}6$2&>e(MPj?v%bQvJ%yoqO@N{nKLWuu&8Ej%)c|&W9F7@ z_00cZ8?1EeGY-K(Ew`)QMi- z@V(S`of3MY8(7p_Uyo9n*E$ODlt4GtZ@DpI3ZV*pqhvN zBsh>d?fVhY3i5$1>GU*XpiuHhF{E)VF++d!$;Ms#N0WYHJ(M48I??k)TZmiStcQku z?_r16#W*FRcQ`4iF)mAKa#l!`KdZadJXb$j(IPmwQceHCkYPdgr`Wt3R0(sV7%&0k zlQyif0azg#2aP@4Y(Ct0z6?e8&_}GeQ-jH6vKO9}ki1n3F1U~k;$mY7QfPG&E&oZs zpoZ3v*|EKW)osHqA~FmrLCti1OcwwDpH;kOADr`*RsMi;e!5A2z{YEP%Q4_-|!wzp7J=I&cAwTR6T}hw12xTH!?^!NW@gqFc6^h7E#S&K>`3 zq+HL@Tj=d~aK>&m1CRJOld8qbYRy;FS=-zIM7rFc5d@+%!0g*(7H4wsOz3^oXQ)mh zZa}L{`V?03mB)Sk`KA>K*vf)OauA#1DE2h=h?bF?JG{Bt{;PJhLov7YH$|g&L^#lM zs9CZ8j|hz~d-+z63K_Piet`#VKM89$ko z>Kb(tzVKqh(fpm~w^vFtta!Ira==B1w({^e=Tk>KR9Sa_*EBu9o@Tw*vT$gRb=WJ= z*h%jh^)ZiAqZ$dq5g$Q2jG+Lffgs`X2SPz835~r3wFCqe85IedAkXA15yGt6P1XIS zS9|I(t2n**<*^m)*fiTD+vTdXa<8)S&S8}9?a}=CT+jTN|H`$OA(c%@cI_2fJWZg+ zz&D|;tAx56!g}poxyHiS2`L)knHM@7?!RRBQhRlwi2awpT&Q_oL@Ml&arwF4-_9aS zK|x|ZNFJ3~nz!WXMPE_v{nI`5!)i*&z5}^I3hiaYxaXM~{jQ$wE zTZcX5gXctnf2N!hj_lB*Yh=WzkeFqlLIk9O7G7TUE*M>BXJ?f|9*@~g$}_G3!T(I8 z5Ewo6WmNF&`PT?dd3X%M8lJEU7Ag+qrlN_U3{2olmLb=P^nd#_{oM;+?ed#}0X zoKLm3M*VK@e0n&23;60Fo#J7hOpPYEMtAI=>OgYjjVG1~f)FLYk%@`5n;U+a&S~oj z@eM&<^}Ib8vS#g@eSkDr*zeNz#8c=Ont8Qp|1=L-UiU9fQg*fYBk77TCRO!OHs0wj zxdWd%o6nd|a%Sy%yjgwx%w}J6D+c%>rayKZjnYP2B6yUr-)bgHZ_(t+IDY97@pYjoEhpzTC=*Nf2-9emT!wCZ6G^ncRwWZ^U_t^_UN_MyN7>Q`4W4VmzM$f z*;Z~2qCl)tpeWDiDEAPRKSdXE3cXzD*)VF>GFAflVrK)7x zO<)S5fK(R?y3phH_kskSot>{VzPGIkJYS;v?-4&?=v3=={~dSX1%(ZGH4FiD>J)>4 zH*W~_*X>BH@A2~wk&hjrftjuXTbuogK;;q&Owbj!K}qr6-w1{S~8=Rp)wl^KT0Y2HUKi6+`Uy4ll}c zYDTZ*-S{kg2O_V87lmYm2b3E&E`BKzCUMc&7~hKngq}j_q4y2>{$6cC-xSBak`++p zWqo*yk9RkX8vD1rFhi7w>0B=sZ#=sevCDK1Qr%YLQXo}339Ozd8S%fbKNO}T$!4Fh zE$ap7%^jvYd999*GO934C*-c|$~t)@(bRMn)H~$@a>B$%;eOzVF#i2TPuz~s$5*}t zU@ii!*9U+}-DZCHOZp#C7zh==G&RYVOtYSnNo6eyfT+y5z zP4;LXPD$XT(bBZSEMT0dHb4P`^|de?nqZ2#6M3YRVi{XAKzI7AA8CF1Z&diw_!tK*f%+r%lZX$~57!^ix7(l z9n@Q+@r%v=yZh7zxxvuMWpuNw^lIJ^rkn$ni4h?=>N}qrf(SVtUA6Dh$<9%;Bs@+X zA*8yf8H>(#g`rXTBC@4KY7sv2dhnu0O_j0z`MAZsc+1pYYjQ($D_(f?W%GTuAv1J3 z1SvX;$&obQ#Gbn_#qj`FhHGPF97C&_!EsJxw3vyl2V$~V=deEHDVLb)N zyMl2CL|bX@d(a3Ggudpx3WjPfh?lMAS+)k�JR2!IvjUdLn*#_snfCTdZ!O=Gk8W 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
  • VYJc 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 From d78363786cc00234e4e4ecb08e87daf9cac49ed6 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Tue, 30 Apr 2019 17:14:36 +0100 Subject: [PATCH 06/21] Fixed two more examples --- examples/surface.cpp | 11 +- examples/update.cpp | 3 +- matplotlibcpp.h | 2965 +++++++++++++++++++++--------------------- 3 files changed, 1517 insertions(+), 1462 deletions(-) diff --git a/examples/surface.cpp b/examples/surface.cpp index 4865f06..2625445 100644 --- a/examples/surface.cpp +++ b/examples/surface.cpp @@ -19,6 +19,15 @@ int main() z.push_back(z_row); } - plt::plot_surface(x, y, z); + std::array shape{x.size(), x[0].size()}; + xt::xtensor xx(shape), xy(shape), xz(shape); + + for (std::size_t i = 0; i < x.size(); ++i) { + xt::view(xx, i, xt::all()) = xt::adapt(x[i]); + xt::view(xy, i, xt::all()) = xt::adapt(y[i]); + xt::view(xz, i, xt::all()) = xt::adapt(z[i]); + } + + plt::plot_surface(xx, xy, xz); plt::show(); } diff --git a/examples/update.cpp b/examples/update.cpp index 113a526..c34fc39 100644 --- a/examples/update.cpp +++ b/examples/update.cpp @@ -36,7 +36,8 @@ int main() xt::xtensor yt{0,0}; plt::title("Tangent of a sine curve"); - plt::xlim(*(x.begin()), *(x.end()-1)); + //plt::xlim(*(x.begin()), *(x.end()-1)); + plt::xlim(x[0], x[n-1]); plt::ylim(-a, a); plt::axis("equal"); diff --git a/matplotlibcpp.h b/matplotlibcpp.h index e269935..2d87089 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -26,1865 +26,1910 @@ #include #include #include +#include #include #include namespace matplotlibcpp { namespace detail { -static std::string s_backend; - -struct _interpreter { - 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_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_scatter; - PyObject *s_python_function_subplot; - 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_xlabel; - PyObject *s_python_function_ylabel; - PyObject *s_python_function_xticks; - PyObject *s_python_function_yticks; - PyObject *s_python_function_grid; - 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_subplots_adjust; - - - /* 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 - or starting a separate process for each. + static std::string s_backend; + + struct _interpreter { + 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_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_scatter; + PyObject *s_python_function_subplot; + 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_xlabel; + PyObject *s_python_function_ylabel; + PyObject *s_python_function_xticks; + PyObject *s_python_function_yticks; + PyObject *s_python_function_grid; + 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_subplots_adjust; + + + /* 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 + or starting a separate process for each. http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program - */ + */ - static _interpreter& get() { - static _interpreter ctx; - return ctx; - } + static _interpreter& get() { + static _interpreter ctx; + return ctx; + } -private: + private: #ifndef WITHOUT_NUMPY # if PY_MAJOR_VERSION >= 3 - void *import_numpy() { - import_array(); // initialize C-API - return NULL; - } + void *import_numpy() { + import_array(); // initialize C-API + return NULL; + } # else - void import_numpy() { - import_array(); // initialize C-API - } + void import_numpy() { + import_array(); // initialize C-API + } # endif #endif - _interpreter() { + _interpreter() { - // optional but recommended + // optional but recommended #if PY_MAJOR_VERSION >= 3 - wchar_t name[] = L"plotting"; + wchar_t name[] = L"plotting"; #else - char name[] = "plotting"; + char name[] = "plotting"; #endif - Py_SetProgramName(name); - Py_Initialize(); + Py_SetProgramName(name); + Py_Initialize(); #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"); - if (!pyplotname || !pylabname || !matplotlibname || !cmname) { - throw std::runtime_error("couldnt create string"); - } - - PyObject* matplotlib = PyImport_Import(matplotlibname); - Py_DECREF(matplotlibname); - if (!matplotlib) { - PyErr_Print(); - throw std::runtime_error("Error loading module matplotlib!"); + PyObject* matplotlibname = PyString_FromString("matplotlib"); + PyObject* pyplotname = PyString_FromString("matplotlib.pyplot"); + PyObject* cmname = PyString_FromString("matplotlib.cm"); + PyObject* pylabname = PyString_FromString("pylab"); + if (!pyplotname || !pylabname || !matplotlibname || !cmname) { + throw std::runtime_error("couldnt create string"); + } + + PyObject* matplotlib = PyImport_Import(matplotlibname); + Py_DECREF(matplotlibname); + if (!matplotlib) { + PyErr_Print(); + 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 + if (!s_backend.empty()) { + 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!"); } + + s_python_colormap = PyImport_Import(cmname); + Py_DECREF(cmname); + 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!"); } + + s_python_function_show = PyObject_GetAttrString(pymod, "show"); + s_python_function_close = PyObject_GetAttrString(pymod, "close"); + s_python_function_draw = PyObject_GetAttrString(pymod, "draw"); + s_python_function_pause = PyObject_GetAttrString(pymod, "pause"); + s_python_function_figure = PyObject_GetAttrString(pymod, "figure"); + s_python_function_fignum_exists = PyObject_GetAttrString(pymod, "fignum_exists"); + s_python_function_plot = PyObject_GetAttrString(pymod, "plot"); + s_python_function_quiver = PyObject_GetAttrString(pymod, "quiver"); + s_python_function_semilogx = PyObject_GetAttrString(pymod, "semilogx"); + s_python_function_semilogy = PyObject_GetAttrString(pymod, "semilogy"); + s_python_function_loglog = PyObject_GetAttrString(pymod, "loglog"); + s_python_function_fill = PyObject_GetAttrString(pymod, "fill"); + s_python_function_fill_between = PyObject_GetAttrString(pymod, "fill_between"); + s_python_function_hist = PyObject_GetAttrString(pymod,"hist"); + s_python_function_scatter = PyObject_GetAttrString(pymod,"scatter"); + s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot"); + s_python_function_legend = PyObject_GetAttrString(pymod, "legend"); + s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim"); + s_python_function_title = PyObject_GetAttrString(pymod, "title"); + s_python_function_axis = PyObject_GetAttrString(pymod, "axis"); + s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel"); + s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel"); + s_python_function_xticks = PyObject_GetAttrString(pymod, "xticks"); + s_python_function_yticks = PyObject_GetAttrString(pymod, "yticks"); + s_python_function_grid = PyObject_GetAttrString(pymod, "grid"); + s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim"); + s_python_function_ion = PyObject_GetAttrString(pymod, "ion"); + s_python_function_ginput = PyObject_GetAttrString(pymod, "ginput"); + s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig"); + s_python_function_annotate = PyObject_GetAttrString(pymod,"annotate"); + s_python_function_clf = PyObject_GetAttrString(pymod, "clf"); + s_python_function_errorbar = PyObject_GetAttrString(pymod, "errorbar"); + s_python_function_tight_layout = PyObject_GetAttrString(pymod, "tight_layout"); + s_python_function_stem = PyObject_GetAttrString(pymod, "stem"); + s_python_function_xkcd = PyObject_GetAttrString(pymod, "xkcd"); + s_python_function_text = PyObject_GetAttrString(pymod, "text"); + s_python_function_suptitle = PyObject_GetAttrString(pymod, "suptitle"); + s_python_function_bar = PyObject_GetAttrString(pymod,"bar"); + s_python_function_subplots_adjust = PyObject_GetAttrString(pymod,"subplots_adjust"); + + if( !s_python_function_show + || !s_python_function_close + || !s_python_function_draw + || !s_python_function_pause + || !s_python_function_figure + || !s_python_function_fignum_exists + || !s_python_function_plot + || !s_python_function_quiver + || !s_python_function_semilogx + || !s_python_function_semilogy + || !s_python_function_loglog + || !s_python_function_fill + || !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_ginput + || !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 + || !s_python_function_text + || !s_python_function_suptitle + || !s_python_function_bar + || !s_python_function_subplots_adjust + ) { 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_fignum_exists) + || !PyFunction_Check(s_python_function_plot) + || !PyFunction_Check(s_python_function_quiver) + || !PyFunction_Check(s_python_function_semilogx) + || !PyFunction_Check(s_python_function_semilogy) + || !PyFunction_Check(s_python_function_loglog) + || !PyFunction_Check(s_python_function_fill) + || !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_ginput) + || !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) + || !PyFunction_Check(s_python_function_text) + || !PyFunction_Check(s_python_function_suptitle) + || !PyFunction_Check(s_python_function_bar) + || !PyFunction_Check(s_python_function_subplots_adjust) + ) { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); } + + s_python_empty_tuple = PyTuple_New(0); } - // 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()); + ~_interpreter() { + Py_Finalize(); } - - PyObject* pymod = PyImport_Import(pyplotname); - Py_DECREF(pyplotname); - 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!"); } - - PyObject* pylabmod = PyImport_Import(pylabname); - Py_DECREF(pylabname); - 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"); - s_python_function_draw = PyObject_GetAttrString(pymod, "draw"); - s_python_function_pause = PyObject_GetAttrString(pymod, "pause"); - s_python_function_figure = PyObject_GetAttrString(pymod, "figure"); - s_python_function_fignum_exists = PyObject_GetAttrString(pymod, "fignum_exists"); - s_python_function_plot = PyObject_GetAttrString(pymod, "plot"); - s_python_function_quiver = PyObject_GetAttrString(pymod, "quiver"); - s_python_function_semilogx = PyObject_GetAttrString(pymod, "semilogx"); - s_python_function_semilogy = PyObject_GetAttrString(pymod, "semilogy"); - s_python_function_loglog = PyObject_GetAttrString(pymod, "loglog"); - s_python_function_fill = PyObject_GetAttrString(pymod, "fill"); - s_python_function_fill_between = PyObject_GetAttrString(pymod, "fill_between"); - s_python_function_hist = PyObject_GetAttrString(pymod,"hist"); - s_python_function_scatter = PyObject_GetAttrString(pymod,"scatter"); - s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot"); - s_python_function_legend = PyObject_GetAttrString(pymod, "legend"); - s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim"); - s_python_function_title = PyObject_GetAttrString(pymod, "title"); - s_python_function_axis = PyObject_GetAttrString(pymod, "axis"); - s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel"); - s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel"); - s_python_function_xticks = PyObject_GetAttrString(pymod, "xticks"); - s_python_function_yticks = PyObject_GetAttrString(pymod, "yticks"); - s_python_function_grid = PyObject_GetAttrString(pymod, "grid"); - s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim"); - s_python_function_ion = PyObject_GetAttrString(pymod, "ion"); - s_python_function_ginput = PyObject_GetAttrString(pymod, "ginput"); - s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig"); - s_python_function_annotate = PyObject_GetAttrString(pymod,"annotate"); - s_python_function_clf = PyObject_GetAttrString(pymod, "clf"); - s_python_function_errorbar = PyObject_GetAttrString(pymod, "errorbar"); - s_python_function_tight_layout = PyObject_GetAttrString(pymod, "tight_layout"); - s_python_function_stem = PyObject_GetAttrString(pymod, "stem"); - s_python_function_xkcd = PyObject_GetAttrString(pymod, "xkcd"); - s_python_function_text = PyObject_GetAttrString(pymod, "text"); - s_python_function_suptitle = PyObject_GetAttrString(pymod, "suptitle"); - s_python_function_bar = PyObject_GetAttrString(pymod,"bar"); - s_python_function_subplots_adjust = PyObject_GetAttrString(pymod,"subplots_adjust"); - - if( !s_python_function_show - || !s_python_function_close - || !s_python_function_draw - || !s_python_function_pause - || !s_python_function_figure - || !s_python_function_fignum_exists - || !s_python_function_plot - || !s_python_function_quiver - || !s_python_function_semilogx - || !s_python_function_semilogy - || !s_python_function_loglog - || !s_python_function_fill - || !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_ginput - || !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 - || !s_python_function_text - || !s_python_function_suptitle - || !s_python_function_bar - || !s_python_function_subplots_adjust - ) { 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_fignum_exists) - || !PyFunction_Check(s_python_function_plot) - || !PyFunction_Check(s_python_function_quiver) - || !PyFunction_Check(s_python_function_semilogx) - || !PyFunction_Check(s_python_function_semilogy) - || !PyFunction_Check(s_python_function_loglog) - || !PyFunction_Check(s_python_function_fill) - || !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_ginput) - || !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) - || !PyFunction_Check(s_python_function_text) - || !PyFunction_Check(s_python_function_suptitle) - || !PyFunction_Check(s_python_function_bar) - || !PyFunction_Check(s_python_function_subplots_adjust) - ) { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); } - - s_python_empty_tuple = PyTuple_New(0); - } - - ~_interpreter() { - Py_Finalize(); - } -}; + }; } // end namespace detail -// must be called before the first regular call to matplotlib to have any effect -inline void backend(const std::string& name) -{ - detail::s_backend = name; -} + // must be called before the first regular call to matplotlib to have any effect + inline void backend(const std::string& name) + { + detail::s_backend = name; + } -inline bool annotate(std::string annotation, double x, double y) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + inline bool annotate(std::string annotation, double x, double y) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - 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); + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "xy", xy); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, str); + 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); + Py_DECREF(args); + Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if(res) Py_DECREF(res); - return res; -} + return res; + } #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 -PyObject* get_array(E&& v) -{ - assert(v.dimension() <= 2); - - if (v.dimension() == 1) { - NPY_TYPES type = select_npy_type::value_type>::type; - if (type == NPY_NOTYPE) - { - std::vector vd(v.size()); + // 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 + PyObject* get_array(E&& v) + { + assert(v.dimension() <= 2); + + if (v.dimension() == 1) { + NPY_TYPES type = select_npy_type::value_type>::type; + if (type == NPY_NOTYPE) + { + std::vector vd(v.size()); + npy_intp vsize = v.size(); + std::copy(v.begin(),v.end(),vd.begin()); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); + return varray; + } + npy_intp vsize = v.size(); - std::copy(v.begin(),v.end(),vd.begin()); - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); return varray; - } + } else { + if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); - //auto ev = xt::make_xshared(std::move(xt::eval(v))); - //npy_intp vsize = ev.size(); - //PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(ev.data())); - npy_intp vsize = v.size(); - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); - return varray; - } else { - if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); - - npy_intp vsize[2] = {static_cast(v.shape()[0]), - static_cast(v.shape()[1])}; - - PyArrayObject *varray = - (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - - double *vd_begin = static_cast(PyArray_DATA(varray)); - - for (const std::size_t v_row_num : xt::arange(v.shape()[0])) { - auto v_row = xt::view(v, v_row_num); - 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]; - } + npy_intp vsize[2] = {static_cast(v.shape()[0]), + static_cast(v.shape()[1])}; - return reinterpret_cast(varray); - } -} + PyArrayObject *varray = + (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); -#else // fallback if we don't have numpy: copy every element of the given vector + double *vd_begin = static_cast(PyArray_DATA(varray)); + + for (const std::size_t v_row_num : xt::arange(v.shape()[0])) { + auto v_row = xt::view(v, v_row_num); + 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]; + } -template -PyObject* get_array(E&& v) -{ - PyObject* list = PyList_New(v.size()); - for(size_t i = 0; i < v.size(); ++i) { - PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); + return reinterpret_cast(varray); + } } - return list; -} -#endif // WITHOUT_NUMPY +#else // fallback if we don't have numpy: copy every element of the given vector -template -bool plot(E1&& x, E2&& y, const std::map& keywords) -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - - // using numpy arrays - //PyObject* xarray = get_array(std::forward(x)); - //PyObject* yarray = get_array(std::forward(y)); - xt::common_tensor_type_t ex = x; - xt::common_tensor_type_t ey = y; - PyObject* xarray = get_array(xt::detail::shared_forward(ex)); - PyObject* yarray = get_array(xt::detail::shared_forward(ey)); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + template + PyObject* get_array(E&& v) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + PyObject* list = PyList_New(v.size()); + for(size_t i = 0; i < v.size(); ++i) { + PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); + } + return list; } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -template -void plot_surface(E1&& x, E2&& y, E3&& z, - const std::map &keywords = - std::map()) -{ - // 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. - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - 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 = get_array(std::forward(x)); - PyObject *yarray = get_array(std::forward(y)); - PyObject *zarray = get_array(std::forward(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) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - - 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); - - 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 -bool stem(E1&& x, E2&& y, const std::map& keywords) -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - - // using numpy arrays - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // 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())); - } +#endif // WITHOUT_NUMPY - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_stem, args, kwargs); + template + bool plot(E1&& x, E2&& y, const std::map& keywords) + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + // using numpy arrays + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - return res; -} + // construct positional args + PyObject* args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); -template -bool fill(E1&& x, E2&& y, const std::map& keywords) -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + // 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())); + } - // using numpy arrays - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); + Py_DECREF(args); + Py_DECREF(kwargs); + if(res) Py_DECREF(res); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + return res; } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); + template + void plot_surface(E1&& x, E2&& y, E3&& z, + const std::map &keywords = + std::map()) + { + // 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. + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - if (res) Py_DECREF(res); + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + 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"); } - return res; -} + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } -template -bool fill_between(E1&& x, E2&& y1, E3&& y2, const std::map& keywords) -{ - assert(x.size() == y1.size()); - assert(x.size() == y2.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } + } - // using numpy arrays - PyObject* xarray = get_array(std::forward(x)); - PyObject* y1array = get_array(std::forward(y1)); - PyObject* y2array = get_array(std::forward(y2)); + assert(x.size() == y.size()); + assert(y.size() == z.size()); - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, y1array); - PyTuple_SetItem(args, 2, y2array); + // using numpy arrays + xt::xtensor::value_type, 2> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 2> yv = y; + PyObject* yarray = get_array(yv); + xt::xtensor::value_type, 2> zv = z; + PyObject* zarray = get_array(zv); - // 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())); - } + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs); + // Build up the kw args. + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); + PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); - Py_DECREF(args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + PyObject *python_colormap_coolwarm = PyObject_GetAttrString( + detail::_interpreter::get().s_python_colormap, "coolwarm"); - return res; -} + PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); -template -bool hist(E&& y, long bins=10, std::string color="b", - double alpha=1.0, bool cumulative=false) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + 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* yarray = get_array(std::forward(y)); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); - PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); - PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); - PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); + 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* plot_args = PyTuple_New(1); + PyObject *gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - PyTuple_SetItem(plot_args, 0, yarray); + 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); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); + 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(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + Py_DECREF(axis); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); + } - return res; -} + template + bool stem(E1&& x, E2&& y, const std::map& keywords) + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -template -bool scatter(E1&& x, E2&& y, - const double s=1.0) // The marker size in points**2 -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + // using numpy arrays + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + // construct positional args + PyObject* args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); + // 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* 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_stem, args, kwargs); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); + Py_DECREF(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 fill(E1&& x, E2&& y, const std::map& keywords) + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -template -bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, - const std::map& keywords = {}) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + // using numpy arrays + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* yarray = get_array(std::forward(y)); + // construct positional args + PyObject* args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); - xt::xtensor x = xt::arange(y.size()); + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* xarray = get_array(x); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill, args, kwargs); - PyObject* kwargs = PyDict_New(); + Py_DECREF(args); + Py_DECREF(kwargs); - 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)); + if (res) Py_DECREF(res); - PyObject* plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + return res; + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); + template + bool fill_between(E1&& x, E2&& y1, E3&& y2, const std::map& keywords) + { + assert(x.size() == y1.size()); + assert(x.size() == y2.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + // using numpy arrays + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv1 = y1; + PyObject* y1array = get_array(yv1); + xt::xtensor::value_type, 1> yv2 = y2; + PyObject* y2array = get_array(yv2); - return res; -} + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, y1array); + PyTuple_SetItem(args, 2, y2array); -inline bool subplots_adjust(const std::map& keywords = {}) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + // 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* 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)); - } + 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); - PyObject* plot_args = PyTuple_New(0); + return res; + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs); + template + bool hist(E&& y, long bins=10, std::string color="b", + double alpha=1.0, bool cumulative=false) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - return res; -} + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); + PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); + PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); + PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); -template -bool named_hist(std::string label, E&& y, long bins=10, std::string color="b", double alpha=1.0) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* plot_args = PyTuple_New(1); - PyObject* yarray = get_array(std::forward(y)); + PyTuple_SetItem(plot_args, 0, yarray); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str())); - PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); - PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); - PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); - 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); + 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 scatter(E1&& x, E2&& y, + const double s=1.0) // The marker size in points**2 + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -template -bool plot(E1&& x, E2&& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - 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); - PyObject* plot_args = PyTuple_New(3); - 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_scatter, plot_args, kwargs); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if(res) Py_DECREF(res); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + return res; + } - return res; -} + template + bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, + const std::map& keywords = {}) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -template -bool quiver(E1&& x, E2&& y, E3&& u, E4&& w, const std::map& keywords = {}) -{ - assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); - PyObject* uarray = get_array(std::forward(u)); - PyObject* warray = get_array(std::forward(w)); + xt::xtensor::value_type, 1> x = xt::arange::value_type>(y.size()); - 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); + PyObject* xarray = get_array(x); - // 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* kwargs = PyDict_New(); - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); + 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)); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + PyObject* plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); - return res; -} + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); -template -bool stem(E1&& x, E2&& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if(res) Py_DECREF(res); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + return res; + } - PyObject* pystring = PyString_FromString(s.c_str()); + inline bool subplots_adjust(const std::map& keywords = {}) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + 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)); + } - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_stem, plot_args); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + PyObject* plot_args = PyTuple_New(0); - return res; -} + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs); -template -bool semilogx(E1&& x, E2&& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if(res) Py_DECREF(res); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + return res; + } - PyObject* pystring = PyString_FromString(s.c_str()); + template + bool named_hist(std::string label, E&& y, long bins=10, std::string color="b", double alpha=1.0) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args); + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str())); + PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); + PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); + PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - return res; -} + PyObject* plot_args = PyTuple_New(1); + PyTuple_SetItem(plot_args, 0, yarray); -template -bool semilogy(E1&& x, E2&& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if(res) Py_DECREF(res); - PyObject* pystring = PyString_FromString(s.c_str()); + return res; + } - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + template + bool plot(E1&& x, E2&& y, const std::string& s = "") + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args); + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + PyObject* pystring = PyString_FromString(s.c_str()); - return res; -} + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); -template -bool loglog(E1&& x, E2&& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + Py_DECREF(plot_args); + if(res) Py_DECREF(res); - PyObject* pystring = PyString_FromString(s.c_str()); + return res; + } - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + template + bool quiver(E1&& x, E2&& y, E3&& u, E4&& w, const std::map& keywords = {}) + { + assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args); + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); + xt::xtensor::value_type, 1> uv = u; + PyObject* uarray = get_array(uv); + xt::xtensor::value_type, 1> wv = w; + PyObject* warray = get_array(wv); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + 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); - return res; -} + // 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())); + } -template -bool errorbar(E1&& x, E2&& y, E3&& yerr, const std::map &keywords = {}) -{ - assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); - PyObject* yerrarray = get_array(std::forward(yerr)); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - // 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())); + return res; } - PyDict_SetItemString(kwargs, "yerr", yerrarray); + template + bool stem(E1&& x, E2&& y, const std::string& s = "") + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject *plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); + PyObject* pystring = PyString_FromString(s.c_str()); - Py_DECREF(kwargs); - Py_DECREF(plot_args); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - if (res) - Py_DECREF(res); - else - throw std::runtime_error("Call to errorbar() failed."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_stem, plot_args); - return res; -} + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); -template -bool named_plot(const std::string& name, E&& y, const std::string& format = "") -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + return res; + } - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + template + bool semilogx(E1&& x, E2&& y, const std::string& s = "") + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* yarray = get_array(std::forward(y)); + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* pystring = PyString_FromString(format.c_str()); + PyObject* pystring = PyString_FromString(s.c_str()); - PyObject* plot_args = PyTuple_New(2); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyTuple_SetItem(plot_args, 0, yarray); - PyTuple_SetItem(plot_args, 1, pystring); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + Py_DECREF(plot_args); + if(res) Py_DECREF(res); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + return res; + } - return res; -} + template + bool semilogy(E1&& x, E2&& y, const std::string& s = "") + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -template -bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject* pystring = PyString_FromString(s.c_str()); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* pystring = PyString_FromString(format.c_str()); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + Py_DECREF(plot_args); + if(res) Py_DECREF(res); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + return res; + } - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + template + bool loglog(E1&& x, E2&& y, const std::string& s = "") + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - return res; -} + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); -template -bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& format = "") -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pystring = PyString_FromString(s.c_str()); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args); - PyObject* pystring = PyString_FromString(format.c_str()); + Py_DECREF(plot_args); + if(res) Py_DECREF(res); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + return res; + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + template + bool errorbar(E1&& x, E2&& y, E3&& yerr, const std::map &keywords = {}) + { + assert(x.size() == y.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); + xt::xtensor::value_type, 1> yerrv = yerr; + PyObject* yerrarray = get_array(yerrv); - return res; -} + // 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())); + } -template -bool named_semilogy(const std::string& name, E1&& x, E2& y, const std::string& format = "") -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyDict_SetItemString(kwargs, "yerr", yerrarray); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); - PyObject* pystring = PyString_FromString(format.c_str()); + Py_DECREF(kwargs); + Py_DECREF(plot_args); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + if (res) + Py_DECREF(res); + else + throw std::runtime_error("Call to errorbar() failed."); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + return res; + } - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + template + bool named_plot(const std::string& name, E&& y, const std::string& format = "") + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - return res; -} + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); -template -bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& format = "") -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject* pystring = PyString_FromString(format.c_str()); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + PyObject* plot_args = PyTuple_New(2); - PyObject* pystring = PyString_FromString(format.c_str()); + PyTuple_SetItem(plot_args, 0, yarray); + PyTuple_SetItem(plot_args, 1, pystring); - PyObject* plot_args = PyTuple_New(3); - 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_plot, plot_args, kwargs); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + return res; + } - return res; -} + template + bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -template -bool plot(E&& y, const std::string& format = "") -{ - xt::xtensor x = xt::arange(y.size()); - return plot(x, y, format); -} + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); -template -bool stem(E&& y, const std::string& format = "") -{ - return stem(xt::arange(y.size()),y,format); -} + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); -template -void text(Numeric x, Numeric y, const std::string& s = "") -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pystring = PyString_FromString(format.c_str()); - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); - PyTuple_SetItem(args, 2, PyString_FromString(s.c_str())); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); - if(!res) throw std::runtime_error("Call to text() failed."); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - Py_DECREF(args); - Py_DECREF(res); -} + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + return res; + } -inline long figure(long number = -1) -{ - PyObject *res; - if (number == -1) - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); - else { - assert(number > 0); + template + bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& format = "") + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - // Make sure interpreter is initialised - detail::_interpreter::get(); + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - 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); - } + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - if(!res) throw std::runtime_error("Call to figure() failed."); + PyObject* pystring = PyString_FromString(format.c_str()); - PyObject* num = PyObject_GetAttrString(res, "number"); - if (!num) throw std::runtime_error("Could not get number attribute of figure object"); - const long figureNumber = PyLong_AsLong(num); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - Py_DECREF(num); - Py_DECREF(res); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); - return figureNumber; -} + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); -inline bool fignum_exists(long number) -{ - // Make sure interpreter is initialised - detail::_interpreter::get(); + return res; + } - 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."); + template + bool named_semilogy(const std::string& name, E1&& x, E2& y, const std::string& format = "") + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - bool ret = PyObject_IsTrue(res); - Py_DECREF(res); - Py_DECREF(args); + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - return ret; -} + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); -inline void figure_size(size_t w, size_t h) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pystring = PyString_FromString(format.c_str()); - const size_t dpi = 100; - PyObject* size = PyTuple_New(2); - PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); - PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi)); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - 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_semilogy, plot_args, kwargs); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); - Py_DECREF(kwargs); + return res; + } - if(!res) throw std::runtime_error("Call to figure_size() failed."); - Py_DECREF(res); -} + template + bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& format = "") + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -inline void legend() -{ - 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* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - Py_DECREF(res); -} + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); -template -void ylim(Numeric left, Numeric right) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pystring = PyString_FromString(format.c_str()); - PyObject* list = PyList_New(2); - PyList_SetItem(list, 0, PyFloat_FromDouble(left)); - PyList_SetItem(list, 1, PyFloat_FromDouble(right)); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, list); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - if(!res) throw std::runtime_error("Call to ylim() failed."); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; + } - Py_DECREF(args); - Py_DECREF(res); -} + template + bool plot(E&& y, const std::string& format = "") + { + xt::xtensor x = xt::arange(y.size()); + return plot(std::move(x), std::forward(y), format); + } -template -void xlim(Numeric left, Numeric right) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + template + bool stem(E&& y, const std::string& format = "") + { + xt::xtensor x = xt::arange(y.size()); + return stem(std::move(x), std::forward(y), format); + } - PyObject* list = PyList_New(2); - PyList_SetItem(list, 0, PyFloat_FromDouble(left)); - PyList_SetItem(list, 1, PyFloat_FromDouble(right)); + template + void text(Numeric x, Numeric y, const std::string& s = "") + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, list); + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); + PyTuple_SetItem(args, 2, PyString_FromString(s.c_str())); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - if(!res) throw std::runtime_error("Call to xlim() failed."); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); + if(!res) throw std::runtime_error("Call to text() failed."); - Py_DECREF(args); - Py_DECREF(res); -} + Py_DECREF(args); + Py_DECREF(res); + } -inline double* xlim() -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + inline long figure(long number = -1) + { + PyObject *res; + if (number == -1) + 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); + PyTuple_SetItem(args, 0, PyLong_FromLong(number)); + res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args); + Py_DECREF(args); + } - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); + if(!res) throw std::runtime_error("Call to figure() failed."); - double* arr = new double[2]; - arr[0] = PyFloat_AsDouble(left); - arr[1] = PyFloat_AsDouble(right); + PyObject* num = PyObject_GetAttrString(res, "number"); + if (!num) throw std::runtime_error("Could not get number attribute of figure object"); + const long figureNumber = PyLong_AsLong(num); - if(!res) throw std::runtime_error("Call to xlim() failed."); + Py_DECREF(num); + Py_DECREF(res); - Py_DECREF(res); - return arr; -} + return figureNumber; + } + inline bool fignum_exists(long number) + { + // Make sure interpreter is initialised + detail::_interpreter::get(); -inline double* ylim() -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + 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* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); + bool ret = PyObject_IsTrue(res); + Py_DECREF(res); + Py_DECREF(args); - double* arr = new double[2]; - arr[0] = PyFloat_AsDouble(left); - arr[1] = PyFloat_AsDouble(right); + return ret; + } - if(!res) throw std::runtime_error("Call to ylim() failed."); + inline void figure_size(size_t w, size_t h) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(res); - return arr; -} + const size_t dpi = 100; + PyObject* size = PyTuple_New(2); + PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); + PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi)); -template -inline void xticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "figsize", size); + PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - // using numpy array - PyObject* ticksarray = get_array(std::forward(ticks)); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple, kwargs); - PyObject* args; - if(labels.size() == 0) { - // construct positional args - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, ticksarray); - } else { - // make tuple of tick labels - PyObject* labelstuple = PyTuple_New(labels.size()); - for (size_t i = 0; i < labels.size(); i++) - PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + Py_DECREF(kwargs); - // construct positional args - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, ticksarray); - PyTuple_SetItem(args, 1, labelstuple); + if(!res) throw std::runtime_error("Call to figure_size() failed."); + Py_DECREF(res); } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + inline void legend() { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + 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); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs); + template + void ylim(Numeric left, Numeric right) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(args); - Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to xticks() failed"); + PyObject* list = PyList_New(2); + PyList_SetItem(list, 0, PyFloat_FromDouble(left)); + PyList_SetItem(list, 1, PyFloat_FromDouble(right)); - Py_DECREF(res); -} + PyObject* args = PyTuple_New(1); + 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."); + + Py_DECREF(args); + Py_DECREF(res); + } -template -inline void xticks(E&& ticks, const std::map& keywords) -{ - xticks(std::forward(ticks), {}, keywords); -} + template + void xlim(Numeric left, Numeric right) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -template -inline void yticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* list = PyList_New(2); + PyList_SetItem(list, 0, PyFloat_FromDouble(left)); + PyList_SetItem(list, 1, PyFloat_FromDouble(right)); - // using numpy array - PyObject* ticksarray = get_array(std::forward(ticks)); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, list); - PyObject* args; - if(labels.size() == 0) { - // construct positional args - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, ticksarray); - } else { - // make tuple of tick labels - PyObject* labelstuple = PyTuple_New(labels.size()); - for (size_t i = 0; i < labels.size(); i++) - PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); + if(!res) throw std::runtime_error("Call to xlim() failed."); - // construct positional args - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, ticksarray); - PyTuple_SetItem(args, 1, labelstuple); + Py_DECREF(args); + Py_DECREF(res); } - // 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_yticks, args, kwargs); + inline double* xlim() + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(args); - Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to yticks() failed"); + PyObject* args = PyTuple_New(0); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); + PyObject* left = PyTuple_GetItem(res,0); + PyObject* right = PyTuple_GetItem(res,1); - Py_DECREF(res); -} + double* arr = new double[2]; + arr[0] = PyFloat_AsDouble(left); + arr[1] = PyFloat_AsDouble(right); -template -inline void yticks(E&& ticks, const std::map& keywords) -{ - yticks(std::forward(ticks), {}, keywords); -} + if(!res) throw std::runtime_error("Call to xlim() failed."); -inline void subplot(long nrows, long ncols, long plot_number) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + Py_DECREF(res); + return arr; + } - // 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)); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); - if(!res) throw std::runtime_error("Call to subplot() failed."); + inline double* ylim() + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(args); - Py_DECREF(res); -} + PyObject* args = PyTuple_New(0); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); + PyObject* left = PyTuple_GetItem(res,0); + PyObject* right = PyTuple_GetItem(res,1); -inline void title(const std::string &titlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + double* arr = new double[2]; + arr[0] = PyFloat_AsDouble(left); + arr[1] = PyFloat_AsDouble(right); - PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pytitlestr); + if(!res) throw std::runtime_error("Call to ylim() failed."); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + Py_DECREF(res); + return arr; } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); - if(!res) throw std::runtime_error("Call to title() failed."); + template + inline void xticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) + { + assert(labels.size() == 0 || ticks.size() == labels.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + // using numpy array + xt::xtensor::value_type, 1> ticksv = ticks; + PyObject* ticksarray = get_array(ticksv); + + PyObject* args; + if(labels.size() == 0) { + // construct positional args + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, ticksarray); + } else { + // make tuple of tick labels + PyObject* labelstuple = PyTuple_New(labels.size()); + for (size_t i = 0; i < labels.size(); i++) + PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + + // construct positional args + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, ticksarray); + PyTuple_SetItem(args, 1, labelstuple); + } - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + // 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())); + } -inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs); - PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pysuptitlestr); + Py_DECREF(args); + Py_DECREF(kwargs); + if(!res) throw std::runtime_error("Call to xticks() failed"); + + Py_DECREF(res); + } - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + template + inline void xticks(E&& ticks, const std::map& keywords) + { + xticks(std::forward(ticks), {}, keywords); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); - if(!res) throw std::runtime_error("Call to suptitle() failed."); + template + inline void yticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) + { + assert(labels.size() == 0 || ticks.size() == labels.size()); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + // using numpy array + xt::xtensor::value_type, 1> ticksv = ticks; + PyObject* ticksarray = get_array(ticksv); + + PyObject* args; + if(labels.size() == 0) { + // construct positional args + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, ticksarray); + } else { + // make tuple of tick labels + PyObject* labelstuple = PyTuple_New(labels.size()); + for (size_t i = 0; i < labels.size(); i++) + PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + + // construct positional args + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, ticksarray); + PyTuple_SetItem(args, 1, labelstuple); + } + + // 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())); + } - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs); -inline void axis(const std::string &axisstr) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + Py_DECREF(args); + Py_DECREF(kwargs); + if(!res) throw std::runtime_error("Call to yticks() failed"); - PyObject* str = PyString_FromString(axisstr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, str); + Py_DECREF(res); + } - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); - if(!res) throw std::runtime_error("Call to title() failed."); + template + inline void yticks(E&& ticks, const std::map& keywords) + { + yticks(std::forward(ticks), {}, keywords); + } - Py_DECREF(args); - Py_DECREF(res); -} + inline void subplot(long nrows, long ncols, long plot_number) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -inline void xlabel(const std::string &str, const std::map &keywords = {}) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + // 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)); - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); + if(!res) throw std::runtime_error("Call to subplot() failed."); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + Py_DECREF(args); + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); - if(!res) throw std::runtime_error("Call to xlabel() failed."); + inline void title(const std::string &titlestr, const std::map &keywords = {}) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pytitlestr); -inline void ylabel(const std::string &str, const std::map& keywords = {}) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); + if(!res) throw std::runtime_error("Call to title() failed."); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); - if(!res) throw std::runtime_error("Call to ylabel() failed."); + inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pysuptitlestr); -inline void grid(bool flag) -{ - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* pyflag = flag ? Py_True : Py_False; - Py_INCREF(pyflag); + 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); + } - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyflag); + inline void axis(const std::string &axisstr) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); - if(!res) throw std::runtime_error("Call to grid() failed."); + PyObject* str = PyString_FromString(axisstr.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, str); - Py_DECREF(args); - Py_DECREF(res); -} + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); + if(!res) throw std::runtime_error("Call to title() failed."); -inline void show(const bool block = true) -{ - PyObject* res; - if(block) - { - res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_show, - detail::_interpreter::get().s_python_empty_tuple); + Py_DECREF(args); + Py_DECREF(res); } - else + + inline void xlabel(const std::string &str, const std::map &keywords = {}) { - 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); - } + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* pystr = PyString_FromString(str.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); - if (!res) throw std::runtime_error("Call to show() failed."); + PyObject* kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - Py_DECREF(res); -} + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); + if(!res) throw std::runtime_error("Call to xlabel() failed."); -inline void close() -{ - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_close, - detail::_interpreter::get().s_python_empty_tuple); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); + } - if (!res) throw std::runtime_error("Call to close() failed."); + inline void ylabel(const std::string &str, const std::map& keywords = {}) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - Py_DECREF(res); -} + PyObject* pystr = PyString_FromString(str.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); -inline void xkcd() { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + PyObject* kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* res; - PyObject *kwargs = PyDict_New(); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); + if(!res) throw std::runtime_error("Call to ylabel() failed."); - res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); + } - Py_DECREF(kwargs); + inline void grid(bool flag) + { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - if (!res) - throw std::runtime_error("Call to show() failed."); + PyObject* pyflag = flag ? Py_True : Py_False; + Py_INCREF(pyflag); - Py_DECREF(res); -} + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyflag); -inline void draw() -{ - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_draw, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); + if(!res) throw std::runtime_error("Call to grid() failed."); - if (!res) throw std::runtime_error("Call to draw() failed."); + Py_DECREF(args); + Py_DECREF(res); + } - Py_DECREF(res); -} + inline void show(const bool block = true) + { + PyObject* res; + if(block) + { + res = PyObject_CallObject( + 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); + } -template -inline void pause(Numeric interval) -{ - 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 show() failed."); - Py_DECREF(args); - Py_DECREF(res); -} + Py_DECREF(res); + } -inline void save(const std::string& filename) -{ - PyObject* pyfilename = PyString_FromString(filename.c_str()); + inline void close() + { + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_close, + detail::_interpreter::get().s_python_empty_tuple); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyfilename); + if (!res) throw std::runtime_error("Call to close() failed."); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args); - if (!res) throw std::runtime_error("Call to save() failed."); + Py_DECREF(res); + } - Py_DECREF(args); - Py_DECREF(res); -} + inline void xkcd() { + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work -inline void clf() { - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_clf, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* res; + PyObject *kwargs = PyDict_New(); + + res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, + detail::_interpreter::get().s_python_empty_tuple, kwargs); - if (!res) throw std::runtime_error("Call to clf() failed."); + Py_DECREF(kwargs); - Py_DECREF(res); -} + if (!res) + throw std::runtime_error("Call to show() failed."); -inline void ion() { - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - detail::_interpreter::get().s_python_empty_tuple); + Py_DECREF(res); + } - if (!res) throw std::runtime_error("Call to ion() failed."); + inline void draw() + { + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_draw, + detail::_interpreter::get().s_python_empty_tuple); - Py_DECREF(res); -} + if (!res) throw std::runtime_error("Call to draw() failed."); -inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -{ - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); + Py_DECREF(res); + } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + template + inline void pause(Numeric interval) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + 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."); + + Py_DECREF(args); + Py_DECREF(res); } - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_ginput, args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(args); - if (!res) throw std::runtime_error("Call to ginput() failed."); - - const size_t len = PyList_Size(res); - std::vector> out; - out.reserve(len); - for (size_t i = 0; i < len; 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)); - out.push_back(position); + inline void save(const std::string& filename) + { + PyObject* pyfilename = PyString_FromString(filename.c_str()); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyfilename); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args); + if (!res) throw std::runtime_error("Call to save() failed."); + + Py_DECREF(args); + Py_DECREF(res); } - Py_DECREF(res); - return out; -} + inline void clf() { + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_clf, + detail::_interpreter::get().s_python_empty_tuple); -// 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); + if (!res) throw std::runtime_error("Call to clf() failed."); - if (!res) throw std::runtime_error("Call to tight_layout() failed."); + Py_DECREF(res); + } - Py_DECREF(res); -} + inline void ion() { + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_ion, + detail::_interpreter::get().s_python_empty_tuple); -// Support for variadic plot() and initializer lists: + if (!res) throw std::runtime_error("Call to ion() failed."); -namespace detail { + Py_DECREF(res); + } -template -using is_function = typename std::is_function>>::type; - -template -struct is_callable_impl; - -template -struct is_callable_impl -{ - typedef is_function type; -}; // 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 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::false_type test( Check* ); - -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() - -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 - bool operator()(IterableX&& x, IterableY&& y, const std::string& format) + inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) { - // 2-phase lookup for distance, begin, end - using std::distance; - using std::begin; - using std::end; - - auto xs = distance(begin(x), end(x)); - auto ys = distance(begin(y), end(y)); - assert(xs == ys && "x and y data must have the same number of elements!"); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + // 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* xlist = PyList_New(xs); - PyObject* ylist = PyList_New(ys); - PyObject* pystring = PyString_FromString(format.c_str()); + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_ginput, args, kwargs); - auto itx = begin(x), ity = begin(y); - for(size_t i = 0; i < xs; ++i) { - PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); - PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); + Py_DECREF(kwargs); + Py_DECREF(args); + if (!res) throw std::runtime_error("Call to ginput() failed."); + + const size_t len = PyList_Size(res); + std::vector> out; + out.reserve(len); + for (size_t i = 0; i < len; 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)); + out.push_back(position); } + Py_DECREF(res); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xlist); - PyTuple_SetItem(plot_args, 1, ylist); - PyTuple_SetItem(plot_args, 2, pystring); + return out; + } - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + // 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); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + if (!res) throw std::runtime_error("Call to tight_layout() failed."); - return res; + Py_DECREF(res); } -}; -template<> -struct plot_impl -{ - template - bool operator()(Iterable&& ticks, Callable&& f, const std::string& format) + // Support for variadic plot() and initializer lists: + +namespace detail { + + template + using is_function = typename std::is_function>>::type; + + template + struct is_callable_impl; + + template + struct is_callable_impl { - 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::size_t size = std::distance(begin(ticks), end(ticks)); - std::array shape{size}; - xt::xtensor y(shape); - //for(auto x : ticks) y.push_back(f(x)); - std::size_t idx = 0; - for(auto x : ticks) y[idx++] = f(x); - //for (auto i = 0ul; i < size; ++i) y[i] = f(ticks[i]); - return plot_impl()(std::forward(ticks), std::move(y), format); - } -}; + typedef is_function type; + }; // a non-object is callable iff it is a function -} // end namespace detail + template + struct is_callable_impl + { + struct Fallback { void operator()(); }; + struct Derived : T, Fallback { }; -// recursion stop for the above -template -bool plot() { return true; } - -template -bool plot(E1&& a, E2&& b, const std::string& format, Args... args) -{ - //return detail::plot_impl>::type>()( - //std::forward(a), std::forward(b), format - //) && plot(args...); - //return plot(std::forward(a), std::forward(b), format) && plot(args...); - return plot(std::forward(a), std::forward(b), format) && plot(std::forward(args)...); -} - -/* - * This group of plot() functions is needed to support initializer lists, i.e. calling - * plot( {1,2,3,4} ) - */ -inline bool plot(std::vector x, std::vector y, const std::string& format = "") { - xt::xtensor x_adapt = xt::adapt(x); - xt::xtensor y_adapt = xt::adapt(y); - return plot(std::move(x_adapt), std::move(y_adapt), format); -} - -inline bool plot(std::vector y, const std::string& format = "") { - xt::xtensor y_adapt = xt::adapt(y); - return plot(std::move(y_adapt), format); -} - -inline bool plot(std::vector x, std::vector y, const std::map& keywords) { - xt::xtensor x_adapt = xt::adapt(x); - xt::xtensor y_adapt = xt::adapt(y); - return plot(std::move(x_adapt), std::move(y_adapt), keywords); -} - -/* - * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting - */ - -class Plot -{ -public: - // default initialization with plot label, some data and format - template - Plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + template struct Check; - assert(x.size() == y.size()); + template + static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match - PyObject* kwargs = PyDict_New(); - if(name != "") - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + template + static std::false_type test( Check* ); - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + 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() - PyObject* pystring = PyString_FromString(format.c_str()); + 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; + }; - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + template + struct plot_impl { }; - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + template<> + struct plot_impl + { + template + bool operator()(IterableX&& x, IterableY&& y, const std::string& format) + { + // 2-phase lookup for distance, begin, end + using std::distance; + using std::begin; + using std::end; + + auto xs = distance(begin(x), end(x)); + auto ys = distance(begin(y), end(y)); + assert(xs == ys && "x and y data must have the same number of elements!"); + + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + PyObject* xlist = PyList_New(xs); + PyObject* ylist = PyList_New(ys); + PyObject* pystring = PyString_FromString(format.c_str()); + + auto itx = begin(x), ity = begin(y); + for(size_t i = 0; i < xs; ++i) { + PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); + PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); + } + + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xlist); + 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); + + Py_DECREF(plot_args); + if(res) Py_DECREF(res); + + return res; + } + }; + + template<> + struct plot_impl + { + template + bool operator()(Iterable&& ticks, 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::size_t size = std::distance(begin(ticks), end(ticks)); + std::array shape{size}; + xt::xtensor y(shape); + //for(auto x : ticks) y.push_back(f(x)); + std::size_t idx = 0; + for(auto x : ticks) y[idx++] = f(x); + //for (auto i = 0ul; i < size; ++i) y[i] = f(ticks[i]); + return plot_impl()(std::forward(ticks), std::move(y), format); + } + }; - Py_DECREF(kwargs); - Py_DECREF(plot_args); +} // end namespace detail - if(res) - { - line= PyList_GetItem(res, 0); + // recursion stop for the above + template + bool plot() { return true; } - if(line) - set_data_fct = PyObject_GetAttrString(line,"set_data"); - else - Py_DECREF(line); - Py_DECREF(res); + template + bool plot(E1&& a, E2&& b, const std::string& format, Args... args) + { + // FIXME + //return detail::plot_impl>::type>()( + //std::forward(a), std::forward(b), format + //) && plot(args...); + //return plot(std::forward(a), std::forward(b), format) && plot(args...); + return plot(std::forward(a), std::forward(b), format) && plot(std::forward(args)...); } + + /* + * This group of plot() functions is needed to support initializer lists, i.e. calling + * plot( {1,2,3,4} ) + */ + inline bool plot(std::vector x, std::vector y, const std::string& format = "") { + xt::xtensor x_adapt = xt::adapt(x); + xt::xtensor y_adapt = xt::adapt(y); + return plot(std::move(x_adapt), std::move(y_adapt), format); } - // shorter initialization with name or format only - // basically calls line, = plot([], []) - Plot(const std::string& name = "", const std::string& format = "") - : Plot(name, xt::xtensor(), xt::xtensor(), format) {} + inline bool plot(std::vector y, const std::string& format = "") { + xt::xtensor y_adapt = xt::adapt(y); + return plot(std::move(y_adapt), format); + } - template - bool update(E1&& x, E2&& y) { - assert(x.size() == y.size()); - if(set_data_fct) - { - PyObject* xarray = get_array(std::forward(x)); - PyObject* yarray = get_array(std::forward(y)); + inline bool plot(std::vector x, std::vector y, const std::map& keywords) { + xt::xtensor x_adapt = xt::adapt(x); + xt::xtensor y_adapt = xt::adapt(y); + return plot(std::move(x_adapt), std::move(y_adapt), keywords); + } + + /* + * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting + */ + + class Plot + { + public: + // default initialization with plot label, some data and format + template + Plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + + assert(x.size() == y.size()); + + PyObject* kwargs = PyDict_New(); + if(name != "") + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); - PyObject* plot_args = PyTuple_New(2); + PyObject* pystring = PyString_FromString(format.c_str()); + + PyObject* plot_args = PyTuple_New(3); 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_plot, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); - PyObject* res = PyObject_CallObject(set_data_fct, plot_args); - if (res) Py_DECREF(res); - return res; + if(res) + { + line= PyList_GetItem(res, 0); + + if(line) + set_data_fct = PyObject_GetAttrString(line,"set_data"); + else + Py_DECREF(line); + Py_DECREF(res); + } } - return false; - } - // clears the plot but keep it available - bool clear() { - return update(xt::xtensor(), xt::xtensor()); - } + // shorter initialization with name or format only + // basically calls line, = plot([], []) + Plot(const std::string& name = "", const std::string& format = "") + : Plot(name, xt::xtensor(), xt::xtensor(), format) {} + + template + bool update(E1&& x, E2&& y) { + assert(x.size() == y.size()); + if(set_data_fct) + { + xt::xtensor::value_type, 1> xv = x; + PyObject* xarray = get_array(xv); + xt::xtensor::value_type, 1> yv = y; + PyObject* yarray = get_array(yv); + + PyObject* plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + + PyObject* res = PyObject_CallObject(set_data_fct, plot_args); + if (res) Py_DECREF(res); + return res; + } + return false; + } - // definitely remove this line - void 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); + // clears the plot but keep it available + bool clear() { + return update(xt::xtensor(), xt::xtensor()); } - decref(); - } - ~Plot() { - decref(); - } -private: + // definitely remove this line + void 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); + } + decref(); + } - void decref() { - if(line) - Py_DECREF(line); - if(set_data_fct) - Py_DECREF(set_data_fct); - } + ~Plot() { + decref(); + } + private: + + void decref() { + if(line) + Py_DECREF(line); + if(set_data_fct) + Py_DECREF(set_data_fct); + } - PyObject* line = nullptr; - PyObject* set_data_fct = nullptr; -}; + PyObject* line = nullptr; + PyObject* set_data_fct = nullptr; + }; } // end namespace matplotlibcpp From e260d92255242a4243a9d1b32d039a84612b7db7 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Tue, 30 Apr 2019 17:47:38 +0100 Subject: [PATCH 07/21] Updated library to only work with lvalues --- examples/modern.cpp | 4 +- examples/update.cpp | 7 +- matplotlibcpp.h | 320 +++++++++++++++++++------------------------- 3 files changed, 142 insertions(+), 189 deletions(-) diff --git a/examples/modern.cpp b/examples/modern.cpp index 1d5a608..2354ec7 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -33,8 +33,8 @@ int main() //plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); //plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-", x, y+1.0, "r-."); //plt::plot(x, y, "r-", x2, xt::eval(y2+0.5), "b-.", xt::eval(x3+1.0), xt::eval(y3+1.0), "g."); - plt::plot(x, y+1.0, "r-"); - //plt::plot(x, y, "r-"); + //plt::plot(x, y+1.0, "r-"); + plt::plot(x, y, "r-"); //plt::plot(x, y, "r-", x, y2, "b.."); diff --git a/examples/update.cpp b/examples/update.cpp index c34fc39..0ea632e 100644 --- a/examples/update.cpp +++ b/examples/update.cpp @@ -36,14 +36,13 @@ int main() xt::xtensor yt{0,0}; plt::title("Tangent of a sine curve"); - //plt::xlim(*(x.begin()), *(x.end()-1)); + // Plot sin once and for all. + plt::named_plot("sin", x, y); + plt::xlim(x[0], x[n-1]); plt::ylim(-a, a); plt::axis("equal"); - // Plot sin once and for all. - plt::named_plot("sin", x, y); - // Prepare plotting the tangent. plt::Plot plot("tangent"); diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 2d87089..341ebe8 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -386,16 +386,14 @@ namespace detail { #endif // WITHOUT_NUMPY template - bool plot(E1&& x, E2&& y, const std::map& keywords) + bool plot(const E1& x, const E2& y, const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); // construct positional args PyObject* args = PyTuple_New(2); @@ -419,7 +417,7 @@ namespace detail { } template - void plot_surface(E1&& x, E2&& y, E3&& z, + void plot_surface(const E1& x, const E2& y, const E3& z, const std::map &keywords = std::map()) { @@ -448,12 +446,9 @@ namespace detail { assert(y.size() == z.size()); // using numpy arrays - xt::xtensor::value_type, 2> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 2> yv = y; - PyObject* yarray = get_array(yv); - xt::xtensor::value_type, 2> zv = z; - PyObject* zarray = get_array(zv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); + PyObject* zarray = get_array(z); // construct positional args PyObject *args = PyTuple_New(3); @@ -512,16 +507,14 @@ namespace detail { } template - bool stem(E1&& x, E2&& y, const std::map& keywords) + bool stem(const E1& x, const E2& y, const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); // construct positional args PyObject* args = PyTuple_New(2); @@ -548,16 +541,14 @@ namespace detail { } template - bool fill(E1&& x, E2&& y, const std::map& keywords) + bool fill(const E1& x, const E2& y, const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); // construct positional args PyObject* args = PyTuple_New(2); @@ -581,19 +572,16 @@ namespace detail { } template - bool fill_between(E1&& x, E2&& y1, E3&& y2, const std::map& keywords) + bool fill_between(const E1& x, const E2& y1, const E3& y2, const std::map& keywords) { assert(x.size() == y1.size()); assert(x.size() == y2.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv1 = y1; - PyObject* y1array = get_array(yv1); - xt::xtensor::value_type, 1> yv2 = y2; - PyObject* y2array = get_array(yv2); + PyObject* xarray = get_array(x); + PyObject* y1array = get_array(y1); + PyObject* y2array = get_array(y2); // construct positional args PyObject* args = PyTuple_New(3); @@ -617,13 +605,12 @@ namespace detail { } template - bool hist(E&& y, long bins=10, std::string color="b", + bool hist(const E& y, long bins=10, std::string color="b", double alpha=1.0, bool cumulative=false) { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* yarray = get_array(y); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); @@ -647,16 +634,14 @@ namespace detail { } template - bool scatter(E1&& x, E2&& y, + bool scatter(const E1& x, const E2& y, const double s=1.0) // The marker size in points**2 { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); @@ -675,13 +660,12 @@ namespace detail { } template - bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, + bool bar(const E& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map& keywords = {}) { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* yarray = get_array(y); xt::xtensor::value_type, 1> x = xt::arange::value_type>(y.size()); @@ -730,12 +714,11 @@ namespace detail { } template - bool named_hist(std::string label, E&& y, long bins=10, std::string color="b", double alpha=1.0) + bool named_hist(std::string label, const E& y, long bins=10, std::string color="b", double alpha=1.0) { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* yarray = get_array(y); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str())); @@ -757,15 +740,13 @@ namespace detail { } template - bool plot(E1&& x, E2&& y, const std::string& s = "") + bool plot(const E1& x, const E2& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(s.c_str()); @@ -783,19 +764,16 @@ namespace detail { } template - bool quiver(E1&& x, E2&& y, E3&& u, E4&& w, const std::map& keywords = {}) + bool quiver(const E1& x, const E2& y, const E3& u, const E4& w, + const std::map& keywords = {}) { assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); - xt::xtensor::value_type, 1> uv = u; - PyObject* uarray = get_array(uv); - xt::xtensor::value_type, 1> wv = w; - PyObject* warray = get_array(wv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); + PyObject* uarray = get_array(u); + PyObject* warray = get_array(w); PyObject* plot_args = PyTuple_New(4); PyTuple_SetItem(plot_args, 0, xarray); @@ -822,15 +800,13 @@ namespace detail { } template - bool stem(E1&& x, E2&& y, const std::string& s = "") + bool stem(const E1& x, const E2& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(s.c_str()); @@ -850,15 +826,13 @@ namespace detail { } template - bool semilogx(E1&& x, E2&& y, const std::string& s = "") + bool semilogx(const E1& x, const E2& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(s.c_str()); @@ -876,15 +850,13 @@ namespace detail { } template - bool semilogy(E1&& x, E2&& y, const std::string& s = "") + bool semilogy(const E1& x, const E2& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(s.c_str()); @@ -902,15 +874,13 @@ namespace detail { } template - bool loglog(E1&& x, E2&& y, const std::string& s = "") + bool loglog(const E1& x, const E2& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(s.c_str()); @@ -928,17 +898,15 @@ namespace detail { } template - bool errorbar(E1&& x, E2&& y, E3&& yerr, const std::map &keywords = {}) + bool errorbar(const E1& x, const E2& y, const E3& yerr, + const std::map &keywords = {}) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); - xt::xtensor::value_type, 1> yerrv = yerr; - PyObject* yerrarray = get_array(yerrv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); + PyObject* yerrarray = get_array(yerr); // construct keyword args PyObject* kwargs = PyDict_New(); @@ -967,15 +935,14 @@ namespace detail { } template - bool named_plot(const std::string& name, E&& y, const std::string& format = "") + bool named_plot(const std::string& name, const E& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(format.c_str()); @@ -994,17 +961,15 @@ namespace detail { } template - bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") + bool named_plot(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1023,17 +988,15 @@ namespace detail { } template - bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& format = "") + bool named_semilogx(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1052,17 +1015,15 @@ namespace detail { } template - bool named_semilogy(const std::string& name, E1&& x, E2& y, const std::string& format = "") + bool named_semilogy(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1081,17 +1042,15 @@ namespace detail { } template - bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& format = "") + bool named_loglog(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1110,17 +1069,17 @@ namespace detail { } template - bool plot(E&& y, const std::string& format = "") + bool plot(const E& y, const std::string& format = "") { xt::xtensor x = xt::arange(y.size()); - return plot(std::move(x), std::forward(y), format); + return plot(x, y, format); } template - bool stem(E&& y, const std::string& format = "") + bool stem(const E& y, const std::string& format = "") { xt::xtensor x = xt::arange(y.size()); - return stem(std::move(x), std::forward(y), format); + return stem(x, y, format); } template @@ -1296,14 +1255,14 @@ namespace detail { } template - inline void xticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) + inline void xticks(const E& ticks, const std::vector &labels = {}, + const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy array - xt::xtensor::value_type, 1> ticksv = ticks; - PyObject* ticksarray = get_array(ticksv); + PyObject* ticksarray = get_array(ticks); PyObject* args; if(labels.size() == 0) { @@ -1339,20 +1298,20 @@ namespace detail { } template - inline void xticks(E&& ticks, const std::map& keywords) + inline void xticks(const E& ticks, const std::map& keywords) { - xticks(std::forward(ticks), {}, keywords); + xticks(ticks, {}, keywords); } template - inline void yticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) + inline void yticks(const E& ticks, const std::vector &labels = {}, + const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy array - xt::xtensor::value_type, 1> ticksv = ticks; - PyObject* ticksarray = get_array(ticksv); + PyObject* ticksarray = get_array(ticks); PyObject* args; if(labels.size() == 0) { @@ -1388,9 +1347,9 @@ namespace detail { } template - inline void yticks(E&& ticks, const std::map& keywords) + inline void yticks(const E& ticks, const std::map& keywords) { - yticks(std::forward(ticks), {}, keywords); + yticks(ticks, {}, keywords); } inline void subplot(long nrows, long ncols, long plot_number) @@ -1710,7 +1669,7 @@ namespace detail { 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; @@ -1730,62 +1689,62 @@ namespace detail { struct plot_impl { template - bool operator()(IterableX&& x, IterableY&& y, const std::string& format) - { - // 2-phase lookup for distance, begin, end - using std::distance; - using std::begin; - using std::end; + bool operator()(IterableX& x, IterableY& y, const std::string& format) + { + // 2-phase lookup for distance, begin, end + using std::distance; + using std::begin; + using std::end; - auto xs = distance(begin(x), end(x)); - auto ys = distance(begin(y), end(y)); - assert(xs == ys && "x and y data must have the same number of elements!"); + auto xs = distance(begin(x), end(x)); + auto ys = distance(begin(y), end(y)); + assert(xs == ys && "x and y data must have the same number of elements!"); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xlist = PyList_New(xs); - PyObject* ylist = PyList_New(ys); - PyObject* pystring = PyString_FromString(format.c_str()); + PyObject* xlist = PyList_New(xs); + PyObject* ylist = PyList_New(ys); + PyObject* pystring = PyString_FromString(format.c_str()); - auto itx = begin(x), ity = begin(y); - for(size_t i = 0; i < xs; ++i) { - PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); - PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); - } + auto itx = begin(x), ity = begin(y); + for(size_t i = 0; i < xs; ++i) { + PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); + PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); + } - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xlist); - PyTuple_SetItem(plot_args, 1, ylist); - PyTuple_SetItem(plot_args, 2, pystring); + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xlist); + 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); + Py_DECREF(plot_args); + if(res) Py_DECREF(res); - return res; - } + return res; + } }; template<> struct plot_impl { template - bool operator()(Iterable&& ticks, 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::size_t size = std::distance(begin(ticks), end(ticks)); - std::array shape{size}; - xt::xtensor y(shape); - //for(auto x : ticks) y.push_back(f(x)); - std::size_t idx = 0; - for(auto x : ticks) y[idx++] = f(x); - //for (auto i = 0ul; i < size; ++i) y[i] = f(ticks[i]); - return plot_impl()(std::forward(ticks), std::move(y), format); - } + bool operator()(Iterable& ticks, 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::size_t size = std::distance(begin(ticks), end(ticks)); + std::array shape{size}; + xt::xtensor y(shape); + //for(auto x : ticks) y.push_back(f(x)); + std::size_t idx = 0; + for(auto x : ticks) y[idx++] = f(x); + //for (auto i = 0ul; i < size; ++i) y[i] = f(ticks[i]); + return plot_impl()(std::forward(ticks), std::move(y), format); + } }; } // end namespace detail @@ -1795,14 +1754,12 @@ namespace detail { bool plot() { return true; } template - bool plot(E1&& a, E2&& b, const std::string& format, Args... args) + bool plot(const E1& a, const E2& b, const std::string& format, Args... args) { // FIXME - //return detail::plot_impl>::type>()( - //std::forward(a), std::forward(b), format - //) && plot(args...); - //return plot(std::forward(a), std::forward(b), format) && plot(args...); - return plot(std::forward(a), std::forward(b), format) && plot(std::forward(args)...); + return detail::plot_impl>::type>()(a, b, format) && plot(args...); + //return plot(a, b, format) && plot(args...); + //return plot(a, b, format) && plot(args...); } /* @@ -1812,18 +1769,18 @@ namespace detail { inline bool plot(std::vector x, std::vector y, const std::string& format = "") { xt::xtensor x_adapt = xt::adapt(x); xt::xtensor y_adapt = xt::adapt(y); - return plot(std::move(x_adapt), std::move(y_adapt), format); + return plot(x_adapt, y_adapt, format); } inline bool plot(std::vector y, const std::string& format = "") { xt::xtensor y_adapt = xt::adapt(y); - return plot(std::move(y_adapt), format); + return plot(y_adapt, format); } inline bool plot(std::vector x, std::vector y, const std::map& keywords) { xt::xtensor x_adapt = xt::adapt(x); xt::xtensor y_adapt = xt::adapt(y); - return plot(std::move(x_adapt), std::move(y_adapt), keywords); + return plot(x_adapt, y_adapt, keywords); } /* @@ -1835,7 +1792,8 @@ namespace detail { public: // default initialization with plot label, some data and format template - Plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + Plot(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { + //Plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { assert(x.size() == y.size()); @@ -1843,10 +1801,8 @@ namespace detail { if(name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1878,14 +1834,12 @@ namespace detail { : Plot(name, xt::xtensor(), xt::xtensor(), format) {} template - bool update(E1&& x, E2&& y) { + bool update(const E1& x, const E2& y) { assert(x.size() == y.size()); if(set_data_fct) { - xt::xtensor::value_type, 1> xv = x; - PyObject* xarray = get_array(xv); - xt::xtensor::value_type, 1> yv = y; - PyObject* yarray = get_array(yv); + PyObject* xarray = get_array(x); + PyObject* yarray = get_array(y); PyObject* plot_args = PyTuple_New(2); PyTuple_SetItem(plot_args, 0, xarray); From ebb8806c56a81eb1e7e9a36f440fcfe3d5277f5c Mon Sep 17 00:00:00 2001 From: khanley6 Date: Thu, 2 May 2019 18:07:45 +0100 Subject: [PATCH 08/21] Updated examples using now working rvalue plotting implementation --- examples/animation.cpp | 4 +- examples/basic.cpp | 5 +- examples/fill.cpp | 2 +- examples/fill_inbetween.cpp | 2 +- examples/modern.cpp | 12 +- examples/quiver.cpp | 2 +- examples/subplot.cpp | 4 +- examples/surface.cpp | 8 +- examples/xkcd.cpp | 4 +- matplotlibcpp.h | 276 ++++++++++++++++++++++++------------ 10 files changed, 206 insertions(+), 113 deletions(-) diff --git a/examples/animation.cpp b/examples/animation.cpp index 5ddb0cd..f4406b3 100644 --- a/examples/animation.cpp +++ b/examples/animation.cpp @@ -21,12 +21,12 @@ int main() // Clear previous plot plt::clf(); // Plot line from given x and y data. Color is selected automatically. - plt::plot(x, y); + plt::plot(x-50000, y+2); // Plot a line whose name will show up as "log(x)" in the legend. plt::named_plot("log(x)", x, z); // Set x-axis to interval [0,1000000] - plt::xlim(0, n*n); + plt::xlim(-50000, n*n); // Add graph title plt::title("Sample figure"); diff --git a/examples/basic.cpp b/examples/basic.cpp index 1fe2239..5671568 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -24,13 +24,14 @@ int main() plt::figure_size(1200, 780); // Plot line from given x and y data. Color is selected automatically. - plt::plot(x, y); + plt::plot(x, y+1); // Plot a red dashed line from given x and y data. - plt::plot(x, w,"r--"); + plt::plot(x, w+1, "r--"); // Plot a line whose name will show up as "log(x)" in the legend. plt::named_plot("log(x)", x, z); + plt::named_plot("log(x)+1", x, z+1); // Set x-axis to interval [0,1000000] plt::xlim(0, 1000*1000); diff --git a/examples/fill.cpp b/examples/fill.cpp index daebcff..dc63102 100644 --- a/examples/fill.cpp +++ b/examples/fill.cpp @@ -26,7 +26,7 @@ int main() { x1 = xt::concatenate(xt::xtuple(x1, xt::view(x2, xt::range(x2.size(), _, -1)))); y1 = xt::concatenate(xt::xtuple(y1, xt::view(y2, xt::range(y2.size(), _, -1)))); - plt::fill(x1, y1, {}); + plt::fill(x1+50, y1+50, {}); } plt::show(); } diff --git a/examples/fill_inbetween.cpp b/examples/fill_inbetween.cpp index 4192125..54df70f 100644 --- a/examples/fill_inbetween.cpp +++ b/examples/fill_inbetween.cpp @@ -27,6 +27,6 @@ int main() { keywords["color"] = "grey"; keywords["hatch"] = "-"; - plt::fill_between(x, y, z, keywords); + plt::fill_between(x, y+2, z, keywords); plt::show(); } diff --git a/examples/modern.cpp b/examples/modern.cpp index 2354ec7..f932bb0 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -7,6 +7,7 @@ namespace plt = matplotlibcpp; #include #include +#include int main() { @@ -20,22 +21,15 @@ int main() xt::xtensor x = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); xt::xtensor y = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); - - xt::xtensor x2 = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); - xt::xtensor x3 = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); xt::xtensor y2 = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); - xt::xtensor y3 = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); + // plot() takes an arbitrary number of (x,y,format)-triples. // x must be iterable (that is, anything providing begin(x) and end(x)), // y must either be callable (providing operator() const) or iterable. - //plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); + plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); //plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-", x, y+1.0, "r-."); - //plt::plot(x, y, "r-", x2, xt::eval(y2+0.5), "b-.", xt::eval(x3+1.0), xt::eval(y3+1.0), "g."); - //plt::plot(x, y+1.0, "r-"); - plt::plot(x, y, "r-"); - //plt::plot(x, y, "r-", x, y2, "b.."); // show plots diff --git a/examples/quiver.cpp b/examples/quiver.cpp index 7870946..1a98ca7 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -21,6 +21,6 @@ int main() } } - plt::quiver(x, y, u, v); + plt::quiver(x+2, y+2, u+3, v+1); plt::show(); } diff --git a/examples/subplot.cpp b/examples/subplot.cpp index 76928bc..6c34512 100644 --- a/examples/subplot.cpp +++ b/examples/subplot.cpp @@ -23,9 +23,9 @@ int main() // Set the "super title" plt::suptitle("My plot"); plt::subplot(1, 2, 1); - plt::plot(x, y, "r-"); + plt::plot(x, y+2, "r-"); plt::subplot(1, 2, 2); - plt::plot(x, z, "k-"); + plt::plot(x-50000, z-2, "k-"); // Add some text to the plot plt::text(100, 90, "Hello!"); diff --git a/examples/surface.cpp b/examples/surface.cpp index 2625445..d7e71a4 100644 --- a/examples/surface.cpp +++ b/examples/surface.cpp @@ -1,6 +1,10 @@ +#define _USE_MATH_DEFINES +#include +#include #include "../matplotlibcpp.h" -#include +#include +#include namespace plt = matplotlibcpp; @@ -28,6 +32,6 @@ int main() xt::view(xz, i, xt::all()) = xt::adapt(z[i]); } - plt::plot_surface(xx, xy, xz); + plt::plot_surface(xx, xy, xz+2); plt::show(); } diff --git a/examples/xkcd.cpp b/examples/xkcd.cpp index 9526b7e..c782e6d 100644 --- a/examples/xkcd.cpp +++ b/examples/xkcd.cpp @@ -7,10 +7,10 @@ namespace plt = matplotlibcpp; int main() { xt::xtensor t = xt::linspace(0, 10, 1000); - xt::xtensor y = xt::sin(2.0 * xt::numeric_constants::PI * t); + xt::xtensor x = xt::sin(2.0 * xt::numeric_constants::PI * t); plt::xkcd(); - plt::plot(t, y); + plt::plot(t, x); plt::title("AN ORDINARY SIN WAVE"); plt::show(); } diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 341ebe8..a95f240 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -329,10 +329,14 @@ namespace detail { template <> struct select_npy_type { const static NPY_TYPES type = NPY_ULONG; }; template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; + // xtensor implementation template - PyObject* get_array(E&& v) + PyObject* get_array(const E& v) { + //std::cout << "LVALUE CALLED" << std::endl; + //std::cout << __PRETTY_FUNCTION__ << "\n\n" << std::endl; assert(v.dimension() <= 2); + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work if (v.dimension() == 1) { NPY_TYPES type = select_npy_type::value_type>::type; @@ -352,7 +356,7 @@ namespace detail { if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); npy_intp vsize[2] = {static_cast(v.shape()[0]), - static_cast(v.shape()[1])}; + static_cast(v.shape()[1])}; PyArrayObject *varray = (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); @@ -371,20 +375,83 @@ namespace detail { } } -#else // fallback if we don't have numpy: copy every element of the given vector + // vector implementation + template + PyObject* get_array(const std::vector& v) + { + //std::cout << "LVALUE VECTOR CALLED" << std::endl; + //std::cout << __PRETTY_FUNCTION__ << "\n\n" << std::endl; + detail::_interpreter::get(); + NPY_TYPES type = select_npy_type::type; + if (type == NPY_NOTYPE) + { + std::vector vd(v.size()); + npy_intp vsize = v.size(); + std::copy(v.begin(),v.end(),vd.begin()); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); + return varray; + } + + npy_intp vsize = v.size(); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); + return varray; + } + + template + PyObject* get_2darray(const std::vector<::std::vector>& v) + { + detail::_interpreter::get(); + 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())}; + + PyArrayObject *varray = + (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); + 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]; + } + + return reinterpret_cast(varray); + } +//#else // fallback if we don't have numpy: copy every element of the given vector + + // xtensor rvalue implementation template - PyObject* get_array(E&& v) + typename std::enable_if_t::value, PyObject*> get_array(E&& v) { - PyObject* list = PyList_New(v.size()); - for(size_t i = 0; i < v.size(); ++i) { - PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); + std::cout << "RVALUE CALLED" << std::endl; + std::cout << __PRETTY_FUNCTION__ << "\n\n" << std::endl; + PyObject* list; + if (v.dimension() == 1) { + list = PyList_New(v.size()); + for(size_t i = 0; i < v.size(); ++i) { + PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); + } + } else { + std::size_t num_rows = v.shape()[0]; + std::size_t num_cols = v.shape()[1]; + list = PyList_New(num_rows); + for(size_t i = 0; i < num_rows; ++i) { + PyObject* row = PyList_New(num_cols); + PyList_SetItem(list, i, row); + for(size_t j = 0; j < num_cols; ++j) { + PyList_SetItem(row, j, PyFloat_FromDouble(v.at(i,j))); + } + } } return list; } #endif // WITHOUT_NUMPY +/* template bool plot(const E1& x, const E2& y, const std::map& keywords) { @@ -415,9 +482,10 @@ namespace detail { return res; } +*/ template - void plot_surface(const E1& x, const E2& y, const E3& z, + void plot_surface(E1&& x, E2&& y, E3&& z, const std::map &keywords = std::map()) { @@ -446,9 +514,9 @@ namespace detail { assert(y.size() == z.size()); // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); - PyObject* zarray = get_array(z); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); + PyObject* zarray = get_array(std::forward(z)); // construct positional args PyObject *args = PyTuple_New(3); @@ -506,6 +574,7 @@ namespace detail { if (res) Py_DECREF(res); } +/* template bool stem(const E1& x, const E2& y, const std::map& keywords) { @@ -539,16 +608,16 @@ namespace detail { return res; } - +*/ template - bool fill(const E1& x, const E2& y, const std::map& keywords) + bool fill(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); // construct positional args PyObject* args = PyTuple_New(2); @@ -572,16 +641,16 @@ namespace detail { } template - bool fill_between(const E1& x, const E2& y1, const E3& y2, const std::map& keywords) + bool fill_between(E1&& x, E2&& y1, E3&& y2, const std::map& keywords) { assert(x.size() == y1.size()); assert(x.size() == y2.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* y1array = get_array(y1); - PyObject* y2array = get_array(y2); + PyObject* xarray = get_array(std::forward(x)); + PyObject* y1array = get_array(std::forward(y1)); + PyObject* y2array = get_array(std::forward(y2)); // construct positional args PyObject* args = PyTuple_New(3); @@ -604,6 +673,7 @@ namespace detail { return res; } +/* template bool hist(const E& y, long bins=10, std::string color="b", double alpha=1.0, bool cumulative=false) @@ -632,7 +702,8 @@ namespace detail { return res; } - +*/ +/* template bool scatter(const E1& x, const E2& y, const double s=1.0) // The marker size in points**2 @@ -658,18 +729,17 @@ namespace detail { return res; } +*/ template - bool bar(const E& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, + bool bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map& keywords = {}) { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* yarray = get_array(y); - - xt::xtensor::value_type, 1> x = xt::arange::value_type>(y.size()); + PyObject* yarray = get_array(std::forward(y)); - PyObject* xarray = get_array(x); + PyObject* xarray = get_array(xt::arange::value_type>(y.size())); PyObject* kwargs = PyDict_New(); @@ -712,7 +782,7 @@ namespace detail { return res; } - +/* template bool named_hist(std::string label, const E& y, long bins=10, std::string color="b", double alpha=1.0) { @@ -738,15 +808,17 @@ namespace detail { return res; } - - template - bool plot(const E1& x, const E2& y, const std::string& s = "") +*/ + // enable_if used to fix overload resolution on variadic call to plot (see below) when the + // last argument is a callable, such as a lambda + template::value>> + bool plot(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -764,16 +836,16 @@ namespace detail { } template - bool quiver(const E1& x, const E2& y, const E3& u, const E4& w, + bool quiver(E1&& x, E2&& y, E3&& u, E4&& w, const std::map& keywords = {}) { assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); - PyObject* uarray = get_array(u); - PyObject* warray = get_array(w); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); + PyObject* uarray = get_array(std::forward(u)); + PyObject* warray = get_array(std::forward(w)); PyObject* plot_args = PyTuple_New(4); PyTuple_SetItem(plot_args, 0, xarray); @@ -799,6 +871,7 @@ namespace detail { return res; } +/* template bool stem(const E1& x, const E2& y, const std::string& s = "") { @@ -824,7 +897,8 @@ namespace detail { return res; } - +*/ +/* template bool semilogx(const E1& x, const E2& y, const std::string& s = "") { @@ -848,7 +922,8 @@ namespace detail { return res; } - +*/ +/* template bool semilogy(const E1& x, const E2& y, const std::string& s = "") { @@ -872,7 +947,8 @@ namespace detail { return res; } - +*/ +/* template bool loglog(const E1& x, const E2& y, const std::string& s = "") { @@ -896,7 +972,8 @@ namespace detail { return res; } - +*/ +/* template bool errorbar(const E1& x, const E2& y, const E3& yerr, const std::map &keywords = {}) @@ -933,16 +1010,17 @@ namespace detail { return res; } - - template - bool named_plot(const std::string& name, const E& y, const std::string& format = "") +*/ +/* + template + bool named_plot(const std::string& name, E&& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* yarray = get_array(y); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -959,17 +1037,18 @@ namespace detail { return res; } +*/ template - bool named_plot(const std::string& name, const E1& x, const E2& y, const std::string& format = "") + bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -986,7 +1065,7 @@ namespace detail { return res; } - +/* template bool named_semilogx(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { @@ -1013,7 +1092,8 @@ namespace detail { return res; } - +*/ +/* template bool named_semilogy(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { @@ -1040,7 +1120,8 @@ namespace detail { return res; } - +*/ +/* template bool named_loglog(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { @@ -1067,20 +1148,23 @@ namespace detail { return res; } +*/ template - bool plot(const E& y, const std::string& format = "") + bool plot(E&& y, const std::string& format = "") { xt::xtensor x = xt::arange(y.size()); - return plot(x, y, format); + return plot(std::move(x), std::forward(y), format); } +/* template bool stem(const E& y, const std::string& format = "") { xt::xtensor x = xt::arange(y.size()); return stem(x, y, format); } +*/ template void text(Numeric x, Numeric y, const std::string& s = "") @@ -1099,7 +1183,6 @@ namespace detail { Py_DECREF(res); } - inline long figure(long number = -1) { PyObject *res; @@ -1253,7 +1336,7 @@ namespace detail { Py_DECREF(res); return arr; } - +/* template inline void xticks(const E& ticks, const std::vector &labels = {}, const std::map& keywords = {}) @@ -1296,13 +1379,15 @@ namespace detail { Py_DECREF(res); } - +*/ +/* template inline void xticks(const E& ticks, const std::map& keywords) { xticks(ticks, {}, keywords); } - +*/ +/* template inline void yticks(const E& ticks, const std::vector &labels = {}, const std::map& keywords = {}) @@ -1345,13 +1430,14 @@ namespace detail { Py_DECREF(res); } - +*/ +/* template inline void yticks(const E& ticks, const std::map& keywords) { yticks(ticks, {}, keywords); - } - + } +*/ inline void subplot(long nrows, long ncols, long plot_number) { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work @@ -1520,7 +1606,7 @@ namespace detail { } inline void xkcd() { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + //detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* res; PyObject *kwargs = PyDict_New(); @@ -1640,7 +1726,6 @@ namespace detail { } // Support for variadic plot() and initializer lists: - namespace detail { template @@ -1664,10 +1749,10 @@ namespace detail { 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 + 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* ); + static std::false_type test( Check* ); public: typedef decltype(test(nullptr)) type; @@ -1689,7 +1774,7 @@ namespace detail { struct plot_impl { template - bool operator()(IterableX& x, IterableY& y, const std::string& format) + bool operator()(IterableX&& x, IterableY&& y, const std::string& format) { // 2-phase lookup for distance, begin, end using std::distance; @@ -1706,7 +1791,9 @@ namespace detail { PyObject* ylist = PyList_New(ys); PyObject* pystring = PyString_FromString(format.c_str()); - auto itx = begin(x), ity = begin(y); + //auto itx = begin(x), ity = begin(y); + auto itx = x.begin(); + auto ity = y.begin(); for(size_t i = 0; i < xs; ++i) { PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); @@ -1730,7 +1817,7 @@ namespace detail { struct plot_impl { template - bool operator()(Iterable& ticks, Callable& f, const std::string& format) + bool operator()(Iterable&& ticks, Callable&& f, const std::string& format) { if(begin(ticks) == end(ticks)) return true; @@ -1742,7 +1829,6 @@ namespace detail { //for(auto x : ticks) y.push_back(f(x)); std::size_t idx = 0; for(auto x : ticks) y[idx++] = f(x); - //for (auto i = 0ul; i < size; ++i) y[i] = f(ticks[i]); return plot_impl()(std::forward(ticks), std::move(y), format); } }; @@ -1753,47 +1839,56 @@ namespace detail { template bool plot() { return true; } + template + void pprint(void) { std::cout << "\n" << __PRETTY_FUNCTION__ << "\n" << std::endl; } + template - bool plot(const E1& a, const E2& b, const std::string& format, Args... args) + bool plot(E1&& a, E2&& b, const std::string& format, Args... args) { - // FIXME - return detail::plot_impl>::type>()(a, b, format) && plot(args...); - //return plot(a, b, format) && plot(args...); - //return plot(a, b, format) && plot(args...); - } - /* - * This group of plot() functions is needed to support initializer lists, i.e. calling - * plot( {1,2,3,4} ) - */ + return detail::plot_impl< + std::integral_constant>::type, + xtl::negation> + >::value> + >()(std::forward(a), std::forward(b), format) && plot(std::forward(args)...); + + //return detail::plot_impl>::type>()( + //std::forward(a), std::forward(b), format) && plot(std::forward(args)...); + } + + // + // This group of plot() functions is needed to support initializer lists, i.e. calling + // plot( {1,2,3,4} ) + /// inline bool plot(std::vector x, std::vector y, const std::string& format = "") { xt::xtensor x_adapt = xt::adapt(x); xt::xtensor y_adapt = xt::adapt(y); - return plot(x_adapt, y_adapt, format); + return plot(std::move(x_adapt), std::move(y_adapt), format); } inline bool plot(std::vector y, const std::string& format = "") { xt::xtensor y_adapt = xt::adapt(y); - return plot(y_adapt, format); + return plot(std::move(y_adapt), format); } +/* inline bool plot(std::vector x, std::vector y, const std::map& keywords) { xt::xtensor x_adapt = xt::adapt(x); xt::xtensor y_adapt = xt::adapt(y); return plot(x_adapt, y_adapt, keywords); } +*/ - /* - * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting - */ - + // + // This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting + // class Plot { public: // default initialization with plot label, some data and format template - Plot(const std::string& name, const E1& x, const E2& y, const std::string& format = "") { - //Plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + Plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { assert(x.size() == y.size()); @@ -1801,8 +1896,8 @@ namespace detail { if(name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1834,12 +1929,12 @@ namespace detail { : Plot(name, xt::xtensor(), xt::xtensor(), format) {} template - bool update(const E1& x, const E2& y) { + bool update(E1&& x, E2&& y) { assert(x.size() == y.size()); if(set_data_fct) { - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* plot_args = PyTuple_New(2); PyTuple_SetItem(plot_args, 0, xarray); @@ -1885,5 +1980,4 @@ namespace detail { PyObject* line = nullptr; PyObject* set_data_fct = nullptr; }; - } // end namespace matplotlibcpp From 533b00f99f946da7b15b7a154a796727958ead68 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Thu, 2 May 2019 18:27:24 +0100 Subject: [PATCH 09/21] Fixed surface example --- examples/surface.cpp | 3 ++- matplotlibcpp.h | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/surface.cpp b/examples/surface.cpp index d7e71a4..5a3e6e1 100644 --- a/examples/surface.cpp +++ b/examples/surface.cpp @@ -32,6 +32,7 @@ int main() xt::view(xz, i, xt::all()) = xt::adapt(z[i]); } - plt::plot_surface(xx, xy, xz+2); + //plt::plot_surface(xx, xy, xz); + plt::plot_surface(xx+2, xy, xz+2); plt::show(); } diff --git a/matplotlibcpp.h b/matplotlibcpp.h index a95f240..2ea862e 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -420,8 +420,8 @@ namespace detail { 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 // xtensor rvalue implementation template typename std::enable_if_t::value, PyObject*> get_array(E&& v) @@ -485,10 +485,13 @@ namespace detail { */ template + //void plot_surface(E1&& x, E2&& y, const E3& z, void plot_surface(E1&& x, E2&& y, E3&& z, const std::map &keywords = std::map()) { + static_assert(std::is_lvalue_reference::value, + "z argument to surface is required to be an lvalue"); // 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 @@ -517,6 +520,7 @@ namespace detail { PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); PyObject* zarray = get_array(std::forward(z)); + //PyObject* zarray = get_array(z); // construct positional args PyObject *args = PyTuple_New(3); From 2cd0df6142ee89b461df8434260c98a46dd088de Mon Sep 17 00:00:00 2001 From: khanley6 Date: Fri, 3 May 2019 10:52:14 +0100 Subject: [PATCH 10/21] Fixed WITHOUT_NUMPY implementation. This macro now exclused surface plots as numpy is required for them --- examples/basic.cpp | 4 ++ examples/surface.cpp | 2 +- matplotlibcpp.h | 166 ++++++++++++++++++++----------------------- 3 files changed, 81 insertions(+), 91 deletions(-) diff --git a/examples/basic.cpp b/examples/basic.cpp index 5671568..505b6af 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -19,6 +19,8 @@ int main() xt::xtensor x = xt::square(i); xt::xtensor y = xt::sin(2 * xt::numeric_constants::PI * i / 360.0); xt::xtensor z = xt::log(i); + + std::vector vy(n, 5); // Set the size of output image = 1200x780 pixels plt::figure_size(1200, 780); @@ -29,6 +31,8 @@ int main() // Plot a red dashed line from given x and y data. plt::plot(x, w+1, "r--"); + plt::plot(x, vy, "g-."); + // Plot a line whose name will show up as "log(x)" in the legend. plt::named_plot("log(x)", x, z); plt::named_plot("log(x)+1", x, z+1); diff --git a/examples/surface.cpp b/examples/surface.cpp index 5a3e6e1..1e52c03 100644 --- a/examples/surface.cpp +++ b/examples/surface.cpp @@ -33,6 +33,6 @@ int main() } //plt::plot_surface(xx, xy, xz); - plt::plot_surface(xx+2, xy, xz+2); + plt::plot_surface(xx+2, xy+5, xz); plt::show(); } diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 2ea862e..a739d8d 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -25,8 +25,6 @@ #include #include -#include -#include #include #include @@ -333,8 +331,6 @@ namespace detail { template PyObject* get_array(const E& v) { - //std::cout << "LVALUE CALLED" << std::endl; - //std::cout << __PRETTY_FUNCTION__ << "\n\n" << std::endl; assert(v.dimension() <= 2); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work @@ -376,13 +372,11 @@ namespace detail { } // vector implementation - template - PyObject* get_array(const std::vector& v) + template + PyObject* get_array(const std::vector& v) { - //std::cout << "LVALUE VECTOR CALLED" << std::endl; - //std::cout << __PRETTY_FUNCTION__ << "\n\n" << std::endl; detail::_interpreter::get(); - NPY_TYPES type = select_npy_type::type; + NPY_TYPES type = select_npy_type::type; if (type == NPY_NOTYPE) { std::vector vd(v.size()); @@ -396,38 +390,17 @@ namespace detail { PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); return varray; } +#endif // WITHOUT_NUMPY - template - PyObject* get_2darray(const std::vector<::std::vector>& v) - { - detail::_interpreter::get(); - 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())}; - - PyArrayObject *varray = - (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - - 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]; - } - - return reinterpret_cast(varray); - } - -//#else // fallback if we don't have numpy: copy every element of the given vector // xtensor rvalue implementation + // if WITHOUT_NUMPY is defined, this function accepts all calls to get_array template +#ifndef WITHOUT_NUMPY typename std::enable_if_t::value, PyObject*> get_array(E&& v) +#else + typename std::enable_if_t::value, PyObject*> get_array(E&& v) +#endif // WITHOUT_NUMPY { - std::cout << "RVALUE CALLED" << std::endl; - std::cout << __PRETTY_FUNCTION__ << "\n\n" << std::endl; PyObject* list; if (v.dimension() == 1) { list = PyList_New(v.size()); @@ -449,18 +422,30 @@ namespace detail { return list; } -#endif // WITHOUT_NUMPY +#ifdef WITHOUT_NUMPY + // vector implementation + template + PyObject* get_array(const std::vector& v) + { + PyObject* list = PyList_New(v.size()); + for(size_t i = 0; i < v.size(); ++i) { + PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); + } + return list; + } +#endif + /* template - bool plot(const E1& x, const E2& y, const std::map& keywords) + bool plot(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); // construct positional args PyObject* args = PyTuple_New(2); @@ -484,12 +469,14 @@ namespace detail { } */ +#ifndef WITHOUT_NUMPY template - //void plot_surface(E1&& x, E2&& y, const E3& z, void plot_surface(E1&& x, E2&& y, E3&& z, const std::map &keywords = std::map()) { + // Passing a list of lists as the z argument results in python throwing: + // `AttributeError: 'list' object has no attribute 'ndim'` static_assert(std::is_lvalue_reference::value, "z argument to surface is required to be an lvalue"); // We lazily load the modules here the first time this function is called @@ -520,7 +507,6 @@ namespace detail { PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); PyObject* zarray = get_array(std::forward(z)); - //PyObject* zarray = get_array(z); // construct positional args PyObject *args = PyTuple_New(3); @@ -577,17 +563,18 @@ namespace detail { Py_DECREF(kwargs); if (res) Py_DECREF(res); } +#endif // WITHOUT_NUMPY /* template - bool stem(const E1& x, const E2& y, const std::map& keywords) + bool stem(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy arrays - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); // construct positional args PyObject* args = PyTuple_New(2); @@ -679,12 +666,12 @@ namespace detail { /* template - bool hist(const E& y, long bins=10, std::string color="b", + bool hist(E&& y, long bins=10, std::string color="b", double alpha=1.0, bool cumulative=false) { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* yarray = get_array(y); + PyObject* yarray = get_array(std::forward(y)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); @@ -709,14 +696,14 @@ namespace detail { */ /* template - bool scatter(const E1& x, const E2& y, + bool scatter(E1&& x, E2&& y, const double s=1.0) // The marker size in points**2 { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); @@ -788,11 +775,11 @@ namespace detail { } /* template - bool named_hist(std::string label, const E& y, long bins=10, std::string color="b", double alpha=1.0) + bool named_hist(std::string label, E&& y, long bins=10, std::string color="b", double alpha=1.0) { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* yarray = get_array(y); + PyObject* yarray = get_array(std::forward(y)); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str())); @@ -877,13 +864,13 @@ namespace detail { /* template - bool stem(const E1& x, const E2& y, const std::string& s = "") + bool stem(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -904,13 +891,13 @@ namespace detail { */ /* template - bool semilogx(const E1& x, const E2& y, const std::string& s = "") + bool semilogx(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -929,13 +916,13 @@ namespace detail { */ /* template - bool semilogy(const E1& x, const E2& y, const std::string& s = "") + bool semilogy(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -954,13 +941,13 @@ namespace detail { */ /* template - bool loglog(const E1& x, const E2& y, const std::string& s = "") + bool loglog(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(s.c_str()); @@ -979,15 +966,15 @@ namespace detail { */ /* template - bool errorbar(const E1& x, const E2& y, const E3& yerr, + bool errorbar(E1&& x, E2&& y, E3&& yerr, const std::map &keywords = {}) { assert(x.size() == y.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); - PyObject* yerrarray = get_array(yerr); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); + PyObject* yerrarray = get_array(std::forward(yerr)); // construct keyword args PyObject* kwargs = PyDict_New(); @@ -1071,15 +1058,15 @@ namespace detail { } /* template - bool named_semilogx(const std::string& name, const E1& x, const E2& y, const std::string& format = "") + bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1099,15 +1086,15 @@ namespace detail { */ /* template - bool named_semilogy(const std::string& name, const E1& x, const E2& y, const std::string& format = "") + bool named_semilogy(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1127,15 +1114,15 @@ namespace detail { */ /* template - bool named_loglog(const std::string& name, const E1& x, const E2& y, const std::string& format = "") + bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* xarray = get_array(x); - PyObject* yarray = get_array(y); + PyObject* xarray = get_array(std::forward(x)); + PyObject* yarray = get_array(std::forward(y)); PyObject* pystring = PyString_FromString(format.c_str()); @@ -1163,10 +1150,10 @@ namespace detail { /* template - bool stem(const E& y, const std::string& format = "") + bool stem(E&& y, const std::string& format = "") { xt::xtensor x = xt::arange(y.size()); - return stem(x, y, format); + return stem(std::move(x), std::forward(y), format); } */ @@ -1342,14 +1329,14 @@ namespace detail { } /* template - inline void xticks(const E& ticks, const std::vector &labels = {}, + inline void xticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy array - PyObject* ticksarray = get_array(ticks); + PyObject* ticksarray = get_array(std::forward(ticks)); PyObject* args; if(labels.size() == 0) { @@ -1386,21 +1373,21 @@ namespace detail { */ /* template - inline void xticks(const E& ticks, const std::map& keywords) + inline void xticks(E&& ticks, const std::map& keywords) { - xticks(ticks, {}, keywords); + xticks(std::forward(ticks), {}, keywords); } */ /* template - inline void yticks(const E& ticks, const std::vector &labels = {}, + inline void yticks(E&& ticks, const std::vector &labels = {}, const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work // using numpy array - PyObject* ticksarray = get_array(ticks); + PyObject* ticksarray = get_array(std::forward(ticks)); PyObject* args; if(labels.size() == 0) { @@ -1437,9 +1424,9 @@ namespace detail { */ /* template - inline void yticks(const E& ticks, const std::map& keywords) + inline void yticks(E&& ticks, const std::map& keywords) { - yticks(ticks, {}, keywords); + yticks(std::forward(ticks), {}, keywords); } */ inline void subplot(long nrows, long ncols, long plot_number) @@ -1610,7 +1597,7 @@ namespace detail { } inline void xkcd() { - //detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work PyObject* res; PyObject *kwargs = PyDict_New(); @@ -1830,7 +1817,6 @@ namespace detail { std::size_t size = std::distance(begin(ticks), end(ticks)); std::array shape{size}; xt::xtensor y(shape); - //for(auto x : ticks) y.push_back(f(x)); std::size_t idx = 0; for(auto x : ticks) y[idx++] = f(x); return plot_impl()(std::forward(ticks), std::move(y), format); @@ -1880,7 +1866,7 @@ namespace detail { inline bool plot(std::vector x, std::vector y, const std::map& keywords) { xt::xtensor x_adapt = xt::adapt(x); xt::xtensor y_adapt = xt::adapt(y); - return plot(x_adapt, y_adapt, keywords); + return plot(std::move(x_adapt), std::move(y_adapt), keywords); } */ From 45da8f422085172775b6c686370c86079eaa1243 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Fri, 3 May 2019 12:29:47 +0100 Subject: [PATCH 11/21] Fixed formatting and removed raw calls --- matplotlibcpp.h | 864 +++++++++++++++++++++++++----------------------- 1 file changed, 457 insertions(+), 407 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index a739d8d..a9ae62e 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -195,7 +195,7 @@ namespace detail { s_python_function_bar = PyObject_GetAttrString(pymod,"bar"); s_python_function_subplots_adjust = PyObject_GetAttrString(pymod,"subplots_adjust"); - if( !s_python_function_show + if ( !s_python_function_show || !s_python_function_close || !s_python_function_draw || !s_python_function_pause @@ -281,14 +281,14 @@ namespace detail { } // end namespace detail // must be called before the first regular call to matplotlib to have any effect - inline void backend(const std::string& name) - { + inline void backend(const std::string& name) { detail::s_backend = name; } - inline bool annotate(std::string annotation, double x, double y) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline bool annotate(std::string annotation, double x, double y) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject * xy = PyTuple_New(2); PyObject * str = PyString_FromString(annotation.c_str()); @@ -302,16 +302,17 @@ namespace detail { 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; } + #ifndef WITHOUT_NUMPY // Type selector for numpy array conversion template struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default @@ -327,20 +328,19 @@ namespace detail { template <> struct select_npy_type { const static NPY_TYPES type = NPY_ULONG; }; template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; + // xtensor implementation template - PyObject* get_array(const E& v) - { + PyObject* get_array(const E& v) { assert(v.dimension() <= 2); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work if (v.dimension() == 1) { NPY_TYPES type = select_npy_type::value_type>::type; - if (type == NPY_NOTYPE) - { + if (type == NPY_NOTYPE) { std::vector vd(v.size()); npy_intp vsize = v.size(); - std::copy(v.begin(),v.end(),vd.begin()); + std::copy(v.begin(), v.end(), vd.begin()); PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); return varray; } @@ -371,17 +371,16 @@ namespace detail { } } + // vector implementation template - PyObject* get_array(const std::vector& v) - { + PyObject* get_array(const std::vector& v) { detail::_interpreter::get(); NPY_TYPES type = select_npy_type::type; - if (type == NPY_NOTYPE) - { + if (type == NPY_NOTYPE) { std::vector vd(v.size()); npy_intp vsize = v.size(); - std::copy(v.begin(),v.end(),vd.begin()); + std::copy(v.begin(), v.end(), vd.begin()); PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); return varray; } @@ -392,15 +391,17 @@ namespace detail { } #endif // WITHOUT_NUMPY + // xtensor rvalue implementation + // if WITHOUT_NUMPY is not defined, this function is taked with copying rvalues // if WITHOUT_NUMPY is defined, this function accepts all calls to get_array template #ifndef WITHOUT_NUMPY - typename std::enable_if_t::value, PyObject*> get_array(E&& v) + typename std::enable_if_t::value, PyObject*> #else - typename std::enable_if_t::value, PyObject*> get_array(E&& v) + typename std::enable_if_t::value, PyObject*> #endif // WITHOUT_NUMPY - { + get_array (E&& v) { PyObject* list; if (v.dimension() == 1) { list = PyList_New(v.size()); @@ -422,11 +423,11 @@ namespace detail { return list; } + #ifdef WITHOUT_NUMPY // vector implementation template - PyObject* get_array(const std::vector& v) - { + PyObject* get_array(const std::vector& v) { PyObject* list = PyList_New(v.size()); for(size_t i = 0; i < v.size(); ++i) { PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); @@ -436,12 +437,12 @@ namespace detail { #endif -/* template - bool plot(E1&& x, E2&& y, const std::map& keywords) - { + bool plot(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); // using numpy arrays PyObject* xarray = get_array(std::forward(x)); @@ -454,50 +455,57 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + for(auto it = keywords.cbegin(); it != keywords.cend(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_plot, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -*/ + #ifndef WITHOUT_NUMPY template void plot_surface(E1&& x, E2&& y, E3&& z, - const std::map &keywords = - std::map()) - { + const std::map &keywords = + std::map()) { // Passing a list of lists as the z argument results in python throwing: // `AttributeError: 'list' object has no attribute 'ndim'` static_assert(std::is_lvalue_reference::value, "z argument to surface is required to be an lvalue"); + // 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. - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + // interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; if (!mpl_toolkitsmod) { 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"); } + 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!"); } + 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!"); } + if (!axis3dmod) + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } assert(x.size() == y.size()); @@ -524,16 +532,16 @@ namespace detail { PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { + for (auto it = keywords.cbegin(); it != keywords.cend(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } - PyObject *fig = - PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); + 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(); @@ -541,6 +549,7 @@ namespace detail { 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); @@ -565,12 +574,13 @@ namespace detail { } #endif // WITHOUT_NUMPY -/* + template - bool stem(E1&& x, E2&& y, const std::map& keywords) - { + bool stem(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); // using numpy arrays PyObject* xarray = get_array(std::forward(x)); @@ -583,8 +593,7 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { + for (auto it = keywords.cbegin(); it != keywords.cend(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } @@ -594,17 +603,18 @@ namespace detail { Py_DECREF(args); Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -*/ + + template - bool fill(E1&& x, E2&& y, const std::map& keywords) - { + bool fill(E1&& x, E2&& y, const std::map& keywords) { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); // using numpy arrays PyObject* xarray = get_array(std::forward(x)); @@ -617,23 +627,24 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + for (auto it = keywords.cbegin(); it != keywords.cend(); ++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, args, kwargs); + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_fill, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if (res) Py_DECREF(res); return res; } + template - bool fill_between(E1&& x, E2&& y1, E3&& y2, const std::map& keywords) - { + bool fill_between(E1&& x, E2&& y1, E3&& y2, const std::map& keywords) { assert(x.size() == y1.size()); assert(x.size() == y2.size()); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work @@ -651,25 +662,26 @@ namespace detail { // 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())); + for(auto it = keywords.cbegin(); it != keywords.cend(); ++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; } -/* + template - bool hist(E&& y, long bins=10, std::string color="b", - double alpha=1.0, bool cumulative=false) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + bool hist(E&& y, long bins=10, std::string color="b", double alpha=1.0, bool cumulative=false) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* yarray = get_array(std::forward(y)); @@ -683,24 +695,23 @@ namespace detail { 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 scatter(E1&& x, E2&& y, - const double s=1.0) // The marker size in points**2 - { + bool scatter(E1&& x, E2&& y, const double s=1.0) { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -712,24 +723,24 @@ namespace detail { 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 bar(E&& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, - const std::map& keywords = {}) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + const std::map& keywords = {}) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* yarray = get_array(std::forward(y)); - PyObject* xarray = get_array(xt::arange::value_type>(y.size())); PyObject* kwargs = PyDict_New(); @@ -742,42 +753,44 @@ namespace detail { 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); + if (res) Py_DECREF(res); return res; } - inline bool subplots_adjust(const std::map& keywords = {}) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline bool subplots_adjust(const std::map& keywords = {}) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { + for (auto it = keywords.cbegin(); it != keywords.cend(); ++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 - bool named_hist(std::string label, E&& y, long bins=10, std::string color="b", double alpha=1.0) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + bool named_hist(std::string label, E&& y, long bins=10, std::string color="b", double alpha=1.0) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* yarray = get_array(std::forward(y)); @@ -787,26 +800,28 @@ namespace detail { 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; } -*/ + + // enable_if used to fix overload resolution on variadic call to plot (see below) when the // last argument is a callable, such as a lambda template::value>> - bool plot(E1&& x, E2&& y, const std::string& s = "") - { + bool plot(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -818,20 +833,23 @@ namespace detail { 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; } + template bool quiver(E1&& x, E2&& y, E3&& u, E4&& w, - const std::map& keywords = {}) - { + const std::map& keywords = {}) { assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -846,9 +864,10 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + for(auto it = keywords.cbegin(); it != keywords.cend(); ++it) { - 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( @@ -856,18 +875,18 @@ namespace detail { Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -/* + template - bool stem(E1&& x, E2&& y, const std::string& s = "") - { + bool stem(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -883,18 +902,18 @@ namespace detail { 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(E1&& x, E2&& y, const std::string& s = "") - { + bool semilogx(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -906,20 +925,22 @@ namespace detail { 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(E1&& x, E2&& y, const std::string& s = "") - { + bool semilogy(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -931,20 +952,22 @@ namespace detail { 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(E1&& x, E2&& y, const std::string& s = "") - { + bool loglog(E1&& x, E2&& y, const std::string& s = "") { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -956,21 +979,23 @@ namespace detail { 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(E1&& x, E2&& y, E3&& yerr, - const std::map &keywords = {}) - { + const std::map &keywords = {}) { assert(x.size() == y.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -978,9 +1003,10 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + for(auto it = keywords.cbegin(); it != keywords.cend(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); } PyDict_SetItemString(kwargs, "yerr", yerrarray); @@ -989,24 +1015,22 @@ namespace detail { 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); - - if (res) - Py_DECREF(res); - else - throw std::runtime_error("Call to errorbar() failed."); + if (!res) throw std::runtime_error("Call to errorbar() failed."); + Py_DECREF(res); return res; } -*/ -/* + + template - bool named_plot(const std::string& name, E&& y, const std::string& format = "") - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + bool named_plot(const std::string& name, E&& y, const std::string& format = "") { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1020,7 +1044,8 @@ namespace detail { 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); @@ -1028,12 +1053,12 @@ namespace detail { return res; } -*/ + template - bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + bool named_plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1048,7 +1073,8 @@ namespace detail { 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); @@ -1056,11 +1082,12 @@ namespace detail { return res; } -/* + + template - bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& format = "") - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + bool named_semilogx(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1075,7 +1102,8 @@ namespace detail { 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); @@ -1083,12 +1111,12 @@ namespace detail { return res; } -*/ -/* + + template - bool named_semilogy(const std::string& name, E1&& x, E2&& y, const std::string& format = "") - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + bool named_semilogy(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1103,7 +1131,8 @@ namespace detail { 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); @@ -1111,12 +1140,12 @@ namespace detail { return res; } -*/ -/* + + template - bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& format = "") - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + bool named_loglog(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1131,7 +1160,8 @@ namespace detail { 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); @@ -1139,47 +1169,48 @@ namespace detail { return res; } -*/ + template - bool plot(E&& y, const std::string& format = "") - { + bool plot(E&& y, const std::string& format = "") { xt::xtensor x = xt::arange(y.size()); return plot(std::move(x), std::forward(y), format); } -/* + template - bool stem(E&& y, const std::string& format = "") - { + bool stem(E&& y, const std::string& format = "") { xt::xtensor x = xt::arange(y.size()); return stem(std::move(x), std::forward(y), format); } -*/ + template - void text(Numeric x, Numeric y, const std::string& s = "") - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + void text(Numeric x, Numeric y, const std::string& s = "") { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* args = PyTuple_New(3); PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); 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."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_text, args); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to text() failed."); Py_DECREF(res); } - inline long figure(long number = -1) - { + + inline long figure(long number = -1) { PyObject *res; - if (number == -1) - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); - else { + if (number == -1) { + 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 @@ -1187,11 +1218,12 @@ namespace detail { PyObject *args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyLong_FromLong(number)); - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args); + 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"); @@ -1203,26 +1235,28 @@ namespace detail { return figureNumber; } - inline bool fignum_exists(long number) - { + + inline bool fignum_exists(long number) { // Make sure interpreter is initialised detail::_interpreter::get(); 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); + Py_DECREF(args); + if (!res) throw std::runtime_error("Call to fignum_exists() failed."); bool ret = PyObject_IsTrue(res); Py_DECREF(res); - Py_DECREF(args); return ret; } - inline void figure_size(size_t w, size_t h) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline void figure_size(size_t w, size_t h) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); const size_t dpi = 100; PyObject* size = PyTuple_New(2); @@ -1233,27 +1267,30 @@ namespace detail { PyDict_SetItemString(kwargs, "figsize", size); PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_figure, 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() - { - 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."); + inline void legend() { + 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); } + template - void ylim(Numeric left, Numeric right) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + void ylim(Numeric left, Numeric right) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* list = PyList_New(2); PyList_SetItem(list, 0, PyFloat_FromDouble(left)); @@ -1262,17 +1299,19 @@ namespace detail { PyObject* args = PyTuple_New(1); 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."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_ylim, args); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to ylim() failed."); Py_DECREF(res); } + template - void xlim(Numeric left, Numeric right) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + void xlim(Numeric left, Numeric right) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* list = PyList_New(2); PyList_SetItem(list, 0, PyFloat_FromDouble(left)); @@ -1281,65 +1320,66 @@ namespace detail { PyObject* args = PyTuple_New(1); 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."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_xlim, args); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to xlim() failed."); Py_DECREF(res); } - inline double* xlim() - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + inline std::array xlim() { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_xlim, args); PyObject* left = PyTuple_GetItem(res,0); PyObject* right = PyTuple_GetItem(res,1); - double* arr = new double[2]; - arr[0] = PyFloat_AsDouble(left); - arr[1] = PyFloat_AsDouble(right); - - if(!res) throw std::runtime_error("Call to xlim() failed."); + std::array arr{PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; + if (!res) throw std::runtime_error("Call to xlim() failed."); Py_DECREF(res); + return arr; } - inline double* ylim() - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + inline std::array ylim() { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_ylim, args); PyObject* left = PyTuple_GetItem(res,0); PyObject* right = PyTuple_GetItem(res,1); - double* arr = new double[2]; - arr[0] = PyFloat_AsDouble(left); - arr[1] = PyFloat_AsDouble(right); - - if(!res) throw std::runtime_error("Call to ylim() failed."); + std::array arr{PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; + if (!res) throw std::runtime_error("Call to ylim() failed."); Py_DECREF(res); + return arr; } -/* + + template inline void xticks(E&& ticks, const std::vector &labels = {}, - const std::map& keywords = {}) - { + const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); // using numpy array PyObject* ticksarray = get_array(std::forward(ticks)); PyObject* args; - if(labels.size() == 0) { + if (labels.size() == 0) { // construct positional args args = PyTuple_New(1); PyTuple_SetItem(args, 0, ticksarray); @@ -1357,40 +1397,41 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + for(auto it = keywords.cbegin(); it != keywords.cend(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + 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(E&& ticks, const std::map& keywords) - { + inline void xticks(E&& ticks, const std::map& keywords) { xticks(std::forward(ticks), {}, keywords); } -*/ -/* + + template inline void yticks(E&& ticks, const std::vector &labels = {}, - const std::map& keywords = {}) - { + const std::map& keywords = {}) { assert(labels.size() == 0 || ticks.size() == labels.size()); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); // using numpy array PyObject* ticksarray = get_array(std::forward(ticks)); PyObject* args; - if(labels.size() == 0) { + if (labels.size() == 0) { // construct positional args args = PyTuple_New(1); PyTuple_SetItem(args, 0, ticksarray); @@ -1408,30 +1449,31 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + for(auto it = keywords.cbegin(); it != keywords.cend(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + 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(E&& ticks, const std::map& keywords) - { + inline void yticks(E&& ticks, const std::map& keywords) { yticks(std::forward(ticks), {}, keywords); } -*/ - inline void subplot(long nrows, long ncols, long plot_number) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + + inline void subplot(long nrows, long ncols, long plot_number) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); // construct positional args PyObject* args = PyTuple_New(3); @@ -1439,115 +1481,135 @@ namespace detail { 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); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to subplot() failed."); Py_DECREF(res); } - inline void title(const std::string &titlestr, const std::map &keywords = {}) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline void title(const std::string &titlestr, + const std::map &keywords = {}) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pytitlestr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + for (auto it = keywords.cbegin(); it != keywords.cend(); ++it) { + PyDict_SetItemString(kwargs, it->first.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); Py_DECREF(args); Py_DECREF(kwargs); + if (!res) throw std::runtime_error("Call to title() failed."); Py_DECREF(res); } - inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline void suptitle(const std::string &suptitlestr, + const std::map &keywords = {}) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pysuptitlestr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + for (auto it = keywords.cbegin(); it != keywords.cend(); ++it) { + PyDict_SetItemString(kwargs, it->first.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); Py_DECREF(args); Py_DECREF(kwargs); + if (!res) throw std::runtime_error("Call to suptitle() failed."); Py_DECREF(res); } - inline void axis(const std::string &axisstr) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline void axis(const std::string &axisstr) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* str = PyString_FromString(axisstr.c_str()); PyObject* args = PyTuple_New(1); 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."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_axis, args); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to title() failed."); Py_DECREF(res); } - inline void xlabel(const std::string &str, const std::map &keywords = {}) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline void xlabel(const std::string &str, + const std::map &keywords = {}) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + for (auto it = keywords.cbegin(); it != keywords.cend(); ++it) { + PyDict_SetItemString(kwargs, it->first.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); Py_DECREF(args); Py_DECREF(kwargs); + if (!res) throw std::runtime_error("Call to xlabel() failed."); Py_DECREF(res); } - inline void ylabel(const std::string &str, const std::map& keywords = {}) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline void ylabel(const std::string &str, + const std::map& keywords = {}) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + for (auto it = keywords.cbegin(); it != keywords.cend(); ++it) { + PyDict_SetItemString(kwargs, it->first.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); Py_DECREF(args); Py_DECREF(kwargs); + if (!res) throw std::runtime_error("Call to ylabel() failed."); Py_DECREF(res); } - inline void grid(bool flag) - { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + + inline void grid(bool flag) { + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* pyflag = flag ? Py_True : Py_False; Py_INCREF(pyflag); @@ -1555,132 +1617,132 @@ namespace detail { PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pyflag); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); - if(!res) throw std::runtime_error("Call to grid() failed."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_grid, args); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to grid() failed."); Py_DECREF(res); } - inline void show(const bool block = true) - { + + inline void show(const bool block = true) { PyObject* res; - if(block) - { + if (block) { res = PyObject_CallObject( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple); - } - else - { + } 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); + res = PyObject_Call( + detail::_interpreter::get().s_python_function_show, + detail::_interpreter::get().s_python_empty_tuple, kwargs); Py_DECREF(kwargs); } - if (!res) throw std::runtime_error("Call to show() failed."); - Py_DECREF(res); } - inline void close() - { + + inline void close() { PyObject* res = PyObject_CallObject( detail::_interpreter::get().s_python_function_close, detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to close() failed."); - Py_DECREF(res); } + inline void xkcd() { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* res; PyObject *kwargs = PyDict_New(); - res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, + res = PyObject_Call( + detail::_interpreter::get().s_python_function_xkcd, detail::_interpreter::get().s_python_empty_tuple, kwargs); Py_DECREF(kwargs); - - if (!res) - throw std::runtime_error("Call to show() failed."); - + if (!res) throw std::runtime_error("Call to show() failed."); Py_DECREF(res); } - inline void draw() - { + + inline void draw() { PyObject* res = PyObject_CallObject( detail::_interpreter::get().s_python_function_draw, detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to draw() failed."); - Py_DECREF(res); } + template - inline void pause(Numeric interval) - { + inline void pause(Numeric interval) { 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."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_pause, args); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to pause() failed."); Py_DECREF(res); } - inline void save(const std::string& filename) - { + + inline void save(const std::string& filename) { PyObject* pyfilename = PyString_FromString(filename.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pyfilename); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args); - if (!res) throw std::runtime_error("Call to save() failed."); + PyObject* res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_save, args); Py_DECREF(args); + if (!res) throw std::runtime_error("Call to save() failed."); Py_DECREF(res); } + inline void clf() { 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."); - Py_DECREF(res); } + inline void ion() { 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 = {}) { 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(auto it = keywords.cbegin(); it != keywords.cend(); ++it) { - 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( @@ -1700,11 +1762,13 @@ namespace detail { position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1)); out.push_back(position); } + Py_DECREF(res); return out; } + // Actually, is there any reason not to call this automatically for every plot? inline void tight_layout() { PyObject *res = PyObject_CallObject( @@ -1712,10 +1776,10 @@ namespace detail { detail::_interpreter::get().s_python_empty_tuple); if (!res) throw std::runtime_error("Call to tight_layout() failed."); - Py_DECREF(res); } + // Support for variadic plot() and initializer lists: namespace detail { @@ -1726,21 +1790,20 @@ namespace detail { struct is_callable_impl; template - struct is_callable_impl - { + struct is_callable_impl { typedef is_function type; }; // a non-object is callable iff it is a function template - struct is_callable_impl - { + struct is_callable_impl { struct Fallback { void operator()(); }; struct Derived : T, Fallback { }; template struct Check; + // 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 + static std::true_type test( ... ); template static std::false_type test( Check* ); @@ -1752,9 +1815,9 @@ namespace detail { }; // 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 + 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; }; @@ -1762,11 +1825,9 @@ namespace detail { struct plot_impl { }; template<> - struct plot_impl - { + struct plot_impl { template - bool operator()(IterableX&& x, IterableY&& y, const std::string& format) - { + bool operator()(IterableX&& x, IterableY&& y, const std::string& format) { // 2-phase lookup for distance, begin, end using std::distance; using std::begin; @@ -1776,13 +1837,13 @@ namespace detail { auto ys = distance(begin(y), end(y)); assert(xs == ys && "x and y data must have the same number of elements!"); - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); PyObject* xlist = PyList_New(xs); PyObject* ylist = PyList_New(ys); PyObject* pystring = PyString_FromString(format.c_str()); - //auto itx = begin(x), ity = begin(y); auto itx = x.begin(); auto ity = y.begin(); for(size_t i = 0; i < xs; ++i) { @@ -1795,22 +1856,22 @@ namespace detail { 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 - { + struct plot_impl { template - bool operator()(Iterable&& ticks, Callable&& f, const std::string& format) - { - if(begin(ticks) == end(ticks)) return true; + bool operator()(Iterable&& ticks, 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 @@ -1818,7 +1879,7 @@ namespace detail { std::array shape{size}; xt::xtensor y(shape); std::size_t idx = 0; - for(auto x : ticks) y[idx++] = f(x); + for (auto x : ticks) y[idx++] = f(x); return plot_impl()(std::forward(ticks), std::move(y), format); } }; @@ -1829,12 +1890,8 @@ namespace detail { template bool plot() { return true; } - template - void pprint(void) { std::cout << "\n" << __PRETTY_FUNCTION__ << "\n" << std::endl; } - template - bool plot(E1&& a, E2&& b, const std::string& format, Args... args) - { + bool plot(E1&& a, E2&& b, const std::string& format, Args... args) { return detail::plot_impl< std::integral_constant> >::value> >()(std::forward(a), std::forward(b), format) && plot(std::forward(args)...); - - //return detail::plot_impl>::type>()( - //std::forward(a), std::forward(b), format) && plot(std::forward(args)...); } // @@ -1862,28 +1916,27 @@ namespace detail { return plot(std::move(y_adapt), format); } -/* - inline bool plot(std::vector x, std::vector y, const std::map& keywords) { + + inline bool plot(std::vector x, std::vector y, + const std::map& keywords) { xt::xtensor x_adapt = xt::adapt(x); xt::xtensor y_adapt = xt::adapt(y); return plot(std::move(x_adapt), std::move(y_adapt), keywords); } -*/ + // // This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting // - class Plot - { + class Plot { public: // default initialization with plot label, some data and format template Plot(const std::string& name, E1&& x, E2&& y, const std::string& format = "") { - assert(x.size() == y.size()); PyObject* kwargs = PyDict_New(); - if(name != "") + if (name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); PyObject* xarray = get_array(std::forward(x)); @@ -1896,16 +1949,16 @@ namespace detail { 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) - { + if (res) { line= PyList_GetItem(res, 0); - if(line) + if (line) set_data_fct = PyObject_GetAttrString(line,"set_data"); else Py_DECREF(line); @@ -1921,8 +1974,7 @@ namespace detail { template bool update(E1&& x, E2&& y) { assert(x.size() == y.size()); - if(set_data_fct) - { + if (set_data_fct) { PyObject* xarray = get_array(std::forward(x)); PyObject* yarray = get_array(std::forward(y)); @@ -1944,8 +1996,7 @@ namespace detail { // definitely remove this line void remove() { - if(line) - { + if (line) { auto remove_fct = PyObject_GetAttrString(line,"remove"); PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(remove_fct, args); @@ -1960,13 +2011,12 @@ namespace detail { private: void decref() { - if(line) + if (line) Py_DECREF(line); - if(set_data_fct) + if (set_data_fct) Py_DECREF(set_data_fct); } - PyObject* line = nullptr; PyObject* set_data_fct = nullptr; }; From d336b70ee5c0934b999e42317eea2c5cb41973ba Mon Sep 17 00:00:00 2001 From: khanley6 Date: Fri, 3 May 2019 12:49:22 +0100 Subject: [PATCH 12/21] Updated readme and removed unnecessary code from the modern example --- README.md | 123 ++++++++++++++++++++++++-------------------- examples/modern.cpp | 5 -- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 338bea7..ffd0ec1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ +matplotlib-cpp-xt +================= + +This is a fork of ![matplotlib-cpp](https://github.com/lava/matplotlib-cpp) +that supports plotting ![xtensor](https://github.com/QuantStack/xtensor) objects + +The README below has been edited slightly to exhibit xtensor plotting capabilities. + + + matplotlib-cpp ============== @@ -17,34 +27,34 @@ int main() { plt::show(); } ``` - g++ minimal.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 - -**Result:** + g++ minimal.cpp -std=c++14 -I/usr/include/python3.6 -lpython3.6 -![Minimal example](./examples/minimal.png) A more comprehensive example: ```cpp #include "matplotlibcpp.h" #include +#include +#include + namespace plt = matplotlibcpp; int main() { // Prepare data. int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i i = xt::linspace(0, (n-1), n); + std::array shape{static_cast(n)}; + xt::xtensor w(shape); w.fill(2.0); + xt::xtensor x = xt::square(i); + xt::xtensor y = xt::sin(2 * xt::numeric_constants::PI * i / 360.0); + xt::xtensor z = xt::log(i); // Set the size of output image to 1200x780 pixels plt::figure_size(1200, 780); // Plot line from given x and y data. Color is selected automatically. - plt::plot(x, y); + plt::plot(x, y + 1.0); // rvalues are supported // Plot a red dashed line from given x and y data. plt::plot(x, w,"r--"); // Plot a line whose name will show up as "log(x)" in the legend. @@ -59,46 +69,39 @@ int main() plt::save("./basic.png"); } ``` - g++ basic.cpp -I/usr/include/python2.7 -lpython2.7 - -**Result:** + g++ basic.cpp -std=c++14 -I/usr/include/python3.6 -lpython3.6 -![Basic example](./examples/basic.png) Alternatively, matplotlib-cpp also supports some C++11-powered syntactic sugar: ```cpp #include #include "matplotlibcpp.h" -using namespace std; +#include +#include + namespace plt = matplotlibcpp; int main() { // Prepare data. int n = 5000; // number of data points - vector x(n),y(n); - for(int i=0; i i = xt::linspace(0, (n-1), n); + xt::xtensor t = 2 * xt::numeric_constants::PI * i / n; + xt::xtensor x = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); + xt::xtensor y = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); // plot() takes an arbitrary number of (x,y,format)-triples. // x must be iterable (that is, anything providing begin(x) and end(x)), // y must either be callable (providing operator() const) or iterable. plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); - // show plots plt::show(); } ``` - g++ modern.cpp -std=c++11 -I/usr/include/python2.7 -lpython - -**Result:** + g++ modern.cpp -std=c++14 -I/usr/include/python3.6 -lpython3.6 -![Modern example](./examples/modern.png) Or some *funny-looking xkcd-styled* example: ```cpp @@ -106,16 +109,14 @@ Or some *funny-looking xkcd-styled* example: #include #include +#include +#include + namespace plt = matplotlibcpp; int main() { - std::vector t(1000); - std::vector x(t.size()); - - for(size_t i = 0; i < t.size(); i++) { - t[i] = i / 100.0; - x[i] = sin(2.0 * M_PI * 1.0 * t[i]); - } + xt::xtensor t = xt::linspace(0, 10, 1000); + xt::xtensor x = xt::sin(2.0 * xt::numeric_constants::PI * t); plt::xkcd(); plt::plot(t, x); @@ -124,28 +125,31 @@ int main() { } ``` - g++ xkcd.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 + g++ xkcd.cpp -std=c++14 -I/usr/include/python3.6 -lpython3.6 -**Result:** - -![xkcd example](./examples/xkcd.png) When working with vector fields, you might be interested in quiver plots: ```cpp #include "../matplotlibcpp.h" +#include +#include + namespace plt = matplotlibcpp; int main() { // u and v are respectively the x and y components of the arrows we're plotting - std::vector x, y, u, v; + std::array shape{121}; + xt::xtensor x(shape), y(shape), u(shape), v(shape); + std::size_t idx = 0; 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); + x[idx] = (i) + u[idx] = (-i); + y[idx] = (j); + v[idx] = (-j); + ++idx; } } @@ -153,16 +157,17 @@ int main() plt::show(); } ``` - g++ quiver.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 - -**Result:** + g++ quiver.cpp -std=c++14 -I/usr/include/python3.6 -lpython3.6 -![quiver example](./examples/quiver.png) When working with 3d functions, you might be interested in 3d plots: ```cpp #include "../matplotlibcpp.h" +#include +#include +#include + namespace plt = matplotlibcpp; int main() @@ -180,14 +185,20 @@ int main() z.push_back(z_row); } - plt::plot_surface(x, y, z); + std::array shape{x.size(), x[0].size()}; + xt::xtensor xx(shape), xy(shape), xz(shape); + + for (std::size_t i = 0; i < x.size(); ++i) { + xt::view(xx, i, xt::all()) = xt::adapt(x[i]); + xt::view(xy, i, xt::all()) = xt::adapt(y[i]); + xt::view(xz, i, xt::all()) = xt::adapt(z[i]); + } + + plt::plot_surface(xx, xy, xz); plt::show(); } ``` -**Result:** - -![surface example](./examples/surface.png) Installation ------------ @@ -196,7 +207,7 @@ matplotlib-cpp works by wrapping the popular python plotting library matplotlib. This means you have to have a working python installation, including development headers. On Ubuntu: - sudo apt-get install python-matplotlib python-numpy python2.7-dev + sudo apt-get install python3-matplotlib python3-numpy python3-dev If, for some reason, you're unable to get a working installation of numpy on your system, you can add the define `WITHOUT_NUMPY` to erase this dependency. @@ -204,7 +215,7 @@ you can add the define `WITHOUT_NUMPY` to erase this dependency. The C++-part of the library consists of the single header file `matplotlibcpp.h` which can be placed anywhere. -Since a python interpreter is opened internally, it is necessary to link against `libpython2.7` in order to use +Since a python interpreter is opened internally, it is necessary to link against `libpython` in order to use matplotlib-cpp. # CMake @@ -217,7 +228,9 @@ target_include_directories(myproject PRIVATE ${PYTHON_INCLUDE_DIRS}) target_link_libraries(myproject ${PYTHON_LIBRARIES}) ``` -# C++11 +# C++14 + +c++14 is now required as `xtensor` uses c++14 features. Currently, c++11 is required to build matplotlib-cpp. The last working commit that did not have this requirement was `717e98e752260245407c5329846f5d62605eff08`. @@ -226,7 +239,7 @@ Note that support for c++98 was dropped more or less accidentally, so if you hav with an ancient compiler and still want to enjoy the latest additional features, I'd probably merge a PR that restores support. -# Python 3 +# Python 2 This library supports both python2 and python3 (although the python3 support is probably far less tested, so it is recommended to prefer python2.7). To switch the used python version, simply change diff --git a/examples/modern.cpp b/examples/modern.cpp index f932bb0..6b2519c 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -21,15 +21,10 @@ int main() xt::xtensor x = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); xt::xtensor y = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); - xt::xtensor x2 = 16*xt::sin(t)*xt::sin(t)*xt::sin(t); - xt::xtensor y2 = 13*xt::cos(t) - 5*xt::cos(2*t) - 2*xt::cos(3*t) - xt::cos(4*t); - - // plot() takes an arbitrary number of (x,y,format)-triples. // x must be iterable (that is, anything providing begin(x) and end(x)), // y must either be callable (providing operator() const) or iterable. plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); - //plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-", x, y+1.0, "r-."); // show plots From 2e9e5f4cee0b9287ad459fd5e0e124661acfb388 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Tue, 7 May 2019 12:31:02 +0100 Subject: [PATCH 13/21] Added support for xfunctions --- examples/types.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++++ matplotlibcpp.h | 18 +++++++++++--- 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 examples/types.cpp diff --git a/examples/types.cpp b/examples/types.cpp new file mode 100644 index 0000000..04e8c59 --- /dev/null +++ b/examples/types.cpp @@ -0,0 +1,59 @@ +#define _USE_MATH_DEFINES +#include +#include +#include "../matplotlibcpp.h" + +#include + +#include +#include + +namespace plt = matplotlibcpp; + +std::vector get_yv(std::size_t len) { + std::vector res(len); + for (std::size_t i = 0; i < len; ++i) { + res[i] = i*i + 2; + } + return res; +} + +template +auto get_fy(E&& e) { + auto res = e + 2.0; + return std::move(res); +} + +int main(int argc, char **argv) { + std::size_t len = 10; + + /***** vectors *****/ + std::vector xv(len), yv(len); + for (std::size_t i = 0; i < len; ++i) { + xv[i] = i; + yv[i] = i*i; + } + + plt::named_plot("vector - lvalue", xv, yv); + plt::named_plot("vector - rvalue", xv, get_yv(len)); + + /***** xtensors *****/ + xt::xtensor xx = xt::linspace(0, len-1, len); + xt::xtensor xy = xt::square(xx) + 4; + + plt::named_plot("xtensor - lvalue", xx, xy, "--"); + plt::named_plot("xtensor - rvalue", xx, xy+1, "--"); + + /***** xfunction*****/ + auto fx = xt::linspace(0, len-1, len); + auto fy = xt::square(xx) + 6; + + plt::named_plot("xfunction - lvalue", fx, fy, "-."); + plt::named_plot("xfunction - rvalue", fx, get_fy(fy), "--"); + + plt::legend(); + plt::show(); + + return 0; +} + diff --git a/matplotlibcpp.h b/matplotlibcpp.h index a9ae62e..99efefe 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -328,10 +328,20 @@ namespace detail { template <> struct select_npy_type { const static NPY_TYPES type = NPY_ULONG; }; template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; +namespace detail { + template class> + struct is_instance : public std::false_type {}; + + template class U> + struct is_instance, U> : public std::true_type {}; + + template + using is_xfunction = is_instance; +} // namespace detail // xtensor implementation template - PyObject* get_array(const E& v) { + std::enable_if_t::value && !detail::is_xfunction::value, PyObject*> get_array(const E& v) { assert(v.dimension() <= 2); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work @@ -397,11 +407,13 @@ namespace detail { // if WITHOUT_NUMPY is defined, this function accepts all calls to get_array template #ifndef WITHOUT_NUMPY - typename std::enable_if_t::value, PyObject*> + typename std::enable_if_t>::value + || (!std::is_lvalue_reference::value && xt::is_xexpression::value) + , PyObject*> #else typename std::enable_if_t::value, PyObject*> #endif // WITHOUT_NUMPY - get_array (E&& v) { + get_array(E&& v) { PyObject* list; if (v.dimension() == 1) { list = PyList_New(v.size()); From 91c1d62a8bee893205e8e3c3bf8b33932359b8f5 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Tue, 7 May 2019 14:26:28 +0100 Subject: [PATCH 14/21] Tidied up get_array implementation a lot thanks to @JohanMabille --- matplotlibcpp.h | 162 +++++++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 70 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 99efefe..a6babdb 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -327,50 +327,99 @@ namespace detail { 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; }; +#endif -namespace detail { - template class> - struct is_instance : public std::false_type {}; - - template class U> - struct is_instance, U> : public std::true_type {}; +#ifdef WITHOUT_NUMPY + // vector implementation + template + PyObject* get_array_impl(const std::vector& v) { + PyObject* list = PyList_New(v.size()); + for(size_t i = 0; i < v.size(); ++i) { + PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); + } + return list; + } + // lvalue xexpression implementation template - using is_xfunction = is_instance; -} // namespace detail + PyObject* get_array_impl(const xt::xexpression& e) { + const E& de = e.derived_cast(); + // Implementation for evaluated lvalue using de - // xtensor implementation - template - std::enable_if_t::value && !detail::is_xfunction::value, PyObject*> get_array(const E& v) { - assert(v.dimension() <= 2); + PyObject* list; + if (de.dimension() == 1) { + list = PyList_New(de.size()); + for(size_t i = 0; i < de.size(); ++i) { + PyList_SetItem(list, i, PyFloat_FromDouble(de.at(i))); + } + } else { + std::size_t num_rows = de.shape()[0]; + std::size_t num_cols = de.shape()[1]; + list = PyList_New(num_rows); + for(size_t i = 0; i < num_rows; ++i) { + PyObject* row = PyList_New(num_cols); + PyList_SetItem(list, i, row); + for(size_t j = 0; j < num_cols; ++j) { + PyList_SetItem(row, j, PyFloat_FromDouble(de.at(i,j))); + } + } + } + return list; + } + +#else // With numpy + // vector implementation + template + PyObject* get_array_impl(const std::vector& v) { + detail::_interpreter::get(); + NPY_TYPES type = select_npy_type::type; + if (type == NPY_NOTYPE) { + std::vector vd(v.size()); + npy_intp vsize = v.size(); + std::copy(v.begin(), v.end(), vd.begin()); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); + return varray; + } + + npy_intp vsize = v.size(); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); + return varray; + } + + // lvalue xexpression implementation + template + PyObject* get_array_impl(const xt::xexpression& e) { + const E& de = e.derived_cast(); + // Implementation for evaluated lvalue using de + assert(de.dimension() <= 2); detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - if (v.dimension() == 1) { + if (de.dimension() == 1) { NPY_TYPES type = select_npy_type::value_type>::type; if (type == NPY_NOTYPE) { - std::vector vd(v.size()); - npy_intp vsize = v.size(); - std::copy(v.begin(), v.end(), vd.begin()); + std::vector vd(de.size()); + npy_intp vsize = de.size(); + std::copy(de.begin(), de.end(), vd.begin()); PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); return varray; } - npy_intp vsize = v.size(); - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); + npy_intp vsize = de.size(); + PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(de.data())); return varray; } else { - if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); + if (de.size() < 1) throw std::runtime_error("get_2d_array v too small"); - npy_intp vsize[2] = {static_cast(v.shape()[0]), - static_cast(v.shape()[1])}; + npy_intp vsize[2] = {static_cast(de.shape()[0]), + static_cast(de.shape()[1])}; PyArrayObject *varray = (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); double *vd_begin = static_cast(PyArray_DATA(varray)); - for (const std::size_t v_row_num : xt::arange(v.shape()[0])) { - auto v_row = xt::view(v, v_row_num); + for (const std::size_t v_row_num : xt::arange(de.shape()[0])) { + auto v_row = xt::view(de, v_row_num); 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); @@ -381,72 +430,45 @@ namespace detail { } } - - // vector implementation - template - PyObject* get_array(const std::vector& v) { - detail::_interpreter::get(); - NPY_TYPES type = select_npy_type::type; - if (type == NPY_NOTYPE) { - std::vector vd(v.size()); - npy_intp vsize = v.size(); - std::copy(v.begin(), v.end(), vd.begin()); - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); - return varray; - } - - npy_intp vsize = v.size(); - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); - return varray; - } #endif // WITHOUT_NUMPY + // rvalue xexpression implementation + template + PyObject* get_array_impl(xt::xexpression&& e) { + E de = e.derived_cast(); - // xtensor rvalue implementation - // if WITHOUT_NUMPY is not defined, this function is taked with copying rvalues - // if WITHOUT_NUMPY is defined, this function accepts all calls to get_array - template -#ifndef WITHOUT_NUMPY - typename std::enable_if_t>::value - || (!std::is_lvalue_reference::value && xt::is_xexpression::value) - , PyObject*> -#else - typename std::enable_if_t::value, PyObject*> -#endif // WITHOUT_NUMPY - get_array(E&& v) { PyObject* list; - if (v.dimension() == 1) { - list = PyList_New(v.size()); - for(size_t i = 0; i < v.size(); ++i) { - PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); + if (de.dimension() == 1) { + list = PyList_New(de.size()); + for(size_t i = 0; i < de.size(); ++i) { + PyList_SetItem(list, i, PyFloat_FromDouble(de.at(i))); } } else { - std::size_t num_rows = v.shape()[0]; - std::size_t num_cols = v.shape()[1]; + std::size_t num_rows = de.shape()[0]; + std::size_t num_cols = de.shape()[1]; list = PyList_New(num_rows); for(size_t i = 0; i < num_rows; ++i) { PyObject* row = PyList_New(num_cols); PyList_SetItem(list, i, row); for(size_t j = 0; j < num_cols; ++j) { - PyList_SetItem(row, j, PyFloat_FromDouble(v.at(i,j))); + PyList_SetItem(row, j, PyFloat_FromDouble(de.at(i,j))); } } } return list; } + // xtensor objects + template )> + PyObject* get_array(E&& e) { + return get_array_impl(xt::eval(std::forward(e))); + } -#ifdef WITHOUT_NUMPY - // vector implementation - template - PyObject* get_array(const std::vector& v) { - PyObject* list = PyList_New(v.size()); - for(size_t i = 0; i < v.size(); ++i) { - PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); - } - return list; + // vectors + template >)> + PyObject* get_array(E&& e) { + return get_array_impl(std::forward(e)); } -#endif template From afdf2be66de83d08076546dac2317603e8b7b0b8 Mon Sep 17 00:00:00 2001 From: Kenneth Hanley Date: Tue, 7 May 2019 15:08:39 +0100 Subject: [PATCH 15/21] Updated CMake config to properly search for numpy and exclude surface.cpp if numpy is not found --- CMakeLists.txt | 11 +++++++++++ examples/CMakeLists.txt | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09b6f75..c17f71d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,17 @@ project(matplotlibcpp_xt VERSION 0.1.0 LANGUAGES CXX) find_package(PythonLibs REQUIRED) find_package(xtensor REQUIRED) +OPTION(USE_NUMPY "Use numpy" ON) + +if (USE_NUMPY) + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + find_package(Numpy REQUIRED) + message(STATUS "Found numpy: ${NUMPY_INCLUDE_DIRS}") +else() + add_compile_definitions(WITHOUT_NUMPY) +endif() + + ## ## TARGET ## create target and add include path diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index adea40b..9dd312b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,10 @@ file(GLOB files "*.cpp") +if (NOT USE_NUMPY) + message(STATUS "Can't build surface.cpp without numpy. Skipping...") + get_filename_component(surface_path ${CMAKE_CURRENT_SOURCE_DIR}/surface.cpp ABSOLUTE) + list(REMOVE_ITEM files "${surface_path}") +endif() + foreach(file ${files}) get_filename_component(file_basename ${file} NAME_WE) @@ -8,6 +14,12 @@ foreach(file ${files}) ${xtensor_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ) + if(NUMPY_FOUND) + target_include_directories(${file_basename} PRIVATE + ${NUMPY_INCLUDE_DIRS} + ) + endif() + target_link_libraries(${file_basename} ${PYTHON_LIBRARIES} ) From e9099cf67317753f11531d44201e3aacb43ce6cf Mon Sep 17 00:00:00 2001 From: Kenneth Hanley Date: Tue, 7 May 2019 16:04:56 +0100 Subject: [PATCH 16/21] Restructured project a bit, adding further cmake support and fixing the examples include directory --- CMakeLists.txt | 53 +++++++++++++++++++++- examples/CMakeLists.txt | 2 +- examples/animation.cpp | 2 +- examples/bar.cpp | 2 +- examples/basic.cpp | 2 +- examples/fill.cpp | 2 +- examples/fill_inbetween.cpp | 2 +- examples/minimal.cpp | 2 +- examples/modern.cpp | 2 +- examples/nonblock.cpp | 2 +- examples/quiver.cpp | 2 +- examples/subplot.cpp | 2 +- examples/surface.cpp | 2 +- examples/types.cpp | 2 +- examples/update.cpp | 2 +- examples/xkcd.cpp | 2 +- matplotlibcpp.h => include/matplotlibcpp.h | 0 matplotlibcppConfig.cmake.in | 14 ++++++ 18 files changed, 80 insertions(+), 17 deletions(-) rename matplotlibcpp.h => include/matplotlibcpp.h (100%) create mode 100644 matplotlibcppConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index c17f71d..76a77c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,13 @@ cmake_minimum_required(VERSION 3.7) ## PROJECT ## name and version ## -project(matplotlibcpp_xt VERSION 0.1.0 LANGUAGES CXX) +project(matplotlibcpp VERSION 0.1.0 LANGUAGES CXX) find_package(PythonLibs REQUIRED) find_package(xtensor REQUIRED) OPTION(USE_NUMPY "Use numpy" ON) +OPTION(BUILD_EXAMPLES "Build examples" OFF) if (USE_NUMPY) set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") @@ -24,6 +25,54 @@ endif() ## TARGET ## create target and add include path ## +set(MPLCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) + add_library(matplotlibcpp INTERFACE) +target_include_directories(matplotlibcpp INTERFACE $ + $) + +if (BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + + + +# Installation +# ============ + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +install(TARGETS matplotlibcpp + EXPORT ${PROJECT_NAME}-targets) + +# Makes the project importable from the build directory +export(EXPORT ${PROJECT_NAME}-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") + + #install(DIRECTORY ${MPLCPP_INCLUDE_DIR} + install(FILES ${MPLCPP_INCLUDE_DIR}/matplotlibcpp.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". +set(MPLCPP_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for matplotlibcppConfig.cmake") + +configure_package_config_file(${PROJECT_NAME}Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION ${MPLCPP_CMAKECONFIG_INSTALL_DIR}) -add_subdirectory(examples) +# matplotlibcpp is header-only and does not depend on the architecture. +# Remove CMAKE_SIZEOF_VOID_P from matplotlibcppConfigVersion.cmake so that +# an matplotlibcppConfig.cmake generated for a 64 bit target can be used for +# 32 bit targets and vice versa. +set(_MPLCPP_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) +unset(CMAKE_SIZEOF_VOID_P) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY SameMajorVersion) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${MPLCPP_CMAKECONFIG_INSTALL_DIR}) +install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}Targets.cmake + DESTINATION ${MPLCPP_CMAKECONFIG_INSTALL_DIR}) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9dd312b..c02bf74 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,7 +12,7 @@ foreach(file ${files}) target_include_directories(${file_basename} PRIVATE ${PYTHON_INCLUDE_DIRS} ${xtensor_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR} + ${MPLCPP_INCLUDE_DIR} ) if(NUMPY_FOUND) target_include_directories(${file_basename} PRIVATE diff --git a/examples/animation.cpp b/examples/animation.cpp index f4406b3..554cdfe 100644 --- a/examples/animation.cpp +++ b/examples/animation.cpp @@ -1,6 +1,6 @@ #define _USE_MATH_DEFINES #include -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/bar.cpp b/examples/bar.cpp index 0e1843c..35bb5f1 100644 --- a/examples/bar.cpp +++ b/examples/bar.cpp @@ -2,7 +2,7 @@ #include #include -#include "../matplotlibcpp.h" +#include namespace plt = matplotlibcpp; #include diff --git a/examples/basic.cpp b/examples/basic.cpp index 505b6af..5c3e6aa 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -1,7 +1,7 @@ #define _USE_MATH_DEFINES #include #include -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/fill.cpp b/examples/fill.cpp index dc63102..31774a6 100644 --- a/examples/fill.cpp +++ b/examples/fill.cpp @@ -1,5 +1,5 @@ #define _USE_MATH_DEFINES -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/fill_inbetween.cpp b/examples/fill_inbetween.cpp index 54df70f..39de0c0 100644 --- a/examples/fill_inbetween.cpp +++ b/examples/fill_inbetween.cpp @@ -1,5 +1,5 @@ #define _USE_MATH_DEFINES -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/minimal.cpp b/examples/minimal.cpp index e16cc60..2e80b9e 100644 --- a/examples/minimal.cpp +++ b/examples/minimal.cpp @@ -1,4 +1,4 @@ -#include "../matplotlibcpp.h" +#include namespace plt = matplotlibcpp; diff --git a/examples/modern.cpp b/examples/modern.cpp index 6b2519c..e55f836 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -1,6 +1,6 @@ #define _USE_MATH_DEFINES #include -#include "../matplotlibcpp.h" +#include using namespace std; namespace plt = matplotlibcpp; diff --git a/examples/nonblock.cpp b/examples/nonblock.cpp index 1e38aba..ab6a72d 100644 --- a/examples/nonblock.cpp +++ b/examples/nonblock.cpp @@ -1,7 +1,7 @@ #define _USE_MATH_DEFINES #include #include -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/quiver.cpp b/examples/quiver.cpp index 1a98ca7..c55d561 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -1,4 +1,4 @@ -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/subplot.cpp b/examples/subplot.cpp index 6c34512..f39b3e6 100644 --- a/examples/subplot.cpp +++ b/examples/subplot.cpp @@ -1,6 +1,6 @@ #define _USE_MATH_DEFINES #include -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/surface.cpp b/examples/surface.cpp index 1e52c03..20170f9 100644 --- a/examples/surface.cpp +++ b/examples/surface.cpp @@ -1,7 +1,7 @@ #define _USE_MATH_DEFINES #include #include -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/types.cpp b/examples/types.cpp index 04e8c59..2a01b46 100644 --- a/examples/types.cpp +++ b/examples/types.cpp @@ -1,7 +1,7 @@ #define _USE_MATH_DEFINES #include #include -#include "../matplotlibcpp.h" +#include #include diff --git a/examples/update.cpp b/examples/update.cpp index 0ea632e..bd9767e 100644 --- a/examples/update.cpp +++ b/examples/update.cpp @@ -1,6 +1,6 @@ #define _USE_MATH_DEFINES #include -#include "../matplotlibcpp.h" +#include #include #include diff --git a/examples/xkcd.cpp b/examples/xkcd.cpp index c782e6d..478e6e2 100644 --- a/examples/xkcd.cpp +++ b/examples/xkcd.cpp @@ -1,6 +1,6 @@ #define _USE_MATH_DEFINES #include -#include "../matplotlibcpp.h" +#include #include namespace plt = matplotlibcpp; diff --git a/matplotlibcpp.h b/include/matplotlibcpp.h similarity index 100% rename from matplotlibcpp.h rename to include/matplotlibcpp.h diff --git a/matplotlibcppConfig.cmake.in b/matplotlibcppConfig.cmake.in new file mode 100644 index 0000000..798b784 --- /dev/null +++ b/matplotlibcppConfig.cmake.in @@ -0,0 +1,14 @@ +# matplotlibcpp cmake module +# This module sets the following variables in your project:: +# +# matplotlibcpp_FOUND - true if matplotlibcpp found on the system +# matplotlibcpp_INCLUDE_DIRS - the directory containing matplotlibcpp header +# matplotlibcpp_LIBRARY - empty + +@PACKAGE_INIT@ + +if(NOT TARGET @PROJECT_NAME@) + include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") + get_target_property(@PROJECT_NAME@_INCLUDE_DIRS matplotlibcpp INTERFACE_INCLUDE_DIRECTORIES) +endif() + From e3bff86398627b223622eeac13258e45970f0ad2 Mon Sep 17 00:00:00 2001 From: Kenneth Hanley Date: Tue, 7 May 2019 16:53:47 +0100 Subject: [PATCH 17/21] More cmake improvements. The installed library now includes the location of its includes and libraries so now includes the path to Python.h (and optionally numpy) and includes the python library --- CMakeLists.txt | 17 +++++++++++++++-- matplotlibcppConfig.cmake.in | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76a77c9..eda0146 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,8 +28,21 @@ endif() set(MPLCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) add_library(matplotlibcpp INTERFACE) -target_include_directories(matplotlibcpp INTERFACE $ - $) +target_include_directories(matplotlibcpp INTERFACE + $ + $ + $ + $ + $ + $ + ) +if (USE_NUMPY) +target_include_directories(matplotlibcpp INTERFACE + $ + $ + ) +endif() +target_link_libraries(matplotlibcpp INTERFACE "${PYTHON_LIBRARIES}") if (BUILD_EXAMPLES) add_subdirectory(examples) diff --git a/matplotlibcppConfig.cmake.in b/matplotlibcppConfig.cmake.in index 798b784..7b84c88 100644 --- a/matplotlibcppConfig.cmake.in +++ b/matplotlibcppConfig.cmake.in @@ -10,5 +10,6 @@ if(NOT TARGET @PROJECT_NAME@) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") get_target_property(@PROJECT_NAME@_INCLUDE_DIRS matplotlibcpp INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(@PROJECT_NAME@_LIBRARY matplotlibcpp INTERFACE_LINK_LIBRARIES) endif() From 37d4470110a559c6dfbbcacf539ec8c7af3aa418 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Tue, 9 Jul 2019 11:52:37 +0100 Subject: [PATCH 18/21] Really crude implementation of imshow - will work on later --- matplotlibcpp.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index a6babdb..c5e9f4d 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -34,6 +34,7 @@ namespace detail { static std::string s_backend; struct _interpreter { + PyObject *s_python_function_imshow; PyObject *s_python_function_show; PyObject *s_python_function_close; PyObject *s_python_function_draw; @@ -155,6 +156,7 @@ namespace detail { Py_DECREF(pylabname); if (!pylabmod) { throw std::runtime_error("Error loading module pylab!"); } + s_python_function_imshow = PyObject_GetAttrString(pymod, "imshow"); s_python_function_show = PyObject_GetAttrString(pymod, "show"); s_python_function_close = PyObject_GetAttrString(pymod, "close"); s_python_function_draw = PyObject_GetAttrString(pymod, "draw"); @@ -196,6 +198,7 @@ namespace detail { s_python_function_subplots_adjust = PyObject_GetAttrString(pymod,"subplots_adjust"); if ( !s_python_function_show + || !s_python_function_imshow || !s_python_function_close || !s_python_function_draw || !s_python_function_pause @@ -234,6 +237,7 @@ namespace detail { ) { throw std::runtime_error("Couldn't find required function!"); } if ( !PyFunction_Check(s_python_function_show) + || !PyFunction_Check(s_python_function_imshow) || !PyFunction_Check(s_python_function_close) || !PyFunction_Check(s_python_function_draw) || !PyFunction_Check(s_python_function_pause) @@ -505,6 +509,40 @@ namespace detail { return res; } + template + bool imshow(E&& im) { + assert(im.dimension() == 2); + + //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); + + // using numpy arrays + PyObject* imarray = get_array(std::forward(im)); + + // construct positional args + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, imarray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + /* + for(auto it = keywords.cbegin(); it != keywords.cend(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } + */ + + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_imshow, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); + + return res; + } + #ifndef WITHOUT_NUMPY template From 32356a302a47d9162f49e1b7c089d5bc92cf7237 Mon Sep 17 00:00:00 2001 From: khanley6 Date: Mon, 15 Jul 2019 18:34:45 +0100 Subject: [PATCH 19/21] Changed cmake filed to allow other projects to build in CI --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eda0146..89b6f63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.7) project(matplotlibcpp VERSION 0.1.0 LANGUAGES CXX) find_package(PythonLibs REQUIRED) -find_package(xtensor REQUIRED) +find_package(xtensor) OPTION(USE_NUMPY "Use numpy" ON) OPTION(BUILD_EXAMPLES "Build examples" OFF) From e6c928dbba761539187730ca3eaba46ed348c72d Mon Sep 17 00:00:00 2001 From: khanley6 Date: Mon, 15 Jul 2019 18:45:49 +0100 Subject: [PATCH 20/21] Changed CMakeLists again... --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89b6f63..dffd9c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.7) project(matplotlibcpp VERSION 0.1.0 LANGUAGES CXX) find_package(PythonLibs REQUIRED) -find_package(xtensor) +#find_package(xtensor) OPTION(USE_NUMPY "Use numpy" ON) OPTION(BUILD_EXAMPLES "Build examples" OFF) From d50b086cf59266689218aec5449d9620f65f73dd Mon Sep 17 00:00:00 2001 From: Kenneth Hanley Date: Sat, 27 Jul 2019 17:24:06 +0100 Subject: [PATCH 21/21] Added imshow keywords --- include/matplotlibcpp.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/matplotlibcpp.h b/include/matplotlibcpp.h index c5e9f4d..7ecfd50 100644 --- a/include/matplotlibcpp.h +++ b/include/matplotlibcpp.h @@ -510,7 +510,8 @@ namespace detail { } template - bool imshow(E&& im) { + bool imshow(E&& im, const std::map &keywords = + std::map()) { assert(im.dimension() == 2); //interpreter needs to be initialized for the numpy commands to work @@ -525,13 +526,11 @@ namespace detail { // construct keyword args PyObject* kwargs = PyDict_New(); - /* for(auto it = keywords.cbegin(); it != keywords.cend(); ++it) { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } - */ PyObject* res = PyObject_Call( detail::_interpreter::get().s_python_function_imshow, args, kwargs);