@@ -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
493577template <typename Numeric>
494578bool 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+
16651800inline void grid (bool flag)
16661801{
16671802 PyObject* pyflag = flag ? Py_True : Py_False;
0 commit comments