|
From: rouckas <ste...@gm...> - 2014-11-07 11:08:40
|
Dear all, I have a problem with using certain class methods as event handlers. In the following example: the method Test.on_press() is never executed. Only "clicked0" and "clicked1" is printed when I click on the canvas. When i use pure matplotlib widgets instead of tkinter embedding, the code works as expected. Is this a matplotlib bug or am I doing something wrong? My software versions are: Python 3.4.0 matplotlib.__version__ == '1.3.1' tkinter.TkVersion == 8.6 in Ubuntu 14.04 Thanks in advance for any help, Stepan -- View this message in context: http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302.html Sent from the matplotlib - users mailing list archive at Nabble.com. |
|
From: rouckas <ste...@gm...> - 2014-11-07 14:31:55
|
I have a little update on the issue: I tried it with different versions of
python and matplotlib and it is still present in
python 2.7.6 + matplotlib 1.4.2
but it works as expected in
python 3.4.0 + matplotlib 1.4.2
Should this be reported as a bug in matplotlib 1.4.2 on python 2.7.6?
BTW, I noticed that my minimal text from previous mail didn't get through to
the mailing list, so I am attaching it again (modified for python 2.7)
without formatting:
from __future__ import print_function
import sys
if sys.version_info < (3, 0):
import Tkinter as tk
else:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.figure as mplfig
class Test:
def on_press(self, event):
print("clicked2")
def connect(self, canvas):
self.cidpress = canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidpress = canvas.mpl_connect(
'button_press_event', lambda event: print("clicked1"))
class App(object):
def on_press(self, event):
print("clicked0")
def __init__(self, master):
self.fig = mplfig.Figure()
self.canvas = FigureCanvasTkAgg(self.fig, master=master)
dl = Test()
dl.connect(self.canvas)
self.cidpress = self.canvas.mpl_connect(
'button_press_event', self.on_press)
self.canvas.get_tk_widget().pack()
self.canvas.draw()
if __name__ == "__main__":
root = tk.Tk()
app = App(root)
tk.mainloop()
this should print
clicked2
clicked1
clicked0
after each click on the canvas. But in python 2.7.6 it prints only
clicked1
clicked0
--
View this message in context: http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302p44307.html
Sent from the matplotlib - users mailing list archive at Nabble.com.
|
|
From: Benjamin R. <ben...@ou...> - 2014-11-07 14:55:37
|
I think it is because your Test() class is not subclassed from "object". Of
course, I have no clue why that would be an issue, but I have seen stranger
things when not subclassing from object.
On Fri, Nov 7, 2014 at 9:31 AM, rouckas <ste...@gm...> wrote:
> I have a little update on the issue: I tried it with different versions of
> python and matplotlib and it is still present in
> python 2.7.6 + matplotlib 1.4.2
>
> but it works as expected in
> python 3.4.0 + matplotlib 1.4.2
>
> Should this be reported as a bug in matplotlib 1.4.2 on python 2.7.6?
>
> BTW, I noticed that my minimal text from previous mail didn't get through
> to
> the mailing list, so I am attaching it again (modified for python 2.7)
> without formatting:
>
> from __future__ import print_function
> import sys
> if sys.version_info < (3, 0):
> import Tkinter as tk
> else:
> import tkinter as tk
> from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
> import matplotlib.figure as mplfig
>
>
> class Test:
> def on_press(self, event):
> print("clicked2")
>
> def connect(self, canvas):
> self.cidpress = canvas.mpl_connect(
> 'button_press_event', self.on_press)
> self.cidpress = canvas.mpl_connect(
> 'button_press_event', lambda event: print("clicked1"))
>
> class App(object):
> def on_press(self, event):
> print("clicked0")
> def __init__(self, master):
> self.fig = mplfig.Figure()
> self.canvas = FigureCanvasTkAgg(self.fig, master=master)
>
> dl = Test()
> dl.connect(self.canvas)
>
> self.cidpress = self.canvas.mpl_connect(
> 'button_press_event', self.on_press)
>
> self.canvas.get_tk_widget().pack()
> self.canvas.draw()
>
> if __name__ == "__main__":
> root = tk.Tk()
> app = App(root)
> tk.mainloop()
>
> this should print
> clicked2
> clicked1
> clicked0
>
> after each click on the canvas. But in python 2.7.6 it prints only
> clicked1
> clicked0
>
>
>
> --
> View this message in context:
> http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302p44307.html
> Sent from the matplotlib - users mailing list archive at Nabble.com.
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Matplotlib-users mailing list
> Mat...@li...
> https://lists.sourceforge.net/lists/listinfo/matplotlib-users
>
|
|
From: rouckas <ste...@gm...> - 2014-11-07 15:05:16
|
Thanks for the tip. However, subclassing from object didn't help. -- View this message in context: http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302p44315.html Sent from the matplotlib - users mailing list archive at Nabble.com. |
|
From: Benjamin R. <ben...@ou...> - 2014-11-07 17:37:56
|
Figured it out! The instance of Test() isn't being retained anywhere, so when it goes out of scope, the garbage collector eventually gets it. The fact that it works in py3k is likely a coincidence as the garbage collector would eventually have cleaned it up at some point. I don't know the scoping/garbage collection rules for lambdas, so I am guessing that they persist as they are part of the code as opposed to a de-reference-able (is that even a word?). Just save the instance of Test as a member variable of App, and you should be good to go! Ben Root On Fri, Nov 7, 2014 at 10:05 AM, rouckas <ste...@gm...> wrote: > Thanks for the tip. However, subclassing from object didn't help. > > > > -- > View this message in context: > http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302p44315.html > Sent from the matplotlib - users mailing list archive at Nabble.com. > > > ------------------------------------------------------------------------------ > _______________________________________________ > Matplotlib-users mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-users > |
|
From: Brendan B. <bre...@br...> - 2014-11-07 19:00:30
|
On 2014-11-07 09:37, Benjamin Root wrote: > Figured it out! The instance of Test() isn't being retained anywhere, so > when it goes out of scope, the garbage collector eventually gets it. The > fact that it works in py3k is likely a coincidence as the garbage > collector would eventually have cleaned it up at some point. I don't > know the scoping/garbage collection rules for lambdas, so I am guessing > that they persist as they are part of the code as opposed to a > de-reference-able (is that even a word?). Just save the instance of Test > as a member variable of App, and you should be good to go! This note in cbook.py (which handles the callback registry) explains it. . . sort of: In practice, one should always disconnect all callbacks when they are no longer needed to avoid dangling references (and thus memory leaks). However, real code in matplotlib rarely does so, and due to its design, it is rather difficult to place this kind of code. To get around this, and prevent this class of memory leaks, we instead store weak references to bound methods only, so when the destination object needs to die, the CallbackRegistry won't keep it alive. The Python stdlib weakref module can not create weak references to bound methods directly, so we need to create a proxy object to handle weak references to bound methods (or regular free functions). This technique was shared by Peter Parente on his `"Mindtrove" blog <http://mindtrove.info/articles/python-weak-references/>`_. Definitely a hidden trap! Also, speaking of the dangers of classes not inheriting from object, I noticed that CallbackRegistry in cbook.py is also an old-style class (doesn't inherit from object). I then did a search and found numerous old-style classes throughout MPL. Is there any reason for this? -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown |
|
From: Štěpán R. <ste...@gm...> - 2014-11-07 20:35:18
|
It works. Thanks a lot for explanation, Ben. Stepan On Fri, Nov 7, 2014 at 6:37 PM, Benjamin Root <ben...@ou...> wrote: > Figured it out! The instance of Test() isn't being retained anywhere, so > when it goes out of scope, the garbage collector eventually gets it. The > fact that it works in py3k is likely a coincidence as the garbage collector > would eventually have cleaned it up at some point. I don't know the > scoping/garbage collection rules for lambdas, so I am guessing that they > persist as they are part of the code as opposed to a de-reference-able (is > that even a word?). Just save the instance of Test as a member variable of > App, and you should be good to go! > > Ben Root > > On Fri, Nov 7, 2014 at 10:05 AM, rouckas <ste...@gm...> wrote: > >> Thanks for the tip. However, subclassing from object didn't help. >> >> >> >> -- >> View this message in context: >> http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302p44315.html >> Sent from the matplotlib - users mailing list archive at Nabble.com. >> >> >> ------------------------------------------------------------------------------ >> _______________________________________________ >> Matplotlib-users mailing list >> Mat...@li... >> https://lists.sourceforge.net/lists/listinfo/matplotlib-users >> > > |
|
From: Thomas C. <tca...@gm...> - 2014-11-07 18:35:54
|
This came up regrading sliders a while ago: https://github.com/matplotlib/matplotlib/issues/3105 and is one of the persistent gotchas with animation code. Tom On Fri Nov 07 2014 at 12:38:28 PM Benjamin Root <ben...@ou...> wrote: > Figured it out! The instance of Test() isn't being retained anywhere, so > when it goes out of scope, the garbage collector eventually gets it. The > fact that it works in py3k is likely a coincidence as the garbage collector > would eventually have cleaned it up at some point. I don't know the > scoping/garbage collection rules for lambdas, so I am guessing that they > persist as they are part of the code as opposed to a de-reference-able (is > that even a word?). Just save the instance of Test as a member variable of > App, and you should be good to go! > > Ben Root > > On Fri, Nov 7, 2014 at 10:05 AM, rouckas <ste...@gm...> wrote: > >> Thanks for the tip. However, subclassing from object didn't help. >> >> >> >> -- >> View this message in context: >> http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302p44315.html >> Sent from the matplotlib - users mailing list archive at Nabble.com. >> >> >> ------------------------------------------------------------------------------ >> _______________________________________________ >> Matplotlib-users mailing list >> Mat...@li... >> https://lists.sourceforge.net/lists/listinfo/matplotlib-users >> > > ------------------------------------------------------------ > ------------------ > _______________________________________________ > Matplotlib-users mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-users > |
|
From: Benjamin R. <ben...@ou...> - 2014-11-07 19:04:05
|
There have been some discussion of adding an fig.animations list (a la ax.images, ax.artists), and have a fig.add_animation() method. We could then update the animation code to add itself to the given figure to make this work for all existing code. Maybe it would be a nice tie-in with the updates to the navigation toolbar (automatically adding useful buttons for starting/pausing animations, etc)? On Fri, Nov 7, 2014 at 1:35 PM, Thomas Caswell <tca...@gm...> wrote: > This came up regrading sliders a while ago: > https://github.com/matplotlib/matplotlib/issues/3105 and is one of the > persistent gotchas with animation code. > > Tom > > On Fri Nov 07 2014 at 12:38:28 PM Benjamin Root <ben...@ou...> wrote: > >> Figured it out! The instance of Test() isn't being retained anywhere, so >> when it goes out of scope, the garbage collector eventually gets it. The >> fact that it works in py3k is likely a coincidence as the garbage collector >> would eventually have cleaned it up at some point. I don't know the >> scoping/garbage collection rules for lambdas, so I am guessing that they >> persist as they are part of the code as opposed to a de-reference-able (is >> that even a word?). Just save the instance of Test as a member variable of >> App, and you should be good to go! >> >> Ben Root >> >> On Fri, Nov 7, 2014 at 10:05 AM, rouckas <ste...@gm...> wrote: >> >>> Thanks for the tip. However, subclassing from object didn't help. >>> >>> >>> >>> -- >>> View this message in context: >>> http://matplotlib.1069221.n5.nabble.com/Problem-with-event-handling-in-matplotlib-in-tkinter-tp44302p44315.html >>> Sent from the matplotlib - users mailing list archive at Nabble.com. >>> >>> >>> ------------------------------------------------------------------------------ >>> _______________________________________________ >>> Matplotlib-users mailing list >>> Mat...@li... >>> https://lists.sourceforge.net/lists/listinfo/matplotlib-users >>> >> >> ------------------------------------------------------------ >> ------------------ >> _______________________________________________ >> Matplotlib-users mailing list >> Mat...@li... >> https://lists.sourceforge.net/lists/listinfo/matplotlib-users >> > |
|
From: Thomas C. <tca...@gm...> - 2014-11-07 19:05:37
|
The old-style classes are because mpl pre-dates new-style classes. On master all classes now inherit from object (as of about 3 weeks ago https://github.com/matplotlib/matplotlib/pull/3662) On Fri Nov 07 2014 at 2:02:15 PM Brendan Barnwell <bre...@br...> wrote: > On 2014-11-07 09:37, Benjamin Root wrote: > > Figured it out! The instance of Test() isn't being retained anywhere, so > > when it goes out of scope, the garbage collector eventually gets it. The > > fact that it works in py3k is likely a coincidence as the garbage > > collector would eventually have cleaned it up at some point. I don't > > know the scoping/garbage collection rules for lambdas, so I am guessing > > that they persist as they are part of the code as opposed to a > > de-reference-able (is that even a word?). Just save the instance of Test > > as a member variable of App, and you should be good to go! > > This note in cbook.py (which handles the callback registry) > explains > it. . . sort of: > > In practice, one should always disconnect all callbacks when they > are no longer needed to avoid dangling references (and thus memory > leaks). However, real code in matplotlib rarely does so, and due > to its design, it is rather difficult to place this kind of code. > To get around this, and prevent this class of memory leaks, we > instead store weak references to bound methods only, so when the > destination object needs to die, the CallbackRegistry won't keep > it alive. The Python stdlib weakref module can not create weak > references to bound methods directly, so we need to create a proxy > object to handle weak references to bound methods (or regular free > functions). This technique was shared by Peter Parente on his > `"Mindtrove" blog > <http://mindtrove.info/articles/python-weak-references/>`_. > > Definitely a hidden trap! > > Also, speaking of the dangers of classes not inheriting from > object, I > noticed that CallbackRegistry in cbook.py is also an old-style class > (doesn't inherit from object). I then did a search and found numerous > old-style classes throughout MPL. Is there any reason for this? > > -- > Brendan Barnwell > "Do not follow where the path may lead. Go, instead, where there is no > path, and leave a trail." > --author unknown > > ------------------------------------------------------------ > ------------------ > _______________________________________________ > Matplotlib-users mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-users > |
|
From: Thomas C. <tca...@gm...> - 2014-11-07 19:13:26
|
I am also beginning to like the idea of hanging all of these things off of FigureManager objects. We have them around, but they are really only used in pyplot (which is a shame) and seems a natural place to put all of these aggregation type objects (list of animations, the toolbar stuff, the navigation stuff, the blit-manager object I want to pull in from scikit-image, etc). @Federico, tell me if I am being dumb about this. Tom On Fri Nov 07 2014 at 2:05:29 PM Thomas Caswell <tca...@gm...> wrote: > The old-style classes are because mpl pre-dates new-style classes. On > master all classes now inherit from object (as of about 3 weeks ago > https://github.com/matplotlib/matplotlib/pull/3662) > > > > On Fri Nov 07 2014 at 2:02:15 PM Brendan Barnwell <bre...@br...> > wrote: > >> On 2014-11-07 09:37, Benjamin Root wrote: >> > Figured it out! The instance of Test() isn't being retained anywhere, so >> > when it goes out of scope, the garbage collector eventually gets it. The >> > fact that it works in py3k is likely a coincidence as the garbage >> > collector would eventually have cleaned it up at some point. I don't >> > know the scoping/garbage collection rules for lambdas, so I am guessing >> > that they persist as they are part of the code as opposed to a >> > de-reference-able (is that even a word?). Just save the instance of Test >> > as a member variable of App, and you should be good to go! >> >> This note in cbook.py (which handles the callback registry) >> explains >> it. . . sort of: >> >> In practice, one should always disconnect all callbacks when they >> are no longer needed to avoid dangling references (and thus memory >> leaks). However, real code in matplotlib rarely does so, and due >> to its design, it is rather difficult to place this kind of code. >> To get around this, and prevent this class of memory leaks, we >> instead store weak references to bound methods only, so when the >> destination object needs to die, the CallbackRegistry won't keep >> it alive. The Python stdlib weakref module can not create weak >> references to bound methods directly, so we need to create a proxy >> object to handle weak references to bound methods (or regular free >> functions). This technique was shared by Peter Parente on his >> `"Mindtrove" blog >> <http://mindtrove.info/articles/python-weak-references/>`_. >> >> Definitely a hidden trap! >> >> Also, speaking of the dangers of classes not inheriting from >> object, I >> noticed that CallbackRegistry in cbook.py is also an old-style class >> (doesn't inherit from object). I then did a search and found numerous >> old-style classes throughout MPL. Is there any reason for this? >> >> -- >> Brendan Barnwell >> "Do not follow where the path may lead. Go, instead, where there is no >> path, and leave a trail." >> --author unknown >> >> ------------------------------------------------------------ >> ------------------ >> _______________________________________________ >> Matplotlib-users mailing list >> Mat...@li... >> https://lists.sourceforge.net/lists/listinfo/matplotlib-users >> > |
|
From: Federico A. <ari...@gm...> - 2014-11-07 19:21:43
|
Sorry I'm lost in the discussion. What is the relation between the weak references in callback registry and moving stuff to the figure manager? Federico On 7 Nov 2014 14:13, "Thomas Caswell" <tca...@gm...> wrote: > I am also beginning to like the idea of hanging all of these things off of > FigureManager objects. We have them around, but they are really only used > in pyplot (which is a shame) and seems a natural place to put all of these > aggregation type objects (list of animations, the toolbar stuff, the > navigation stuff, the blit-manager object I want to pull in from > scikit-image, etc). > > @Federico, tell me if I am being dumb about this. > > Tom > > On Fri Nov 07 2014 at 2:05:29 PM Thomas Caswell <tca...@gm...> > wrote: > >> The old-style classes are because mpl pre-dates new-style classes. On >> master all classes now inherit from object (as of about 3 weeks ago >> https://github.com/matplotlib/matplotlib/pull/3662) >> >> >> >> On Fri Nov 07 2014 at 2:02:15 PM Brendan Barnwell <bre...@br...> >> wrote: >> >>> On 2014-11-07 09:37, Benjamin Root wrote: >>> > Figured it out! The instance of Test() isn't being retained anywhere, >>> so >>> > when it goes out of scope, the garbage collector eventually gets it. >>> The >>> > fact that it works in py3k is likely a coincidence as the garbage >>> > collector would eventually have cleaned it up at some point. I don't >>> > know the scoping/garbage collection rules for lambdas, so I am guessing >>> > that they persist as they are part of the code as opposed to a >>> > de-reference-able (is that even a word?). Just save the instance of >>> Test >>> > as a member variable of App, and you should be good to go! >>> >>> This note in cbook.py (which handles the callback registry) >>> explains >>> it. . . sort of: >>> >>> In practice, one should always disconnect all callbacks when they >>> are no longer needed to avoid dangling references (and thus memory >>> leaks). However, real code in matplotlib rarely does so, and due >>> to its design, it is rather difficult to place this kind of code. >>> To get around this, and prevent this class of memory leaks, we >>> instead store weak references to bound methods only, so when the >>> destination object needs to die, the CallbackRegistry won't keep >>> it alive. The Python stdlib weakref module can not create weak >>> references to bound methods directly, so we need to create a proxy >>> object to handle weak references to bound methods (or regular free >>> functions). This technique was shared by Peter Parente on his >>> `"Mindtrove" blog >>> <http://mindtrove.info/articles/python-weak-references/>`_. >>> >>> Definitely a hidden trap! >>> >>> Also, speaking of the dangers of classes not inheriting from >>> object, I >>> noticed that CallbackRegistry in cbook.py is also an old-style class >>> (doesn't inherit from object). I then did a search and found numerous >>> old-style classes throughout MPL. Is there any reason for this? >>> >>> -- >>> Brendan Barnwell >>> "Do not follow where the path may lead. Go, instead, where there is no >>> path, and leave a trail." >>> --author unknown >>> >>> ------------------------------------------------------------ >>> ------------------ >>> _______________________________________________ >>> Matplotlib-users mailing list >>> Mat...@li... >>> https://lists.sourceforge.net/lists/listinfo/matplotlib-users >>> >> |