On Fri, Jun 20, 2008 at 8:41 AM, Alan G Isaac <[EMAIL PROTECTED]> wrote: >> On Thu, Jun 19, 2008 at 3:37 PM, Alan G Isaac <[EMAIL PROTECTED]> wrote: >>> I still do not see why a figure has a canvas as data. > > On Thu, 19 Jun 2008, John Hunter apparently wrote: >> This is just a convenience so the child can see the parent. If I have >> a function that gets a line, I can do line.axes.figure.canvas and walk >> backwards up the containment hierarchy to get what I need. This is >> backwards because a canvas holds a figure which holds an axes which >> holds a line, but everybody stores a reference to their parent. A >> side effect of having so many cyclic references is that we cannot use >> __del__ anywhere in the mpl class hierarchy since this breaks garbage >> collection with cyclic references. > > Thanks for the explanation! > Alan > PS If anyone wants to share an example where it is useful > to work "backwards" like that, I'm sure I would learn > from it.
Take a look at the draggable rectangle code in the example below. The rDraggableRectangle class needs to be able to update the canvas with a draw, but rather than having to pass in the canvas instance explicitly, we can just get it from the rectangle. Ie, the artist knows what canvas he is in even though the canvas contains the rectangle. The PDF event handling tutorial which contains this example is at http://matplotlib.sourceforge.net/pycon/event_handling_tut.pdf if you want some context. import numpy as np import matplotlib.pyplot as plt class DraggableRectangle: def __init__(self, rect): self.rect = rect self.press = None def connect(self): 'connect to all the events we need' self.cidpress = self.rect.figure.canvas.mpl_connect( 'button_press_event', self.on_press) self.cidrelease = self.rect.figure.canvas.mpl_connect( 'button_release_event', self.on_release) self.cidmotion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_motion) def on_press(self, event): 'on button press we will see if the mouse is over us and store some data' if event.inaxes != self.rect.axes: return contains, attrd = self.rect.contains(event) if not contains: return print 'event contains', self.rect.xy x0, y0 = self.rect.xy self.press = x0, y0, event.xdata, event.ydata def on_motion(self, event): 'on motion we will move the rect if the mouse is over us' if self.press is None: return if event.inaxes != self.rect.axes: return x0, y0, xpress, ypress = self.press dx = event.xdata - xpress dy = event.ydata - ypress #print 'x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f'%(x0, xpress, event.xdata, dx, x0+dx) self.rect.set_x(x0+dx) self.rect.set_y(y0+dy) self.rect.figure.canvas.draw() def on_release(self, event): 'on release we reset the press data' self.press = None self.rect.figure.canvas.draw() def disconnect(self): 'disconnect all the stored connection ids' self.rect.figure.canvas.mpl_disconnect(self.cidpress) self.rect.figure.canvas.mpl_disconnect(self.cidrelease) self.rect.figure.canvas.mpl_disconnect(self.cidmotion) fig = plt.figure() ax = fig.add_subplot(111) rects = ax.bar(range(10), 20*np.random.rand(10)) drs = [] for rect in rects: dr = DraggableRectangle(rect) dr.connect() drs.append(dr) plt.show() ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users