Skip to content

Commit 59d32ec

Browse files
committed
Backport the following fixes:
- "why does matplotlib-cpp throw runtime exceptions in the 3d examples": https://stackoverflow.com/questions/76077363/why-does-matplotlib-cpp-throw-runtime-exceptions-in-the-3d-examples - "fix: update api to support matplotlib-3.7.1 version lava#352": lava#352
1 parent 235d114 commit 59d32ec

File tree

1 file changed

+47
-2
lines changed

1 file changed

+47
-2
lines changed

matplotlibcpp.h

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,33 @@ bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const st
470470
return res;
471471
}
472472

473+
// FIXME: <https://stackoverflow.com/questions/76077363/why-does-matplotlib-cpp-throw-runtime-exceptions-in-the-3d-examples>
474+
//Given a figure, create a subplot with a 3d axis and return a pointer to that axis. also calls incref on the axis pointer.
475+
PyObject* init_3d_axis(PyObject *fig)
476+
{
477+
PyObject *asp_kwargs = PyDict_New();
478+
PyDict_SetItemString(asp_kwargs, "projection", PyString_FromString("3d"));
479+
480+
PyObject *asp = PyObject_GetAttrString(fig, "add_subplot");
481+
Py_INCREF(asp);
482+
PyObject *tmpax = PyObject_Call(asp, detail::_interpreter::get().s_python_empty_tuple, asp_kwargs);
483+
Py_INCREF(tmpax);
484+
485+
PyObject *gca = PyObject_GetAttrString(fig, "gca");
486+
if (!gca) throw std::runtime_error("No gca");
487+
Py_INCREF(gca);
488+
PyObject *axis = PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, detail::_interpreter::get().s_python_empty_tuple);
489+
490+
if (!axis) throw std::runtime_error("No axis");
491+
Py_INCREF(axis);
492+
493+
Py_DECREF(gca);
494+
Py_DECREF(tmpax);
495+
Py_DECREF(asp);
496+
return axis;
497+
}
498+
499+
473500
// TODO - it should be possible to make this work by implementing
474501
// a non-numpy alternative for `detail::get_2darray()`.
475502
#ifndef WITHOUT_NUMPY
@@ -555,6 +582,8 @@ void plot_surface(const std::vector<::std::vector<Numeric>> &x,
555582
Py_DECREF(fig_exists);
556583
if (!fig) throw std::runtime_error("Call to figure() failed.");
557584

585+
PyObject *axis = init_3d_axis(fig);
586+
/*
558587
PyObject *gca_kwargs = PyDict_New();
559588
PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
560589
@@ -569,6 +598,7 @@ void plot_surface(const std::vector<::std::vector<Numeric>> &x,
569598
570599
Py_DECREF(gca);
571600
Py_DECREF(gca_kwargs);
601+
*/
572602

573603
PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface");
574604
if (!plot_surface) throw std::runtime_error("No surface");
@@ -723,6 +753,8 @@ void plot3(const std::vector<Numeric> &x,
723753
}
724754
if (!fig) throw std::runtime_error("Call to figure() failed.");
725755

756+
PyObject *axis = init_3d_axis(fig);
757+
/*
726758
PyObject *gca_kwargs = PyDict_New();
727759
PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
728760
@@ -737,6 +769,7 @@ void plot3(const std::vector<Numeric> &x,
737769
738770
Py_DECREF(gca);
739771
Py_DECREF(gca_kwargs);
772+
*/
740773

741774
PyObject *plot3 = PyObject_GetAttrString(axis, "plot");
742775
if (!plot3) throw std::runtime_error("No 3D line plot");
@@ -1126,6 +1159,8 @@ bool scatter(const std::vector<NumericX>& x,
11261159
Py_DECREF(fig_exists);
11271160
if (!fig) throw std::runtime_error("Call to figure() failed.");
11281161

1162+
PyObject *axis = init_3d_axis(fig);
1163+
/*
11291164
PyObject *gca_kwargs = PyDict_New();
11301165
PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
11311166
@@ -1140,6 +1175,7 @@ bool scatter(const std::vector<NumericX>& x,
11401175
11411176
Py_DECREF(gca);
11421177
Py_DECREF(gca_kwargs);
1178+
*/
11431179

11441180
PyObject *plot3 = PyObject_GetAttrString(axis, "scatter");
11451181
if (!plot3) throw std::runtime_error("No 3D line plot");
@@ -1503,6 +1539,8 @@ bool quiver(const std::vector<NumericX>& x, const std::vector<NumericY>& y, cons
15031539
detail::_interpreter::get().s_python_empty_tuple);
15041540
if (!fig) throw std::runtime_error("Call to figure() failed.");
15051541

1542+
PyObject *axis = init_3d_axis(fig);
1543+
/*
15061544
PyObject *gca_kwargs = PyDict_New();
15071545
PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
15081546
@@ -1516,6 +1554,7 @@ bool quiver(const std::vector<NumericX>& x, const std::vector<NumericY>& y, cons
15161554
Py_INCREF(axis);
15171555
Py_DECREF(gca);
15181556
Py_DECREF(gca_kwargs);
1557+
*/
15191558

15201559
//plot our boys bravely, plot them strongly, plot them with a wink and clap
15211560
PyObject *plot3 = PyObject_GetAttrString(axis, "quiver");
@@ -2526,7 +2565,7 @@ inline void set_zlabel(const std::string &str, const std::map<std::string, std::
25262565
if (res) Py_DECREF(res);
25272566
}
25282567

2529-
inline void grid(bool flag)
2568+
inline void grid(bool flag, const std::map<std::string, std::string>& keywords = std::map<std::string, std::string>())
25302569
{
25312570
detail::_interpreter::get();
25322571

@@ -2536,10 +2575,16 @@ inline void grid(bool flag)
25362575
PyObject* args = PyTuple_New(1);
25372576
PyTuple_SetItem(args, 0, pyflag);
25382577

2539-
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
2578+
PyObject* kwargs = PyDict_New();
2579+
for (auto it = keywords.begin(); it != keywords.end(); ++it) {
2580+
PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
2581+
}
2582+
2583+
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_grid, args, kwargs);
25402584
if(!res) throw std::runtime_error("Call to grid() failed.");
25412585

25422586
Py_DECREF(args);
2587+
Py_DECREF(kwargs);
25432588
Py_DECREF(res);
25442589
}
25452590

0 commit comments

Comments
 (0)