将 matplotlib 图表嵌入 Qt/C++ 应用程序

Posted

技术标签:

【中文标题】将 matplotlib 图表嵌入 Qt/C++ 应用程序【英文标题】:Embedding a matplotlib chart into Qt/C++ application 【发布时间】:2013-09-07 23:40:11 【问题描述】:

我正在使用 Qt/C++ 开发一个面向数学的 GUI 应用程序,并希望嵌入一个 Python 脚本,包括 NumPy 和 Matplotlib。使用 Python C API,我终于设法运行脚本,从 Python 变量中检索值,包括 NumPy 数组等。但我未能将 Matplotlib 图表绘制到我的 Qt/C++ 应用程序中。

最好说,我已经设法使用 Python 脚本将图表的 RGBA 缓冲区保存到变量中,然后将变量的值作为缓冲区类型的 PyObject 获取,获取缓冲区并将其转换为 QImage,然后转换为 QPixmap最后放入QLabel中显示出来。

但我仍然错过了它的交互行为、调整大小等。虽然它似乎可以通过将 Qt 鼠标事件转发到 figure.canvas.button_press_event 来完成,但它变得过于复杂......所以我得出结论我没有充分了解 Python 嵌入的原理。我遗漏了一些明显的东西。

我发现了一些将 matplotlib 图表嵌入到 PyQt 或 PySide(即用 Python 编写)应用程序中的示例,在这些应用程序中我看到了 QMainWindow.setCentralWidget(canvas) 或 layout.addWidget(canvas) 之类的东西。这里的画布是 FigureCanvasQTAgg 对象(http://matplotlib.org/api/backend_qt4agg_api.html)。

这表明画布继承自 QWidget。但是当我尝试使用 Python 的 C API 在 C++ 代码中模仿这一点时,我只以 PyObject *canvas 结束,不知道如何将其转换为 QWidget。这是我的 sn-p 没有重要步骤:

//draw a figure in Python script called from C++ app
PyRun_SimpleString("import matplotlib\n"
"matplotlib.use('Qt4agg')\n" //use Qt4 backend
"import pylab\n"
"pylab.plot(randn(10))\n" //plot something
"fig = pylab.gcf()\n" //take current figure
"canvas = fig.canvas" //canvas is of FigureCanvasQTAgg type

//get canvas as PyObject
PyObject* m = PyImport_AddModule("__main__");
PyObject* canvas = PyObject_GetAttrString(m, "canvas");
//from what I know, canvas is a PyObject wrapped around an object derived from QWidget

//...
//... here I do not know how to convert canvas (i.e. PyObject) into canvasWidget (i.e. QWidget)???
//... 

//show chart as a widget
MyWindow.setCentralWidget(canvasWidget)

正如我所写,我一定遗漏了一些明显的东西。我到处搜索,但没有成功。任何帮助将不胜感激。

【问题讨论】:

这是一个奇怪的问题,你想在 c++ 中包装一个 c++ 类的 python 包装器;) 你是正确的 FigureCanvasQTAgg 一个 QWidget 对象,但我也不太了解嵌入以获取对底层 QT 对象的引用。 tcaswell - 是的,这正是我需要的 - 从 PyObject 中提取引用或指针或任何 QWidget。 我唯一的建议是看看PyQtPySide到底在做什么。 发布的答案能解决您的问题吗? 抱歉,没有及时回复,感谢您的耐心等待。我将检查建议的解决方案。然而,我决定否则并选择了最安全的方式,并将我的整个应用程序重新设计为纯 Python+PyQt 应用程序,与 Qt/C++ 相比,它可能存在一些性能缺陷,但到目前为止它似乎令人满意。无论如何,出于好奇,我会测试你和 bks 的建议。感谢您的帮助。 【参考方案1】:

对于 PySide,我建议阅读 this comp.lib.qt.pyside thread 以及 PySide 文档中关于 type converters 的部分。我不能保证this code 的绝对正确性,但它似乎可以满足您的要求。

对于 PyQt,the same comp.lib.qt.pyside thread 链接到 unwrapping SIP objects 的示例,这正是您所需要的。

【讨论】:

你能总结一下链接的内容吗?它们看起来是正确的,但是链接会腐烂,从而降低了此答案的长期有用性。

以上是关于将 matplotlib 图表嵌入 Qt/C++ 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Matplotlib 将图形嵌入到 UI PyQt5

将 NetworkX 图嵌入 PyQT 小部件

如何修改此代码,以便我不会每次都重新绘制图表,matplotlib

5 matplotlib-绘制精美的图表

用PyQtGraph绘制可视化数据图表

Python图表绘制:matplotlib绘图库入门