|
From: Gael V. <gae...@no...> - 2006-10-29 11:11:54
|
For those who have never used matlab, ginput is a blocking call that
takes one optional argument n, waits for n click on the current figure,
and returns the coordinates of those n clicks. I have been trying to
write such a function in pylab and I can't find a solution.
Here is a first attempt:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
from pylab import *
from time import sleep
class gInput(object):
""" Class that create a callable object to retrieve mouse click in a
blocking way, =E0 la MatLab.
"""
def on_click(self, event):
""" Event handler that will be passed to the current figure to
retrive clicks.
"""
print "called"
if event.inaxes:
self.clicks.append((event.x, event.y))
print self.clicks
def __call__(self, n):
""" Blocking call to retrieve n coordinate pairs through mouse
clicks.
"""
assert isinstance(n, int), "Requires an integer argument"
connect('button_press_event', self.on_click)
self.clicks =3D []
tmp =3D 0
while len(self.clicks)<n :
sleep(0.1)
tmp +=3D 1
if tmp =3D=3D 100:
break
return self.clicks
ginput =3D gInput()
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
++
I run this in ipython -pylab.
This fails. I am not to sure why. It seems the "connect" does not happen
until the __call__ function returns. This is probably due to
eventloop/thread problems that I don't master terribly well. Is there a
solution for this problem (ie a blocking call to retrieve coordinates).
If so it would be great to have such a function in pylab.
Cheers,
Ga=EBl
|
|
From: John H. <jdh...@ac...> - 2006-10-30 14:23:24
|
>>>>> "Gael" == Gael Varoquaux <gae...@no...> writes:
Gael> For those who have never used matlab, ginput is a blocking
Gael> call that takes one optional argument n, waits for n click
Gael> on the current figure, and returns the coordinates of those
Gael> n clicks. I have been trying to write such a function in
Gael> pylab and I can't find a solution.
blocking calls in pylab with gtk threading may be possible but it is
beyond my powers. I would write this with a callback, eg create a
class that takes a callback in the constructor and calls the callback
after n clicks with a list of n coords. blocking input calls may be
easier in tkagg. If there is a gtk/threading guru on hand, I'd be
interested if anyone has ideas on how to do this.
JDH
|
|
From: Gael V. <gae...@no...> - 2006-10-30 14:45:32
|
On Mon, Oct 30, 2006 at 08:21:20AM -0600, John Hunter wrote: > blocking calls in pylab with gtk threading may be possible but it is > beyond my powers. I would write this with a callback, eg create a > class that takes a callback in the constructor and calls the callback > after n clicks with a list of n coords. Yes this is the right way of doing this (I have been experimenting a bit yesterday). However have a blocking call would be really nice for casual programmers, like so many physicists, who have no idea what eventloops and threads are. I think that for such a blocking call to work, all we would need is a way to start and stop the eventloop (I am talking in wx terms, the only GUI toolkit I know). That way when a script call ginput the ginput call adds a few callbacks to the canvas (that's the easy part) and starts the eventloop. The callbacks stop the eventloop when the right number of points as been acquired. Now I have no clue if this is possible, but that would certainly make writing small interactive scripts much easier. Cheers, Ga=EBl |
|
From: John H. <jdh...@ac...> - 2006-10-30 14:53:00
|
>>>>> "Gael" == Gael Varoquaux <gae...@no...> writes:
Gael> On Mon, Oct 30, 2006 at 08:21:20AM -0600, John Hunter wrote:
>> blocking calls in pylab with gtk threading may be possible but
>> it is beyond my powers. I would write this with a callback, eg
>> create a class that takes a callback in the constructor and
>> calls the callback after n clicks with a list of n coords.
Gael> Yes this is the right way of doing this (I have been
Gael> experimenting a bit yesterday). However have a blocking call
Gael> would be really nice for casual programmers, like so many
Gael> physicists, who have no idea what eventloops and threads
Gael> are.
Gael> I think that for such a blocking call to work, all we would
Gael> need is a way to start and stop the eventloop (I am talking
Gael> in wx terms, the only GUI toolkit I know). That way when a
Gael> script call ginput the ginput call adds a few callbacks to
Gael> the canvas (that's the easy part) and starts the
Gael> eventloop. The callbacks stop the eventloop when the right
Gael> number of points as been acquired.
Gael> Now I have no clue if this is possible, but that would
Gael> certainly make writing small interactive scripts much
Gael> easier.
Nadia pursued blocking calls for a while and I think she made some
progress. You are right about this model fitting the brain of
physicists better than a callback approach. Maybe Nadia can bring us
up to speed on where she left off.
JDH
|
|
From: Christopher B. <Chr...@no...> - 2006-10-30 18:36:27
|
Gael Varoquaux wrote:
> I think that for such a blocking call to work, all we would need is a
> way to start and stop the eventloop (I am talking in wx terms, the only
> GUI toolkit I know).
That's a trick, because if you stop the event loop, then you don't get
the mouse clicks...
However, perhaps you can take advantage of a similar feature (at least
in wx) -- can you make the Frame Modal temporarily? My understanding of
how model dialogs work is that they stop the main event loop, and then
have their own event loop, for just that frame -- then you could catch
the mouse event you want, and make it non-modal again.
What I don't know is if you can make a Frame model/non-model without
hiding and showing it in the process...
I also don't know if other toolkits work similarly.
-Chris
--
Christopher Barker, Ph.D.
Oceanographer
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception
Chr...@no...
|
|
From: Gael V. <gae...@no...> - 2006-10-30 18:50:38
|
On Mon, Oct 30, 2006 at 10:36:09AM -0800, Christopher Barker wrote:
> However, perhaps you can take advantage of a similar feature (at least=20
> in wx) -- can you make the Frame Modal temporarily? My understanding of=
=20
> how model dialogs work is that they stop the main event loop, and then=20
> have their own event loop, for just that frame -- then you could catch=20
> the mouse event you want, and make it non-modal again.
I far as I have seen in ipython the execution of a script blocks the
eventloop. Now in another shell if the shell is not aware of the event
loop, calling show() will block until the windows is closed (that might b=
e
a good blocking call for my purpose). This leaves us with the case where
the shell is a wx shell and lives in the eventloop. A wx guru would
probably give us the solution here.
Now I am probably talking nonsense, as I don't know much about gui and
event loop, but it does look like there might be a solution (and the
chances that I actually implement this are close to zero, given my
knowledge of these things).
Ga=C3l
|
|
From: Fernando P. <fpe...@gm...> - 2006-10-30 19:38:07
|
On 10/30/06, Gael Varoquaux <gae...@no...> wrote:
> On Mon, Oct 30, 2006 at 10:36:09AM -0800, Christopher Barker wrote:
> > However, perhaps you can take advantage of a similar feature (at least
> > in wx) -- can you make the Frame Modal temporarily? My understanding of
> > how model dialogs work is that they stop the main event loop, and then
> > have their own event loop, for just that frame -- then you could catch
> > the mouse event you want, and make it non-modal again.
>
> I far as I have seen in ipython the execution of a script blocks the
> eventloop. Now in another shell if the shell is not aware of the event
> loop, calling show() will block until the windows is closed (that might be
> a good blocking call for my purpose). This leaves us with the case where
> the shell is a wx shell and lives in the eventloop. A wx guru would
> probably give us the solution here.
Jut to clarify, Gael: in ipython (with -pylab or -{g,w,q}thread), what
happens is that IPython lets the GUI toolkit run in the main thread,
and then attaches its own routines for user code execution as the
toolkit's idle timer callback and runs in a secondary thread (each
toolkit has its own way of doing this, but the basic idea is the
same).
The only blocking that you see comes from blocking code which your
scripts may call (typically extension code, C, Fortran, etc), since at
that point the Python interpreter can't switch out of this secondary
thread. But as long as your scripts do NOT call any extension
blocking code, the Python interpreter will switch out every 100
bytecodes between your user code and the main thread.
This two-thread arrangement has a big drawback: the inability to
interrupt long-running calculations (even non-blocking ones) with
Ctrl-C, because it is simply impossible in Python to toss asynchronous
signals accross threads. And yes, I've tried even using the
undocumented Python C-API for cross-thread asynchronous signals via
this recipe:
http://sebulba.wikispaces.com/recipe+thread2
I spent some time on this, unsuccessfully. I still don't understand
why it doesn't work, since what I'm trying to do seems to be exactly
what that recipe is for. If anyone ever gets this to work, *please*
send it to me. It would be a major usability improvement to get
interruptibility of long computations in the threaded Pylab
environments (GTK, QT and Wx). In fact, this is part of the reason
why I'm resisting a switch to Wx: I really hate not being able to
cleanly stop a computation that is taking longer than I meant, or
which I accidentally started.
Cheers,
f
|
|
From: Gael V. <gae...@no...> - 2006-10-30 19:59:57
|
On Mon, Oct 30, 2006 at 12:37:42PM -0700, Fernando Perez wrote:
> Jut to clarify, Gael: in ipython (with -pylab or -{g,w,q}thread), what
> happens is that IPython lets the GUI toolkit run in the main thread,
> and then attaches its own routines for user code execution as the
> toolkit's idle timer callback and runs in a secondary thread (each
> toolkit has its own way of doing this, but the basic idea is the
> same).
OK, similar to launching a wx application and starting a thread in it
with ipython attached to this thread ? Is there a "hook" to the main
eventloop that would be accessible to the code running in ipython. Thus
a wx.CallAfter or alike in different toolkits, and other eventloop and
multi-threaded programming tricks might be useful here. Maybe this
solution would even provide the solution for blocking calls with MPL
with most multi-threaded cases.
The problem I hit in my first attempt was that the "connect" call
executed in my function did not seem to be executed until the function
returned. If I can connect a callback to the figure in the beginning of
the function, then loop waiting and checking a parameter the will be set
be the callback, then process the parameter when available.
I do not see why this could not work, but then my understanding of
multithreaded programming is quite poor.
> This two-thread arrangement has a big drawback: the inability to
> interrupt long-running calculations (even non-blocking ones) with
> Ctrl-C, because it is simply impossible in Python to toss asynchronous
> signals accross threads.=20
Yes :-<. Have you tried getting some help from a guru, it seems to be
worth the while.
Cheers,
Ga=C3l
|