在同一进程中将 matplotlib 与 Qt5 后端一起使用并运行现有 QApplication

Posted

技术标签:

【中文标题】在同一进程中将 matplotlib 与 Qt5 后端一起使用并运行现有 QApplication【英文标题】:Using matplotlib with Qt5 backend with an existing QApplication running, in the same process 【发布时间】:2020-01-08 10:36:33 【问题描述】:

我们有一个使用 PySide2 的 Qt5 应用程序。最近,我们想在 PySide2 应用程序在同一进程中(在不同的线程中)运行时使用 matplotlib 显示绘图,但随后 matplotlib 崩溃(使用 PySide2 时)或在绘图前冻结(使用 PyQt5 时)。

这是一个最小示例,取消注释第 23 行以使 matplotlib 崩溃或冻结:

from threading import Thread

from PySide2.QtWidgets import QApplication, QLabel

import matplotlib
matplotlib.use('QT5Agg')
import matplotlib.pyplot as plt


def start_qt_app():
    t = Thread(target=qt_app_thread_func)
    t.start()


def qt_app_thread_func():
    app = QApplication()
    label = QLabel("Hello World")
    label.show()
    app.exec_()


# Uncomment the line below to make matplotlib crash.
#start_qt_app()

plt.plot([1, 2, 3, 4])
plt.show()

input("Press enter to quit.")

print("Finished.")

我的猜测是,这与我们只能在一个进程中运行 1 个 QApplication 的限制有关。所以这会导致 matplotlib 出现问题。

我该如何解决这个问题?我想到的一个解决方案是为 matplotlib 创建一个代理对象,该对象在另一个进程中运行 matplotlib,但我不确定这是否是劳动强度最低的解决方案。也许我可以让 matplotlib 使用现有的 QApplication?我无法在另一个进程中运行我们的 PySide2 应用程序,因为它使用动态创建的 numpy 数组从主线程传递到 GUI,并且在另一个进程中启动它会降低性能。

【问题讨论】:

Matplotlib,就像任何其他 GUI 必须在主线程中运行一样。 在此回答***.com/questions/59501454/… 【参考方案1】:

您应该使用 asyncqt 来管理 ui 和应用程序线程。从 asyncqt QEventLoop 是您可以使用的一种方式

await loop.run_in_executor(exec, method_name)

asyncqt 是 quamash 为 PyQt5 编写的衍生库。示例代码相同。因此,根据您的喜好,您可以使用带有 PySide2 的 asyncqt 或带有 PyQt5 的 quamash 来让您的应用在后台任务运行时做出响应。

asyncqt examples

asyncqt 0.7.0 pypi

Quamash 0.6.1

【讨论】:

【参考方案2】:

正如@ImportanceOfBeingErnest 指出的那样,matplotlib 可以与 Qt 一起使用,如官方示例所示:Embedding in Qt。

例子:

from PySide2.QtWidgets import QApplication, QLabel

import matplotlib
matplotlib.use('QT5Agg')

from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure

if __name__ == '__main__':
    app = QApplication()

    label = QLabel("Hello World")
    label.show()

    canvas = FigureCanvas(Figure(figsize=(5, 3)))
    ax = canvas.figure.subplots()
    ax.plot([1, 2, 3, 4])

    canvas.show()

    app.exec_()

【讨论】:

以上是关于在同一进程中将 matplotlib 与 Qt5 后端一起使用并运行现有 QApplication的主要内容,如果未能解决你的问题,请参考以下文章

Matplotlib植入PyQt5 + QT5的UI呈现

Qt5 应用程序中的 matplotlib RectangleSelector 图形故障

在 Matplotlib 3.1.2 中使用 qt5agg 后端,get_backend() 会改变行为

带有 Qt5Agg 后端的 matplotlib 返回空的刻度标签

未找到 Matplotlib Qt5Agg 后端

『Python』matplotlib共享绘图区域坐标轴