1

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.

3
  • Can you tell if your callbacks are firing or not? Commented Jan 31, 2014 at 3:21
  • I can tell with print statements -- they aren't. Commented Jan 31, 2014 at 9:29
  • Can you add the tool bar and see if the zoom and pan work correctly? I am trying to sort out if all callbacks are broken or just your new ones are not connected. Commented Jan 31, 2014 at 12:45

1 Answer 1

2

Don't ask me why, but changing drs to self.drs (lines 75 and 79) seems to work. As if you had to prevent drsand 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()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.