【问题标题】:Matplotlib interactive event loopsMatplotlib 交互式事件循环
【发布时间】:2018-01-21 16:57:58
【问题描述】:

Matplotlib 如何为 Qt 等后端库设置事件循环,同时仍允许通过 python REPL 进行交互?至少对于 Qt 来说,主事件循环必须在主线程中运行,但这就是 REPL 所在的地方,对,所以我正在努力看看这两者如何共存。

我当前的尝试在单独的 Python 中启动 QApplication threading.Thread

def mainloop():
    app = QtWidgets.QApplication([])
    while True:
        app.processEvents()
        time.sleep(0.01)
t = threading.Thread(target=mainloop)
t.daemon = True
t.start()

哪种方法有效,但我收到此警告,有时会崩溃:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QApplication(0x7fc5cc001820), parent's thread is QThread(0x7fc5cc001a40), current thread is QThread(0x2702160)

更新 1

这是使用QThread的尝试:

from PyQt5 import QtGui, QtCore, QtWidgets
import time

class Mainloop(QtCore.QObject):
    def __init__(self):
        super().__init__()
        self.app = QtWidgets.QApplication([])

    def run(self):
        while True:
            self.app.processEvents()
            time.sleep(1)

t = QtCore.QThread()
m = Mainloop()
m.moveToThread(t)
t.started.connect(m.run)
t.start()

# Essentially I want to be able to interactively build a GUI here
dialog = QtWidgets.QDialog()
dialog.show()

更新 2

基本上,我想模拟以下 interactive python 会话,即不将其作为脚本运行以呈现现成的 GUI。是什么让图形窗口的外观不阻塞python解释器?

Python 2.7.13 (default, Jan 19 2017, 14:48:08) 
Type "copyright", "credits" or "license" for more information.

IPython 5.2.2 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import matplotlib.pyplot as plt

In [2]: plt.ion()

In [3]: fig = plt.figure()

In [4]: # The last command opens a figure window which remains responsive.
   ...:  I can resize it and the window redraws, yet I can still interact 
   ...: with the python interpreter and interactively add new content to t
   ...: he figure

In [5]: ax = fig.add_subplot(111)

In [6]: # The last command updated the figure window and I can still inter
   ...: act with the interpreter

In [7]: 

【问题讨论】:

  • 感谢您的回复。忘了提到我还使用app.exec_() 尝试了不同的版本。不知道我是否误会了什么。我没有使用 app.exec_() 的原因是因为它会在 Qt 主事件循环中阻止 python REPL。你能解释一下为什么这应该有效吗?
  • 我尝试使用 QThread 更新了问题。我可以在 Update 1 中运行代码而不会出现错误,但是 QDialog 没有响应,也就是说,当我调整窗口大小时它不会重新绘制窗口,所以我猜 Qt 事件没有处理事件循环。

标签: python matplotlib pyqt


【解决方案1】:

魔术不是由 Matplotlib 完成的,而是由 IPython 完成的,实际上称为 magic command

如果您使用ipython --gui=qt 启动IPython,或键入%gui qt,Qt 事件循环将启动并集成到IPython 中(--matplotlib 选项也可以执行此操作,但用于默认后端)。之后,您可以在命令行上创建小部件,而无需启动事件循环。

~> ipython
Python 3.5.3 |Continuum Analytics, Inc.| (default, Mar  6 2017, 12:15:08)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: %gui qt

In [2]: from PyQt5 import QtWidgets

In [3]: win = QtWidgets.QPushButton("click me")

In [4]: win.show()

In [5]: win.raise_()

Integrating with GUI event loop 上有一个简短的部分解释了它是如何在幕后工作的。但为了清楚起见,您不必遵循这些说明,因为已经为 Qt 实现了事件循环集成。只需使用 %gui qt 魔法命令即可。

更新

所以实际上你也可以在没有 IPython 的情况下做到这一点。 PyQt 使得同时拥有常规 Python shell 和运行事件循环成为可能,如 PyQt 参考指南中的 Using PyQt5 from the Python Shell 部分所述。

小区别是您需要自己显式创建QApplication。例如类型:

~> python
Python 3.6.0 |Continuum Analytics, Inc.| (default, Dec 23 2016, 13:19:00)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from PyQt5.QtWidgets import QApplication, QWidget
>>> a = QApplication([])
>>> w = QWidget()
>>> w.show()
>>> w.raise_()

我想知道这如何与 Matplotlib 一起工作,并在 the source code of pyplot 中查看了一下。在我看来,Matplotlib 可以处理这两种情况。当您执行plt.ion() 时,会调用install_repl_displayhook 函数。它的文档字符串说:

安装一个 repl 显示挂钩,以便自动显示任何陈旧的图形 当控制权返回给 repl 时重绘。这适用于 IPython 终端和内核,以及原版 python shell。

因此,即使 IPython 不是 Matplotlib 的依赖项,Matplotlib 也知道 IPython 并且可以检测它是在 IPython shell 中还是在常规 Python shell 中。

【讨论】:

  • 感谢您的链接,但我不明白这是完整的答案。 matplotlib 不是 ipython 的依赖项,不是相反吗?因为我可以在带有 matplotlib 的常规 python shell 中运行上面更新 2 中的代码,但没有安装 ipython,所以我看不出 IPython 中的所有魔法是如何发生的?
猜你喜欢
  • 2015-08-20
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多