Combining matplotlib's mouse button events with pick events
Question: 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](http://matplotlib.org/examples/event_handling/lasso_demo.html) 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](http://stackoverflow.com/questions/32322090/combine-key-and-mouse-
button-events-in-wxpython-panel-using-matplotlib) 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.


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

