8000 Add 3D line plot and zlabel function. · hypercode-go/matplotlib-cpp@811ebfb · GitHub
[go: up one dir, main page]

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 811ebfb

Browse files
brianphunglava
authored andcommitted
Add 3D line plot and zlabel function.
1 parent 9b23ca0 commit 811ebfb

File tree

4 files changed

+166
-1
lines changed

4 files changed

+166
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ WITHOUT_NUMPY := $(findstring $(CXXFLAGS), WITHOUT_NUMPY)
1515
# Examples requiring numpy support to compile
1616
EXAMPLES_NUMPY := surface
1717
EXAMPLES := minimal basic modern animation nonblock xkcd quiver bar \
18-
fill_inbetween fill update subplot2grid colorbar \
18+
fill_inbetween fill update subplot2grid colorbar lines3d \
1919
$(if WITHOUT_NUMPY,,$(EXAMPLES_NUMPY))
2020

2121
# Prefix every example with 'examples/build/'

examples/lines3d.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "../matplotlibcpp.h"
2+
3+
#include <cmath>
4+
5+
namespace plt = matplotlibcpp;
6+
7+
int main()
8+
{
9+
std::vector<double> x, y, z;
10+
double theta, r;
11+
double z_inc = 4.0/99.0; double theta_inc = (8.0 * M_PI)/99.0;
12+
13+
for (double i = 0; i < 100; i += 1) {
14+
theta = -4.0 * M_PI + theta_inc*i;
15+
z.push_back(-2.0 + z_inc*i);
16+
r = z[i]*z[i] + 1;
17+
x.push_back(r * sin(theta));
18+
y.push_back(r * cos(theta));
19+
}
20+
21+
std::map<std::string, std::string> keywords;
22+
keywords.insert(std::pair<std::string, std::string>("label", "parametric curve") );
23+
24+
plt::plot3(x, y, z, keywords);
25+
plt::xlabel("x label");
26+
plt::ylabel("y label");
27+
plt::set_zlabel("z label"); // set_zlabel rather than just zlabel, in accordance with the Axes3D method
28+
plt::legend();
29+
plt::show();
30+
}

examples/lines3d.png

74.7 KB
Loading

matplotlibcpp.h

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct _interpreter {
7474
PyObject *s_python_function_axvline;
7575
PyObject *s_python_function_xlabel;
7676
PyObject *s_python_function_ylabel;
77+
PyObject *s_python_function_gca;
7778
PyObject *s_python_function_xticks;
7879
PyObject *s_python_function_yticks;
7980
PyObject *s_python_function_tick_params;
@@ -208,6 +209,7 @@ struct _interpreter {
208209
s_python_function_axvline = safe_import(pymod, "axvline");
209210
s_python_function_xlabel = safe_import(pymod, "xlabel");
210211
s_python_function_ylabel = safe_import(pymod, "ylabel");
212+
s_python_function_gca = safe_import(pymod, "gca");
211213
s_python_function_xticks = safe_import(pymod, "xticks");
212214
s_python_function_yticks = safe_import(pymod, "yticks");
213215
s_python_function_tick_params = safe_import(pymod, "tick_params");
@@ -489,6 +491,88 @@ void plot_surface(const std::vector<::std::vector<Numeric>> &x,
489491
}
490492
#endif // WITHOUT_NUMPY
491493

494+
template <typename Numeric>
495+
void plot3(const std::vector<Numeric> &x,
496+
const std::vector<Numeric> &y,
497+
const std::vector<Numeric> &z,
498+
const std::map<std::string, std::string> &keywords =
499+
std::map<std::string, std::string>())
500+
{
501+
// Same as with plot_surface: We lazily load the modules here the first time
502+
// this function is called because I'm not sure that we can assume "matplotlib
503+
// installed" implies "mpl_toolkits installed" on all platforms, and we don't
504+
// want to require it for people who don't need 3d plots.
505+
static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
506+
if (!mpl_toolkitsmod) {
507+
detail::_interpreter::get();
508+
509+
PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
510+
PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
511+
if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); }
512+
513+
mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
514+
Py_DECREF(mpl_toolkits);
515+
if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); }
516+
517+
axis3dmod = PyImport_Import(axis3d);
518+
Py_DECREF(axis3d);
519+
if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); }
520+
}
521+
522+
assert(x.size() == y.size());
523+
assert(y.size() == z.size());
524+
525+
PyObject *xarray = get_array(x);
526+
PyObject *yarray = get_array(y);
527+
PyObject *zarray = get_array(z);
528+
529+
// construct positional args
530+
PyObject *args = PyTuple_New(3);
531+
PyTuple_SetItem(args, 0, xarray);
532+
PyTuple_SetItem(args, 1, yarray);
533+
PyTuple_SetItem(args, 2, zarray);
534+
535+
// Build up the kw args.
536+
PyObject *kwargs = PyDict_New();
537+
538+
for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
539+
it != keywords.end(); ++it) {
540+
PyDict_SetItemString(kwargs, it->first.c_str(),
541+
PyString_FromString(it->second.c_str()));
542+
}
543+
544+
PyObject *fig =
545+
PyObject_CallObject(detail::_interpreter::get().s_python_function_figure,
546+
detail::_interpreter::get().s_python_empty_tuple);
547+
if (!fig) throw std::runtime_error("Call to figure() failed.");
548+
549+
PyObject *gca_kwargs = PyDict_New();
550+
PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
551+
552+
PyObject *gca = PyObject_GetAttrString(fig, "gca");
553+
if (!gca) throw std::runtime_error("No gca");
554+
Py_INCREF(gca);
555+
PyObject *axis = PyObject_Call(
556+
gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
557+
558+
if (!axis) throw std::runtime_error("No axis");
559+
Py_INCREF(axis);
560+
561+
Py_DECREF(gca);
562+
Py_DECREF(gca_kwargs);
563+
564+
PyObject *plot3 = PyObject_GetAttrString(axis, "plot");
565+
if (!plot3) throw std::runtime_error("No 3D line plot");
566+
Py_INCREF(plot3);
567+
PyObject *res = PyObject_Call(plot3, args, kwargs);
568+
if (!res) throw std::runtime_error("Failed 3D line plot");
569+
Py_DECREF(plot3);
570+
571+
Py_DECREF(axis);
572+
Py_DECREF(args);
573+
Py_DECREF(kwargs);
574+
if (res) Py_DECREF(res);
575+
}
492576

