matplotlib & wxPython question

Hi people,

I hope I’ve come to the right place - if not please redirect me :).

I’ve been trying to get matplotlib & wxPython to work
together. I’ve pretty much succeeded - I’ve written a program (attached below)
which plots a sine function, with a slider controlling the number of cycles. So
far so good.

However, after moving the slider around for several seconds,
the program suddenly starts spewing out error messages in the console. The
program itself doesn’t close or crash, but the plot stops updating itself.

Can you help me understand the problem and fix it? Is it a
memory thing, or perhaps something else?

Thank you very much for your help!

Assaf.

Short note: the “important” parts are the PlotPanel class, with its init_plot_data which gets called every time the slider is moved, and the OnSlider function of the main frame, which is bound to the slider-movement event.

Other than that, the program consists of two panes separated by a sash.
I’m using PSPAD to edit my files, and run my programs using Python.exe on a windows XP operating system.

---------------------------------------------------------------- Begin attachment ------------------------------------------------------------------------

#!/usr/bin/env python

import matplotlib
matplotlib.use(‘WXAgg’)
from matplotlib.backends.backend_wxagg import Toolbar, FigureCanvasWxAgg

from matplotlib.figure import Figure
import numpy as npy

import wx

class PlotPanel(wx.Panel):
“”" This class represents a basic embelishment on the wx.Panel class, allowing for plots. “”"

def __init__(self, parent):

    wx.Panel.__init__(self, parent, -1)
    self.fig = Figure()
    self.canvas = FigureCanvasWxAgg(self, -1, self.fig)
    self.figHandle = self.fig.add_subplot(111)
    # Now put all into a sizer

    sizer = wx.BoxSizer(wx.VERTICAL)
    # This way of adding to sizer allows resizing
    sizer.Add(self.canvas, 1, wx.LEFT|wx.TOP|wx.GROW)
    self.SetSizer(sizer)
    self.Fit()

def init_plot_data(self,x = [1,2,3,4], y = [1,2,3,4]):
    self.figHandle.clear()
    self.figHandle.plot(x,y)
    self.canvas.draw()

class MyFrame(wx.Frame):
def init(self, parent = None, id = -1, pos = (10,10), title = “HelloWorld”, size = (800,600)):

    wx.Frame.__init__(self, parent,id,title, pos, size)
    self.CreateMenu()
    # Create a status bar
    self.CreateStatusBar()
    # Create the toolbar
    self.AddToolBar()

    # Create splitter window
    self.initpos = 70
    self.sp = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
    # First panel is for the slider
    self.p1 = wx.Panel(self.sp)
    # Second panel is for plotting

    self.p2 = PlotPanel(self.sp)
    self.p2.Hide()
    self.p1.SetBackgroundColour("cornflower blue")
    self.p2.SetBackgroundColour("sky blue")
    self.sp.Initialize

(self.p1)
self.sp.SetMinimumPaneSize(10)
self.sp.SplitHorizontally(self.p1, self.p2, self.initpos)
# Create user input slider
self.slider = wx.Slider(self.p1, 100, 25, 1, 100, pos=(10,10), size=(250,-1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
self.slider.SetTickFreq(10,1)
self.slider.SetForegroundColour(“white”)
self.Bind(wx.EVT_SLIDER, self.OnSlider, self.slider)

    self.slider.CentreOnParent()
    # Create plotting panel
    self.p2.init_plot_data()

   
def CreateMenu(self):
    # Define menus
    menuFile = wx.Menu()
    menuHelp = wx.Menu()
    # Add items
    menuFile.Append(1, "&Open...")
    menuFile.AppendSeparator()
    menuFile.Append(3, "E&xit")
    menuHelp.Append(1, "&About")

    # Create the menu bar
    menuBar = wx.MenuBar()
    menuBar.Append(menuFile,"&File")
    menuBar.Append(menuHelp,"&Help")
    # Add to frame
    self.SetMenuBar(menuBar)

def AddToolBar(self):
    toolbar = self.CreateToolBar(wx.NO_BORDER)
    toolbar.SetToolBitmapSize((32,32))
    for each in self.ToolBarData():
        if not each[0]:

            toolbar.AddSeparator()
        else:
            bmp = wx.Image(each[1], wx.BITMAP_TYPE_PNG).ConvertToBitmap()
            toolbar.AddSimpleTool(-1,bmp, each[0], each[2]);
    toolbar.Realize()

def ToolBarData(self):
    return (("Open", "folder.png", "Open a WAV file", self.OnOpen),
            ("Play", "media-playback-start.png

“, “Play current file”, self.OnPlay),
(”", “”, “”, “”),
(“Help”, “help-browser.png”, “Browse online help”, self.OnHelp))

def OnOpen():
    pass
   
def OnPlay():
    pass
   
def OnHelp():
    pass
   
def OnSlider(self, event):
    sliderValue = self.slider.GetValue()
    self.SetStatusText('Ive been moved!')
    curX = npy.arange(0,10,0.05)
    curY = npy.sin(sliderValue*curX)
    self.p2.init_plot_data(curX,curY)

class App(wx.App):
def OnInit(self):
self.frame = MyFrame()
self.frame.Show()
self.SetTopWindow(self.frame)
return True

def main():
app = App(False)

app.MainLoop()

if name == ‘main’:
main()

------------------------------------------------------------------- End attachment

···

1) You might get better luck on the MPL list for this -- you seem to have done the embedding right, so it's really an MPL issue.

2) You can change the data on a line object in MPL, without calling plot again, so you can re-use all the existing axis, etc, etc. That may be faster and more robust.

3) Check out wxMPL for embedding MPL in wx -- it does some of the work for you, and has some nice features.

