@@ -74,6 +74,7 @@ struct _interpreter {
74
74
PyObject *s_python_function_axvline;
75
75
PyObject *s_python_function_xlabel;
76
76
PyObject *s_python_function_ylabel;
77
+ PyObject *s_python_function_gca;
77
78
PyObject *s_python_function_xticks;
78
79
PyObject *s_python_function_yticks;
79
80
PyObject *s_python_function_tick_params;
@@ -208,6 +209,7 @@ struct _interpreter {
208
209
s_python_function_axvline = safe_import (pymod, " axvline" );
209
210
s_python_function_xlabel = safe_import (pymod, " xlabel" );
210
211
s_python_function_ylabel = safe_import (pymod, " ylabel" );
212
+ s_python_function_gca = safe_import (pymod, " gca" );
211
213
s_python_function_xticks = safe_import (pymod, " xticks" );
212
214
s_python_function_yticks = safe_import (pymod, " yticks" );
213
215
s_python_function_tick_params = safe_import (pymod, " tick_params" );
@@ -489,6 +491,88 @@ void plot_surface(const std::vector<::std::vector<Numeric>> &x,
489
491
}
490
492
#endif // WITHOUT_NUMPY
491
493
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
+ }
492
576
493
577
template <typename Numeric>
494
578
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
1662
1746
Py_DECREF (res);
1663
1747
}
1664
1748
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
+
1665
1800
inline void grid (bool flag)
1666
1801
{
1667
1802
PyObject* pyflag = flag ? Py_True : Py_False;
0 commit comments