title: How can I link axes of imshow plots for zooming and panning?
body: <p>Suppose I have a figure canvas with 3 plots... 2 are images of the same dimensions plotted with imshow, and the other is some other kind of subplot. I'd like to be able to link the x and y axes of the imshow plots so that when I zoom in one (using the zoom tool provided by the NavigationToolbar), the other zooms to the same coordinates, and when I pan in one, the other pans as well.</p>
  
  <p>Subplot methods such as scatter and histogram can be passed kwargs specifying an axes for sharex and sharey, but imshow has no such configuration.</p>
  
  <p>I started hacking my way around this by subclassing NavigationToolbar2WxAgg (shown below)... but there are several problems here.
  1) This will link the axes of all plots in a canvas since all I've done is get rid of the checks for a.in_axes()
  2) This worked well for panning, but zooming caused all subplots to zoom from the same global point, rather than from the same point in each of their respective axes.</p>
  
  <p>Can anyone suggest a workaround?</p>
  
  <p>Much thanks!
  -Adam</p>
  
  <pre><code>from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
  class MyNavToolbar(NavigationToolbar2WxAgg):
      def __init__(self, canvas, cpfig):
          NavigationToolbar2WxAgg.__init__(self, canvas)
  
      # overrided
      # As mentioned in the code below, the only difference here from overridden
      # method is that this one doesn't check a.in_axes(event) when deciding which
      # axes to start the pan in...
      def press_pan(self, event):
          'the press mouse button in pan/zoom mode callback'
  
          if event.button == 1:
              self._button_pressed=1
          elif  event.button == 3:
              self._button_pressed=3
          else:
              self._button_pressed=None
              return
  
          x, y = event.x, event.y
  
          # push the current view to define home if stack is empty
          if self._views.empty(): self.push_current()
  
          self._xypress=[]
          for i, a in enumerate(self.canvas.figure.get_axes()):
              # only difference from overridden method is that this one doesn't
              # check a.in_axes(event)
              if x is not None and y is not None and a.get_navigate():
                  a.start_pan(x, y, event.button)
                  self._xypress.append((a, i))
                  self.canvas.mpl_disconnect(self._idDrag)
                  self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan)
  
      # overrided
      def press_zoom(self, event):
          'the press mouse button in zoom to rect mode callback'
          if event.button == 1:
              self._button_pressed=1
          elif  event.button == 3:
              self._button_pressed=3
          else:
              self._button_pressed=None
              return
  
          x, y = event.x, event.y
  
          # push the current view to define home if stack is empty
          if self._views.empty(): self.push_current()
  
          self._xypress=[]
          for i, a in enumerate(self.canvas.figure.get_axes()):
              # only difference from overridden method is that this one doesn't
              # check a.in_axes(event) 
              if x is not None and y is not None and a.get_navigate() and a.can_zoom():
                  self._xypress.append(( x, y, a, i, a.viewLim.frozen(), a.transData.frozen()))
  
          self.press(event)
  </code></pre>