将 matplotlib 的鼠标按钮事件与选取事件相结合



基于鼠标按钮和键事件的组合,对散点图的点应用不同的功能。当按下鼠标左键时,调用matplotlib的Lasso小部件,并使用包含的点功能1。当Shift+LMB被按下时,一个Lasso被绘制出来,功能2在包含的点上发生。当Alt+LMB被按下时,Lasso被绘制,并与包含点功能3发生。最后,但并非最不重要的是,当我按下RMB时,会触发一个拾取事件,并给出散点图中选定点的索引。

由于我添加了pick事件,上述功能可以正常工作,直到第一次为触发pick事件。当它被触发时,似乎画布被锁定,我不能使用任何其他功能。虽然,我得到了选定点的索引,但我没有得到任何错误,并且画布变得无响应。

我修改了取自这个问题的代码,这实际上是我想要做的。

代码:

import logging
import matplotlib
from matplotlib.widgets import Lasso
from matplotlib.colors import colorConverter
from matplotlib.collections import RegularPolyCollection
from matplotlib import path
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import rand
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

class Datum(object):
      colorin = colorConverter.to_rgba('red')
      colorShift = colorConverter.to_rgba('cyan')
      colorCtrl = colorConverter.to_rgba('pink')
      colorout = colorConverter.to_rgba('blue')
      def __init__(self, x, y, include=False):
         self.x = x
         self.y = y
         if include:
            self.color = self.colorin
         else:
            self.color = self.colorout

class LassoManager(object):
      def __init__(self, ax, data):
         self.axes = ax
         self.canvas = ax.figure.canvas
         self.data = data
         self.Nxy = len(data)
         facecolors = [d.color for d in data]
         self.xys = [(d.x, d.y) for d in data]
         fig = ax.figure
         self.collection = RegularPolyCollection(fig.dpi, 6, sizes=(100,),facecolors=facecolors, offsets = self.xys, transOffset = ax.transData)
         ax.add_collection(self.collection)
         self.pick=self.canvas.mpl_connect('pick_event', self.onpick)
         self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
         self.keyPress = self.canvas.mpl_connect('key_press_event', self.onKeyPress)
         self.keyRelease = self.canvas.mpl_connect('key_release_event', self.onKeyRelease)
         self.lasso = None
         self.shiftKey = False
         self.ctrlKey = False
      def callback(self, verts):
          logging.debug('in LassoManager.callback(). Shift: %s, Ctrl: %s' % (self.shiftKey, self.ctrlKey))
          facecolors = self.collection.get_facecolors()
          p = path.Path(verts)
          ind = p.contains_points(self.xys)
          for i in range(len(self.xys)):
              if ind[i]:
                 if self.shiftKey:
                    facecolors[i] = Datum.colorShift
                 elif self.ctrlKey:
                    facecolors[i] = Datum.colorCtrl
                 else:
                    facecolors[i] = Datum.colorin
                    print self.xys[i]
              else:
                   facecolors[i] = Datum.colorout
          self.canvas.draw_idle()
          self.canvas.widgetlock.release(self.lasso)
          del self.lasso
      def onpress(self, event):
           if self.canvas.widgetlock.locked(): return
           if event.inaxes is None:    return
           self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback)
           # acquire a lock on the widget drawing
           self.canvas.widgetlock(self.lasso)
      def onKeyPress(self, event):
          logging.debug('in LassoManager.onKeyPress(). Event received: %s (key: %s)' % (event, event.key))
          if event.key == 'alt':
             self.ctrlKey = True
          if event.key == 'shift':
             self.shiftKey = True
      def onKeyRelease(self, event):
          logging.debug('in LassoManager.onKeyRelease(). Event received: %s (key: %s)' % (event, event.key))
          if event.key == 'alt':
             self.ctrlKey = False
          if event.key == 'shift':
             self.shiftKey = False

      def onpick(self,event):
          if event.mouseevent.button == 3:
             index = event.ind
             print('onpick scatter:', index, np.take(x, index), np.take(y, index))
      if __name__ == '__main__':
         x,y =rand(2,100)
         data = [Datum(*xy) for xy in zip(x,y)]
         fig = plt.figure()
         ax = plt.axes()
         ax.scatter(x,y,picker=True)
         lman = LassoManager(ax, data)
         plt.show()