-Chris

Assaf Tal wrote:

···

Hi people,

I hope I've come to the right place - if not please redirect me :).

I've been trying to get matplotlib & wxPython to work together. I've pretty much succeeded - I've written a program (attached below) which plots a sine function, with a slider controlling the number of cycles. So far so good.

However, after moving the slider around for several seconds, the program suddenly starts spewing out error messages in the console. The program itself doesn't close or crash, but the plot stops updating itself.

Can you help me understand the problem and fix it? Is it a memory thing, or perhaps something else?

Thank you very much for your help!

Assaf.

Short note: the "important" parts are the PlotPanel class, with its init_plot_data which gets called every time the slider is moved, and the OnSlider function of the main frame, which is bound to the slider-movement event.
Other than that, the program consists of two panes separated by a sash.
I'm using PSPAD to edit my files, and run my programs using Python.exe on a windows XP operating system.

---------------------------------------------------------------- Begin attachment ------------------------------------------------------------------------

#!/usr/bin/env python

import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import Toolbar, FigureCanvasWxAgg

from matplotlib.figure import Figure
import numpy as npy
import wx

class PlotPanel(wx.Panel):
    """ This class represents a basic embelishment on the wx.Panel class, allowing for plots. """

    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)
        self.fig = Figure()
        self.canvas = FigureCanvasWxAgg(self, -1, self.fig)
        self.figHandle = self.fig.add_subplot(111)
        # Now put all into a sizer
        sizer = wx.BoxSizer(wx.VERTICAL)
        # This way of adding to sizer allows resizing
        sizer.Add(self.canvas, 1, wx.LEFT|wx.TOP|wx.GROW)
        self.SetSizer(sizer)
        self.Fit()

    def init_plot_data(self,x = [1,2,3,4], y = [1,2,3,4]):
        self.figHandle.clear()
        self.figHandle.plot(x,y)
        self.canvas.draw()
class MyFrame(wx.Frame):
    def __init__(self, parent = None, id = -1, pos = (10,10), title = "HelloWorld", size = (800,600)):
        wx.Frame.__init__(self, parent,id,title, pos, size)
        self.CreateMenu()
        # Create a status bar
        self.CreateStatusBar()
        # Create the toolbar
        self.AddToolBar()
        # Create splitter window
        self.initpos = 70
        self.sp = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        # First panel is for the slider
        self.p1 = wx.Panel(self.sp)
        # Second panel is for plotting
        self.p2 = PlotPanel(self.sp)
        self.p2.Hide()
        self.p1.SetBackgroundColour("cornflower blue")
        self.p2.SetBackgroundColour("sky blue")
        self.sp.Initialize (self.p1)
        self.sp.SetMinimumPaneSize(10)
        self.sp.SplitHorizontally(self.p1, self.p2, self.initpos)
        # Create user input slider
        self.slider = wx.Slider(self.p1, 100, 25, 1, 100, pos=(10,10), size=(250,-1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
        self.slider.SetTickFreq(10,1)
        self.slider.SetForegroundColour("white")
        self.Bind(wx.EVT_SLIDER, self.OnSlider, self.slider)
        self.slider.CentreOnParent()
        # Create plotting panel
        self.p2.init_plot_data()
    
           def CreateMenu(self):
        # Define menus
        menuFile = wx.Menu()
        menuHelp = wx.Menu()
        # Add items
        menuFile.Append(1, "&Open...")
        menuFile.AppendSeparator()
        menuFile.Append(3, "E&xit")
        menuHelp.Append(1, "&About")
        # Create the menu bar
        menuBar = wx.MenuBar()
        menuBar.Append(menuFile,"&File")
        menuBar.Append(menuHelp,"&Help")
        # Add to frame
        self.SetMenuBar(menuBar)

    def AddToolBar(self):
        toolbar = self.CreateToolBar(wx.NO_BORDER)
        toolbar.SetToolBitmapSize((32,32))
        for each in self.ToolBarData():
            if not each[0]:
                toolbar.AddSeparator()
            else:
                bmp = wx.Image(each[1], wx.BITMAP_TYPE_PNG).ConvertToBitmap()
                toolbar.AddSimpleTool(-1,bmp, each[0], each[2]);
        toolbar.Realize()
       def ToolBarData(self):
        return (("Open", "folder.png", "Open a WAV file", self.OnOpen),
                ("Play", "media-playback-start.png ", "Play current file", self.OnPlay),
                ("", "", "", ""),
                ("Help", "help-browser.png", "Browse online help", self.OnHelp))

    def OnOpen():
        pass
           def OnPlay():
        pass
           def OnHelp():
        pass
           def OnSlider(self, event):
        sliderValue = self.slider.GetValue()
        self.SetStatusText('Ive been moved!')
        curX = npy.arange(0,10,0.05)
        curY = npy.sin(sliderValue*curX)
        self.p2.init_plot_data(curX,curY)
       
class App(wx.App):
    def OnInit(self):
        self.frame = MyFrame()
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True
   def main():
    app = App(False)
    app.MainLoop()
   if __name__ == '__main__':
    main()
   
------------------------------------------------------------------- End attachment ------------------------------------------------------------------------

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov