为什么matplotlib-cpp在3d例子中抛出运行时异常

42fyovps  于 2023-05-01  发布在  其他
关注(0)|答案(1)|浏览(341)

使用https://github.com/lava/matplotlib-cpp进行测试。我有Python 3。10.10,麻木1。24.2和matplotlib 3。7.1
matplotlib-cpp的作者不发布版本。我在2023-04-21使用了当前版本(提交ef 038)。
当我构建“surface”示例(根据作者的说明)并运行结果可执行文件时,我得到了以下内容:
terminate在抛出'std::runtime_error'的示例后调用what():No axis [1] 17416 IOT指令(内核转储)
github issues讨论中的报告似乎表明,有些人已经成功地运行了matplotlib-cpp示例。
对我来说,2D的例子似乎是可行的。然而,如上所述,3d示例全部失败。
我尝试了github issues讨论中建议的一些更改,但没有任何帮助。
编辑:这是来自GCC的回溯

(gdb) bt
#0 __pthread_kill_implementation (threadid=, signo=signo@entry=6, no_tid=no_tid@entry=0)
at pthread_kill.c:44
#1 0x00007ffff74a0953 in __pthread_kill_internal (signo=6, threadid=) at pthread_kill.c:78
#2 0x00007ffff7451ea8 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3 0x00007ffff743b53d in __GI_abort () at abort.c:79
#4 0x00007ffff769a833 in __gnu_cxx::__verbose_terminate_handler ()
at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/vterminate.cc:95
#5 0x00007ffff76a6d0c in __cxxabiv1::__terminate (handler=)
at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:48
#6 0x00007ffff76a6d79 in std::terminate () at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:58
#7 0x00007ffff76a6fdd in __cxxabiv1::__cxa_throw (obj=,
tinfo=0x555555562d60 <typeinfo for std::runtime_error@GLIBCXX_3.4>,
dest=0x7ffff76be480 std::runtime_error::~runtime_error())
at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_throw.cc:98
#8 0x000055555555a369 in matplotlibcpp::plot_surface (x=std::vector of length 41, capacity 64 = {...},
y=std::vector of length 41, capacity 64 = {...}, z=std::vector of length 41, capacity 64 = {...},
keywords=std::map with 0 elements, fig_number=0) at ../matplotlibcpp.h:567
#9 0x00005555555569e7 in main () at surface.cpp:22
o2g1uqev

o2g1uqev1#

发生的是matplotlib API自matplotlib-cpp上次更新以来发生了变化。
在最近的matplotlib版本中,没有将projection=3d传递给gca()函数。相反,应该显式地创建一个子图add_subplot(projection=3d)
附加的补丁修复了表面, Flutter ,和lines 3d的例子给我。
我已经分解出一段代码,将其剪切/粘贴在4个地方,并将其作为一个新函数。在该函数中,我实现了我所描述的修复。但是,我选择保留对gca()的调用,尽管我认为它是多余的。

diff --git a/matplotlibcpp.h b/matplotlibcpp.h
  index d95d46a..da7568d 100644
  --- a/matplotlibcpp.h
  +++ b/matplotlibcpp.h
  @@ -470,6 +470,31 @@ bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const st
       return res;
   }

  +//Given a figure, create a subplot with a 3d axis and return a pointer to that axis. also calls incref on the axis pointer.
  +PyObject* init_3d_axis(PyObject *fig)
  +{
  +  PyObject *asp_kwargs = PyDict_New();
  +  PyDict_SetItemString(asp_kwargs, "projection", PyString_FromString("3d"));
  +
  +  PyObject *asp = PyObject_GetAttrString(fig, "add_subplot");
  +  Py_INCREF(asp);
  +  PyObject *tmpax = PyObject_Call(asp, detail::_interpreter::get().s_python_empty_tuple, asp_kwargs);
  +  Py_INCREF(tmpax);
  +
  +  PyObject *gca = PyObject_GetAttrString(fig, "gca");
  +  if (!gca) throw std::runtime_error("No gca");
  +  Py_INCREF(gca);
  +  PyObject *axis = PyObject_Call(gca, detail::_interpreter::get().s_python_empty_tuple, detail::_interpreter::get().s_python_empty_tuple);
  +
  +  if (!axis) throw std::runtime_error("No axis");
  +  Py_INCREF(axis);
  +
  +  Py_DECREF(gca);
  +  Py_DECREF(tmpax);
  +  Py_DECREF(asp);
  +  return axis;
  +}
  +
   // TODO - it should be possible to make this work by implementing
   // a non-numpy alternative for `detail::get_2darray()`.
   #ifndef WITHOUT_NUMPY
  @@ -554,21 +579,8 @@ void plot_surface(const std::vector<::std::vector<Numeric>> &x,
     }
     Py_DECREF(fig_exists);
     if (!fig) throw std::runtime_error("Call to figure() failed.");
  -
  -  PyObject *gca_kwargs = PyDict_New();
  -  PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
  -
  -  PyObject *gca = PyObject_GetAttrString(fig, "gca");
  -  if (!gca) throw std::runtime_error("No gca");
  -  Py_INCREF(gca);
  -  PyObject *axis = PyObject_Call(
  -      gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
  -
  -  if (!axis) throw std::runtime_error("No axis");
  -  Py_INCREF(axis);
  -
  -  Py_DECREF(gca);
  -  Py_DECREF(gca_kwargs);
  +
  +  PyObject *axis = init_3d_axis(fig);

     PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface");
     if (!plot_surface) throw std::runtime_error("No surface");
  @@ -723,20 +735,7 @@ void plot3(const std::vector<Numeric> &x,
     }
     if (!fig) throw std::runtime_error("Call to figure() failed.");

  -  PyObject *gca_kwargs = PyDict_New();
  -  PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
  -
  -  PyObject *gca = PyObject_GetAttrString(fig, "gca");
  -  if (!gca) throw std::runtime_error("No gca");
  -  Py_INCREF(gca);
  -  PyObject *axis = PyObject_Call(
  -      gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
  -
  -  if (!axis) throw std::runtime_error("No axis");
  -  Py_INCREF(axis);
  -
  -  Py_DECREF(gca);
  -  Py_DECREF(gca_kwargs);
  +  PyObject *axis = init_3d_axis(fig);

     PyObject *plot3 = PyObject_GetAttrString(axis, "plot");
     if (!plot3) throw std::runtime_error("No 3D line plot");
  @@ -1126,20 +1125,7 @@ bool scatter(const std::vector<NumericX>& x,
     Py_DECREF(fig_exists);
     if (!fig) throw std::runtime_error("Call to figure() failed.");

  -  PyObject *gca_kwargs = PyDict_New();
  -  PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
  -
  -  PyObject *gca = PyObject_GetAttrString(fig, "gca");
  -  if (!gca) throw std::runtime_error("No gca");
  -  Py_INCREF(gca);
  -  PyObject *axis = PyObject_Call(
  -      gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
  -
  -  if (!axis) throw std::runtime_error("No axis");
  -  Py_INCREF(axis);
  -
  -  Py_DECREF(gca);
  -  Py_DECREF(gca_kwargs);
  +  PyObject *axis = init_3d_axis(fig);

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

  -  PyObject *gca_kwargs = PyDict_New();
  -  PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
  -
  -  PyObject *gca = PyObject_GetAttrString(fig, "gca");
  -  if (!gca) throw std::runtime_error("No gca");
  -  Py_INCREF(gca);
  -  PyObject *axis = PyObject_Call(
  -      gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs);
  -
  -  if (!axis) throw std::runtime_error("No axis");
  -  Py_INCREF(axis);
  -  Py_DECREF(gca);
  -  Py_DECREF(gca_kwargs);
  +  PyObject *axis = init_3d_axis(fig);

     //plot our boys bravely, plot them strongly, plot them with a wink and clap
     PyObject *plot3 = PyObject_GetAttrString(axis, "quiver");

相关问题