title: Matplotlib: Cursor snap to plotted data with datetime axis
body: <p>I have a plot of 3 data sets that have datetime objetcs on the x axis.
  I want to have a cursor that snaps to the data and shows the precise x and y value.</p>
  
  <p>I already have a "snap to cursor", but that only works for scalar x axes.
  Can anyone help me to modify the snap to cursor so that it works for datetime x axes as well?</p>
  
  <p>Here are my data plots:
  <img src="https://i.stack.imgur.com/SIT0l.png" alt="enter image description here"></p>
  
  <pre><code>import numpy as np
  import matplotlib.pyplot as plot
  import matplotlib.ticker as mticker
  import matplotlib.dates as dates
  import datetime
  import Helpers
  
  fig = plot.figure(1)
  DAU = (  2,  20,  25,  60, 190, 210,  18, 196, 212)
  WAU = ( 50, 160, 412, 403, 308, 379, 345, 299, 258)
  MAU = (760, 620, 487, 751, 612, 601, 546, 409, 457)
  
  firstDay = datetime.datetime(2012,1,15)
  
  #create an array with len(DAU) entries from given starting day
  dayArray = [firstDay + datetime.timedelta(days = i) for i in xrange(len(DAU))]
  
  line1 = plot.plot(dayArray, DAU, 'o-', color = '#336699')
  line2 = plot.plot(dayArray, WAU, 'o-', color = '#993333')
  line3 = plot.plot(dayArray, MAU, 'o-', color = '#89a54e')
  
  ax = plot.subplot(111)
  dateLocator   = mticker.MultipleLocator(2)
  dateFormatter = dates.DateFormatter('%d.%m.%Y')
  ax.xaxis.set_major_locator(dateLocator)
  ax.xaxis.set_major_formatter(dateFormatter)
  fig.autofmt_xdate(rotation = 90, ha = 'center')
  
  yMax = max(np.max(DAU), np.max(WAU), np.max(MAU))
  yLimit = 100 - (yMax % 100) + yMax
  plot.yticks(np.arange(0, yLimit + 1, 100))
  
  plot.title('Active users', weight = 'bold')
  plot.grid(True, axis = 'both')
  plot.subplots_adjust(bottom = 0.2)
  plot.subplots_adjust(right = 0.82)
  
  legend = plot.legend((line1[0], line2[0], line3[0]),
                   ('DAU',
                   'WAU',
                   'MAU'),
                   'upper left',
                   bbox_to_anchor = [1, 1],
                   shadow = True)
  
  frame = legend.get_frame()
  frame.set_facecolor('0.80')
  for t in legend.get_texts():
      t.set_fontsize('small')
  
  #THIS DOES NOT WORK
  cursor = Helpers.SnaptoCursor(ax, dayArray, DAU, 'euro daily')
  plot.connect('motion_notify_event', cursor.mouse_move)
  
  plot.show()
  </code></pre>
  
  <p>And this is my module "Helper" that contains the "SnaptoCursor" class:
  (I got the basic SnaptoCursor class from somewhere else and modified it a little bit)</p>
  
  <pre><code>from __future__ import print_function
  import numpy as np
  import matplotlib.pyplot as plot
  
  def minsec(sec, unused):
      """
      Returns a string of the input seconds formatted as mm'ss''.
      """
      minutes = sec // 60
      sec = sec - minutes * 60
      return '{0:02d}\'{1:02d}\'\''.format(int(minutes), int(sec))
  
  class SnaptoCursor():
      """
      A cursor with crosshair snaps to the nearest x point.
      For simplicity, I'm assuming x is sorted.
      """
      def __init__(self, ax, x, y, formatting, z = None):
          """
          ax: plot axis
          x: plot spacing
          y: plot data
          formatting: string flag for desired formatting
          z: optional second plot data
          """
          self.ax = ax
          self.lx = ax.axhline(color = 'k')  #the horiz line
          self.ly = ax.axvline(color = 'k')  #the vert line
          self.x = x
          self.y = y
          self.z = z
          # text location in axes coords
          self.txt = ax.text(0.6, 0.9, '', transform = ax.transAxes)
          self.formatting = formatting
  
      def format(self, x, y):
          if self.formatting == 'minsec':
              return 'x={0:d}, y='.format(x) + minsec(y, 0)
  
          elif self.formatting == 'daily euro':
              return u'day {0:d}: {1:.2f}€'.format(x, y)
  
      def mouse_move(self, event):
          if not event.inaxes: return
  
          mouseX, mouseY = event.xdata, event.ydata
  
          #searchsorted: returns an index or indices that suggest where x should be inserted
          #so that the order of the list self.x would be preserved
          indx = np.searchsorted(self.x, [mouseX])[0]
  
          mouseX = self.x[indx]
          #if z wasn't defined
          if self.z == None:
              mouseY = self.y[indx]
          #if z was defined: compare the distance between mouse and the two plots y and z
          #and use the nearest one
          elif abs(mouseY - self.y[indx]) &lt; abs(mouseY - self.z[indx]):
              mouseY = self.y[indx]
          else:
              mouseY = self.z[indx]
  
          #update the line positions
          self.lx.set_ydata(mouseY)
          self.ly.set_xdata(mouseX)
  
          self.txt.set_text(self.format(mouseX, mouseY))
          plot.draw()
  </code></pre>
  
  <p>Of course this does not work since I am calling the SnaptoCursor with the datetime array "dayArray", which is supposed to be compared to the mouse coordinates later on. And these data types are not comparable.</p>