diff --git a/gallery/lines_bars_and_markers/CMakeLists.txt b/gallery/lines_bars_and_markers/CMakeLists.txt index 6f02e56..c936eb7 100644 --- a/gallery/lines_bars_and_markers/CMakeLists.txt +++ b/gallery/lines_bars_and_markers/CMakeLists.txt @@ -6,10 +6,11 @@ add_demo(fill_between_demo fill_between_demo.cpp) add_demo(fill_betweenx_demo fill_betweenx_demo.cpp) add_demo(scatter_with_legend scatter_with_legend.cpp) add_demo(scatter_hist scatter_hist.cpp) +add_demo(errorbar_limits_simple errorbar_limits_simple.cpp) +add_demo(errorbar_subsample errorbar_subsample.cpp) -# TODO: macro for this! add_custom_target(lines_bars_and_markers - DEPENDS bar_label_demo fill simple_plot scatter_symbol fill_between_demo fill_betweenx_demo scatter_with_legend scatter_hist + DEPENDS bar_label_demo fill simple_plot scatter_symbol fill_between_demo fill_betweenx_demo scatter_with_legend scatter_hist errorbar_limits_simple errorbar_subsample COMMAND bar_label_demo COMMAND fill COMMAND simple_plot @@ -18,6 +19,8 @@ add_custom_target(lines_bars_and_markers COMMAND fill_betweenx_demo COMMAND scatter_with_legend COMMAND scatter_hist + COMMAND errorbar_limits_simple + COMMAND errorbar_subsample COMMENT "running lines_bars_and_markers" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../images" ) diff --git a/gallery/lines_bars_and_markers/errorbar_limits_simple.cpp b/gallery/lines_bars_and_markers/errorbar_limits_simple.cpp new file mode 100644 index 0000000..963135f --- /dev/null +++ b/gallery/lines_bars_and_markers/errorbar_limits_simple.cpp @@ -0,0 +1,54 @@ +// example +// https://matplotlib.org/stable/gallery/lines_bars_and_markers/errorbar_limits_simple.html + +#include +#include + +#include + +#include +#include + +#include + +namespace py = pybind11; +using namespace py::literals; +using namespace std; +using namespace matplotlibcpp17; + +int main() { + py::scoped_interpreter guard{}; + auto plt = pyplot::import(); + auto fig = plt.figure(); + auto x_ = xt::arange(0.0, 10.0, 1.0); + auto y_ = 2.5 * xt::sin(x_ / 20 * M_PI); + auto y1_ = y_ + 1.0, y2_ = y_ + 2.0, y3_ = y_ + 3.0; + auto yerr_ = xt::linspace(0.05, 0.2, 10); + vector x(x_.begin(), x_.end()), y(y_.begin(), y_.end()), + yerr(yerr_.begin(), yerr_.end()), y3(y3_.begin(), y3_.end()), + y2(y2_.begin(), y2_.end()), y1(y1_.begin(), y1_.end()); + plt.errorbar(Args(x, y3), + Kwargs("yerr"_a = yerr, "label"_a = "both limits (default)")); + plt.errorbar(Args(x, y2), Kwargs("yerr"_a = yerr, "uplims"_a = true, + "label"_a = "uplims=True")); + plt.errorbar(Args(x, y1), + Kwargs("yerr"_a = yerr, "uplims"_a = true, "lolims"_a = true, + "label"_a = "uplims=True, lolims=True")); + + vector upperlimits, lowerlimits; + for (auto i : {0, 1, 2, 3, 4}) { + upperlimits.push_back(true); + upperlimits.push_back(false); + lowerlimits.push_back(false); + lowerlimits.push_back(true); + } + plt.errorbar(Args(x, y), Kwargs("yerr"_a = yerr, "uplims"_a = upperlimits, + "lolims"_a = lowerlimits, + "label"_a = "subsets of uplims and lolims")); + plt.legend(Args(), Kwargs("loc"_a = "lower right")); +#if USE_GUI + plt.show(); +#else + plt.savefig(Args("errorbar_limits_simple.png")); +#endif +} diff --git a/gallery/lines_bars_and_markers/errorbar_subsample.cpp b/gallery/lines_bars_and_markers/errorbar_subsample.cpp new file mode 100644 index 0000000..4b54b1f --- /dev/null +++ b/gallery/lines_bars_and_markers/errorbar_subsample.cpp @@ -0,0 +1,54 @@ +// example from +// https://matplotlib.org/stable/gallery/lines_bars_and_markers/errorbar_subsample.html + +#include +#include + +#include + +#include +#include + +#include + +namespace py = pybind11; +using namespace py::literals; +using namespace std; +using namespace matplotlibcpp17; + +int main() { + auto x_ = xt::arange(0.1, 4.0, 0.1); + auto y1_ = xt::exp(-1.0 * x_); + auto y2_ = xt::exp(-0.5 * x_); + auto y1err_ = 0.1 + 0.1 * xt::sqrt(x_); + auto y2err_ = 0.1 + 0.1 * xt::sqrt(x_ / 2.0); + vector x(x_.begin(), x_.end()), y1(y1_.begin(), y1_.end()), + y2(y2_.begin(), y2_.end()), y1err(y1err_.begin(), y1err_.end()), + y2err(y2err_.begin(), y2err_.end()); + + py::scoped_interpreter guard{}; + auto plt = pyplot::import(); + auto [fig, axs] = plt.subplots( + 1, 3, Kwargs("sharex"_a = true, "figsize"_a = py::make_tuple(12, 6))); + auto ax0 = axs[0], ax1 = axs[1], ax2 = axs[2]; + ax0.set_title(Args("all errorbars")); + ax0.errorbar(Args(x, y1), Kwargs("yerr"_a = y1err)); + ax0.errorbar(Args(x, y1), Kwargs("yerr"_a = y2err)); + + ax1.set_title(Args("only every 6th errorbar")); + ax1.errorbar(Args(x, y1), Kwargs("yerr"_a = y1err, "errorevery"_a = 6)); + ax1.errorbar(Args(x, y2), Kwargs("yerr"_a = y2err, "errorevery"_a = 6)); + + ax2.set_title(Args("second seris shifted by 3")); + ax2.errorbar(Args(x, y1), + Kwargs("yerr"_a = y1err, "errorevery"_a = py::make_tuple(0, 6))); + ax2.errorbar(Args(x, y2), + Kwargs("yerr"_a = y2err, "errorevery"_a = py::make_tuple(3, 6))); + + fig.suptitle(Args("Errorbar subsampling")); +#if USE_GUI + plt.show(); +#else + plt.savefig(Args("erorbar_subsample.png")); +#endif +} diff --git a/gallery/mplot3d/CMakeLists.txt b/gallery/mplot3d/CMakeLists.txt index 4c48bc4..c2cc39f 100644 --- a/gallery/mplot3d/CMakeLists.txt +++ b/gallery/mplot3d/CMakeLists.txt @@ -2,13 +2,15 @@ add_demo(lines3d lines3d.cpp) add_demo(lorenz_attractor lorenz_attractor.cpp) add_demo(contour3d contour3d.cpp) add_demo(subplot3d subplot3d.cpp) +add_demo(errorbar3d errorbar3d.cpp) add_custom_target(mplot3d - DEPENDS lines3d lorenz_attractor contour3d subplot3d + DEPENDS lines3d lorenz_attractor contour3d subplot3d errorbar3d COMMAND lines3d COMMAND lorenz_attractor COMMAND contour3d COMMAND subplot3d + COMMAND errorbar3d COMMENT "running mplot3d" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../images" ) diff --git a/gallery/mplot3d/errorbar3d.cpp b/gallery/mplot3d/errorbar3d.cpp new file mode 100644 index 0000000..5efed41 --- /dev/null +++ b/gallery/mplot3d/errorbar3d.cpp @@ -0,0 +1,49 @@ +// example from https://matplotlib.org/stable/gallery/mplot3d/errorbar3d.html + +#include +#include + +#include + +#include +#include + +#include +#include + +namespace py = pybind11; +using namespace py::literals; +using namespace std; +using namespace matplotlibcpp17; + +int main() { + py::scoped_interpreter guard{}; + auto plt = pyplot::import(); + auto ax = plt.figure().add_subplot(Args(), Kwargs("projection"_a = "3d")); + auto t_ = xt::arange(0.0, 2 * M_PI + 0.1, 0.01); + auto x_ = xt::sin(1.0 * t_); + auto y_ = xt::cos(3.0 * t_); + auto z_ = xt::sin(5.0 * t_); + vector t(t_.begin(), t_.end()), x(x_.begin(), x_.end()), + y(y_.begin(), y_.end()), z(z_.begin(), z_.end()); + + const int estep = 15; + vector i, zuplims, zlolims; + std::iota(i.begin(), i.end(), 0); + std::transform(i.begin(), i.end(), std::back_inserter(zuplims), [](int i) { + return (i % 15 == 0) and ((i / estep) % 3 == 0); + }); + std::transform(i.begin(), i.end(), std::back_inserter(zlolims), [](int i) { + return (i % 15 == 0) and ((i / estep) % 3 == 2); + }); + + ax.errorbar(Args(x, y, z, 0.2), + Kwargs("zuplims"_a = zuplims, "zlolims"_a = zlolims, + "errorevery"_a = estep)); + + ax.set_xlabel(Args("X label")); + ax.set_ylabel(Args("Y label")); + ax.set_zlabel(Args("Z label")); + + plt.show(); +} diff --git a/gallery/statistics/CMakeLists.txt b/gallery/statistics/CMakeLists.txt index 577ba1e..be84ebb 100644 --- a/gallery/statistics/CMakeLists.txt +++ b/gallery/statistics/CMakeLists.txt @@ -1,8 +1,10 @@ add_demo(hist hist.cpp) +add_demo(errorbar errorbar.cpp) add_custom_target(statitics - DEPENDS hist + DEPENDS hist errorbar COMMAND hist + COMMAND errorbar COMMENT "running hist" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../images" ) diff --git a/gallery/statistics/errorbar.cpp b/gallery/statistics/errorbar.cpp new file mode 100644 index 0000000..28f74f8 --- /dev/null +++ b/gallery/statistics/errorbar.cpp @@ -0,0 +1,31 @@ +// example from https://matplotlib.org/stable/gallery/statistics/errorbar.html + +#include +#include + +#include + +#include + +#include + +namespace py = pybind11; +using namespace py::literals; +using namespace std; +using namespace matplotlibcpp17; + +int main() { + py::scoped_interpreter guard{}; + auto plt = pyplot::import(); + auto x_ = xt::arange(0.1, 4.0, 0.5); + auto y_ = xt::exp(-x_); + vector x(x_.begin(), x_.end()), y(y_.begin(), y_.end()); + + auto [fig, ax] = plt.subplots(); + ax.errorbar(Args(x, y), Kwargs("xerr"_a = 0.2, "yerr"_a = 0.4)); +#if USE_GUI + plt.show(); +#else + plt.savefig(Args("erorrbar.png")); +#endif +} diff --git a/include/matplotlibcpp17/axes.h b/include/matplotlibcpp17/axes.h index 41ff7e8..56dd024 100644 --- a/include/matplotlibcpp17/axes.h +++ b/include/matplotlibcpp17/axes.h @@ -69,6 +69,10 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper { pybind11::object contour(const pybind11::tuple &args = pybind11::tuple(), const pybind11::dict &kwargs = pybind11::dict()); + // errorbar + pybind11::object errorbar(const pybind11::tuple &args = pybind11::tuple(), + const pybind11::dict &kwargs = pybind11::dict()); + // fill pybind11::object fill(const pybind11::tuple &args = pybind11::tuple(), const pybind11::dict &kwargs = pybind11::dict()); @@ -213,6 +217,7 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper { #endif LOAD_FUNC_ATTR(barh, self); LOAD_FUNC_ATTR(contour, self); + LOAD_FUNC_ATTR(errorbar, self); LOAD_FUNC_ATTR(fill, self); LOAD_FUNC_ATTR(fill_between, self); LOAD_FUNC_ATTR(fill_betweenx, self); @@ -232,8 +237,10 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper { plot_wireframe_attr = self.attr("plot_wireframe"); set_zlabel_attr = self.attr("set_zlabel"); INFO_MSG("Loaded Axes3D"); + projection_3d = true; + } catch (...) { + projection_3d = false; } - catch(...) {} LOAD_FUNC_ATTR(quiver, self); LOAD_FUNC_ATTR(quiverkey, self); LOAD_FUNC_ATTR(scatter, self); @@ -258,6 +265,7 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper { pybind11::object bar_label_attr; pybind11::object barh_attr; pybind11::object contour_attr; + pybind11::object errorbar_attr; pybind11::object fill_attr; pybind11::object fill_between_attr; pybind11::object fill_betweenx_attr; @@ -289,6 +297,7 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper { pybind11::object set_zlabel_attr; pybind11::object text_attr; pybind11::object tick_params_attr; + bool projection_3d; }; // add_artist @@ -353,6 +362,19 @@ pybind11::object Axes::contour(const pybind11::tuple &args, return obj; } +// errorbar +pybind11::object Axes::errorbar(const pybind11::tuple &args, + const pybind11::dict &kwargs) { + if (not projection_3d) { + pybind11::object obj = errorbar_attr(*args, **kwargs); + return obj; + } else { + ERROR_MSG("Call to errorbar with projection='3d' is invalid because " + "matplotlib version is < 3.4.0"); + std::exit(0); + } +} + // fill pybind11::object Axes::fill(const pybind11::tuple &args, const pybind11::dict &kwargs) { diff --git a/include/matplotlibcpp17/pyplot.h b/include/matplotlibcpp17/pyplot.h index d188626..7e2f43c 100644 --- a/include/matplotlibcpp17/pyplot.h +++ b/include/matplotlibcpp17/pyplot.h @@ -41,6 +41,10 @@ struct DECL_STRUCT_ATTR PyPlot { pybind11::object clf(const pybind11::tuple &args = pybind11::tuple(), const pybind11::dict &kwargs = pybind11::dict()); + // errorbar + pybind11::object errorbar(const pybind11::tuple &args = pybind11::tuple(), + const pybind11::dict &kwargs = pybind11::dict()); + // figaspect std::tuple figaspect(const pybind11::tuple &args = pybind11::tuple(), @@ -118,6 +122,7 @@ struct DECL_STRUCT_ATTR PyPlot { LOAD_FUNC_ATTR(axis, mod); LOAD_FUNC_ATTR(cla, mod); LOAD_FUNC_ATTR(clf, mod); + LOAD_FUNC_ATTR(errorbar, mod); LOAD_FUNC_ATTR(figaspect, mod); LOAD_FUNC_ATTR(figure, mod); LOAD_FUNC_ATTR(gca, mod); @@ -141,6 +146,7 @@ struct DECL_STRUCT_ATTR PyPlot { pybind11::object axis_attr; pybind11::object cla_attr; pybind11::object clf_attr; + pybind11::object errorbar_attr; pybind11::object figaspect_attr; pybind11::object figure_attr; pybind11::object gca_attr; @@ -187,6 +193,13 @@ pybind11::object PyPlot::clf(const pybind11::tuple &args, return ret; } +// errorbar +pybind11::object PyPlot::errorbar(const pybind11::tuple &args, + const pybind11::dict &kwargs) { + pybind11::object ret = errorbar_attr(*args, **kwargs); + return ret; +} + // figaspect std::tuple PyPlot::figaspect(const pybind11::tuple &args, const pybind11::dict &kwargs) {