Search code examples
pythonmatplotlibwxpythonexec

Closing a pyplot window in wxpython with Ctrl-W causes a segmentation fault


The graphical user interface to a programming/modeling environment I've created depends heavily on executing arbitrary python code from a wxwidgets gui. Below is a minimal, but typical example of how the GUI lets users create matplotlib graphs:

UPDATE: Turns out, the bug doesn't rely on scripts being executed! See below

import wx
script = """
import matplotlib.pyplot as pl
import numpy as np

x = np.linspace(0, 1, 100)
y = x ** 1.4
pl.figure()
pl.plot(x, y)
pl.show()
"""
class Main(wx.Frame):
    def __init__(self):
        super(Main, self).__init__(None)
        button = wx.Button(self, wx.ID_ANY, 'Run')
        button.Bind(wx.EVT_BUTTON, self.action_run)
        self.Show()
    def action_run(self, e=None):
        exec(script)
if __name__ == '__main__':
    app = wx.App(False)
    frame = Main()
    app.MainLoop()

Usually, the GUI would do a lot more than show just a run button, and the script is not static but entered by the user / read from a file. It works fine, on linux, mac and windows but...

If you close the figure using the mouse everything's ok. If you close the figure with Ctrl-W the application crashes with a segfault.

Does anybody have any ideas why this happens or how to debug this?

Update: here are the versions involved

>>> wx.version()
'wx.2.8.12.0 (gtk2-unicode)'
>>> mpl.__version__
'1.3.1'

The segfault occurs on linux (Fedora 20, Gnome 3.10.2)

Versions:

  • Windows 7, Matplotlib 1.3.1, wxPython 2.8.12.1: no bug
  • Fedora 20, Gnome 3.10.2, Matplotlib 1.3.1, wxPython 2.8.12.0: bug
  • Fedora 20, Gnome 3.10.2, Matplotlib 1.4.2, wxPython 2.8.12.0: bug

Update 2:

It also happens without the script execution!

#!/usr/bin/env python
import wx
import matplotlib
matplotlib.use('wxAgg')
import matplotlib.pyplot as pl
class Main(wx.Frame):
    def __init__(self):
        super(Main, self).__init__(None)
        button = wx.Button(self, wx.ID_ANY, 'Run')
        button.Bind(wx.EVT_BUTTON, self.action_run)
        self.Show()
    def action_run(self, e=None):
        pl.figure()
        pl.plot([1,2,3,4,5], [3,1,2,5,4])
        pl.show()
if __name__ == '__main__':
    app = wx.App(False)
    frame = Main()
    app.MainLoop()

Solution

  • It's a bug :-/

    Filed bug reports at:

    https://github.com/matplotlib/matplotlib/issues/3690

    and

    http://trac.wxwidgets.org/ticket/16622