显示来自其他文件的 Matplotlib 图

Display Matplotlib plots from Other File

我有一个 PyQt 文件,点击一个按钮,运行来自另一个 python 文件(我们称之为 calc.py)的函数,该文件执行非常高级的计算并使用 matplotlib 来绘制结果。

我想在 PyQt window 中显示 calc.py 生成的这个图,计算后生成的是 complete/the 图。虽然,鉴于计算和数字是在另一个文件中进行的,我不确定执行此操作的最佳方法。

pyqt.py

import PyQt5 . . .
from calc import do_calc

class Window(QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.title_label = QLabel("Label Text", self)  #random label in top of window
            
        ###code here to display matplotlib plot in my PyQt app####

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

calc.py

import matplotlib.pyplot as plt
 
def do_calc():
   plt.figure()
   for i in x: 
      ...        #really complex calculation here
      plt.plot()

   plt.draw()

我一直在研究 other examples 如何在 Qt 中显示 matplotlib 图,但它们通常围绕着 PyQt 文件或小部件 class 中进行的计算进行定位,我真的不能在这种情况下做。我可以将 calc.py 文件更改为 return 项目或做任何其他可能有用的事情,但计算可能需要保留在该文件中,因此它可以 运行 独立于 PyQt

解决方案是 hack(将来可能会失败),假设 calc.py 中 matplotlib 使用的后端使用 PyQt5,为此需要先导入 PyQt5,然后 calc.py .

逻辑是使用 plt.ion 让 matplotlib 不阻塞事件循环,然后在以 FigureCanvas 作为其 centralWidget 的顶层 (windows) 中搜索。

calc.py

import matplotlib.pyplot as plt
import numpy as np


def do_calc():
    t = np.arange(0.0, 2.0, 0.01)
    s = 1 + np.sin(2 * np.pi * t)

    fig, ax = plt.subplots()
    ax.plot(t, s)

    ax.set(
        xlabel="time (s)",
        ylabel="voltage (mV)",
        title="About as simple as it gets, folks",
    )
    ax.grid()
    plt.show()

main.py

import sys

from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget

import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvas

from calc import do_calc



class Window(QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.title_label = QLabel("Label Text")

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        lay = QVBoxLayout(central_widget)
        lay.addWidget(self.title_label)

        plt.ion()
        do_calc()

        for tl in QApplication.topLevelWidgets():
            if isinstance(tl, QMainWindow) and isinstance(
                tl.centralWidget(), FigureCanvas
            ):
                lay.addWidget(tl)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

另一个更好的选择是获得所有数字,然后是 canvas,最后是那个 canvas 的 window:

class Window(QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.title_label = QLabel("Label Text")

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        lay = QVBoxLayout(central_widget)
        lay.addWidget(self.title_label)

        plt.ion()
        do_calc()

        for i in plt.get_fignums():
            canvas = plt.figure(i).canvas
            if isinstance(canvas, QWidget):
                lay.addWidget(canvas.window())