Jupyter笔记本中的阻塞,互动情节

时间:2017-11-03 17:08:19

标签: python matplotlib jupyter-notebook

我正试图从Jupyter笔记本中获取一个交互式,阻止matplotlib窗口。也就是说,我希望matplotlib窗口出现并在笔记本中执行以暂停直到它关闭。但是我的代码的各种合理看似的排列似乎都不起作用。

以下产生预期结果:

%matplotlib
import matplotlib.pyplot as plt

a=[1,2,3]
b=[4,5,6]

plt.figure()
plt.plot(a,b)
plt.show(block=True)
print("hi")

只有一次。如果代码第二次运行,内核似乎会锁定,我必须重新启动它,这对我的应用程序来说是不行的。

以下备选方案产生了一个交互式窗口,但代码直接进入print语句而不等待窗口关闭:

%matplotlib
import matplotlib.pyplot as plt

a=[1,2,3]
b=[4,5,6]

plt.figure()
plt.plot(a,b)
plt.show()
print("hi")

我得到了相同的结果:

%matplotlib
import matplotlib.pyplot as plt

a=[1,2,3]
b=[4,5,6]

plt.figure()
plt.plot(a,b)
plt.ioff()
plt.show()
print("hi")

%matplotlib
import matplotlib.pyplot as plt

a=[1,2,3]
b=[4,5,6]

plt.figure()
plt.plot(a,b)
plt.ion()
plt.show()
print("hi")

我怎样才能实现这个目标? (目标是在交互式matplotlib窗口关闭之后才执行print("hi")。)

(我使用的是Python 3.5.3和Jupyter笔记本服务器5.0.0。)

2 个答案:

答案 0 :(得分:1)

我猜你无法阻止中间一个单元格的执行。但是,注释中描述的用例似乎允许处理图本身的事件循环中的所有内容。

# cell 1:
%matplotlib
import matplotlib.pyplot as plt
import numpy as np

class InterAct():
    def __init__(self):
        self.fig, self.ax = plt.subplots()
        self.ax.axis([0,1,0,1])
        self.ax.set_title("Click to choose points, close to proceed")
        self.plot, = self.ax.plot([],[], color="crimson", ls="", marker="o")
        self.points = []
        self.fig.canvas.mpl_connect("button_press_event", self.select_point)
        self.fig.canvas.mpl_connect("close_event", self.process)
        plt.show()

    def select_point(self, event):
        self.points.append((event.xdata,event.ydata))
        x,y = list(zip(*self.points))
        self.plot.set_data(x,y)
        self.fig.canvas.draw_idle()

    def process(self, event):
        points = np.array(self.points)
        mean = points.mean(axis=0)
        r = np.sqrt(np.sum((points-mean)**2, axis=1)).max()

        self.fig2, self.ax2 = plt.subplots()
        self.ax2.axis([0,1,0,1])
        self.ax2.set_title("The result is:")
        poly = plt.Polygon(points, edgecolor="C0", fill=True, alpha=0.5)
        circ = plt.Circle(mean, r, color="crimson", fill=False)
        self.ax2.add_patch(circ)
        self.ax2.add_patch(poly)

        self.fig2.show()
        #plt.show()

然后

# cell 2
i = InterAct()

这将首先显示一个matplotlib图,用户可以交互式地执行某些操作(在这种情况下单击以选择点)。然后,当用户关闭图形时,将处理这些点并显示带有结果的新图形。

答案 1 :(得分:1)

如果有人在窗口关闭之前寻找“阻塞执行”,这里有一个简单的解决方案。将此代码放在一个单元格中。

# Provided the backend is interactive
# e.g. %matplotlib qt5
fig = plt.figure()
plt.show()

try:
    while fig.number in plt.get_fignums():
        plt.pause(0.1)
except:
    plt.close(fig.number)
    raise

print("hi!")

此代码段中的循环一直等到当前图形出现在活动图形列表中。当用户关闭图形窗口时,其编号从 plt.get_fignums() 返回的列表中消失。

为了使单元格可中断,代码段会捕获异常。当用户通过中断内核(又名停止)按钮停止单元时,KeyboardInterrupt 错误会被注入 Python 事件循环。该代码段捕获它并关闭图 fig

plt.pause 中的持续时间定义了脚本反应的延迟。该值越大,关闭窗口和打印hi!

之间的延迟越长

单元格可以被重新执行任意次数。