出口matplotlib上的PyQt分段错误

时间:2016-10-12 20:53:43

标签: matplotlib pyqt4

我正在使用PyQt4和matplotlib制作一个gui。我发现this非常有用的问题/答案,我正在尝试使用标签式gui窗口。一切似乎都很好(有一些小的调整);但是,每当我关闭主窗口时,我都会出现“Python意外退出”错误以及分段错误。虽然这不会影响程序的运行,但它很烦人,我想解决这个问题。

现在,在试图弄清楚发生了什么的时候,我得到了下面的MWE(或者如果你愿意的话,最小的例子)

import sys

import matplotlib
matplotlib.use('Qt4agg')

import matplotlib.pyplot as plt

import numpy as np

from PyQt4 import QtCore
from PyQt4 import QtGui as qt


if __name__ == "__main__":

    fig = plt.figure()

    x, y = np.random.randn(2, 40)

    ax = fig.add_subplot(111)

    ax.plot(x, y, 'o')    

    ax.hold(False)

    app = qt.QApplication(sys.argv)

    # ui = MplMultiTab(figures=[fig], labels=["yay"])

    ui = qt.QMainWindow()
    ui.main_frame = qt.QWidget()

    vbox = qt.QVBoxLayout()

    vbox.addWidget(fig.canvas)

    ui.main_frame.setLayout(vbox)
    ui.setCentralWidget(ui.main_frame)

    ui.show()

    sys.exit(app.exec_())

问题似乎是将图形画布添加到窗口,好像我不这样做而是制作一个空的gui(删除vbox.addWidget(fig.canvas))一切都很好并且没有段错误。

任何人都可以看到出现问题或是matplotlib或pyqt中的错误吗?同样有趣的是,如果我设置我的gui类似于this answer,那么我没有分段错误,但我无法弄清楚它们之间的区别是什么。

对于每个人的信息,我在python 3.5.2上使用Pyxt verion 4.11.4和OSX 10.11.6上的matplotlib 1.5.3版运行它。

1 个答案:

答案 0 :(得分:3)

PyQt documentation中所述:

  

对于使用Qt的任何GUI应用程序,无论应用程序在任何给定时间是否具有0,1,2或更多窗口,都只有一个QApplication对象。

我认为这里最有可能发生的是QApplication在生成数字时由pyplot静默创建。此QApplication用于管理FigureManager的主事件循环,这是由pyplot创建的GUI,用于在屏幕上显示图形。

因此,由于已经使用pyplot创建了QApplication,我认为在代码中进一步调用qt.QApplication(sys.argv)时通常会引发错误,但有些Qt似乎没有看到并允许创建另一个QApplication。这可能是在尝试关闭应用程序时导致冲突的原因。我看到3个不同的选项来解决这个问题:

1 - 将pyplot代码放入QApplication中,以便pyplot看到它并使用它而不是构建自己的代码:

import sys
import matplotlib
matplotlib.use('Qt4agg')
import matplotlib.pyplot as plt
import numpy as np
from PyQt4 import QtGui as qt

if __name__ == '__main__':

    app = qt.QApplication(sys.argv)

    fig, ax = plt.subplots()
    x, y = np.random.randn(2, 40)
    ax.plot(x, y, 'o')

    ui = qt.QWidget()
    vbox = qt.QVBoxLayout()
    vbox.addWidget(fig.canvas)
    ui.setLayout(vbox)
    ui.show()

    sys.exit(app.exec_())

2 - 使用指向已由pyplot构建的QApplication的指针,而不是创建一个新指针:

import sys
import matplotlib
matplotlib.use('Qt4agg')
import matplotlib.pyplot as plt
import numpy as np
from PyQt4 import QtGui as qt

if __name__ == '__main__':

    fig, ax = plt.subplots()
    x, y = np.random.randn(2, 40)
    ax.plot(x, y, 'o')

    app = qt.QApplication.instance()

    ui = qt.QWidget()
    vbox = qt.QVBoxLayout()
    vbox.addWidget(fig.canvas)
    ui.setLayout(vbox)
    ui.show()

    sys.exit(app.exec_())

3 - 正如matplotlib documentation中所建议的那样,在Qt接口中嵌入mpl图时避免使用pyplot接口,而是使用面向对象的API。在这种情况下,您的MWE可以重写为:

import sys
import matplotlib
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
import numpy as np
from PyQt4 import QtGui as qt

if __name__ == '__main__':

    app = qt.QApplication(sys.argv)

    fig = matplotlib.figure.Figure()
    canvas = FigureCanvasQTAgg(fig)
    ax = fig.add_subplot(111)
    x, y = np.random.randn(2, 40)
    ax.plot(x, y, 'o')

    ui = qt.QWidget()
    vbox = qt.QVBoxLayout()
    vbox.addWidget(canvas)
    ui.setLayout(vbox)
    ui.show()

    sys.exit(app.exec_())