-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Implement STL-like interface for plotting generic data structures#276
Implement STL-like interface for plotting generic data structures #276Hs293Go wants to merge 4 commits into
Conversation
This commit implements a STL-algorithm-like interface to plot 2D line plots and scatter plots from data in a range defined by a pair of iterators. New interfaces are in the matplotlibcpp::stl namespace
Two new examples demonstrate that the stl-like interface is able to work with raw buffers, std::vector|list|deque|etc and Eigen Vector objects
amadeus84
commented
Mar 12, 2022
I came across the same problem, I have data in c-style arrays
doble* x, * y:
size_t n; // same for x and y
and to pass it to plt::plot() I'd have to copy it into a vector first. Ranges (C++20) work! I tried. But perhaps the simplest solution I came up with was
auto xx = std::span(x, n);
auto yy = std:;span(y, n);
plt::plot(xx, yy, "");
(of course, you can put the span directly into plot(), no need to have xx and yy). And, of course, this works also when y has length a multiple of lenght of x:
double* x, * y;
size_t nx=100, ny = 5*nx;
for (size_t offset = 0; offset < ny; offset += nx)
plt::plot(std::span(x, nx), std::span(y+offset, nx), "");
So far so good, and if this is available in C++20, I don't see why we shouldn't use it. In fact, the whole variadic template part of matplotlibcpp looks like was specifically done with ranges in mind - all that's needed is begin(), end(), etc. i.e all the things a range would have.
The problem though, is that for types other than vector, matplotlibcpp ends up calling plot_impl(), which then copies the inputs to PyObject arrays. It defeats the purpose of using span / ranges in the first place.
Perhaps we can have a template specialization of plot (or plot_impl) for contiguous ranges, that would not iterate and copy the input data to PyObject arrays, but rather call PyArray_SimpleNewFromData(), like plot(vector) does, via get_array(). According to https://numpy.org/devdocs/reference/c-api/array.html PyArray_SimpleNewFromData() does not copy the data.
I'm experimenting with this now.
Hs293Go
commented
Mar 12, 2022
@amadeus84 I like your ideas! A potential difficulty may arise from the fact that plotting is always with a pair of ranges, and some inspiration might be taken from zip_view (currently in range-v3 only) to design concepts that ensure compatibility between the pair of ranges.
Alas, matplotlibcpp seem to be unmaintained for almost a year already. I've switched to the technique of using pybind11 to embed the python interpreter in C++ code and plot using the native matplotlib API. I just made public a demo of the code I've been sharing around: https://github.com/Hs293Go/demo_pybind11_matplotlib
amadeus84
commented
Mar 18, 2022
@amadeus84 I like your ideas! A potential difficulty may arise from the fact that plotting is always with a pair of ranges, and some inspiration might be taken from
zip_view(currently inrange-v3only) to design concepts that ensure compatibility between the pair of ranges.Alas,
matplotlibcppseem to be unmaintained for almost a year already. I've switched to the technique of usingpybind11to embed the python interpreter in C++ code and plot using the native matplotlib API. I just made public a demo of the code I've been sharing around: https://github.com/Hs293Go/demo_pybind11_matplotlib
I now have support for ranges in my repository: https://github.com/amadeus84/matplotlib-cpp
This PR is motivated by the desire to plot data in generic data structures without the boilerplate of copying data into
std::vectorsbefore each plot. (I just had to plot a 101385-element Eigen::VectorXd and the copy was NOT fun).The solution adopted is to follow the example of the STL and define the graph data by a pair of templated input iterators. For ease of use, the interface is designed to mimic the STL in the following manner.
only 2D lineplots and scatter plots are addressed for the time being.
In due diligence, the examples
stl_containers.cppandeigen_objects.cppand a section reviewing this interface in the README are added.I think the main sticking points regarding this PR are
I suppose C++20
<ranges>is the silver bullet to resolve point 1, and C++20contiguous_iteratorconcept deals with point 2, but this is the most elegant solution I have for now. If there's anything I can to do better before this PR can be merged, let me know!