From: Jerzy K. <jer...@un...> - 2012-01-26 21:24:14
|
Does anybody know how to generate and process my "private" events? I can subclass the Event() class, say, MyEvent, with a name "my_event", and I can - canvas.mpl_connect('my_event', aCallback) but then, how to fire one? (I don't want to call the callback directly). Suppose that the interface, when show() is active launches a simulation/visualisation program which animates many things in its figure. From time to time something "special" appears, and its behaviour should be steered by those private events. (Yes, I know that I can do it in several other ways, or write my own event-processing loop, or use directly wxPython or PyGTK instead of Matplotlib. So, I don't need the replacement solution, but just a way to fire events within Matplotlib...) Thank you. Jerzy Karczmarczuk Caen, France |
From: Benjamin R. <ben...@ou...> - 2012-01-26 21:39:59
|
On Thu, Jan 26, 2012 at 3:24 PM, Jerzy Karczmarczuk < jer...@un...> wrote: > Does anybody know how to generate and process my "private" events? I can > subclass the Event() class, say, MyEvent, > with a name "my_event", and I can - > canvas.mpl_connect('my_event', aCallback) > > but then, how to fire one? (I don't want to call the callback directly). > > > Suppose that the interface, when show() is active launches a > simulation/visualisation program which animates many things in its > figure. From time to time something "special" appears, and its behaviour > should be steered by those private events. > > (Yes, I know that I can do it in several other ways, or write my own > event-processing loop, or use directly wxPython or PyGTK instead of > Matplotlib. So, I don't need the replacement solution, but just a way to > fire events within Matplotlib...) > > Thank you. > > Jerzy Karczmarczuk > Caen, France > > It is smart to simply re-use mpl's event callback system. Luckily, in the latest release, we allowed for arbitary events to be added. To answer your question, take a look at how pick_event() is declared in backend_bases.py: def pick_event(self, mouseevent, artist, **kwargs): """ This method will be called by artists who are picked and will fire off :class:`PickEvent` callbacks registered listeners """ s = 'pick_event' event = PickEvent(s, self, mouseevent, artist, **kwargs) self.callbacks.process(s, event) The function that "fires" the event is "self.callbacks.process(s, event)", where "self" is the figure canvas. I hope this helps! Ben Root |
From: Jerzy K. <jer...@un...> - 2012-01-27 10:54:43
|
Benjamin Root answers my query concerning user-generated events : > To answer your question, take a look at how pick_event() is declared > in backend_bases.py: > > def pick_event(self, mouseevent, artist, **kwargs): > ... > self.callbacks.process(s, event) > > The function that "fires" the event is "self.callbacks.process(s, > event)", where "self" is the figure canvas. Dear Ben, thank you, but this is not exactly my problem. I don't want to call the callback myself, since the event should be "fired" from within a callback. I should have been more precise. Let's distil the problem. [This is a part of my current teaching...] I did already what you suggest here... Imagine an animation, which consists in generating a trajectory, segment after segment (say, of a planet). Classically this is a loop, but when it runs, the rest of the program is blocked. So, instead, the code behaves as a Python generator, generates just one segment, and that's all. But it "yields" something, it posts an event, put it in a queue, and somebody else, the mainloop() or similar, pops it off the queue and re-launches the callback. (With generators, it calls the .next()). No timers, as in Timer or Funct animations... It must be "decentralized", no recursive calls. My callback from time to time creates another planet, or destroys an existent, and there are simultaneous trajectories on the screen, several concurrent events in the queue. And the system should remain reactive, interpret buttons, sliders, etc. I know how to do this by hand, how to write my own event loop, declare a queue, and how to add to my private "virtual" event handling also the callbacks of mouse events. But this is an overkill, I repeat the functionalities which are already there, the event queue in particular. I did it with wx. But Matplotlib protects the user from the concrete back-end, and I want to protect my students as well, so I look for a "GUI-neutral" solution. Thanks. Jerzy |
From: Tony Yu <ts...@gm...> - 2012-01-27 16:54:34
|
On Fri, Jan 27, 2012 at 5:54 AM, Jerzy Karczmarczuk < jer...@un...> wrote: > Benjamin Root answers my query concerning user-generated events : > > To answer your question, take a look at how pick_event() is declared > > in backend_bases.py: > > > > def pick_event(self, mouseevent, artist, **kwargs): > > ... > > self.callbacks.process(s, event) > > > > The function that "fires" the event is "self.callbacks.process(s, > > event)", where "self" is the figure canvas. > Dear Ben, thank you, but this is not exactly my problem. I don't want to > call the callback myself, since the event should be "fired" from within > a callback. I should have been more precise. Let's distil the problem. > [This is a part of my current teaching...] I did already what you > suggest here... > > Imagine an animation, which consists in generating a trajectory, segment > after segment (say, of a planet). Classically this is a loop, but when > it runs, the rest of the program is blocked. So, instead, the code > behaves as a Python generator, generates just one segment, and that's > all. But it "yields" something, it posts an event, put it in a queue, > and somebody else, the mainloop() or similar, pops it off the queue and > re-launches the callback. (With generators, it calls the .next()). No > timers, as in Timer or Funct animations... > > It must be "decentralized", no recursive calls. My callback from time to > time creates another planet, or destroys an existent, and there are > simultaneous trajectories on the screen, several concurrent events in > the queue. And the system should remain reactive, interpret buttons, > sliders, etc. > > I know how to do this by hand, how to write my own event loop, declare a > queue, and how to add to my private "virtual" event handling also the > callbacks of mouse events. But this is an overkill, I repeat the > functionalities which are already there, the event queue in particular. > > I did it with wx. But Matplotlib protects the user from the concrete > back-end, and I want to protect my students as well, so I look for a > "GUI-neutral" solution. > > Thanks. > > Jerzy > I'm not sure if this matches your use case, but have you looked into using a coroutine. (I only recently learned about them---see presentation slides linked on this page <http://www.dabeaz.com/coroutines/>. So obviously I'm going out of my way to find a use case :) I've attached a simple example below. -Tony #~~~ import matplotlib.pyplot as plt import numpy as np def datalistener(): fig, ax = plt.subplots() line, = ax.plot(0, 0, 'o-') i = 1 while True: y0 = yield x = np.hstack((line.get_xdata(), i)) y = np.hstack((line.get_ydata(), y0)) line.set_data((x, y)) ax.update_datalim(np.transpose((x, y))) ax.autoscale_view() plt.draw() i += 1 plt.ion() plotdata = datalistener() # initialize the coroutine plotdata.next() while True: y = raw_input('enter data point: ') try: plotdata.send(float(y)) except: break |
From: Jerzy K. <jer...@un...> - 2012-01-27 21:12:31
|
Tony Yu suggests that my multiple and changing animation problems could be solved using coroutining. > have you looked into using a coroutine. /... /I've attached a simple > example below. > > import matplotlib.pyplot as plt > import numpy as np > def datalistener(): > ... > while True: > y0 = yield > x = np.hstack((line.get_xdata(), i)) > ... > plt.ion() > ... Thank you Tony. No, unfortunately this is again a "side solution". Of course, coroutines, or just a simple event loop using Python generators without .send(), are perfectly decent tools to simulate parallel "movements". But, coroutines as such, are better adapted to situations where the actors transfer the control among themselves, where there is a network of direct communications, a "multi-ping-pong". In my case this is redundant, my "planets" which move concurrently are independent, and they, after having updated their properties, need only to yield the control to the interface, to draw them. The interface resumes (by calling, no .send() is needed) all the actors in sequence. I repeat again : I COULD have written my own event loop (under ion()). But I don't want to do this, since show() which calls some lower level mainloop() does all this already! In particular, it handles the physical events, all mousing, which need anyway some lower-level mechanisms, and my own coroutines won't help. I MUST use the built-in tools in order to handle the mouse. So, I repeat, my only [as I see it] rational choice is to plug-in my events into the standard loop. Under, say, plain wxPython, I can write my own, and call ProcessPendingEvents(), but with Matplotlib, no idea. Ben Root suggested to look some existing codes, say the Picker. But this is called upon a physical event, which is "fired" under the hood. My events are "virtual", I have to post them myself from a callback, so it canot call recursively another callback, or I am dead. Best regards. Jerzy |
From: Benjamin R. <ben...@ou...> - 2012-01-27 21:56:03
|
On Fri, Jan 27, 2012 at 4:54 AM, Jerzy Karczmarczuk < jer...@un...> wrote: > Benjamin Root answers my query concerning user-generated events : > > To answer your question, take a look at how pick_event() is declared > > in backend_bases.py: > > > > def pick_event(self, mouseevent, artist, **kwargs): > > ... > > self.callbacks.process(s, event) > > > > The function that "fires" the event is "self.callbacks.process(s, > > event)", where "self" is the figure canvas. > Dear Ben, thank you, but this is not exactly my problem. I don't want to > call the callback myself, since the event should be "fired" from within > a callback. I should have been more precise. Let's distil the problem. > [This is a part of my current teaching...] I did already what you > suggest here... > > Imagine an animation, which consists in generating a trajectory, segment > after segment (say, of a planet). Classically this is a loop, but when > it runs, the rest of the program is blocked. So, instead, the code > behaves as a Python generator, generates just one segment, and that's > all. But it "yields" something, it posts an event, put it in a queue, > and somebody else, the mainloop() or similar, pops it off the queue and > re-launches the callback. (With generators, it calls the .next()). No > timers, as in Timer or Funct animations... > > It must be "decentralized", no recursive calls. My callback from time to > time creates another planet, or destroys an existent, and there are > simultaneous trajectories on the screen, several concurrent events in > the queue. And the system should remain reactive, interpret buttons, > sliders, etc. > > I know how to do this by hand, how to write my own event loop, declare a > queue, and how to add to my private "virtual" event handling also the > callbacks of mouse events. But this is an overkill, I repeat the > functionalities which are already there, the event queue in particular. > > I did it with wx. But Matplotlib protects the user from the concrete > back-end, and I want to protect my students as well, so I look for a > "GUI-neutral" solution. > > Thanks. > > Jerzy > > Still not sure why my suggestion would not work: http://matplotlib.sourceforge.net/api/cbook_api.html#matplotlib.cbook.CallbackRegistry You can have things set up such that event being triggered can subsequently trigger other events as well. An event can even connect a new event as well. An example where I do this is when I want to hide a line while it is clicked. In the function that I connect to a "button_press_event", I make the artist invisible, and I also create a lambda function that sets the visibility of that artist to True (and subsequently disconnects itself) and connect that lambda to a "button_release_event". Keep in mind that these "events" are merely key'ed by strings like "button_press_event", there is nothing magical about them. So, when you call the .process() function with a string value and an Event object, it passes that object to every connection that was made with that same string value. You can call the process() function from anywhere, even within an event. Now, I haven't tried connecting a generator function with a yield statement before, so I don't know how well that would work, but I don't know why it wouldn't. Why exactly would the callback registry not work for you? Ben Root |
From: Jerzy K. <jer...@un...> - 2012-01-28 16:31:25
|
Benjamin Root about my miserable event problem : > Still not sure why my suggestion would not work: > > http://matplotlib.sourceforge.net/api/cbook_api.html#matplotlib.cbook.CallbackRegistry I thought I told you. Probably I am doing something utterly false, but my distilled problem is that*I am generating events from within a callback*. Here you are a complete skeleton program. from pylab import * from matplotlib.cbook import * from matplotlib.widgets import Button fig=figure() ax = fig.add_subplot(1,1,1) xis=axis([0,1,0,1]) subplots_adjust(left=0.1, bottom=0.1) clrax = axes([0.67, 0.02, 0.08, 0.04]) clbut = Button(clrax, 'Clear', color="1.0") goax = axes([0.88, 0.02, 0.08, 0.04]) gobut = Button(goax, 'Go', color="#40ffa0") cbacks = CallbackRegistry() def line(*evt): plot(rand(2),rand(2)) ; draw() cbacks.process('line_', None) linv = cbacks.connect('line_', line) def clr(ev=None): del ax.lines[:] clbut.on_clicked(clr) def start(evt): cbacks.process('line_', None) gobut.on_clicked(start) subplot(1,1,1) show() The function line() is the main iterative engine, a "loop" without looping. It should post an event which re-launches it, and still leaving the master loop active, so I can clear the figure. Nope. This is a /*recursive call*/. Python bombs after a while, recursive limit exceeded, and only then the Clear button wakes up. Thank you for your effort. Jerzy |
From: Benjamin R. <ben...@ou...> - 2012-01-28 20:32:50
|
On Sat, Jan 28, 2012 at 10:31 AM, Jerzy Karczmarczuk < jer...@un...> wrote: > Benjamin Root about my miserable event problem : > > Still not sure why my suggestion would not work: > > > http://matplotlib.sourceforge.net/api/cbook_api.html#matplotlib.cbook.CallbackRegistry > > > I thought I told you. Probably I am doing something utterly false, but my > distilled problem is that* I am generating events from within a callback*. > Here you are a complete skeleton program. > > > from pylab import * > from matplotlib.cbook import * > from matplotlib.widgets import Button > fig=figure() > ax = fig.add_subplot(1,1,1) > xis=axis([0,1,0,1]) > subplots_adjust(left=0.1, bottom=0.1) > clrax = axes([0.67, 0.02, 0.08, 0.04]) > clbut = Button(clrax, 'Clear', color="1.0") > goax = axes([0.88, 0.02, 0.08, 0.04]) > gobut = Button(goax, 'Go', color="#40ffa0") > cbacks = CallbackRegistry() > > def line(*evt): > plot(rand(2),rand(2)) ; draw() > cbacks.process('line_', None) > > linv = cbacks.connect('line_', line) > > def clr(ev=None): del ax.lines[:] > clbut.on_clicked(clr) > def start(evt): cbacks.process('line_', None) > gobut.on_clicked(start) > > subplot(1,1,1) > show() > > The function line() is the main iterative engine, a "loop" without > looping. It should post an event which re-launches it, and still leaving > the master loop active, so I can clear the figure. > > Nope. This is a *recursive call*. > Python bombs after a while, recursive limit exceeded, and only then the > Clear button wakes up. > > Thank you for your effort. > > Jerzy > > Jerzy, 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 call to process() is protected by an if-statement that checks to see if evt is less than 10, and the call to process passes "evt + 1". The initial call to process passes a value of zero. The program then produces 10 random lines just fine when I press "Go". Does that help clear up your problem? Ben Root |
From: Benjamin R. <ben...@ou...> - 2012-01-29 00:53:20
|
On Sat, Jan 28, 2012 at 4:10 PM, Jerzy Karczmarczuk < jer...@un...> wrote: > 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. |
From: Jerzy K. <jer...@un...> - 2012-01-29 11:41:25
|
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 |
From: Benjamin R. <ben...@ou...> - 2012-01-29 16:53:52
|
On Sunday, January 29, 2012, Jerzy Karczmarczuk < jer...@un...> 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 |
From: Fernando P. <fpe...@gm...> - 2012-01-29 18:43:59
|
On Sun, Jan 29, 2012 at 3:41 AM, Jerzy Karczmarczuk <jer...@un...> 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. 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 |
From: Jerzy K. <jer...@un...> - 2012-01-29 20:20:52
|
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 |
From: Fernando P. <fpe...@gm...> - 2012-01-29 20:45:34
|
On Sun, Jan 29, 2012 at 12:20 PM, Jerzy Karczmarczuk <jer...@un...> wrote: > 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 :) > 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 :) Cheers, f |
From: Jerzy K. <jer...@un...> - 2012-01-29 22:29:55
|
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 |
From: Fernando P. <fpe...@gm...> - 2012-01-29 22:33:35
|
On Sun, Jan 29, 2012 at 2:29 PM, Jerzy Karczmarczuk <jer...@un...> wrote: > This is a temporal pause, not an undetermined suspension, restartable. Ah, never mind then. I didn't read the docstring and misunderstood the discussion in the pull request. Cheers, f |