matplotlib:如何将鼠标事件处理约束到最顶级的艺术家?

时间:2014-01-02 13:18:19

标签: python matplotlib

我在matplotlib中寻找一种方法,在单个轴上创建多个交互式艺术家(即矩形,圆形等),可以使用鼠标调整大小/旋转/移动。我成功地尝试this example在matplotlib中创建一个“可拖动”矩形。然而,当两个这样的可拖动矩形重叠时,两个都将移动,而不仅仅是我想要的最顶端的矩形。如何确保只有鼠标指针下方最顶级的艺术家才能响应鼠标事件?

1 个答案:

答案 0 :(得分:1)

为此,您需要设置每个矩形的zorder。然后在on_push事件中使用此zorder来选择要移动的正确对象。我修改了给出的示例代码来执行此操作。我注释掉了DraggableRectangle的on_press事件处理程序,并添加了另一个用于处理on_press事件的类。

import numpy as np
import matplotlib.pyplot as plt

class DraggableRectangle:
    def __init__(self, rect):
        self.rect = rect
        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):
        'on button press we will see if the mouse is over us and 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

        x0, y0 = self.rect.xy
        self.press = x0, y0, event.xdata, event.ydata

    def on_motion(self, event):
        'on motion we will move the rect if the mouse is over us'
        if self.press is None: return
        if event.inaxes != self.rect.axes: return
        x0, y0, xpress, ypress = self.press
        dx = event.xdata - xpress
        dy = event.ydata - ypress
        #print 'x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f'%(x0, xpress, event.xdata, 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):
        'on release we reset the press data'
        self.press = None
        self.rect.figure.canvas.draw()

    def disconnect(self):
        'disconnect all the stored connection ids'
        self.rect.figure.canvas.mpl_disconnect(self.cidpress)
        self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
        self.rect.figure.canvas.mpl_disconnect(self.cidmotion)

class RectangleHandler():

    def __init__(self, drs):
        self.drs = drs
        self.ax = drs[0].rect.axes

        self.cidpress = self.ax.figure.canvas.mpl_connect(
            'button_press_event', self.on_press)

    def on_press(self, event):
        if event.inaxes != self.ax: return
        for dr in self.drs:
            rect = dr.rect
            contains, attrd = rect.contains(event)
            if contains:
                zorder = rect.zorder
                try:
                    if zorder > maxZorder: 
                        maxZorder = zorder
                        rectToDrag = dr
                except NameError:
                    maxZorder = zorder
                    rectToDrag = dr
        try:
            if rectToDrag:
                rectToDrag.on_press(event)
        except UnboundLocalError:
            pass


fig = plt.figure()
ax = fig.add_subplot(111)
rects = ax.bar(range(10), 20*np.random.rand(10))
drs = []
for i, rect in enumerate(rects):
    rect.zorder = i
    dr = DraggableRectangle(rect)
    dr.connect()
    drs.append(dr)

rh = RectangleHandler(drs)
plt.show()