Hi,

Following Gael Varoquaux's lead on adding a ginput command to matplotlib
(nice job!), I added a waitforbuttonpress function to matplotlib.  The
patch is attached (generate using svn diff from the
matplotlib/trunk/matplotlib directory).  waitforbuttonpress is a simple
function with a matlab equivalent that returns a list of true/false's -
true for a keyboard click and false for a mouse click.  I use it in
matlab regularly as a simple yes/no question (often to decide whether or
not to save a figure).  

The way I have implemented it is by adding an additional class
BlockingKeyMouseInput, which is quite similar to BlockingMouseInput, but
waits for both key and mouse events.  A smarter person than I could
probably combine these two classes and make something that would serve
both functions.  But I am basically new to python and don't feel
comfortable.  Perhaps someone else could take a look and make
improvements/simplifications?

The other thing that I have noticed with both ginput and
waitforbuttonpress is that if you use ctrl-c to break out of either,
then the callback functions remain attached to their respective events
(e.g., try ginput(n=-1,timeout=-1,verbose=True) and hit ctrl-c).  This
probably isn't a huge problem, but it would be nice if there was a way
to say "if ctrl-c is pressed, cleanup nicely".  Does someone know if
that is possible?

Cheers,
David


-- 
**********************************
David M. Kaplan
Charge de Recherche 1
Institut de Recherche pour le Developpement
Centre de Recherche Halieutique Mediterraneenne et Tropicale
av. Jean Monnet
B.P. 171
34203 Sete cedex
France

Phone: +33 (0)4 99 57 32 27
Fax: +33 (0)4 99 57 32 95
http://www.ur097.ird.fr/team/dkaplan/index.html
**********************************

-- 
**********************************
David M. Kaplan
Assistant Researcher
UCSC / Institute of Marine Sciences
Ocean Sciences
1156 High St.
SC, CA 95064

Phone: 831-459-4789
Fax: 831-459-4882
http://pmc.ucsc.edu/~dmk/
**********************************
Index: lib/matplotlib/pyplot.py
===================================================================
--- lib/matplotlib/pyplot.py	(revision 5735)
+++ lib/matplotlib/pyplot.py	(working copy)
@@ -335,7 +335,21 @@
 if Figure.ginput.__doc__ is not None:
     ginput.__doc__ = dedent(Figure.ginput.__doc__)
 
+def waitforbuttonpress(*args, **kwargs):
+    """
+    Blocking call to interact with the figure.
 
+    This will wait for *n* key or mouse clicks from the user and
+    return a list containing True's for keyboard clicks and False's
+    for mouse clicks.
+
+    If *timeout* is negative, does not timeout.
+    """
+    return gcf().waitforbuttonpress(*args, **kwargs)
+if Figure.waitforbuttonpress.__doc__ is not None:
+    waitforbuttonpress.__doc__ = dedent(Figure.waitforbuttonpress.__doc__)
+
+
 # Putting things in figures
 
 def figtext(*args, **kwargs):
Index: lib/matplotlib/figure.py
===================================================================
--- lib/matplotlib/figure.py	(revision 5735)
+++ lib/matplotlib/figure.py	(working copy)
@@ -6,6 +6,9 @@
 :class:`SubplotParams`
     control the default spacing of the subplots
 
+:class:`BlockingKeyMouseInput`
+    creates a callable object to retrieve key or mouse clicks in a blocking way for interactive sessions
+
 :class:`BlockingMouseInput`
     creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions
 
@@ -118,6 +121,78 @@
         setattr(self, s, val)
 
 
+class BlockingKeyMouseInput(object):
+    """
+    Class that creates a callable object to retrieve key or mouse clicks in a
+    blocking way.
+    """
+    def __init__(self, fig):
+        self.fig = fig
+
+
+    def on_mouse_click(self, event):
+        """
+        Event handler that will be passed to the current figure to
+        retrieve clicks.
+        """
+        self.events.append(event)
+        self.buttons.append(event.button)
+        self.keyormouse.append(False)
+        
+        if len(self.keyormouse) >= self.n:
+            self.done = True
+
+    def on_key_click(self, event):
+        """
+        Event handler that will be passed to the current figure to
+        retrieve key presses.
+        """
+        self.events.append(event)
+        self.keys.append(event.key)
+        self.keyormouse.append(True)
+
+        if len(self.keyormouse) >= self.n:
+            self.done = True
+
+    def __call__(self, n=1, timeout=-1 ):
+        """
+        Blocking call to retrieve n key or mouse events
+        """
+        self.done        = False
+        self.keys      = []
+        self.buttons       = []
+        self.events       = []
+        self.keyormouse = []
+
+        assert isinstance(n, int), "Requires an integer argument"
+        self.n = n
+
+        # Ensure that the figure is shown
+        self.fig.show()
+        # connect the click events to the on_click function call
+        self.callbackm = self.fig.canvas.mpl_connect('button_press_event',
+                                                     self.on_mouse_click)
+        self.callbackk = self.fig.canvas.mpl_connect('key_press_event',
+                                                    self.on_key_click)
+        # wait for n clicks
+        counter = 0
+        while not self.done:
+            self.fig.canvas.flush_events()
+            time.sleep(0.01)
+
+            # check for a timeout
+            counter += 1
+            if timeout > 0 and counter > timeout/0.01:
+                print "Timeout reached";
+                break;
+
+        # Disconnect the event, clean the figure, and return what we have
+        self.fig.canvas.mpl_disconnect(self.callbackm)
+        self.callbackm = None
+        self.fig.canvas.mpl_disconnect(self.callbackk)
+        self.callbackk = None
+        return (self.keyormouse,self.keys,self.buttons,self.events)
+
 class BlockingMouseInput(object):
     """
     Class that creates a callable object to retrieve mouse clicks in a
@@ -1119,8 +1194,25 @@
         return blocking_mouse_input(n=n, timeout=timeout,
                                           verbose=verbose, show_clicks=True)
 
+    def waitforbuttonpress(self, n=1, timeout=-1):
+        """
+        call signature::
 
+          waitforbuttonpress(self, n=1, timeout=-1)
 
+        Blocking call to interact with the figure.
+
+        This will wait for *n* key or mouse clicks from the user and
+        return a list containing True's for keyboard clicks and
+        False's for mouse clicks.
+
+        If *timeout* is negative, does not timeout.
+        """
+
+        blocking_input = BlockingKeyMouseInput(self)
+        return blocking_input(n=n, timeout=timeout)[0]
+
+
 def figaspect(arg):
     """
     Create a figure with specified aspect ratio.  If *arg* is a number,
-------------------------------------------------------------------------
Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW!
Studies have shown that voting for your favorite open source project,
along with a healthy diet, reduces your potential for chronic lameness
and boredom. Vote Now at http://www.sourceforge.net/community/cca08
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to