如何在macOS上使用非阻塞matplotlib(如IPython的%matplotlib)构建Python REPL



我正在用macOS编写一个终端REPL并且很难复制IPython的%matplotlib魔法获得的非阻塞matplotlib绘图行为。

考虑以下简单的 REPL(我在 macOS 10.12 上使用 Anaconda 的 Python 3.5):

#!/usr/bin/env pythonw
# Basic REPL (note: doesn't show output)
_globals = _locals = globals().copy()
while True:
    command = input(">>> ")
    res = exec(command, _globals, _locals)

pythonw是使情节正确聚焦所必需的。

如果在此外壳中运行

import matplotlib.pyplot as plt
plt.plot([1, 2])
plt.show()

它会阻止。 我试过了

import matplotlib
matplotlib.interactive(True)
import matplotlib.pyplot as plt
plt.plot([1, 2])

这不会阻止,但出现的绘图窗口完全没有响应。我什至无法关闭它。运行

import matplotlib.pyplot as plt
plt.plot([1, 2])
plt.show(block=False)

是一样的。

另一方面,如果你跑

%matplotlib
import matplotlib.pyplot as plt
plt.plot([1, 2])

在IPython 5.1.0中,它可以完美运行。REPL 不会阻塞,我可以与情节互动。

尝试阅读IPython源代码以找出我需要复制的内容,但是我无法弄清楚。我什至尝试过运行IPython.core.pylabtools.activate_matplotlib("MacOSX"),但它不起作用。

我发现IPython 4.2.1实际上做错了,这让我能够将IPython代码库一分为二并找到答案。

使用prompt-toolkit的IPython 5有一个特殊的输入钩子,它传递给prompt-toolkit的run_application eventloop参数。IPython的inputhook在IPython.terminal.pt_inputhooks.osx中定义。该代码对 macOS API 执行一堆ctypes调用(基本上,获取 GUI 事件循环)。

我不知道如何将它用于我的问题中的虚拟 REPL,但我实际上正在使用提示工具包,所以这对我来说很好。要使用它,请使用

from IPython.terminal.pt_inputhooks.osx import inputhook
from prompt_toolkit.shortcuts import create_eventloop
# <prompt-toolkit stuff>
... 
run_application(eventloop=create_eventloop(inputhook)

在导入matplotlib.pyplot之前,您仍然需要matplotlib.interactive(True)调用以使绘图自动显示(否则您必须一直调用plt.show(),更重要的是,绘图将阻塞)。

最新更新