Re: [matplotlib-devel] Possible bug in matplotlib.cbook.CallbackRegistry
Here is a bit more detail and a simple example. The example below places red squares in an axes. When the user clicks on an existing red square - another square is created and added. When the user hits any key a square is deleted from the axes. The error is triggered by clicking on the red square and then hitting any key, and then clicking a red square again. Diagnosis: By monitoring cbook.py line 235 and cbook.py line 263 it can be seen that after the second mouse click (following one of the squares being deleted), that the process() function builds a loop and begins handling the button press callbacks. Note that there is a dead reference coming later in this list. The first callback involves another square being created and the connect() method being called. In the connect() call - the dead reference is deleted from the callback list. Now upon returning to the process() callback this dead reference is no longer in the callback list and a Key Exception is triggered once it gets to it in the loop. Problem: There are two locations where dead references are cleared from the callback list. When these loops get intermingled - as the case with a callback leading to another connect mid-loop - the exception occurs when both loops attempt to delete the dead reference. Possible Solutions: 1. Trap the KeyException at the point of attempting to delete it from the list in both places. 2. Place the dead reference check and deletion within a single method ... and perform this check at beginning of the process() and connect() methods before processing callbacks. Sample Code import matplotlib matplotlib.use('WXAGG') from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg from matplotlib.pyplot import Figure, Axes, Rectangle import wx import random class SquareManager(object): def __init__(self, axes): self.axes = axes self.canvas = axes.figure.canvas self.squares = [] self.last_x = 0 self.canvas.mpl_connect('key_press_event', self.on_key_press) def add_square(self): self.last_x += .1 s = Square(self, self.axes, [self.last_x, .4], .05, .05, facecolor='red', edgecolor='black') self.squares.append(s) self._refresh() def on_key_press(self, evt): if len(self.squares) == 0: return # delete the first square - results in no error # self.squares[0].remove() # del self.squares[0] # delete the last square - results in the error self.squares[-1].remove() del self.squares[-1] self._refresh() def _refresh(self): self.canvas.draw() class Square(Rectangle): def __init__(self, manager, axes, *args, **kwds): Rectangle.__init__(self, *args, **kwds) axes.add_patch(self) self.manager = manager axes.figure.canvas.mpl_connect('button_press_event', self.selected) def selected(self, evt): within, _ = self.contains(evt) if within: self.manager.add_square() app = wx.PySimpleApp() frame = wx.Frame(None) fig = Figure() canvas = FigureCanvasWxAgg(frame, -1, fig) a = Axes(fig, [.1, .1, .8, .8]) fig.add_axes(a) sm = SquareManager(a) sm.add_square() frame.Show() app.MainLoop() # To demonstrate the error: # # 1. click on red sqaure # 2. press any key # 3. click on red sqaure again -- The demand for IT networking professionals continues to grow, and the demand for specialized networking skills is growing even more rapidly. Take a complimentary Learning@Cisco Self-Assessment and learn about Cisco certifications, training, and career opportunities. http://p.sf.net/sfu/cisco-dev2dev ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] Possible bug in matplotlib.cbook.CallbackRegistry
I've run into this same issue in the past, and have it "fixed" in my own local copy of matplotlib. I just placed a check to make sure that cid actually was in the callbacks for s before deleting it. That is quite possibly a band-aid; I never looked far enough in to see. But it is possibly another way of fixing the problem. def process(self, s, *args, **kwargs): """ process signal *s*. All of the functions registered to receive callbacks on *s* will be called with *\*args* and *\*\*kwargs* """ if s in self.callbacks: for cid, proxy in self.callbacks[s].items(): # Clean out dead references if proxy.inst is not None and proxy.inst() is None: if cid in self.callbacks[s]: #<--- here del self.callbacks[s][cid] else: proxy(*args, **kwargs) On Tue, Oct 25, 2011 at 1:09 PM, wrote: > Here is a bit more detail and a simple example. > > The example below places red squares in an axes. When the user clicks on an > existing red square - another square is created and added. When the user hits > any key a square is deleted from the axes. The error is triggered by > clicking on the red square and then hitting any key, and then clicking a red > square again. > > Diagnosis: > By monitoring cbook.py line 235 and cbook.py line 263 it can be seen that > after the second mouse click (following one of the squares being deleted), > that the process() function builds a loop and begins handling the button > press callbacks. Note that there is a dead reference coming later in this > list. The first callback involves another square being created and the > connect() method being called. In the connect() call - the dead reference is > deleted from the callback list. Now upon returning to the process() callback > this dead reference is no longer in the callback list and a Key Exception is > triggered once it gets to it in the loop. > > Problem: > There are two locations where dead references are cleared from the callback > list. When these loops get intermingled - as the case with a callback > leading to another connect mid-loop - the exception occurs when both loops > attempt to delete the dead reference. > > Possible Solutions: > 1. Trap the KeyException at the point of attempting to delete it from the > list in both places. > > 2. Place the dead reference check and deletion within a single method ... and > perform this check at beginning of the process() and connect() methods before > processing callbacks. > > > Sample Code > > > import matplotlib > matplotlib.use('WXAGG') > > from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg > from matplotlib.pyplot import Figure, Axes, Rectangle > > import wx > import random > > class SquareManager(object): > def __init__(self, axes): > self.axes = axes > self.canvas = axes.figure.canvas > self.squares = [] > self.last_x = 0 > > self.canvas.mpl_connect('key_press_event', self.on_key_press) > > def add_square(self): > self.last_x += .1 > s = Square(self, self.axes, [self.last_x, .4], > .05, .05, facecolor='red', edgecolor='black') > self.squares.append(s) > self._refresh() > > def on_key_press(self, evt): > if len(self.squares) == 0: return > > # delete the first square - results in no error > # self.squares[0].remove() > # del self.squares[0] > > # delete the last square - results in the error > self.squares[-1].remove() > del self.squares[-1] > > self._refresh() > > def _refresh(self): > self.canvas.draw() > > > class Square(Rectangle): > def __init__(self, manager, axes, *args, **kwds): > Rectangle.__init__(self, *args, **kwds) > axes.add_patch(self) > > self.manager = manager > axes.figure.canvas.mpl_connect('button_press_event', self.selected) > > def selected(self, evt): > within, _ = self.contains(evt) > if within: > self.manager.add_square() > > > app = wx.PySimpleApp() > frame = wx.Frame(None) > fig = Figure() > canvas = FigureCanvasWxAgg(frame, -1, fig) > a = Axes(fig, [.1, .1, .8, .8]) > fig.add_axes(a) > > sm = SquareManager(a) > sm.add_square() > > frame.Show() > app.MainLoop() > > > # To demonstrate the error: > # > # 1. click on red sqaure > # 2. press any key > # 3. click on red sqaure again > > > > > > > > > > -- > The demand for IT networking professionals continues to grow, and the > demand for specialized networking skills is growing even more rapidly. > Take a complimentary Learning@Cisco Self-Assessment and learn > about Cisco certifications, training, and career opportunities. > http://p.sf.net/sfu/cisco-dev2dev > _
Re: [matplotlib-devel] Possible bug in matplotlib.cbook.CallbackRegistry
Daniel - Yes that works. In my case - I hate to edit any existing third party code bases - or it bites me later when I upgrade. For now - I simply do my own dead reference clean up externally when doing the deletes. Really, that would be the same as just doing a disconnect - but for other reasons (not worth going into detail here) - I prefer deleting and not having to know all of the connection points. My solution ensures that the dead references aren't around later. I mainly wanted to get it out into the devel community - get smart eyeballs on it - and hope that it gets addresses in a future release. It will likely be a fairly straightforward fix - as you show. -- The demand for IT networking professionals continues to grow, and the demand for specialized networking skills is growing even more rapidly. Take a complimentary Learning@Cisco Self-Assessment and learn about Cisco certifications, training, and career opportunities. http://p.sf.net/sfu/cisco-dev2dev___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
[matplotlib-devel] which to fork from?
For small bugfixes, am I supposed to fork from v1.1.x, or master? -- Daniel Hyams dhy...@gmail.com -- The demand for IT networking professionals continues to grow, and the demand for specialized networking skills is growing even more rapidly. Take a complimentary Learning@Cisco Self-Assessment and learn about Cisco certifications, training, and career opportunities. http://p.sf.net/sfu/cisco-dev2dev ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] which to fork from?
On Tuesday, October 25, 2011, Daniel Hyams wrote: > For small bugfixes, am I supposed to fork from v1.1.x, or master? > V1.1.x is the maintenance branch. Master is for new features. When bugfixes are made and merged to v1.1.x, we then merge it to master. Ben Root -- The demand for IT networking professionals continues to grow, and the demand for specialized networking skills is growing even more rapidly. Take a complimentary Learning@Cisco Self-Assessment and learn about Cisco certifications, training, and career opportunities. http://p.sf.net/sfu/cisco-dev2dev___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] which to fork from?
On Tue, Oct 25, 2011 at 3:52 PM, Daniel Hyams wrote: > For small bugfixes, am I supposed to fork from v1.1.x, or master? I say 'master' (Mike's been pushing some things to v1.1.x, but as he said in a comment to #551, "Pushed to v1.1.x since this is pretty serious yet simple-to-fix bug -- it should be on the maintenance branch.") best, -- Paul Ivanov 314 address only used for lists, off-list direct email at: http://pirsquared.org | GPG/PGP key id: 0x0F3E28F7 -- The demand for IT networking professionals continues to grow, and the demand for specialized networking skills is growing even more rapidly. Take a complimentary Learning@Cisco Self-Assessment and learn about Cisco certifications, training, and career opportunities. http://p.sf.net/sfu/cisco-dev2dev ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel