I am attempting to modify the "Draggable Rectangle Exercise" found in the matplotlib docs so that it works inside a wxPython window.
I have the following so far:
import wx
import matplotlib
matplotlib.interactive(True)
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import numpy as np
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()
self.rect.figure.canvas.draw_idle()
def on_release(self, event):
'on release we reset the press data'
self.press = None
#self.rect.figure.canvas.draw()
self.rect.figure.canvas.draw_idle()
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)
class Frame(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None, title=title, pos=(150,150), size=(800,600))
self.panel = wx.Panel(self)
self.figure = Figure(figsize=(6, 4), dpi=100)
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self.panel, wx.ID_ANY, self.figure)
rects = self.axes.bar(range(10), 20*np.random.rand(10))
drs = []
for rect in rects:
dr = DraggableRectangle(rect)
dr.connect()
drs.append(dr)
app = wx.App(redirect=False)
top = Frame("test")
top.Show()
app.MainLoop()
Unfortunately this doesn't work as advertised; the bars appear on the graph but they are not draggable at all. Copying and pasting the example as-is works fine, it's only when I try to use it with wxPython that I run into problems.
Don't ask me why, but changing drs
to self.drs
(lines 75 and 79) seems to work. As if you had to prevent drs
and all dr
from being garbage collected. (Related to Wx Matplotlib Event Handling ?)
import wx
import matplotlib
matplotlib.interactive(True)
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import numpy as np
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):
print "on_press"
'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):
print "on_motion"
'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()
self.rect.figure.canvas.draw_idle()
def on_release(self, event):
print "on_release"
'on release we reset the press data'
self.press = None
#self.rect.figure.canvas.draw()
self.rect.figure.canvas.draw_idle()
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)
class Frame(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None, title=title, pos=(150,150), size=(800,600))
self.panel = wx.Panel(self)
self.figure = Figure(figsize=(6, 4), dpi=100)
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self.panel, wx.ID_ANY, self.figure)
rects = self.axes.bar(range(10), 20*np.random.rand(10))
self.drs = []
for rect in rects:
dr = DraggableRectangle(rect)
dr.connect()
self.drs.append(dr)
print "test"
app = wx.PySimpleApp()#redirect=False)
top = Frame("test")
top.Show()
app.MainLoop()