493577
template<typename Numeric>
494578
bool stem(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
@@ -1662,6 +1746,57 @@ inline void ylabel(const std::string &str, const std::map<std::string, std::stri
16621746
Py_DECREF(res);
16631747
}
16641748

1749+
inline void set_zlabel(const std::string &str, const std::map<std::string, std::string>& keywords = {}) {
1750+
// Same as with plot_surface: We lazily load the modules here the first time
1751+
// this function is called because I'm not sure that we can assume "matplotlib
1752+
// installed" implies "mpl_toolkits installed" on all platforms, and we don't
1753+
// want to require it for people who don't need 3d plots.
1754+
static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
1755+
if (!mpl_toolkitsmod) {
1756+
detail::_interpreter::get();
1757+
1758+
PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
1759+
PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
1760+
if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); }
1761+
1762+
mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
1763+
Py_DECREF(mpl_toolkits);
1764+
if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); }
1765+
1766+
axis3dmod = PyImport_Import(axis3d);
1767+
Py_DECREF(axis3d);
1768+
if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); }
1769+
}
1770+
1771+
PyObject* pystr = PyString_FromString(str.c_str());
1772+
PyObject* args = PyTuple_New(1);
1773+
PyTuple_SetItem(args, 0, pystr);
1774+
1775+
PyObject* kwargs = PyDict_New();
1776+
for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1777+
PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1778+
}
1779+
1780+
PyObject *ax =
1781+
PyObject_CallObject(detail::_interpreter::get().s_python_function_gca,
1782+
detail::_interpreter::get().s_python_empty_tuple);
1783+
if (!ax) throw std::runtime_error("Call to gca() failed.");
1784+
Py_INCREF(ax);
1785+
1786+
PyObject *zlabel = PyObject_GetAttrString(ax, "set_zlabel");
1787+
if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found.");
1788+
Py_INCREF(zlabel);
1789+
1790+
PyObject *res = PyObject_Call(zlabel, args, kwargs);
1791+
if (!res) throw std::runtime_error("Call to set_zlabel() failed.");
1792+
Py_DECREF(zlabel);
1793+
1794+
Py_DECREF(ax);
1795+
Py_DECREF(args);
1796+
Py_DECREF(kwargs);
1797+
if (res) Py_DECREF(res);
1798+
}
1799+
16651800
inline void grid(bool flag)
16661801
{
16671802
PyObject* pyflag = flag ? Py_True : Py_False;

0 commit comments

Comments
 (0)
0