有什么建议可能导致这个故障吗?

你这次遇到的问题是,当你点击一个艺术家时,你同时生成了一个PickEvent和一个MouseEventMouseEvent锁定画布,并阻止您在之后执行任何其他操作。

最好的解决方案是防止MouseEventPickEvent之后被解雇,但我不知道是否有办法做到这一点。相反,我添加了一个测试来检查onpress()是否在onpick()之后被调用以禁用锁定机制。
import logging
import matplotlib
from matplotlib.widgets import Lasso
from matplotlib.colors import colorConverter
from matplotlib.collections import RegularPolyCollection
from matplotlib import path
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import rand
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

class Datum(object):
      colorin = colorConverter.to_rgba('red')
      colorShift = colorConverter.to_rgba('cyan')
      colorCtrl = colorConverter.to_rgba('pink')
      colorout = colorConverter.to_rgba('blue')
      def __init__(self, x, y, include=False):
         self.x = x
         self.y = y
         if include:
            self.color = self.colorin
         else:
            self.color = self.colorout

class LassoManager(object):
      def __init__(self, ax, data):
         self.axes = ax
         self.canvas = ax.figure.canvas
         self.data = data
         self.Nxy = len(data)
         facecolors = [d.color for d in data]
         self.xys = [(d.x, d.y) for d in data]
         fig = ax.figure
         self.collection = RegularPolyCollection(fig.dpi, 6, sizes=(100,),facecolors=facecolors, offsets = self.xys, transOffset = ax.transData)
         ax.add_collection(self.collection)
         self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
         self.keyPress = self.canvas.mpl_connect('key_press_event', self.onKeyPress)
         self.keyRelease = self.canvas.mpl_connect('key_release_event', self.onKeyRelease)
         self.pick=self.canvas.mpl_connect('pick_event', self.onpick)
         self.lasso = None
         self.shiftKey = False
         self.ctrlKey = False
         self.pickEvent = False
      def callback(self, verts):
          logging.debug('in LassoManager.callback(). Shift: %s, Ctrl: %s' % (self.shiftKey, self.ctrlKey))
          facecolors = self.collection.get_facecolors()
          p = path.Path(verts)
          ind = p.contains_points(self.xys)
          for i in range(len(self.xys)):
              if ind[i]:
                 if self.shiftKey:
                    facecolors[i] = Datum.colorShift
                 elif self.ctrlKey:
                    facecolors[i] = Datum.colorCtrl
                 else:
                    facecolors[i] = Datum.colorin
                    print self.xys[i]
              else:
                   facecolors[i] = Datum.colorout
          self.canvas.draw_idle()
          self.canvas.widgetlock.release(self.lasso)
          del self.lasso
      def onpress(self, event):
            logging.debug('in LassoManager.onpress(). Event received: %s' % event)
            if self.pickEvent:
                self.pickEvent = False
                return
            if self.canvas.widgetlock.locked(): return
            if event.inaxes is None: return
            self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback)
            # acquire a lock on the widget drawing
            self.canvas.widgetlock(self.lasso)
      def onKeyPress(self, event):
          logging.debug('in LassoManager.onKeyPress(). Event received: %s (key: %s)' % (event, event.key))
          if event.key == 'alt':
             self.ctrlKey = True
          if event.key == 'shift':
             self.shiftKey = True
      def onKeyRelease(self, event):
          logging.debug('in LassoManager.onKeyRelease(). Event received: %s (key: %s)' % (event, event.key))
          if event.key == 'alt':
             self.ctrlKey = False
          if event.key == 'shift':
             self.shiftKey = False
      def onpick(self, event):
          logging.debug('in LassoManager.onpick(). Event received: %s' % event)
          self.pickEvent = True
          if event.mouseevent.button == 3:
             index = event.ind
             print 'onpick scatter: ', index, np.take(x, index), np.take(y, index)

if __name__ == '__main__':
    x,y =rand(2,100)
    data = [Datum(*xy) for xy in zip(x,y)]
    fig = plt.figure()
    ax = plt.axes()
    ax.scatter(x,y,picker=True)
    lman = LassoManager(ax, data)
    plt.show()

最新更新