Wx Matplotlib Event Handling

2019-09-04 16:44发布

问题:

I am working on a WX-MPL app to display and interactively process data based on user input. I am having a difficulties setting up the MPL mouse events to work within the WX app.

The goal is to have a series of editable vertical lines that delineate the begin and end times for features which have been identified in earlier processing. Users should be able to drag the lines along the x-axis, delete unwanted lines, and insert new lines.

So far I have been able to achieve this functionality using the standard MPL plot figure (I think its Tk). When I try to integrate these classes into my app, something is going astray with the event handling and I am not able to interact with the line objects or create new line objects. So I backed up a step and have been trying to add complexity into my working example to determine where the problems are coming into the picture.

When running the working example as a simple WX app, the NewVLineListener class appears to no longer receive button_press_events. Below is the code related to the the specific problem I am experiencing.

This is the first time I have worked with mouse events and I am surely missing something... Any advice would be greatly appreciated.

Also, I am running WX 2.8.12 and MPL 1.1.1rc.

from matplotlib.figure import Figure
import wx
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg

class NewVLineListener:
    global castLog, count, dvls, ax1
    lock = None  # only one can be animated at a time
    def __init__(self, fig):
        self.fig = fig

    def connect(self):
        'connect to all the events we need'
        self.cidpressright = self.fig.canvas.mpl_connect(
        'button_press_event', self.on_press_right)

    def on_press_right(self, event):
        global count, castLog, dvls, ax1
        print event.button
        if event.button != 3: return
        tag = 'Begin'
        # Increase castLog Key to accomodate new Vline
        count += 1
        print 'count: ', count
        # Set castLog values to x-value of triggering event
        castLog[str(count)] = { tag:event.xdata }
        # Spawn a new DraggableVline instance
        color_map = {'Begin':'g', 'End':'r'}
        dvl = DraggableVline(self.fig, ax1.axvline(x=castLog[str(count)][tag], linewidth=2, color=color_map[tag]), count, tag)
        dvl.connect()
        dvls.append(dvl)

        canvas = self.fig.canvas
        canvas.draw()

class MainFrame(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY)
            global castLog, count, ax1, dvls
            fig = Figure()
            canvas = FigureCanvasWxAgg(self, -1, fig)
            ax1 = fig.add_subplot(111)

            # Create empty dict that will hold new V-line Data
            castLog = { } 
            dvls = [ ]
            count = 0

            # Instantiate New Vline Listener
            NVL = NewVLineListener(fig)
            NVL.connect()

if __name__ == '__main__':
        app = wx.PySimpleApp()
        app.frame = MainFrame()
        app.frame.Show()
        app.MainLoop()

回答1:

I got it!

I think the reference to the NewVlineListener object was being garbage collected so the events were never being received. By adding the NVL object reference to the array of references to draggable vline objects, it sticks around and receives the events as expected.

class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY)
        global castLog, count, ax1, dvls
        fig = Figure()
        canvas = FigureCanvasWxAgg(self, -1, fig)
        ax1 = fig.add_subplot(111)

        # Create empty dict that will hold new V-line Data
        castLog = { } 
        dvls = [ ]
        count = 0

        # Instantiate New Vline Listener
        NVL = NewVLineListener(fig)
        NVL.connect()
        dvls.append(NVL) # This keeps NVL reference from being garbage collected?

I still find it interesting that naming the NewVlineListener object is not enough to keep the reference around, and that it works fine with pyplot but now with wx, however this seems to work.