繁体   English   中英

Matplotlib mpl_connect 放在 Jupyter 笔记本调用的子程序中时不起作用

[英]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 并将其保存在变量中。

https://matplotlib.org/stable/users/explain/event_handling.html#:~:text=%20canvas%20retains%20only,functions%20used%20as%20callbacks

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM