Search code examples
pythonpython-3.xwxpython

Different matlibplots for different popup choices in wx


I am making a simple gui for a signal generator with wx. I want to display a small plot of say a sine wave when the option "Sine" is chosen, and a plot of a square wave when "Square" is chosen from the menu. I am a newbie in python, and therefore the classes and inheritance of these is difficult for me.

In the (much stripped down) code i have a variable 'wave' inside the class 'ServelPanel' that holds which wavetype is chosen. However, when I try and plot the waveform in the MainFrame class, I cannot for the life of me retrieve the 'wave'-variable. I have tried to inherit classes, set the 'wave'-variable global, and am out of ideas.

import wx, random, math, os
from pyo import *

from numpy import arange, sin, pi, sign
import matplotlib
matplotlib.use('WXAgg')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as 
FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
import matplotlib.pyplot as plt

class BasePanel(wx.Panel):
    def __init__(self, parent, title):
        wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
        self.SetMaxSize((230,150))
        self.sliders = []
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.titleSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.close = wx.StaticText(self, id=-1, label="X")
        self.close.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
        self.titleSizer.Add(self.close, 0, wx.LEFT, 5)
        self.title = wx.StaticText(self, id=-1, label=title)
        off = (210 - self.title.GetSize()[0]) / 2
        self.titleSizer.Add(self.title, 0, wx.LEFT, off)
        self.sizer.Add(self.titleSizer, 0, wx.BOTTOM|wx.TOP, 4)

class ServerPanel(wx.Panel):
    def __init__(self, parent, colour="#DDDDE7"):
        wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
        self.SetBackgroundColour(colour)
        self.SetMinSize((230,250))
        self.fileformat = self.wavetype = 0
        self.title = wx.StaticText(self, id=-1, label="--- Simple Wave 
Generator ---", pos=(40,5))
        font, psize = self.title.GetFont(), 
        self.title.GetFont().GetPointSize()
        font.SetPointSize(psize-2)
        self.waveText = 
        wx.StaticText(self,id=-1,label="Waveform",pos(15,60))
        self.popupWave = wx.Choice(self, id=wx.ID_ANY, pos=(13,70), 
        size(70,20), choices=["Sine","Square"])
        self.popupWave.Bind(wx.EVT_CHOICE, self.changeWave)

        objs = [self.waveText]
        for obj in objs:
            obj.SetFont(font)

     def changeWave(self, evt):
        global wave
        wave = evt.GetInt()
        if wave == 1: wave = 2
        self.wavetype = wave

class MainFrame(wx.Frame,ServerPanel):
    def __init__(self, parent=None, title=u"Sine Test", size=(250,300)):
        wx.Frame.__init__(self, parent, id=-1, title=title, size=size)
        self.server = Server().boot()
        self.sizer = wx.FlexGridSizer(4,4,0,0)        
        self.panel = wx.Panel(self)
        self.serverPanel = ServerPanel(self.panel)
        self.sizer.Add(self.serverPanel)        
        self.panel.SetSizer(self.sizer)
        pan = CanvasPanel(self.panel)
        pan.draw()
        self.Show()

class CanvasPanel(wx.Panel):
        def __init__(self, parent):
        wx.Panel.__init__(self, parent, id=-1, pos=wx.Point(100,60), 
        size=wx.Size(80, 50))
        figsize = (80*1.0/80, 50*1.0/80)
        self.figure = Figure(figsize, dpi=80)
        self.axes = self.figure.add_subplot(111)
        self.axes.set_axis_off()
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas,1,wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()

    def draw(self):
        t = arange(0.0, 3.0, 0.01)
        s = sin(2 * pi * t)
        self.axes.plot(t, s)

    def drawSqr(self):
        t = arange(0.0, 3.0, 0.01)
        s = sign(sin(2 * pi * t))
        self.axes.plot(t, s)

mainFrame = MainFrame()
app.MainLoop()

Ps: I know the "minimal working example" is not really minimal, but it's what I could get working for the moment. Please excuse a novice.

In the example I have hard coded a drawing to show in the MainFrame class, so you see where the drawing should be.

enter image description here


Solution

  • If we boil your code down a bit, remove un-needed classes, use sizers rather than mixing sizers and positional statements, clean up the indentation issues, remove undeclared items and unused imports.
    We get something along these lines.

    import wx
    from numpy import arange, sin, pi, sign
    import matplotlib
    matplotlib.use('WXAgg')
    
    from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
    from matplotlib.figure import Figure
    
    class MainFrame(wx.Frame):
        def __init__(self, parent=None, title=u"Sine Test", size=(250,300)):
            wx.Frame.__init__(self, parent, id=-1, title=title, size=size)
            self.panel = wx.Panel(self,-1,style=wx.SUNKEN_BORDER)
            self.panel.SetBackgroundColour("#DDDDE7")
            self.panel.SetMinSize((230,250))
            self.wavetype = 0
            self.title = wx.StaticText(self.panel, id=-1, label="--- Simple Wave Generator ---")
            font, psize = self.title.GetFont(), self.title.GetFont().GetPointSize()
            font.SetPointSize(psize-2)
            self.waveText = wx.StaticText(self.panel,id=-1,label="Waveform")
            self.popupWave = wx.Choice(self.panel, id=wx.ID_ANY, size=(70,30), choices=["Sine","Square"])
            self.popupWave.Bind(wx.EVT_CHOICE, self.changeWave)
            self.pan = CanvasPanel(self)
    
            self.sizer =  wx.GridBagSizer(hgap=5,vgap=5)
            self.main_sizer = wx.BoxSizer(wx.VERTICAL)
            self.sizer.Add(self.title, pos=(0,0), span=(1,4), flag = wx.ALL|wx.ALIGN_CENTER)
            self.sizer.Add(self.waveText, pos=(2,0), flag = wx.ALL)
            self.sizer.Add(self.popupWave, pos=(3,0), flag = wx.ALL)
            self.sizer.Add(self.pan, pos=(3,1), span=(3,3), flag = wx.ALL|wx.EXPAND)
            self.panel.SetSizer(self.sizer)
            self.main_sizer.Add(self.panel,1,wx.EXPAND)
            self.SetSizer(self.main_sizer)
    
            self.popupWave.SetSelection(0)
            self.pan.wavetype = self.popupWave.GetSelection()
            self.pan.draw()
            self.Show()
    
        def changeWave(self, evt):
            wave = evt.GetSelection()
            self.pan.wavetype = wave
            self.pan.draw()
    
    
    class CanvasPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent, id=-1, size=wx.Size(80, 50))
            figsize = (80*1.0/80, 50*1.0/80)
            self.figure = Figure(figsize, dpi=80)
            self.wavetype = parent.wavetype
            self.axes = self.figure.add_subplot(111)
            self.axes.set_axis_off()
            self.canvas = FigureCanvas(self, -1, self.figure)
            self.sizer = wx.BoxSizer(wx.VERTICAL)
            self.sizer.Add(self.canvas,1,wx.LEFT | wx.TOP | wx.GROW)
            self.SetSizer(self.sizer)
            self.Fit()
    
        def draw(self):
            #Clear any previous data
            self.axes.clear()
            self.axes.set_axis_off()
            #Plot new wave
            if self.wavetype == 0:
                t = arange(0.0, 3.0, 0.01)
                s = sin(2 * pi * t)
                self.axes.plot(t, s)
            else:
                t = arange(0.0, 3.0, 0.01)
                s = sign(sin(2 * pi * t))
                self.axes.plot(t, s)
            self.Layout()
    
    app=wx.App()
    mainFrame = MainFrame()
    app.MainLoop()
    

    enter image description here enter image description here

    It may not be exactly what you are after, so feel free to play with it!