Matplotlib 交互式事件循环 [英] Matplotlib interactive event loops

查看:57
本文介绍了Matplotlib 交互式事件循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How does Matplotlib set up the event loop for backend libraries such as Qt while still allowing interaction via the python REPL? At least for Qt the main event loop must run in the main thread, but that's where the REPL is, right, so I'm struggling to see how the two can coexist.

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

My current attempt starts a QApplication in a separate Python 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()

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

which sort-of works, but I get this warning and it sometimes crashes:

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

基本上,我想模拟以下 交互式 python 会话,也就是说,不将其作为脚本运行以呈现现成的 GUI.阻止图形窗口外观阻止python解释器的魔术是什么?

Update 2

Basically, I want to emulate the following interactive python session, that is, not running it as a script to present a ready made GUI. What is the magic that keeps the appearance of the figure window from blocking the python interpreter?

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]: 

推荐答案

魔术不是由 Matplotlib 完成的,而是由 IPython 完成的,在一个实际称为

The magic is not done by Matplotlib but by IPython, in an actually called magic command.

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

If you start IPython with ipython --gui=qt, or type %gui qt, the Qt event loop will be started and integrated into IPython (the --matplotlib option does this as well but for the default backend). After that you can just create widgets on the command line without having to start the event loop.

~> 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_()

关于

There is a short section on Integrating with GUI event loop that explains how this works under the hood. But just to be clear, you don't have to follow those instructions because event loop integration has already been implemented for Qt. Just use the %gui qt magic-command.

更新

所以确实你也可以在没有 IPython 的情况下做到这一点.如使用 Python Shell 中的 PyQt5 来自 PyQt 参考指南.

So indeed you can do this without IPython as well. PyQt makes it possible to have both a regular Python shell and a running event loop simultaneously, as explained in the section on Using PyQt5 from the Python Shell from the PyQt reference guide.

与众不同之处在于,您需要自己明确创建 QApplication .例如类型:

Small difference is that you need to explicitly create the QApplication yourself. For instance type:

~> 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一起使用,并在 pyplot的源代码.在我看来,Matplotlib可以处理这两种情况.当您执行 plt.ion()时,将调用 install_repl_displayhook 函数.它的文档字符串说:

I was wondering how this works with Matplotlib and looked around a bit in the source code of pyplot. It seems to me that Matplotlib can handle both situations. When you execute plt.ion() a install_repl_displayhook function is called. Its doc-string says:

安装一个 repl 显示钩子,以便自动显示任何陈旧的图形当控制返回到 repl 时重绘.这适用于IPython终端和内核以及香草python壳.

Install a repl display hook so that any stale figure are automatically redrawn when control is returned to the repl. This works with IPython terminals and kernels, as well as vanilla python shells.

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

So, even though IPython is not a dependency of Matplotlib, Matplotlib is aware of IPython and can detect if it is in the IPython shell or in a regular Python shell.

这篇关于Matplotlib 交互式事件循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