On Thu, Jan 31, 2008 at 04:41:41PM +0100, Gael Varoquaux wrote:
> > If this seems like a good organization to you, I'll wait for a new
> > patch and then contribute that.

> Give me a few days, but it will come.

Here is the new patch. I added visual feedback when accumulating points.
I hope the docstrings are clear.

Cheers,

Gaƫl
Index: backend_bases.py
===================================================================
--- backend_bases.py    (revision 4908)
+++ backend_bases.py    (working copy)
@@ -1151,7 +1151,13 @@
         """
         return self.callbacks.disconnect(cid)
 
+    def flush_events(self):
+        """ Flush the GUI events for the figure. Implemented only for
+        backends with GUIs.
+        """
+        raise NotImplementedError
 
+
 class FigureManagerBase:
     """
     Helper class for matlab mode, wraps everything up into a neat bundle
Index: pyplot.py
===================================================================
--- pyplot.py   (revision 4908)
+++ pyplot.py   (working copy)
@@ -272,6 +272,20 @@
 if Figure.savefig.__doc__ is not None:
     savefig.__doc__ = dedent(Figure.savefig.__doc__)
 
+def ginput(*args, **kwargs):
+    """
+    Blocking call to interact with the figure. 
+
+    This will wait for n clicks from the user and return a list of the 
+    coordinates of each click.
+
+    If timeout is negative, does not timeout.
+    """
+    return gcf().ginput(*args, **kwargs)
+if Figure.ginput.__doc__ is not None:
+    ginput.__doc__ = dedent(Figure.ginput.__doc__)
+
+
 # Putting things in figures
 
 def figtext(*args, **kwargs):
Index: figure.py
===================================================================
--- figure.py   (revision 4908)
+++ figure.py   (working copy)
@@ -2,6 +2,7 @@
 Figure class -- add docstring here!
 """
 import numpy as npy
+import time
 
 import artist
 from artist import Artist
@@ -96,6 +97,83 @@
         setattr(self, s, val)
 
 
+class BlockingMouseInput(object):
+    """ Class that creates a callable object to retrieve mouse clicks in a 
+        blocking way. 
+    """
+    def __init__(self, fig):
+        self.fig = fig
+
+
+    def on_click(self, event):
+        """ Event handler that will be passed to the current figure to
+            retrieve clicks.
+        """
+        if event.button == 3:
+            # If it's a right click, pop the last coordinates.
+            if len(self.clicks) > 0:
+                self.clicks.pop()
+                if self.show_clicks:
+                    mark = self.marks.pop()
+                    mark.remove()
+                    self.fig.canvas.draw()
+        elif event.button == 2 and self.n < 0:
+            # If it's a middle click, and we are in infinite mode, finish
+            self.done = True
+        elif event.inaxes:
+            # If it's a valid click, append the coordinates to the list
+            self.clicks.append((event.xdata, event.ydata))
+            if self.verbose: 
+                print "input %i: %f,%f" % (len(self.clicks), 
+                                    event.xdata, event.ydata)
+            if self.show_clicks:
+                self.marks.extend(
+                    event.inaxes.plot([event.xdata,], [event.ydata,], 'r+') )
+                self.fig.canvas.draw()
+            if self.n > 0 and len(self.clicks) >= self.n:
+                self.done = True
+
+
+    def __call__(self, n=1, timeout=30, verbose=False, show_clicks=True):
+        """ Blocking call to retrieve n coordinate pairs through mouse 
+            clicks.
+        """
+        self.verbose     = verbose
+        self.done        = False
+        self.clicks      = []
+        self.show_clicks = True
+        self.marks       = []
+
+        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.callback = self.fig.canvas.mpl_connect('button_press_event', 
+                                                    self.on_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 "ginput timeout"; 
+                break;
+
+        # Disconnect the event, clean the figure, and return what we have
+        self.fig.canvas.mpl_disconnect(self.callback)
+        self.callback = None
+        if self.show_clicks:
+            for mark in self.marks:
+                mark.remove()
+            self.fig.canvas.draw()
+        return self.clicks
+
+
 class Figure(Artist):
 
     def __str__(self):
@@ -892,8 +970,24 @@
                 ax.update_params()
                 ax.set_position(ax.figbox)
 
+    def ginput(self, n=1, timeout=30, verbose=False, show_clicks=True):
+        """
+        ginput(self, n=1, timeout=30, verbose=False, show_clicks=True)
+        
+        Blocking call to interact with the figure. 
 
+        This will wait for n clicks from the user and return a list of the 
+        coordinates of each click. If timeout is negative, does not
+        timeout. If n is negative, accumulate clicks until a middle
+        click terminates the input. Right clicking cancels last input.
+        """
 
+        blocking_mouse_input = BlockingMouseInput(self)
+        return blocking_mouse_input(n=n, timeout=timeout,
+                                          verbose=verbose, show_clicks=True)
+
+
+
 def figaspect(arg):
     """
     Create a figure with specified aspect ratio.  If arg is a number,
Index: backends/backend_qt.py
===================================================================
--- backends/backend_qt.py      (revision 4908)
+++ backends/backend_qt.py      (working copy)
@@ -175,6 +175,9 @@
 
         return key
 
+    def flush_events(self):
+        qt.qApp.processEvents()
+
 class FigureManagerQT( FigureManagerBase ):
     """
     Public attributes
Index: backends/backend_gtk.py
===================================================================
--- backends/backend_gtk.py     (revision 4908)
+++ backends/backend_gtk.py     (working copy)
@@ -386,6 +386,13 @@
     def get_default_filetype(self):
         return 'png'
 
+    def flush_events(self):
+        gtk.gdk.threads_enter()        
+        while gtk.events_pending():
+            gtk.main_iteration(True)
+        gtk.gdk.flush()
+        gtk.gdk.threads_leave()
+        
             
 class FigureManagerGTK(FigureManagerBase):
     """
Index: backends/backend_tkagg.py
===================================================================
--- backends/backend_tkagg.py   (revision 4908)
+++ backends/backend_tkagg.py   (working copy)
@@ -269,8 +269,9 @@
         key = self._get_key(event)
         FigureCanvasBase.key_release_event(self, key, guiEvent=event)
 
+    def flush_events(self):
+        self._master.update()
 
-
 class FigureManagerTkAgg(FigureManagerBase):
     """
     Public attributes
Index: backends/backend_wx.py
===================================================================
--- backends/backend_wx.py      (revision 4908)
+++ backends/backend_wx.py      (working copy)
@@ -1301,6 +1301,9 @@
             wxapp.Yield()
         return True
 
+    def flush_events(self):
+        wx.Yield()
+
 class FigureManagerWx(FigureManagerBase):
     """
     This class contains the FigureCanvas and GUI frame
Index: backends/backend_qt4.py
===================================================================
--- backends/backend_qt4.py     (revision 4908)
+++ backends/backend_qt4.py     (working copy)
@@ -13,7 +13,7 @@
 from matplotlib.mathtext import MathTextParser
 from matplotlib.widgets import SubplotTool
 
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtCore, QtGui, Qt
 
 backend_version = "0.9.1"
 def fn_name(): return sys._getframe(1).f_code.co_name
@@ -174,6 +174,9 @@
 
         return key
 
+    def flush_events(self):
+        Qt.qApp.processEvents()
+
 class FigureManagerQT( FigureManagerBase ):
     """
     Public attributes
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to