我正试图从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。)
答案 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!
单元格可以被重新执行任意次数。