Skip to content
Snippets Groups Projects
Commit d547bc73 authored by soblin's avatar soblin
Browse files

adding mplot3d/subplot3d

parent 836600e0
No related branches found
No related tags found
No related merge requests found
project(matplotlibcpp17)
cmake_minimum_required(VERSION 3.12)
find_package(Python3 COMPONENTS Interpreter Development)
find_package(Python3 COMPONENTS Interpreter Development NumPy)
find_package(pybind11 REQUIRED)
if(NOT DEFINED ADD_DEMO)
......@@ -16,19 +16,24 @@ set(matplotlibcpp17_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include")
function(add_demo name path)
add_executable(${name} ${path})
target_include_directories(${name} PUBLIC ${pybind11_INCLUDE_DIR} ${Python3_INCLUDE_DIRS} ${matplotlibcpp17_INCLUDE_DIRS})
target_include_directories(${name} PUBLIC
${Python3_INCLUDE_DIRS}
${Python3_NumPy_INCLUDE_DIRS}
${pybind11_INCLUDE_DIR}
${matplotlibcpp17_INCLUDE_DIRS}
)
target_link_libraries(${name} ${Python3_LIBRARIES} pybind11::embed)
endfunction()
if(${ADD_DEMO})
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-Wall -g -DUSE_GUI=${USE_GUI}")
add_subdirectory(gallery/lines_bars_and_markers)
add_subdirectory(gallery/subplots_axes_and_figures)
add_subdirectory(gallery/statistics)
add_subdirectory(gallery/images_contours_and_fields)
add_subdirectory(gallery/shapes_and_collections)
add_subdirectory(gallery/artist_animation)
# add_subdirectory(gallery/lines_bars_and_markers)
# add_subdirectory(gallery/subplots_axes_and_figures)
# add_subdirectory(gallery/statistics)
# add_subdirectory(gallery/images_contours_and_fields)
# add_subdirectory(gallery/shapes_and_collections)
# add_subdirectory(gallery/artist_animation)
add_subdirectory(gallery/mplot3d)
endif()
......
......
add_demo(lines3d lines3d.cpp)
add_demo(lorenz_attractor lorenz_attractor.cpp)
add_demo(contour3d contour3d.cpp)
add_demo(subplot3d subplot3d.cpp)
add_custom_target(mplot3d
DEPENDS lines3d lorenz_attractor contour3d
DEPENDS lines3d lorenz_attractor contour3d subplot3d
COMMAND lines3d
COMMAND lorenz_attractor
COMMAND contour3d
COMMAND subplot3d
COMMENT "running mplot3d"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../images"
)
// example https://matplotlib.org/stable/gallery/mplot3d/subplot3d.html
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
#include <matplotlibcpp17/matplotlibcpp17.h>
#include <algorithm>
#include <vector>
namespace py = pybind11;
using namespace py::literals;
using namespace std;
using namespace matplotlibcpp17;
// NOTE: looks like vector<vector<T>> is naturally converted thanks to pybind11
// ref: https://github.com/pybind/pybind11/issues/1071
using mesh2D = vector<vector<double>>;
template <typename T> std::vector<T> arange(T start, T end, T h) {
int N = static_cast<int>((end - start) / h);
std::vector<T> xs(N);
T val = start;
for (int i = 0; i < N; ++i) {
xs[i] = val;
val += h;
}
return xs;
}
tuple<mesh2D, mesh2D> meshgrid(const vector<double> &x,
const vector<double> &y) {
mesh2D X(y.size()), Y(y.size());
for (unsigned i = 0; i < y.size(); ++i) {
X[i].resize(x.size());
Y[i].resize(x.size());
}
for (unsigned i = 0; i < y.size(); ++i) {
for (unsigned j = 0; j < x.size(); ++j) {
const double x0 = x[j], y0 = y[i];
X[i][j] = x0;
Y[i][j] = y0;
}
}
return {X, Y};
}
// from mpl_toolkits.axes3d.py
tuple<mesh2D, mesh2D, mesh2D> get_test_data(double delta = 0.05) {
const vector<double> xs = arange(-3.0, 3.0, delta);
const auto ys = xs;
mesh2D X(ys.size()), Y(ys.size()), Z(ys.size());
for (unsigned i = 0; i < ys.size(); ++i) {
X[i].resize(xs.size());
Y[i].resize(xs.size());
Z[i].resize(xs.size());
}
for (unsigned i = 0; i < ys.size(); ++i) {
for (unsigned j = 0; j < xs.size(); ++j) {
const double x = xs[j], y = ys[i];
const double z1 = exp(-(pow(x, 2) + pow(y, 2)) / 2.0) / (2 * M_PI);
const double z2 =
exp(-(pow((x - 1) / 1.5, 2) + pow((y - 1) / 0.5, 2)) / 2.0) /
(2 * M_PI * 0.5 * 1.5);
X[i][j] = x * 10;
Y[i][j] = y * 10;
Z[i][j] = (z2 - z1) * 500;
}
}
return {X, Y, Z};
}
int main() {
py::scoped_interpreter guard{};
auto plt = matplotlibcpp17::pyplot::import();
auto [w, h] = plt.figaspect(args_(0.5));
auto fig = plt.figure(args_(), kwargs_("figsize"_a = py::make_tuple(w, h)));
{
auto ax = fig.add_subplot(args_(1, 2, 1), kwargs_("projection"_a = "3d"));
vector<double> xs = arange(-5.0, 5.0, 0.25);
vector<double> ys = xs;
auto [X, Y] = meshgrid(xs, ys);
mesh2D Z(X.size());
for (unsigned j = 0; j < ys.size(); ++j)
Z[j].resize(xs.size());
for (unsigned j = 0; j < ys.size(); ++j) {
for (unsigned i = 0; i < xs.size(); ++i) {
const double x = xs[i], y = ys[j];
Z[j][i] = sin(sqrt(x * x + y * y));
}
}
// NOTE: conversion to numpy array
// ref: https://github.com/pybind/pybind11/issues/2066
auto X_ = py::array(py::cast(std::move(X)));
auto Y_ = py::array(py::cast(std::move(Y)));
auto Z_ = py::array(py::cast(std::move(Z)));
auto surf = ax.plot_surface(
args_(X_, Y_, Z_), kwargs_("rstride"_a = 1, "cstride"_a = 1,
"linewidth"_a = 0, "antialiased"_a = false));
}
{
auto ax = fig.add_subplot(args_(1, 2, 2), kwargs_("projection"_a = "3d"));
auto [X, Y, Z] = get_test_data(0.05);
auto X_ = py::array(py::cast(std::move(X)));
auto Y_ = py::array(py::cast(std::move(Y)));
auto Z_ = py::array(py::cast(std::move(Z)));
ax.plot_wireframe(args_(X_, Y_, Z_),
kwargs_("rstride"_a = 10, "cstride"_a = 10));
}
#if USE_GUI
plt.show();
#else
plt.savefig(args_("subplot3d.png"));
#endif
}
......@@ -123,6 +123,16 @@ public:
pybind11::object plot(const pybind11::tuple &args = pybind11::tuple(),
const pybind11::dict &kwargs = pybind11::dict());
// plot_surface
pybind11::object
plot_surface(const pybind11::tuple &args = pybind11::tuple(),
const pybind11::dict &kwargs = pybind11::dict());
// plot_wireframe
pybind11::object
plot_wireframe(const pybind11::tuple &args = pybind11::tuple(),
const pybind11::dict &kwargs = pybind11::dict());
// quiver
quiver::Quiver quiver(const pybind11::tuple &args = pybind11::tuple(),
const pybind11::dict &kwargs = pybind11::dict());
......@@ -212,6 +222,8 @@ private:
LOAD_FUNC_ATTR(invert_yaxis, self);
LOAD_FUNC_ATTR(legend, self);
LOAD_FUNC_ATTR(plot, self);
LOAD_FUNC_ATTR(plot_surface, self);
LOAD_FUNC_ATTR(plot_wireframe, self);
LOAD_FUNC_ATTR(quiver, self);
LOAD_FUNC_ATTR(quiverkey, self);
LOAD_FUNC_ATTR(scatter, self);
......@@ -250,6 +262,8 @@ private:
pybind11::object invert_yaxis_attr;
pybind11::object legend_attr;
pybind11::object plot_attr;
pybind11::object plot_surface_attr;
pybind11::object plot_wireframe_attr;
pybind11::object quiver_attr;
pybind11::object quiverkey_attr;
pybind11::object scatter_attr;
......@@ -429,6 +443,20 @@ pybind11::object Axes::plot(const pybind11::tuple &args,
return ret;
}
// plot_surface
pybind11::object Axes::plot_surface(const pybind11::tuple &args,
const pybind11::dict &kwargs) {
pybind11::object ret = plot_surface_attr(*args, **kwargs);
return ret;
}
// plot_wireframe
pybind11::object Axes::plot_wireframe(const pybind11::tuple &args,
const pybind11::dict &kwargs) {
pybind11::object ret = plot_wireframe_attr(*args, **kwargs);
return ret;
}
// quiver
quiver::Quiver Axes::quiver(const pybind11::tuple &args,
const pybind11::dict &kwargs) {
......
......
......@@ -41,6 +41,11 @@ public:
pybind11::object clf(const pybind11::tuple &args = pybind11::tuple(),
const pybind11::dict &kwargs = pybind11::dict());
// figaspect
std::tuple<double, double>
figaspect(const pybind11::tuple &args = pybind11::tuple(),
const pybind11::dict &kwargs = pybind11::dict());
// figure
figure::Figure figure(const pybind11::tuple &args = pybind11::tuple(),
const pybind11::dict &kwargs = pybind11::dict());
......@@ -113,6 +118,7 @@ private:
LOAD_FUNC_ATTR(axis, mod);
LOAD_FUNC_ATTR(cla, mod);
LOAD_FUNC_ATTR(clf, mod);
LOAD_FUNC_ATTR(figaspect, mod);
LOAD_FUNC_ATTR(figure, mod);
LOAD_FUNC_ATTR(gca, mod);
LOAD_FUNC_ATTR(gcf, mod);
......@@ -135,6 +141,7 @@ private:
pybind11::object axis_attr;
pybind11::object cla_attr;
pybind11::object clf_attr;
pybind11::object figaspect_attr;
pybind11::object figure_attr;
pybind11::object gca_attr;
pybind11::object gcf_attr;
......@@ -180,6 +187,15 @@ pybind11::object PyPlot::clf(const pybind11::tuple &args,
return ret;
}
// figaspect
std::tuple<double, double> PyPlot::figaspect(const pybind11::tuple &args,
const pybind11::dict &kwargs) {
pybind11::list l = figaspect_attr(*args, **kwargs);
double width = l[0].cast<double>();
double height = l[1].cast<double>();
return {width, height};
}
// figure
figure::Figure PyPlot::figure(const pybind11::tuple &args,
const pybind11::dict &kwargs) {
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment