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

Reply via email to