Combining matplotlib's mouse button events with pick events

谁都会走 提交于 2019-12-11 12:19:07

问题


Based on combination of mouse button and key events, different functionalities are applied to the points of a scatter plot. When the left mouse button is pressed matplotlib's Lasso widget is called and with the included points functionality 1 takes place. When Shift+LMB are pressed a Lasso is drawn and functionality 2 takes place with the included points. When Alt+LMB are pressed a Lasso is drawn and with the included points functionality 3 takes place. Last, but not least, when I press the RMB a pick event is triggered and the index of the selected point in the scatter plot is given.

Since I added the pick event, the aforementioned functionalities work correctly until a pick event is triggered for the first time. When it is triggered it seems that the canvas gets locked and I can not use any other functionality. Although, I get the index of the selected point, I do not get any errors, and the canvas becomes unresponsive.

I modified the code taken from this question, which is actually what I want to do.

Code:

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()

Any suggestions on what might be causing this malfunction? Thanks in advance.


回答1:


The problem you're having this time is that you have both a PickEvent and a MouseEvent that are generated at the same time when you click on an artist. The MouseEvent locks the canvas and prevents you from doing anything else afterward.

The best solution would be to prevent the MouseEvent from being fired after the PickEvent, but I don't know if there's a way to do that. Instead, I added a test to check whether onpress() was called after onpick() to disable the locking mechanism.

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()


来源:https://stackoverflow.com/questions/32444770/combining-matplotlibs-mouse-button-events-with-pick-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!