2

I would like to display a context menu over a matplotlib figure inside of a wxPython window when the mouse is clicked.

Unfortunately, after it detects the click, the PopupMenu method is called, but it neither returns nor displays a popup. (This is with the stock Python in Ubuntu 12.10 inside of VirtualBox with a Windows 7 host.)

Here is my code so far; what am I missing? i.e. How do I get the PopupMenu to actually display?

import wx
import numpy
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigCanvas
from wxPython.wx import *

class MatplotlibContext(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'some title')
        self.panel = wx.Panel(self)
        self.fig = Figure()
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.axes = self.fig.add_subplot(111)
        x = numpy.linspace(0, 6.28)
        y = numpy.sin(x)
        self.axes.plot(x, y)
        self.canvas.draw()
        self.canvas.mpl_connect('button_press_event', self.context_menu)        
        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.panel.SetSizer(self.vbox)
        self.vbox.Fit(self)

    def context_menu(self, event):
        print 'in context_menu callback: clicked at (%g, %g)' % (event.x, event.y)
        menu = wxMenu()
        item_id = wxNewId()
        menu.Append(item_id, 'item') 
        wx.EVT_MENU(menu, item_id, self.callback)
        self.PopupMenu(menu, wx.Point(event.x, event.y))
        menu.Destroy()

    def callback(self, event):
        print 'menu selection: %r' % event.GetId()

app = wx.PySimpleApp()
app.frame = MatplotlibContext()
app.frame.Show()
app.MainLoop()

Edit 2013-01-31: corrected typo in the code. Revised question:

The code above doesn't work on two different machines where I ran Ubuntu 12.10 in a VirtualBox nor on a 12.04 installed directly, but mostly works on a fourth machine running 12.10. I have no idea why there's a difference.

Otherwise, I guess my question is now:

  • How do I fix the up/down coordinate issue? (If I click a certain distance from the top of the window, it displays that distance from the bottom.)
  • If I open a PopupMenu (and optionally close it), then the process does not terminate when the main window is closed. How do I fix this?

Edit 2013-10-02: version information

For one of the machines where this doesn't work, I'm running Ubuntu 13.04 with Python 2.7.4, Matplotlib 1.2.1, and wx 2.8.12.1.

8
  • Your code works for me on Fedora 18 with stock python 2.7.3; the only problem is that the menu appears in the wrong position - not where the click was. Commented Jan 31, 2013 at 6:46
  • It mostly works on Windows 7 too. It gives some errors and warnings but the menu shows up. The Y-axis coordinate seems to be reverted inside the chart however. Commented Jan 31, 2013 at 10:35
  • I guess you should fix the coordinates, it is probably out of window on your system. Also fix typo here menu.Destory(). Commented Jan 31, 2013 at 10:43
  • 1
    Try removing the wx.Point(event.x, event.y) from the PopupMenu call. I never use it and it shows in the right position "automagically" for me. If I remove it from your code, it shows at the correct position. Commented Jan 31, 2013 at 19:04
  • Thanks for catching the typo @Fenikso. I've tried with VirtualBox installs on two machines and can't get it to work there, but it does work on a straight install, although that doesn't really prove VirtualBox is the problem. I edited the question to address the two other remaining issues: up vs down and process longevity. Commented Jan 31, 2013 at 19:06

1 Answer 1

1

One thing I've found is that with some combinations of wxpython/matplotlib (not sure which ones), you can somehow lock up the event loop by showing a modal window object from a matplotlib event handler. The issue is that the matplotlib FigureCanvas doesn't release the mouse automatically, so the breakage occurs when e.g. a modal dialog tries to grab input before the mouse release event has fired.

There seems to be a simple solution, at least for the cases I've run into. Insert:

event.guiEvent.GetEventObject().ReleaseMouse()

at the start of the event handler.

Sign up to request clarification or add additional context in comments.

1 Comment

No luck. On at least one machine where this doesn't work (versions added to the question), the matplotlib event handler keeps working in that subsequent clicks will trigger calls to context_menu, but the calls to PopupMenu never display a popup and never return.

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.