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):
+"""
+