diff --git a/.clang-format b/.clang-format index 028caeb..8968ebb 100644 --- a/.clang-format +++ b/.clang-format @@ -4,3 +4,4 @@ NamespaceIndentation: None Language: Cpp Standard: Auto ColumnLimit: 80 +SortIncludes: false diff --git a/CMakeLists.txt b/CMakeLists.txt index de92d31..767a737 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,4 @@ +project(matplotlib-cpp11) cmake_minimum_required(VERSION 3.0) find_package(PythonLibs 3 REQUIRED) @@ -16,7 +17,9 @@ endfunction() if(${ADD_DEMO}) set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_FLAGS "-Wall -g") add_demo(simple_plot gallery/lines_bars_and_markers/simple_plot.cpp) + add_demo(align_labels_demo gallery/subplots_axes_and_figures/align_labels_demo.cpp) endif() if(NOT DEFINED DO_TEST) diff --git a/README.md b/README.md index bc7b0a6..3b23311 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,11 @@ This project aims to replace [matplotlibcpp](https://github.com/lava/matplotlib- ## Usage Just add include path to `include` directory of this project. + +## Demos + +`gallery` folder contains corresponding examples from [the official website of matplotlib](https://matplotlib.org/stable/gallery) with the same structure. + +## Contributing + +Contributions to this project are welcome if you could add or want/need more modules :) diff --git a/gallery/lines_bars_and_markers/simple_plot.cpp b/gallery/lines_bars_and_markers/simple_plot.cpp index 6d0e6c2..9be440c 100644 --- a/gallery/lines_bars_and_markers/simple_plot.cpp +++ b/gallery/lines_bars_and_markers/simple_plot.cpp @@ -16,8 +16,9 @@ template std::vector arange(T start, T end, T h) { int N = static_cast((end - start) / h); std::vector xs(N); T val = start; - while (val <= end) { - xs.push_back(val); + for (int i = 0; i < N; ++i) { + xs[i] = val; + ; val += h; } return xs; @@ -26,7 +27,7 @@ template std::vector arange(T start, T end, T h) { using namespace std; int main() { - py::scoped_interpreter guard{}; + py::initialize_interpreter(); auto plt = matplotlib_cpp11::import(); auto t = arange(0.0, 2.0, 0.01); decltype(t) s; diff --git a/gallery/subplots_axes_and_figures/align_labels_demo.cpp b/gallery/subplots_axes_and_figures/align_labels_demo.cpp index 2123f02..73c725b 100644 --- a/gallery/subplots_axes_and_figures/align_labels_demo.cpp +++ b/gallery/subplots_axes_and_figures/align_labels_demo.cpp @@ -1,2 +1,56 @@ // example from // https://matplotlib.org/stable/gallery/subplots_axes_and_figures/align_labels_demo.html#sphx-glr-gallery-subplots-axes-and-figures-align-labels-demo-py + +#include +#include + +#include + +#include +#include +#include + +namespace py = pybind11; +using namespace py::literals; + +template std::vector arange(T start, T end, T h) { + int N = static_cast((end - start) / h); + std::vector xs(N); + T val = start; + for (int i = 0; i < N; ++i) { + xs[i] = val; + ; + val += h; + } + return xs; +} + +using namespace std; +namespace pyplot = matplotlib_cpp11; + +int main() { + py::initialize_interpreter(); + auto plt = pyplot::import(); + auto fig = pyplot::Figure(plt.figure("tight_layout"_a = true)); + auto gs = pyplot::GridSpec(2, 2); + auto ax = pyplot::Axes(fig.add_subplot(gs(0, -1))); + ax.plot(arange(0, 1000000, 10000)); + ax.set_ylabel("YLabel0"); + ax.set_xlabel("XLabel0"); + for (auto i : {0, 1}) { + ax = pyplot::Axes(fig.add_subplot(gs(1, i))); + auto ys = arange(1.0, 0.0, -0.1); + decltype(ys) xs; + std::for_each(ys.begin(), ys.end(), + [&](auto val) { xs.push_back(val * 2000); }); + ax.plot(xs, ys); + ax.set_ylabel(string("YLabel1 " + to_string(i))); + ax.set_xlabel(string("XLabel1 " + to_string(i))); + if (i == 0) { + for (auto &&tick : ax.get_xticklabels()) + tick.set_rotation(55); + } + } + fig.align_labels(); + plt.show(); +} diff --git a/include/matplotlib_cpp11/axes.h b/include/matplotlib_cpp11/axes.h index 6187c55..eb77218 100644 --- a/include/matplotlib_cpp11/axes.h +++ b/include/matplotlib_cpp11/axes.h @@ -1,20 +1,31 @@ +#include + struct __attribute__((visibility("hidden"))) Axes { - Axes() {} Axes(pybind11::object axes) { self = axes; load_attrs(); } - Axes(pybind11::module mod) { - self = mod.attr("axes"); - load_attrs(); - } void load_attrs() { LOAD_ATTR(plot, self); LOAD_ATTR(set, self); LOAD_ATTR(grid, self); + LOAD_ATTR(set_xlabel, self); + LOAD_ATTR(set_ylabel, self); + get_xticklabels_attr = self.attr("get_xticklabels"); } pybind11::object self; pybind11::object plot; pybind11::object set; pybind11::object grid; + pybind11::object set_xlabel; + pybind11::object set_ylabel; + pybind11::object get_xticklabels_attr; + std::vector get_xticklabels() { + pybind11::list ret = get_xticklabels_attr(); + std::vector texts; + for (pybind11::size_t i = 0; i < ret.size(); ++i) { + texts.push_back(Text(ret[i])); + } + return texts; + } }; diff --git a/include/matplotlib_cpp11/common.h b/include/matplotlib_cpp11/common.h new file mode 100644 index 0000000..44613ee --- /dev/null +++ b/include/matplotlib_cpp11/common.h @@ -0,0 +1,4 @@ +#define LOAD_ATTR(attr_, mod_) \ + do { \ + attr_ = mod_.attr(#attr_); \ + } while (0) diff --git a/include/matplotlib_cpp11/figure.h b/include/matplotlib_cpp11/figure.h index 67251ae..7096d7f 100644 --- a/include/matplotlib_cpp11/figure.h +++ b/include/matplotlib_cpp11/figure.h @@ -1,15 +1,15 @@ struct __attribute__((visibility("hidden"))) Figure { - Figure() {} Figure(pybind11::object figure) { self = figure; load_attrs(); } - Figure(pybind11::module mod) { - self = mod.attr("figure"); - load_attrs(); + void load_attrs() { + LOAD_ATTR(savefig, self); + LOAD_ATTR(add_subplot, self); + LOAD_ATTR(align_labels, self); } - void load_attrs() { LOAD_ATTR(savefig, self); } pybind11::object self; pybind11::object savefig; pybind11::object add_subplot; + pybind11::object align_labels; }; diff --git a/include/matplotlib_cpp11/gridspec.h b/include/matplotlib_cpp11/gridspec.h new file mode 100644 index 0000000..b882741 --- /dev/null +++ b/include/matplotlib_cpp11/gridspec.h @@ -0,0 +1,29 @@ +struct __attribute__((visibility("hidden"))) GridSpec { + GridSpec(int nrow_, int ncol_) { + nrow = nrow_; + ncol = ncol_; + load_attrs(); + } + void load_attrs() { + gridspec_attr = + pybind11::module::import("matplotlib.gridspec").attr("GridSpec"); + self = gridspec_attr(nrow, ncol); + } + pybind11::object operator()(int r, int c) { + // if r == -1 or c == -1, do slice + if (r == -1) { + if (c == -1) { + return self; + } + auto rs = pybind11::slice(0, nrow, 1); + return self[pybind11::make_tuple(rs, c)]; + } else if (c == -1) { + auto cs = pybind11::slice(0, ncol, 1); + return self[pybind11::make_tuple(r, cs)]; + } else + return self[pybind11::make_tuple(r, c)]; + } + int nrow, ncol; + pybind11::object self; + pybind11::object gridspec_attr; +}; diff --git a/include/matplotlib_cpp11/matplotlib_cpp11.h b/include/matplotlib_cpp11/matplotlib_cpp11.h index 3663790..21c9743 100644 --- a/include/matplotlib_cpp11/matplotlib_cpp11.h +++ b/include/matplotlib_cpp11/matplotlib_cpp11.h @@ -5,30 +5,14 @@ namespace matplotlib_cpp11 { -static bool g_imported = false; - -#define LOAD_ATTR(attr_, mod_) \ - do { \ - attr_ = mod_.attr(#attr_); \ - } while (0) +#include "common.h" +#include "text.h" #include "axes.h" #include "figure.h" +#include "gridspec.h" #include "pyplot.h" -static pyplot &import() { - static pyplot g_pyplot; - static Figure g_figure; - static Axes g_axes; - if (not g_imported) { - g_imported = true; - // pyplot singleton - auto mod = pybind11::module::import("matplotlib.pyplot"); - g_pyplot = pyplot(mod); - } - return g_pyplot; -} - } // namespace matplotlib_cpp11 #endif /* MATPLOTLIBCPP_11_H */ diff --git a/include/matplotlib_cpp11/pyplot.h b/include/matplotlib_cpp11/pyplot.h index 3edc8f9..eedb192 100644 --- a/include/matplotlib_cpp11/pyplot.h +++ b/include/matplotlib_cpp11/pyplot.h @@ -9,6 +9,8 @@ struct __attribute__((visibility("hidden"))) pyplot { LOAD_ATTR(show, mod); subplot_attr = mod.attr("subplot"); subplots_attr = mod.attr("subplots"); + LOAD_ATTR(figure, mod); + LOAD_ATTR(axes, mod); } pybind11::module mod; pybind11::object plot; @@ -22,6 +24,19 @@ struct __attribute__((visibility("hidden"))) pyplot { pybind11::object fig = ret[0], ax = ret[1]; return {Figure(fig), Axes(ax)}; } - Figure figure() { return Figure(mod); } - Axes axes() { return Axes(mod); } + pybind11::object figure; + pybind11::object axes; }; + +static bool g_imported = false; + +static pyplot &import() { + static pyplot g_pyplot; + if (not g_imported) { + g_imported = true; + // pyplot singleton + auto mod = pybind11::module::import("matplotlib.pyplot"); + g_pyplot = pyplot(mod); + } + return g_pyplot; +} diff --git a/include/matplotlib_cpp11/text.h b/include/matplotlib_cpp11/text.h new file mode 100644 index 0000000..ae7a4f1 --- /dev/null +++ b/include/matplotlib_cpp11/text.h @@ -0,0 +1,9 @@ +struct __attribute__((visibility("hidden"))) Text { + Text(pybind11::object text) { + self = text; + load_attrs(); + } + void load_attrs() { LOAD_ATTR(set_rotation, self); } + pybind11::object self; + pybind11::object set_rotation; +};