Events

Ben Root, about my example in which an infinite callback loop

overflows :

  So, where is your terminating condition?  Of course it

will continuously call itself if you have nothing to stop it.
Protect that call to “process” with some sort of if-statement and
use “evt” to carry some sort of state that can be tested in that
if-statement.

  For example, I modified your example to use "evt" to carry an

integer.

  The program then produces 10 random lines just fine

when I press “Go”.

  Does that help clear up your problem?
No, I am afraid this not the solution, Ben. My program is distilled,

the truth is more complicated, but I don’t need any fixed
termination condition, this is a simulation program which works
continuously until some other button invalidates some variable, say
“running” (or kills the window, etc.). It should go forever
[of course the real program doesn’t pollute the axes.lines memory,
this is a non-issue].

Right, so you need to create your web of callbacks accordingly. The callback registry is just simply a tool that we created for our use. Keep in mind that your original question to this thread was “how do I fire events?”. I answered that question a while back.

The issue is that calling a callback from a callback is an

abomination in general!

Then don’t do it! If it happens in mpl, it is rare and well controlled.

It should never happen. What SHOULD happen,

and takes place in a “standard” event loop is that the last line of
my procedure “line” is, equivalent [simplified] to

if running: push(line,queue)

The main loop works as follows:

while notempty(queue):

  `  cbak=pop(queue)`

  `  call(cbak,...)`
This "distributed loop" may run as long as you wish, no recursion

overflow, and the possibility to stop it by another callback which
assigns running=False.

Ok, but the callback registry is not an event loop. It is just a callback registry. The main-loops are in the respective GUI toolkits.

I repeat that I can in principle write it myself, under ion(), and

never call show().
But mainloop() of ANY GUI backend does already everything
that. But I don’t know how to find the access to the event queue.

There is no event queue in the CallbackRegistry. What we have done in the respective GUI backends is to link various GUI actions to calls to process(). The CallbackRegistry itself is GUI-neutral and heck, it doesn’t even assume a GUI exists, which allows for us to still use the callback registry for other uses in non-interactive modes and headless modes. Therefore, there is no mainloop, there is no event queue.

Under wx, when I write my own loop, there are shortcuts. app.Dispatch()
processes the first event in the queue, or waits until something
happens. Or I call app.ProcessPendingEvents().

My callbacks would call `PostEvent(dest, event)`    . The

destination is a window. I did it some years ago, I don’t remember
the details, but Post did not block anything, returned immediately,
and the callback containing it, as well. It is possible to Post an
event also from another thread, and thus faking a Timer.

MPL was written with single-threadedness in mind. There is an example of multi-processing and mpl, but I don’t know how applicable it would be to you. I will link it here in case it inspires someone:

http://matplotlib.sourceforge.net/examples/misc/multiprocess.html

If there were only the "virtual events", I wouldn't bother anybody.

But I have to deal with all the mouse events as well as with the
virtual ones. Cumbersome.

I also noticed that in the example you posted, you created your own callback registry. Why didn’t you use the existing one that comes with the figure canvas?

Quite honestly, I (and I suspect others) are not sure what you are asking of us. You seem to be quite knowledgeable, but – quite frankly – all I see is you complaining about the problem. Is there a bug that you wish to report? Is there a fundamental design flaw in mpl that you wish to address? Or are you confused about how to use the CallbackRegistry?

My only guess is that you were hoping that there was a GUI-neutral mainloop in mpl. I am sorry to say that one doesn’t exist in the manner you are speaking. Each backend communicates with the GUI’s mainloop as needed by the toolkit. There is no abstracted API for this. Instead, very specific actions have been created for each backends. All other actions (like object picking, changes in the axes and such) are GUI-neutral and do not need direct interaction with the mainloop (only a call to draw() when finished).

I really want to help you here, but I need you to be very clear about what you want and to exclude any extraneous “rants” you may have.

Cheers!
Ben Root

P.S. - Please keep this thread on-list.

···

On Sat, Jan 28, 2012 at 4:10 PM, Jerzy Karczmarczuk <jerzy.karczmarczuk@…3937…> wrote:

I believe that I should terminate this thread (from my side), since the image is clear. The actual version of Matplotlib is not adapted to my needs, a rather involved animation of many objects, and changing. The last dialogue with Benjamin Root, whom I am deeply grateful, cleared my doubts. Ben confirms that I am on my own:

// you need to create your web of callbacks accordingly. The callback registry is just simply a tool that we created for our use. Keep in mind that your original question to this thread was "how do I fire events?". I answered that question a while back.

My question - sorry for being unclear - was how to fire events ASYNCHRONOUSLY. How to post them, to be processed by the event loop, not how to call callbacks.

Ok, but the callback registry is not an event loop. It is just a callback registry. The main-loops are in the respective GUI toolkits.

I know that. I read a good part of the matlotlib source, but not all of this, since I thought that asking questions might be more efficient. And actually it was.

There is no event queue in the CallbackRegistry. What we have done in the respective GUI backends is to link various GUI actions to calls to process(). The CallbackRegistry itself is GUI-neutral and heck, it doesn't even assume a GUI exists, which allows for us to still use the callback registry for other uses in non-interactive modes and headless modes. Therefore, there is no mainloop, there is no event queue.

This, I believe, is the final answer. Sigh. OK. I am not saved from the Pooh syndrome (The more he looked inside the more Piglet wasn't there), since now I plan to either code something myself, or to give it as a project to my students. I believe that Matplotlib merits this, there is plenty of potentialities, but the animation seems to be still in statu nascendi.

  I also noticed that in the example you posted, you created your own callback registry. Why didn't you use the existing one that comes with the figure canvas?

Oh, of course. But this was accidental, it doesn't change anything.

Quite honestly, I (and I suspect others) are not sure what you are asking of us. You seem to be quite knowledgeable, but -- quite frankly -- all I see is you complaining about the problem. /.../ I need you to be very clear about what you want and to exclude any extraneous "rants" you may have.

NO SIR. I am not complaining (cite my "complaints" if you disagree). I am trying to find a solution to a problem of delayed, asynchronous event processing within Matplotlib. I try to be compact, this is just a mailing list. And please: what "rants"??? I would never say anything bad about the system nor its authors, I am asking questions. No bugs to reports (only that from time to time Python declares some execution error of a sub-process, but it may have several sources).

My only guess is that you were hoping that there was a GUI-neutral mainloop in mpl. I am sorry to say that one doesn't exist in the manner you are speaking.

Again, this IS the answer. Thank you very much.

···

================

There is one "rant", if you wish (of course, I am joking).

The animation objects (FuncAnimation, etc.) are coded as they are, probably sufficient for you. They are "one shot". But if you want to stop and to resume your animation, they are not so well adapted. Calling ._stop (not documented) from a callback is deadly, because of the cleaning procedures. You can't re-_start it. The only way - as I see it - is to create another animation. OK, but this might not be the most efficient way to do it.

I am afraid that my fascination by Matplotlib, which I really use for my teaching of scientific programming and visualization, pushed me to try to use the package outside its actual limits. Sorry bor bothering you. If I find something of general interest, I will post it, perhaps.

All the best, sincerely.

Jerzy Karczmarczuk
Caen, France

No problem, I am glad to see the question cleared up. I suspect that what I interpreated as a rant was more related to my frustrations, so I apologize.

I wonder if the Timer class in cbook.py might be useful to you? It is GUI-neutral and it could act as a global “heartbeat” for your simulator.

As for your issues with the animation class. It is a very new feature and we welcome any feedback. The _stop() function is intended, iirc, to be used for when the figure window closes. What you are looking for is some sort of pause() function. Feel free to file a feature request on mpl’s github page.

Cheers!
Ben Root

···

On Sunday, January 29, 2012, Jerzy Karczmarczuk <jerzy.karczmarczuk@…3937…> wrote:

I believe that I should terminate this thread (from my side), since the image is clear. The actual version of Matplotlib is not adapted to my needs, a rather involved animation of many objects, and changing. The last dialogue with Benjamin Root, whom I am deeply grateful, cleared my doubts. Ben confirms that I am on my own:

// you need to create your web of callbacks accordingly. The callback registry is just simply a tool that we created for our use. Keep in mind that your original question to this thread was “how do I fire events?”. I answered that question a while back.

My question - sorry for being unclear - was how to fire events ASYNCHRONOUSLY. How to post them, to be processed by the event loop, not how to call callbacks.

Ok, but the callback registry is not an event loop. It is just a callback registry. The main-loops are in the respective GUI toolkits.

I know that. I read a good part of the matlotlib source, but not all of this, since I thought that asking questions might be more efficient. And actually it was.

There is no event queue in the CallbackRegistry. What we have done in the respective GUI backends is to link various GUI actions to calls to process(). The CallbackRegistry itself is GUI-neutral and heck, it doesn’t even assume a GUI exists, which allows for us to still use the callback registry for other uses in non-interactive modes and headless modes. Therefore, there is no mainloop, there is no event queue.

This, I believe, is the final answer. Sigh. OK. I am not saved from the Pooh syndrome (The more he looked inside the more Piglet wasn’t there), since now I plan to either code something myself, or to give it as a project to my students. I believe that Matplotlib merits this, there is plenty of potentialities, but the animation seems to be still in statu nascendi.

I also noticed that in the example you posted, you created your own callback registry. Why didn’t you use the existing one that comes with the figure canvas?

Oh, of course. But this was accidental, it doesn’t change anything.

Quite honestly, I (and I suspect others) are not sure what you are asking of us. You seem to be quite knowledgeable, but – quite frankly – all I see is you complaining about the problem. /…/ I need you to be very clear about what you want and to exclude any extraneous “rants” you may have.

NO SIR. I am not complaining (cite my “complaints” if you disagree). I am trying to find a solution to a problem of delayed, asynchronous event processing within Matplotlib. I try to be compact, this is just a mailing list. And please: what “rants”??? I would never say anything bad about the system nor its authors, I am asking questions. No bugs to reports (only that from time to time Python declares some execution error of a sub-process, but it may have several sources).

My only guess is that you were hoping that there was a GUI-neutral mainloop in mpl. I am sorry to say that one doesn’t exist in the manner you are speaking.

Again, this IS the answer. Thank you very much.

================

There is one “rant”, if you wish (of course, I am joking).

The animation objects (FuncAnimation, etc.) are coded as they are, probably sufficient for you. They are “one shot”. But if you want to stop and to resume your animation, they are not so well adapted. Calling ._stop (not documented) from a callback is deadly, because of the cleaning procedures. You can’t re-_start it. The only way - as I see it - is to create another animation. OK, but this might not be the most efficient way to do it.

I am afraid that my fascination by Matplotlib, which I really use for my teaching of scientific programming and visualization, pushed me to try to use the package outside its actual limits. Sorry bor bothering you. If I find something of general interest, I will post it, perhaps.

All the best, sincerely.

Jerzy Karczmarczuk
Caen, France

Actually many thanks for this very interesting discussion! Just on
Friday I came to this same conclusion while preparing some lecture
material using animations. The lack of a clean pause/restart
functionality is indeed problematic. Furthermore, closing a window
that's running an animation, at least with the Qt backend, gave rise
to a massive swarm of 'C++ object has been deleted' messages flooding
the console where my ipython kernel had been started.

One thing to keep in mind, if you go down the road of implementing a
full-blown event loop for matplotlib, is how well it will play with
existing event loops. Whenever an interactive GUI backend is running,
there's already an event loop at work: that of the GUI toolkit.
Integrating multiple event loops in the same process takes some
delicate footwork if you don't want to end up with a nasty fight
between the two.

In any case, keep us posted on any progress!

Best,

f

···

On Sun, Jan 29, 2012 at 3:41 AM, Jerzy Karczmarczuk <jerzy.karczmarczuk@...3937...> wrote:

There is one "rant", if you wish (of course, I am joking).

The animation objects (FuncAnimation, etc.) are coded as they are,
probably sufficient for you. They are "one shot". But if you want to
stop and to resume your animation, they are not so well adapted.

Fernando Perez :

The lack of a clean pause/restart
functionality is indeed problematic. Furthermore, closing a window
that's running an animation, at least with the Qt backend, gave rise
to a massive swarm of 'C++ object has been deleted' messages flooding
the console where my ipython kernel had been started.

` This happens also with different backends and the driving
interface (say, Idle with Tkinter…)

  Some solutions exist. The simplest one is the following.

  1. Use a particular event source, e.g. launch:

`

ani = anima.FuncAnimation(fig, proc, repeat=False, frames=sourcegen)
`

`where`

`

def sourcegen():

  `    while running: yield 0 #or whatever`

  `    return`

Include a button`

`

def astop(ev=None):

  `    global running`

  `    running=False`

  `stopbutton.on_clicked(astop)`
and it will kill your animation in a proper way. Restarting it

demands that “ani” be recreated within a callback, say, a startbutton.

But this is not pausing. Recreating the animation, recreating and

starting a timer, connecting all the callbacks… this takes time,
and you SEE it.

if you go down the road of implementing a
full-blown event loop for matplotlib, is how well it will play with
existing event loops. Whenever an interactive GUI backend is running,
there's already an event loop at work: that of the GUI toolkit.
Integrating multiple event loops in the same process takes some
delicate footwork if you don't want to end up with a nasty fight
between the two.

Absolutely.

But first, you don't need to launch show() and force some

mainloop(), MainLoop(), gtk.main(), etc. under the hood. We wrote
some loops under wx, simple-minded ; there is one included in the
standard docs-and-demos. I don’t know yet how to force WindowUpdate
from Matplotlib, but some “plugin” solution should exist, since
Matplotlib does that already.

Second, even if an event loop runs already, the question is to plug

in the access to the concrete event queue mechanism, not to
superpose another one, and yell with horror at which level declare
callbacks…

Thank you, Fernando.

Jerzy Karczmarczuk

This happens also with different backends and the driving interface (say,
Idle with Tkinter...)
Some solutions exist. The simplest one is the following.

Thanks for the tips! It would really be nice if in animation mode,
the mpl windows had automatically a play/pause toggle at the very
least, so that regular users could get more functional animations
without having to wire these extra tricks.

I now see there's even a pause() call:

https://github.com/matplotlib/matplotlib/pull/148

so it seems like it should be an easy matter of adding the button and
wire it to pause(). Perhaps one of your students could make a nice
contribution :slight_smile:

Absolutely.
But first, you don't need to launch show() and force some mainloop(),
MainLoop(), gtk.main(), etc. under the hood. We wrote some loops under wx,
simple-minded ; there is one included in the standard docs-and-demos. I
don't know yet how to force WindowUpdate from Matplotlib, but some "plugin"
solution should exist, since Matplotlib does that already.

Second, even if an event loop runs already, the question is to plug in the
access to the concrete event queue mechanism, not to superpose another one,
and yell with horror at which level declare callbacks...

Best of luck. Having burned many hours on the ipython/matplotlib
event loop integration over the years, I don't envy you right now if
you're going to fight this little battle... But I'll happily cheer you
from the safety of the sidelines :slight_smile:

Cheers,

f

···

On Sun, Jan 29, 2012 at 12:20 PM, Jerzy Karczmarczuk <jerzy.karczmarczuk@...3937...> wrote:

Fernando Perez:

I now see there's even a pause() call:

https://github.com/matplotlib/matplotlib/pull/148

so it seems like it should be an easy matter of adding the button and
wire it to pause().

This is a temporal pause, not an undetermined suspension, restartable.

Jerzy

Ah, never mind then. I didn't read the docstring and misunderstood
the discussion in the pull request.

Cheers,

f

···

On Sun, Jan 29, 2012 at 2:29 PM, Jerzy Karczmarczuk <jerzy.karczmarczuk@...3937...> wrote:

This is a temporal pause, not an undetermined suspension, restartable.