[英]Python - ProcessPoolExecutor hangs when called from a mpl_connect handler
[英]Matplotlib mpl_connect not working when placed in subroutine called by Jupyter notebook
我正在使用在线交互式matplotlib
示例中提供的 Draggable Rectangles 示例: https ://matplotlib.org/stable/users/explain/event_handling.html#draggable-rectangle-exercise。 我根据自己的使用对其进行了一些修改:除了可拖动之外,绘制的每个矩形还应该在触发on_release
时翻转颜色。
当我将这一切都放在同一个 Jupyter 单元中时,它会按预期运行:
%matplotlib widget
class DraggableRectangle:
def __init__(self, coords, width, height, color, id_val, ax):
rect = Rectangle(coords, width, height, color=color)
ax.add_patch(rect)
self.rect = rect
self.id_val = id_val
self.press = None
def connect(self):
"""Connect to all the events we need."""
self.cidpress = self.rect.figure.canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidrelease = self.rect.figure.canvas.mpl_connect(
'button_release_event', self.on_release)
self.cidmotion = self.rect.figure.canvas.mpl_connect(
'motion_notify_event', self.on_motion)
def on_press(self, event):
"""Check whether mouse is over us; if so, store some data."""
if event.inaxes != self.rect.axes:
return
contains, attrd = self.rect.contains(event)
if not contains:
return
print('event contains', self.rect.xy)
self.press = self.rect.xy, (event.xdata, event.ydata), self.id_val
def on_motion(self, event):
"""Move the rectangle if the mouse is over us."""
if self.press is None or event.inaxes != self.rect.axes:
return
(x0, y0), (xpress, ypress), _ = self.press
dx = event.xdata - xpress
dy = event.ydata - ypress
print(f'x0={x0}, xpress={xpress}, event.xdata={event.xdata}, '
f'dx={dx}, x0+dx={x0+dx}')
self.rect.set_x(x0+dx)
self.rect.set_y(y0+dy)
self.rect.figure.canvas.draw()
def on_release(self, event):
"""Clear button press information."""
print("Releasing the rectangle")
if self.id_val == self.press[2]:
if self.rect.get_facecolor() == (0.0, 0.0, 1.0, 1.0):
self.rect.set_color((1.0, 0.0, 0.0, 1.0))
else:
self.rect.set_color((0.0, 0.0, 1.0, 1.0))
self.press = None
self.rect.figure.canvas.draw()
def disconnect(self):
"""Disconnect all callbacks."""
self.rect.figure.canvas.mpl_disconnect(self.cidpress)
self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
fig = plt.figure()
ax = fig.add_subplot(111)
drs = []
id_val = 1
for i in np.arange(0, 250, 50):
for j in np.arange(0, 150, 50):
dr = DraggableRectangle((100 + i, 100 + j), 25, 25, (0.0, 0.0, 1.0, 1.0), id_val, ax)
dr.connect()
drs.append(dr)
id_val += 1
plt.xlim([0, 1000])
plt.ylim([0, 1000])
但是,假设我这样重构代码:
矩形.py
# assume all imports have been made
class DraggableRectangle:
def __init__(self, coords, width, height, color, id_val, ax):
rect = Rectangle(coords, width, height, color=color)
ax.add_patch(rect)
self.rect = rect
self.id_val = id_val
self.press = None
def connect(self):
"""Connect to all the events we need."""
self.cidpress = self.rect.figure.canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidrelease = self.rect.figure.canvas.mpl_connect(
'button_release_event', self.on_release)
self.cidmotion = self.rect.figure.canvas.mpl_connect(
'motion_notify_event', self.on_motion)
def on_press(self, event):
"""Check whether mouse is over us; if so, store some data."""
if event.inaxes != self.rect.axes:
return
contains, attrd = self.rect.contains(event)
if not contains:
return
print('event contains', self.rect.xy)
self.press = self.rect.xy, (event.xdata, event.ydata), self.id_val
def on_motion(self, event):
"""Move the rectangle if the mouse is over us."""
if self.press is None or event.inaxes != self.rect.axes:
return
(x0, y0), (xpress, ypress), _ = self.press
dx = event.xdata - xpress
dy = event.ydata - ypress
print(f'x0={x0}, xpress={xpress}, event.xdata={event.xdata}, '
f'dx={dx}, x0+dx={x0+dx}')
self.rect.set_x(x0+dx)
self.rect.set_y(y0+dy)
self.rect.figure.canvas.draw()
def on_release(self, event):
"""Clear button press information."""
print("Releasing the rectangle")
if self.id_val == self.press[2]:
if self.rect.get_facecolor() == (0.0, 0.0, 1.0, 1.0):
self.rect.set_color((1.0, 0.0, 0.0, 1.0))
else:
self.rect.set_color((0.0, 0.0, 1.0, 1.0))
self.press = None
self.rect.figure.canvas.draw()
def disconnect(self):
"""Disconnect all callbacks."""
self.rect.figure.canvas.mpl_disconnect(self.cidpress)
self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
def plot():
fig = plt.figure()
ax = fig.add_subplot(111)
drs = []
id_val = 1
for i in np.arange(0, 250, 50):
for j in np.arange(0, 150, 50):
dr = DraggableRectangle((100 + i, 100 + j), 25, 25, (0.0, 0.0, 1.0, 1.0), id_val, ax)
dr.connect()
drs.append(dr)
id_val += 1
plt.xlim([0, 1000])
plt.ylim([0, 1000])
木星细胞:
%matplotlib widget
import rectangle
rectangle.plot()
重构版本显示矩形,但不添加任何所需的交互功能。
将不胜感激这方面的任何指示。 我是否必须直接在 Jupyter 内部实现mpl_connect
或者有什么方法可以重构我的代码以便它可以添加交互性?
回调存储为弱引用,并在包含对象被垃圾回收时停止运行。 退出绘图功能时,所有 DraggableRectangle 对象都将丢失。 返回 drs 并将其保存在变量中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.