Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

+1-1
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

+30
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

+135
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)