Index: src/sas/sasgui/guiframe/local_perspectives/plotting/binder.py
===================================================================
--- src/sas/sasgui/guiframe/local_perspectives/plotting/binder.py	(revision 20fa5fe0c3e314a850432d5e463d03ceed3e453a)
+++ src/sas/sasgui/guiframe/local_perspectives/plotting/binder.py	(revision 5251ec6db8aae214addfa0a5a1da16820994958b)
@@ -2,6 +2,8 @@
 Extension to MPL to support the binding of artists to key/mouse events.
 """
+from __future__ import print_function
+
+import sys
 import logging
-import sys
 
 logger = logging.getLogger(__name__)
@@ -16,4 +18,5 @@
     artist = None
     prop = {}
+
     def __init__(self, artist=None, prop={}):
         self.artist, self.prop = artist, self.prop
@@ -25,15 +28,18 @@
         return self.artist is not other.artist
 
-    def __nonzero__(self):
+    def __bool__(self):
         return self.artist is not None
+
+    __nonzero__ = __bool__
+
 
 class BindArtist(object):
     """
-        Track keyboard modifiers for events.
-        TODO: Move keyboard modifier support into the backend.  We cannot
-        TODO: properly support it from outside the windowing system since there
-        TODO: is no way to recognized whether shift is held down when the mouse
-        TODO: first clicks on the the application window.
+    Track keyboard modifiers for events.
     """
+    # TODO: Move keyboard modifier support into the backend.  We cannot
+    # TODO: properly support it from outside the windowing system since there
+    # TODO: is no way to recognized whether shift is held down when the mouse
+    # TODO: first clicks on the the application window.
     control, shift, alt, meta = False, False, False, False
 
@@ -46,6 +52,8 @@
               'scroll', 'key', 'keyup']
     # TODO: Need our own event structure
+
     def __init__(self, figure):
         canvas = figure.canvas
+
         # Link to keyboard/mouse
         try:
@@ -59,5 +67,5 @@
             ]
         except:
-            # print "bypassing scroll_event: wrong matplotlib version"
+            logger.warn("bypassing scroll_event: wrong matplotlib version")
             self._connections = [
                 canvas.mpl_connect('motion_notify_event', self._onMotion),
@@ -67,10 +75,14 @@
                 canvas.mpl_connect('key_release_event', self._onKeyRelease),
             ]
+
         # Turn off picker if it hasn't already been done
         try:
             canvas.mpl_disconnect(canvas.button_pick_id)
             canvas.mpl_disconnect(canvas.scroll_pick_id)
-        except:
-            logger.error(sys.exc_value)
+        except Exception as exc:
+            logger.error(exc)
+
+        self._current = None
+        self._actions = {}
         self.canvas = canvas
         self.figure = figure
@@ -83,5 +95,4 @@
 
         Use clearall() to reset all connections.
-
         """
         for h in artists:
@@ -108,4 +119,5 @@
         for action in self.events:
             self._actions[action] = {}
+
         # Need activity state
         self._artists = []
@@ -121,6 +133,6 @@
             for cid in self._connections:
                 self.canvas.mpl_disconnect(cid)
-        except:
-            pass
+        except Exception as exc:
+            logger.error("Error disconnection canvas: %s" % exc)
         self._connections = []
 
@@ -169,28 +181,26 @@
         sure it applies.  E.g., the callback for 'press' might be:
             if event.button == 1 and event.shift: process Shift-click
