content: import numpy as np
  try:
      from matplotlib import lines
  except ImportError:
      pass
  
  __all__ = ['CanvasToolBase', 'ToolHandles']
  
  
  def _pass(*args):
      pass
  
  
  class CanvasToolBase(object):
      """Base canvas tool for matplotlib axes.
  
      Parameters
      ----------
      ax : :class:`matplotlib.axes.Axes`
          Matplotlib axes where tool is displayed.
      on_move : function
          Function called whenever a control handle is moved.
          This function must accept the end points of line as the only argument.
      on_release : function
          Function called whenever the control handle is released.
      on_enter : function
          Function called whenever the "enter" key is pressed.
      useblit : bool
          If True, update canvas by blitting, which is much faster than normal
          redrawing (turn off for debugging purposes).
      """
      def __init__(self, ax, on_move=None, on_enter=None, on_release=None,
                   useblit=True):
          self.ax = ax
          self.canvas = ax.figure.canvas
          self.img_background = None
          self.cids = []
          self._artists = []
          self.active = True
  
          if useblit:
              self.connect_event('draw_event', self._blit_on_draw_event)
          self.useblit = useblit
  
          self.callback_on_move = _pass if on_move is None else on_move
          self.callback_on_enter = _pass if on_enter is None else on_enter
          self.callback_on_release = _pass if on_release is None else on_release
  
          self.connect_event('key_press_event', self._on_key_press)
  
      def connect_event(self, event, callback):
          """Connect callback with an event.
  
          This should be used in lieu of `figure.canvas.mpl_connect` since this
          function stores call back ids for later clean up.
          """
          cid = self.canvas.mpl_connect(event, callback)
          self.cids.append(cid)
  
      def disconnect_events(self):
          """Disconnect all events created by this widget."""
          for c in self.cids:
              self.canvas.mpl_disconnect(c)
  
      def ignore(self, event):
          """Return True if event should be ignored.
  
          This method (or a version of it) should be called at the beginning
          of any event callback.
          """
          return not self.active
  
      def set_visible(self, val):
          for artist in self._artists:
              artist.set_visible(val)
  
      def _blit_on_draw_event(self, event=None):
          self.img_background = self.canvas.copy_from_bbox(self.ax.bbox)
          self._draw_artists()
  
      def _draw_artists(self):
          for artist in self._artists:
              self.ax.draw_artist(artist)
  
      def remove(self):
          """Remove artists and events from axes.
  
          Note that the naming here mimics the interface of Matplotlib artists.
          """
          #TODO: For some reason, RectangleTool doesn't get properly removed
          self.disconnect_events()
          for a in self._artists:
              a.remove()
  
      def redraw(self):
          """Redraw image and canvas artists.
  
          This method should be called by subclasses when artists are updated.
          """
          if self.useblit and self.img_background is not None:
              self.canvas.restore_region(self.img_background)
              self._draw_artists()
              self.canvas.blit(self.ax.bbox)
          else:
              self.canvas.draw_idle()
  
      def _on_key_press(self, event):
          if event.key == 'enter':
              self.callback_on_enter(self.geometry)
              self.set_visible(False)
              self.redraw()
  
      @property
      def geometry(self):
          """Geometry information that gets passed to callback functions."""
          return None
  
  
  class ToolHandles(object):
      """Control handles for canvas tools.
  
      Parameters
      ----------
      ax : :class:`matplotlib.axes.Axes`
          Matplotlib axes where tool handles are displayed.
      x, y : 1D arrays
          Coordinates of control handles.
      marker : str
          Shape of marker used to display handle. See `matplotlib.pyplot.plot`.
      marker_props : dict
          Additional marker properties. See :class:`matplotlib.lines.Line2D`.
      """
      def __init__(self, ax, x, y, marker='o', marker_props=None):
          self.ax = ax
  
          props = dict(marker=marker, markersize=7, mfc='w', ls='none',
                       alpha=0.5, visible=False)
          props.update(marker_props if marker_props is not None else {})
          self._markers = lines.Line2D(x, y, animated=True, **props)
          self.ax.add_line(self._markers)
          self.artist = self._markers
  
      @property
      def x(self):
          return self._markers.get_xdata()
  
      @property
      def y(self):
          return self._markers.get_ydata()
  
      def set_data(self, pts, y=None):
          """Set x and y positions of handles"""
          if y is not None:
              x = pts
              pts = np.array([x, y])
          self._markers.set_data(pts)
  
      def set_visible(self, val):
          self._markers.set_visible(val)
  
      def set_animated(self, val):
          self._markers.set_animated(val)
  
      def draw(self):
          self.ax.draw_artist(self._markers)
  
      def closest(self, x, y):
          """Return index and pixel distance to closest index."""
          pts = np.transpose((self.x, self.y))
          # Transform data coordinates to pixel coordinates.
          pts = self.ax.transData.transform(pts)
          diff = pts - ((x, y))
          dist = np.sqrt(np.sum(diff**2, axis=1))
          return np.argmin(dist), np.min(dist)
  