Skip to content

Commit 92c6899

Browse files
authored
Merge pull request #13 from soblin/feature/error-bar
Feature/error bar
2 parents 6a18d73 + b72adfa commit 92c6899

File tree

9 files changed

+235
-5
lines changed

9 files changed

+235
-5
lines changed

gallery/lines_bars_and_markers/CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ add_demo(fill_between_demo fill_between_demo.cpp)
66
add_demo(fill_betweenx_demo fill_betweenx_demo.cpp)
77
add_demo(scatter_with_legend scatter_with_legend.cpp)
88
add_demo(scatter_hist scatter_hist.cpp)
9+
add_demo(errorbar_limits_simple errorbar_limits_simple.cpp)
10+
add_demo(errorbar_subsample errorbar_subsample.cpp)
911

10-
# TODO: macro for this!
1112
add_custom_target(lines_bars_and_markers
12-
DEPENDS bar_label_demo fill simple_plot scatter_symbol fill_between_demo fill_betweenx_demo scatter_with_legend scatter_hist
13+
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
1314
COMMAND bar_label_demo
1415
COMMAND fill
1516
COMMAND simple_plot
@@ -18,6 +19,8 @@ add_custom_target(lines_bars_and_markers
1819
COMMAND fill_betweenx_demo
1920
COMMAND scatter_with_legend
2021
COMMAND scatter_hist
22+
COMMAND errorbar_limits_simple
23+
COMMAND errorbar_subsample
2124
COMMENT "running lines_bars_and_markers"
2225
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../images"
2326
)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// example
2+
// https://matplotlib.org/stable/gallery/lines_bars_and_markers/errorbar_limits_simple.html
3+
4+
#include <pybind11/embed.h>
5+
#include <pybind11/stl.h>
6+
7+
#include <matplotlibcpp17/pyplot.h>
8+
9+
#include <xtensor/xbuilder.hpp>
10+
#include <xtensor/xmath.hpp>
11+
12+
#include <vector>
13+
14+
namespace py = pybind11;
15+
using namespace py::literals;
16+
using namespace std;
17+
using namespace matplotlibcpp17;
18+
19+
int main() {
20+
py::scoped_interpreter guard{};
21+
auto plt = pyplot::import();
22+
auto fig = plt.figure();
23+
auto x_ = xt::arange(0.0, 10.0, 1.0);
24+
auto y_ = 2.5 * xt::sin(x_ / 20 * M_PI);
25+
auto y1_ = y_ + 1.0, y2_ = y_ + 2.0, y3_ = y_ + 3.0;
26+
auto yerr_ = xt::linspace(0.05, 0.2, 10);
27+
vector<double> x(x_.begin(), x_.end()), y(y_.begin(), y_.end()),
28+
yerr(yerr_.begin(), yerr_.end()), y3(y3_.begin(), y3_.end()),
29+
y2(y2_.begin(), y2_.end()), y1(y1_.begin(), y1_.end());
30+
plt.errorbar(Args(x, y3),
31+
Kwargs("yerr"_a = yerr, "label"_a = "both limits (default)"));
32+
plt.errorbar(Args(x, y2), Kwargs("yerr"_a = yerr, "uplims"_a = true,
33+
"label"_a = "uplims=True"));
34+
plt.errorbar(Args(x, y1),
35+
Kwargs("yerr"_a = yerr, "uplims"_a = true, "lolims"_a = true,
36+
"label"_a = "uplims=True, lolims=True"));
37+
38+
vector<bool> upperlimits, lowerlimits;
39+
for (auto i : {0, 1, 2, 3, 4}) {
40+
upperlimits.push_back(true);
41+
upperlimits.push_back(false);
42+
lowerlimits.push_back(false);
43+
lowerlimits.push_back(true);
44+
}
45+
plt.errorbar(Args(x, y), Kwargs("yerr"_a = yerr, "uplims"_a = upperlimits,
46+
"lolims"_a = lowerlimits,
47+
"label"_a = "subsets of uplims and lolims"));
48+
plt.legend(Args(), Kwargs("loc"_a = "lower right"));
49+
#if USE_GUI
50+
plt.show();
51+
#else
52+
plt.savefig(Args("errorbar_limits_simple.png"));
53+
#endif
54+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// example from
2+
// https://matplotlib.org/stable/gallery/lines_bars_and_markers/errorbar_subsample.html
3+
4+
#include <pybind11/embed.h>
5+
#include <pybind11/stl.h>
6+
7+
#include <matplotlibcpp17/pyplot.h>
8+
9+
#include <xtensor/xbuilder.hpp>
10+
#include <xtensor/xmath.hpp>
11+
12+
#include <vector>
13+
14+
namespace py = pybind11;
15+
using namespace py::literals;
16+
using namespace std;
17+
using namespace matplotlibcpp17;
18+
19+
int main() {
20+
auto x_ = xt::arange(0.1, 4.0, 0.1);
21+
auto y1_ = xt::exp(-1.0 * x_);
22+
auto y2_ = xt::exp(-0.5 * x_);
23+
auto y1err_ = 0.1 + 0.1 * xt::sqrt(x_);
24+
auto y2err_ = 0.1 + 0.1 * xt::sqrt(x_ / 2.0);
25+
vector<double> x(x_.begin(), x_.end()), y1(y1_.begin(), y1_.end()),
26+
y2(y2_.begin(), y2_.end()), y1err(y1err_.begin(), y1err_.end()),
27+
y2err(y2err_.begin(), y2err_.end());
28+
29+
py::scoped_interpreter guard{};
30+
auto plt = pyplot::import();
31+
auto [fig, axs] = plt.subplots(
32+
1, 3, Kwargs("sharex"_a = true, "figsize"_a = py::make_tuple(12, 6)));
33+
auto ax0 = axs[0], ax1 = axs[1], ax2 = axs[2];
34+
ax0.set_title(Args("all errorbars"));
35+
ax0.errorbar(Args(x, y1), Kwargs("yerr"_a = y1err));
36+
ax0.errorbar(Args(x, y1), Kwargs("yerr"_a = y2err));
37+
38+
ax1.set_title(Args("only every 6th errorbar"));
39+
ax1.errorbar(Args(x, y1), Kwargs("yerr"_a = y1err, "errorevery"_a = 6));
40+
ax1.errorbar(Args(x, y2), Kwargs("yerr"_a = y2err, "errorevery"_a = 6));
41+
42+
ax2.set_title(Args("second seris shifted by 3"));
43+
ax2.errorbar(Args(x, y1),
44+
Kwargs("yerr"_a = y1err, "errorevery"_a = py::make_tuple(0, 6)));
45+
ax2.errorbar(Args(x, y2),
46+
Kwargs("yerr"_a = y2err, "errorevery"_a = py::make_tuple(3, 6)));
47+
48+
fig.suptitle(Args("Errorbar subsampling"));
49+
#if USE_GUI
50+
plt.show();
51+
#else
52+
plt.savefig(Args("erorbar_subsample.png"));
53+
#endif
54+
}

gallery/mplot3d/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ add_demo(lines3d lines3d.cpp)
22
add_demo(lorenz_attractor lorenz_attractor.cpp)
33
add_demo(contour3d contour3d.cpp)
44
add_demo(subplot3d subplot3d.cpp)
5+
add_demo(errorbar3d errorbar3d.cpp)
56

67
add_custom_target(mplot3d
7-
DEPENDS lines3d lorenz_attractor contour3d subplot3d
8+
DEPENDS lines3d lorenz_attractor contour3d subplot3d errorbar3d
89
COMMAND lines3d
910
COMMAND lorenz_attractor
1011
COMMAND contour3d
1112
COMMAND subplot3d
13+
COMMAND errorbar3d
1214
COMMENT "running mplot3d"
1315
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../images"
1416
)

gallery/mplot3d/errorbar3d.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// example from https://matplotlib.org/stable/gallery/mplot3d/errorbar3d.html
2+
3+
#include <pybind11/embed.h>
4+
#include <pybind11/stl.h>
5+
6+
#include <matplotlibcpp17/pyplot.h>
7+
8+
#include <xtensor/xbuilder.hpp>
9+
#include <xtensor/xmath.hpp>
10+
11+
#include <vector>
12+
#include <algorithm>
13+
14+
namespace py = pybind11;
15+
using namespace py::literals;
16+
using namespace std;
17+
using namespace matplotlibcpp17;
18+
19+
int main() {
20+
py::scoped_interpreter guard{};
21+
auto plt = pyplot::import();
22+
auto ax = plt.figure().add_subplot(Args(), Kwargs("projection"_a = "3d"));
23+
auto t_ = xt::arange(0.0, 2 * M_PI + 0.1, 0.01);
24+
auto x_ = xt::sin(1.0 * t_);
25+
auto y_ = xt::cos(3.0 * t_);
26+
auto z_ = xt::sin(5.0 * t_);
27+
vector<double> t(t_.begin(), t_.end()), x(x_.begin(), x_.end()),
28+
y(y_.begin(), y_.end()), z(z_.begin(), z_.end());
29+
30+
const int estep = 15;
31+
vector<int> i, zuplims, zlolims;
32+
std::iota(i.begin(), i.end(), 0);
33+
std::transform(i.begin(), i.end(), std::back_inserter(zuplims), [](int i) {
34+
return (i % 15 == 0) and ((i / estep) % 3 == 0);
35+
});
36+
std::transform(i.begin(), i.end(), std::back_inserter(zlolims), [](int i) {
37+
return (i % 15 == 0) and ((i / estep) % 3 == 2);
38+
});
39+
40+
ax.errorbar(Args(x, y, z, 0.2),
41+
Kwargs("zuplims"_a = zuplims, "zlolims"_a = zlolims,
42+
"errorevery"_a = estep));
43+
44+
ax.set_xlabel(Args("X label"));
45+
ax.set_ylabel(Args("Y label"));
46+
ax.set_zlabel(Args("Z label"));
47+
48+
plt.show();
49+
}

gallery/statistics/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
add_demo(hist hist.cpp)
2+
add_demo(errorbar errorbar.cpp)
23

34
add_custom_target(statitics
4-
DEPENDS hist
5+
DEPENDS hist errorbar
56
COMMAND hist
7+
COMMAND errorbar
68
COMMENT "running hist"
79
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../images"
810
)

gallery/statistics/errorbar.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// example from https://matplotlib.org/stable/gallery/statistics/errorbar.html
2+
3+
#include <pybind11/embed.h>
4+
#include <pybind11/stl.h>
5+
6+
#include <matplotlibcpp17/pyplot.h>
7+
8+
#include <xtensor/xrandom.hpp>
9+
10+
#include <random>
11+
12+
namespace py = pybind11;
13+
using namespace py::literals;
14+
using namespace std;
15+
using namespace matplotlibcpp17;
16+
17+
int main() {
18+
py::scoped_interpreter guard{};
19+
auto plt = pyplot::import();
20+
auto x_ = xt::arange(0.1, 4.0, 0.5);
21+
auto y_ = xt::exp(-x_);
22+
vector<double> x(x_.begin(), x_.end()), y(y_.begin(), y_.end());
23+
24+
auto [fig, ax] = plt.subplots();
25+
ax.errorbar(Args(x, y), Kwargs("xerr"_a = 0.2, "yerr"_a = 0.4));
26+
#if USE_GUI
27+
plt.show();
28+
#else
29+
plt.savefig(Args("erorrbar.png"));
30+
#endif
31+
}

include/matplotlibcpp17/axes.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper {
6969
pybind11::object contour(const pybind11::tuple &args = pybind11::tuple(),
7070
const pybind11::dict &kwargs = pybind11::dict());
7171

72+
// errorbar
73+
pybind11::object errorbar(const pybind11::tuple &args = pybind11::tuple(),
74+
const pybind11::dict &kwargs = pybind11::dict());
75+
7276
// fill
7377
pybind11::object fill(const pybind11::tuple &args = pybind11::tuple(),
7478
const pybind11::dict &kwargs = pybind11::dict());
@@ -213,6 +217,7 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper {
213217
#endif
214218
LOAD_FUNC_ATTR(barh, self);
215219
LOAD_FUNC_ATTR(contour, self);
220+
LOAD_FUNC_ATTR(errorbar, self);
216221
LOAD_FUNC_ATTR(fill, self);
217222
LOAD_FUNC_ATTR(fill_between, self);
218223
LOAD_FUNC_ATTR(fill_betweenx, self);
@@ -232,8 +237,10 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper {
232237
plot_wireframe_attr = self.attr("plot_wireframe");
233238
set_zlabel_attr = self.attr("set_zlabel");
234239
INFO_MSG("Loaded Axes3D");
240+
projection_3d = true;
241+
} catch (...) {
242+
projection_3d = false;
235243
}
236-
catch(...) {}
237244
LOAD_FUNC_ATTR(quiver, self);
238245
LOAD_FUNC_ATTR(quiverkey, self);
239246
LOAD_FUNC_ATTR(scatter, self);
@@ -258,6 +265,7 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper {
258265
pybind11::object bar_label_attr;
259266
pybind11::object barh_attr;
260267
pybind11::object contour_attr;
268+
pybind11::object errorbar_attr;
261269
pybind11::object fill_attr;
262270
pybind11::object fill_between_attr;
263271
pybind11::object fill_betweenx_attr;
@@ -289,6 +297,7 @@ struct DECL_STRUCT_ATTR Axes : public BaseWrapper {
289297
pybind11::object set_zlabel_attr;
290298
pybind11::object text_attr;
291299
pybind11::object tick_params_attr;
300+
bool projection_3d;
292301
};
293302

294303
// add_artist
@@ -353,6 +362,19 @@ pybind11::object Axes::contour(const pybind11::tuple &args,
353362
return obj;
354363
}
355364

365+
// errorbar
366+
pybind11::object Axes::errorbar(const pybind11::tuple &args,
367+
const pybind11::dict &kwargs) {
368+
if (not projection_3d) {
369+
pybind11::object obj = errorbar_attr(*args, **kwargs);
370+
return obj;
371+
} else {
372+
ERROR_MSG("Call to errorbar with projection='3d' is invalid because "
373+
"matplotlib version is < 3.4.0");
374+
std::exit(0);
375+
}
376+
}
377+
356378
// fill
357379
pybind11::object Axes::fill(const pybind11::tuple &args,
358380
const pybind11::dict &kwargs) {

include/matplotlibcpp17/pyplot.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ struct DECL_STRUCT_ATTR PyPlot {
4141
pybind11::object clf(const pybind11::tuple &args = pybind11::tuple(),
4242
const pybind11::dict &kwargs = pybind11::dict());
4343

44+
// errorbar
45+
pybind11::object errorbar(const pybind11::tuple &args = pybind11::tuple(),
46+
const pybind11::dict &kwargs = pybind11::dict());
47+
4448
// figaspect
4549
std::tuple<double, double>
4650
figaspect(const pybind11::tuple &args = pybind11::tuple(),
@@ -118,6 +122,7 @@ struct DECL_STRUCT_ATTR PyPlot {
118122
LOAD_FUNC_ATTR(axis, mod);
119123
LOAD_FUNC_ATTR(cla, mod);
120124
LOAD_FUNC_ATTR(clf, mod);
125+
LOAD_FUNC_ATTR(errorbar, mod);
121126
LOAD_FUNC_ATTR(figaspect, mod);
122127
LOAD_FUNC_ATTR(figure, mod);
123128
LOAD_FUNC_ATTR(gca, mod);
@@ -141,6 +146,7 @@ struct DECL_STRUCT_ATTR PyPlot {
141146
pybind11::object axis_attr;
142147
pybind11::object cla_attr;
143148
pybind11::object clf_attr;
149+
pybind11::object errorbar_attr;
144150
pybind11::object figaspect_attr;
145151
pybind11::object figure_attr;
146152
pybind11::object gca_attr;
@@ -187,6 +193,13 @@ pybind11::object PyPlot::clf(const pybind11::tuple &args,
187193
return ret;
188194
}
189195

196+
// errorbar
197+
pybind11::object PyPlot::errorbar(const pybind11::tuple &args,
198+
const pybind11::dict &kwargs) {
199+
pybind11::object ret = errorbar_attr(*args, **kwargs);
200+
return ret;
201+
}
202+
190203
// figaspect
191204
std::tuple<double, double> PyPlot::figaspect(const pybind11::tuple &args,
192205
const pybind11::dict &kwargs) {

0 commit comments

Comments
 (0)