-
-        :TODO: Only receive events with the correct modifiers (e.g., S-click,
-        :TODO:   or *-click for any modifiers).
-        :TODO: Only receive button events for the correct button (e.g., click1
-        :TODO:   release3, or dclick* for any button)
-        :TODO: Support virtual artist, so that and artist can be flagged as
-        :TODO:   having a tag list and receive the correct events
-        :TODO: Support virtual events for binding to button-3 vs shift button-1
-        :TODO:   without changing callback code
-        :TODO: Attach multiple callbacks to the same event?
-        :TODO: Clean up interaction with toolbar modes
-        :TODO: push/pushclear/pop context so that binding changes
-            for the duration
-        :TODO:   e.g., to support ? context sensitive help
-
-        """
+        """
+        #TODO: Only receive events with the correct modifiers (e.g., S-click,
+        #TODO:   or *-click for any modifiers).
+        #TODO: Only receive button events for the correct button (e.g., click1
+        #TODO:   release3, or dclick* for any button)
+        #TODO: Support virtual artist, so that and artist can be flagged as
+        #TODO:   having a tag list and receive the correct events
+        #TODO: Support virtual events for binding to button-3 vs shift button-1
+        #TODO:   without changing callback code
+        #TODO: Attach multiple callbacks to the same event?
+        #TODO: Clean up interaction with toolbar modes
+        #TODO: push/pushclear/pop context so that binding changes for the duration
+        #TODO:   e.g., to support ? context sensitive help
+
         # Check that the trigger is valid
         if trigger not in self._actions:
-            raise ValueError, "%s invalid --- valid triggers are %s" \
-                % (trigger, ", ".join(self.events))
+            raise ValueError("%s invalid --- valid triggers are %s"
+                % (trigger, ", ".join(self.events)))
+
         # Register the trigger callback
         self._actions[trigger][artist] = action
-        # print "==> added",artist,[artist],"to",trigger,":",
-        # self._actions[trigger].keys()
+
         # Maintain a list of all artists
         if artist not in self._artists:
@@ -203,5 +213,6 @@
         """
         if action not in self.events:
-            raise ValueError, "Trigger expects " + ", ".join(self.events)
+            raise ValueError("Trigger expects " + ", ".join(self.events))
+
         # Tag the event with modifiers
         for mod in ('alt', 'control', 'shift', 'meta'):
@@ -210,4 +221,5 @@
         setattr(ev, 'action', action)
         setattr(ev, 'prop', {})
+
         # Fallback scheme. If the event does not return false, pass to parent.
         processed = False
@@ -233,8 +245,6 @@
         """
         # TODO: sort by zorder of axes then by zorder within axes
-        self._artists.sort(cmp=lambda x, y: cmp(y.zorder, x.zorder))
-        # print "search"," ".join([str(h) for h in self._artists])
+        self._artists.sort(key=lambda x: x.zorder, reverse=True)
         found = Selection()
-        # print "searching in",self._artists
         for artist in self._artists:
             # TODO: should contains() return false if invisible?
@@ -250,5 +260,4 @@
                 found.artist, found.prop = artist, prop
                 break
-        # print "found",found.artist
 
         # TODO: how to check if prop is equal?
@@ -257,4 +266,5 @@
             self.trigger(found, 'enter', event)
         self._current = found
+
         return found
 
@@ -274,16 +284,15 @@
 
             transform = self._hasclick.artist.get_transform()
-            # x,y = event.xdata,event.ydata
+            #x,y = event.xdata,event.ydata
             x, y = event.x, event.y
             try:
                 x, y = transform.inverted().transform_point((x, y))
-
-            except:
+            except: # CRUFT: matplotlib-0.91 support
                 x, y = transform.inverse_xy_tup((x, y))
+
             event.xdata, event.ydata = x, y
             self.trigger(self._hasclick, 'drag', event)
         else:
             found = self._find_current(event)
-            # print "found",found.artist
             self.trigger(found, 'motion', event)
 
@@ -296,7 +305,4 @@
         # Check for double-click
         event_time = time.time()
-        # print event_time,self._last_time,self.dclick_threshhold
-        # print (event_time > self._last_time + self.dclick_threshhold)
-        # print event.button,self._last_button
         if (event.button != self._last_button) or \
                 (event_time > self._last_time + self.dclick_threshhold):
@@ -381,4 +387,5 @@
             setattr(self, event.key, False)
             return
+
         if self._haskey:
             self.trigger(self._haskey, 'keyup', event)
@@ -391,3 +398,2 @@
         found = self._find_current(event)
         self.trigger(found, 'scroll', event)
-
