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()
···
On Fri, Jun 20, 2008 at 8:41 AM, Alan G Isaac <aisaac@...310...> wrote:
On Thu, Jun 19, 2008 at 3:37 PM, Alan G Isaac <aisaac@...310...> 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.