示例#1
0
class PlotFrame(wx.Frame):
    help_msg = """  Menus for  
     Save           export figure (png,eps,bmp) to file 
     Copy           copy bitmap of figure to the system clipboard
     Print Setup    setup size of figure for printing
     Print Preview  preview printer page
     Print          send figure to a system printer
     Exit           end application
    
     where 'figure' means an image of the matplotlib canvas
 
  In addition, "Ctrl-C" is bound to copy-figure-to-clipboard
"""

    start_msg = """        Use Menus to test printing
        or Ctrl-C to copy plot image to clipboard  """

    about_msg = """        printing_in_wx version 0.1  12-Nov-2004
        Matt Newville <*****@*****.**>"""

    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Test Printing with WX Backend")
        self.fig = Figure((5.0, 3.0), 100)
        self.canvas = FigCanvas(self, -1, self.fig)
        self.axes = self.fig.add_axes([0.15, 0.15, 0.75, 0.75])

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        sizer.Add(wx.StaticText(self, -1, self.start_msg), 0,
                  wx.ALIGN_LEFT | wx.TOP)

        self.canvas.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent)

        self.SetSizer(sizer)
        self.Fit()
        self.Build_Menus()
        self.Plot_Data()

    def Build_Menus(self):
        """ build menus """
        MENU_EXIT = wx.NewId()
        MENU_SAVE = wx.NewId()
        MENU_PRINT = wx.NewId()
        MENU_PSETUP = wx.NewId()
        MENU_PREVIEW = wx.NewId()
        MENU_CLIPB = wx.NewId()
        MENU_HELP = wx.NewId()

        menuBar = wx.MenuBar()

        f0 = wx.Menu()
        f0.Append(MENU_SAVE, "&Export", "Save Image of Plot")
        f0.AppendSeparator()
        f0.Append(MENU_PSETUP, "Page Setup...", "Printer Setup")
        f0.Append(MENU_PREVIEW, "Print Preview...", "Print Preview")
        f0.Append(MENU_PRINT, "&Print", "Print Plot")
        f0.AppendSeparator()
        f0.Append(MENU_EXIT, "E&xit", "Exit")
        menuBar.Append(f0, "&File")

        f1 = wx.Menu()
        f1.Append(MENU_HELP, "Quick Reference", "Quick Reference")

        menuBar.Append(f1, "&Help")

        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.onPrint, id=MENU_PRINT)
        self.Bind(wx.EVT_MENU, self.onPrinterSetup, id=MENU_PSETUP)
        self.Bind(wx.EVT_MENU, self.onPrinterPreview, id=MENU_PREVIEW)
        self.Bind(wx.EVT_MENU, self.onClipboard, id=MENU_CLIPB)
        self.Bind(wx.EVT_MENU, self.onExport, id=MENU_SAVE)
        self.Bind(wx.EVT_MENU, self.onExit, id=MENU_EXIT)
        self.Bind(wx.EVT_MENU, self.onHelp, id=MENU_HELP)

    # the printer / clipboard methods are implemented
    # in backend_wx, and so are very simple to use.
    def onPrinterSetup(self, event=None):
        self.canvas.Printer_Setup(event=event)

    def onPrinterPreview(self, event=None):
        self.canvas.Printer_Preview(event=event)

    def onPrint(self, event=None):
        self.canvas.Printer_Print(event=event)

    def onClipboard(self, event=None):
        self.canvas.Copy_to_Clipboard(event=event)

    def onKeyEvent(self, event=None):
        """ capture , act upon keystroke events"""
        if event == None: return
        key = event.KeyCode()
        if (key < wx.WXK_SPACE or key > 255): return

        if (event.ControlDown() and chr(key) == 'C'):  # Ctrl-C
            self.onClipboard(event=event)

    def onHelp(self, event=None):
        dlg = wx.MessageDialog(self, self.help_msg, "Quick Reference",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onExport(self, event=None):
        """ save figure image to file"""
        file_choices = "PNG (*.png)|*.png|" \
                       "PS (*.ps)|*.ps|" \
                       "EPS (*.eps)|*.eps|" \
                       "BMP (*.bmp)|*.bmp"

        thisdir = os.getcwd()

        dlg = wx.FileDialog(self,
                            message='Save Plot Figure as...',
                            defaultDir=thisdir,
                            defaultFile='plot.png',
                            wildcard=file_choices,
                            style=wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path, dpi=300)
            if (path.find(thisdir) == 0):
                path = path[len(thisdir) + 1:]
            print 'Saved plot to %s' % path

    def onExit(self, event=None):
        self.Destroy()

    def Plot_Data(self):
        t = numpy.arange(0.0, 5.0, 0.01)
        s = numpy.sin(2.0 * numpy.pi * t)
        c = numpy.cos(0.4 * numpy.pi * t)
        self.axes.plot(t, s)
        self.axes.plot(t, c)
示例#2
0
class PlotFrame(wx.Frame):
    help_msg="""  Menus for
     Import...import project settings file
     Export...export figure (png, jpg) to file
     Print Setup...setup size of figure for printing
     Print Preview...preview printer page
     Print...send figure to a system printer
     Exit...end application

     Basic-2D...View basic 2D representation of data
     Advanced-2D...View 2D representation (with span selection control)
     Advanced-3D...View 3D representation of data

     View-Grid...Toggle grid
     View-Legend...Toggle legend
     View-Fill...Toggle fill representation of data (only for 2D)

     where 'figure' means an image of the matplotlib canvas

     In addition, "Ctrl-C" is bound to copy-figure-to-clipboard    
    """

    about_msg="""
        Option_price_visualisation v0.1  29-Aug-2013

        Nathan Floor, [email protected]
    """

    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Visualise Option Prices and Greeks", size=(300, 500))
        self.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent)

        # intialise variables when start program
        self.viewLegend = False
        self.viewGrid = True
        self.viewFill = False
        
        self.reInitialiseData()
        
        # build interface
        self.Build_Menus()
        self.Build_Panel()
        self.statusbar = self.CreateStatusBar()
        self.Plot_Data()
        self.SetSize(size=(900, 550))

    def reInitialiseData(self):
        self.fileReader = csvReader.Reader()
        self.current_view = 0
        self.time = numpy.arange(0, 31, 1)
        self.indmin = 0
        self.indmax = 31
        self.strike_price = 0

        # initialise data arrays
        self.option_price = []
        self.stock_price = []
        self.delta = []
        self.gamma = []
        self.vega = []
        self.theta = []
        self.rho = []
        self.risidual = []
        
        # initialise secondary data sets
        self.option_price_fill = []
        self.time_span_fill = []
        self.delta_fill = []
        self.gamma_fill = []
        self.vega_fill = []
        self.theta_fill = []
        self.rho_fill = []
        
        # initialise bump values
        self.stock_bump = 0
        self.time_bump = 0
        self.rate_bump = 0
        self.volitile_bump = 0

    # on span-selection of graph
    def onselect(self, xmin, xmax):
        # initialise data sets
        option_price = []
        delta = []
        gamma = []
        theta = []
        rho = []
        vega = []
        maxYLimlist = []
        minYLimlist = []

        # identify the indices of new data set based on selection
        self.indmin = int(xmin)
        #self.indmax = numpy.searchsorted(t, (xmin, xmax))
        self.indmax = min(len(self.time)-1, int(xmax)+1)

        self.time_span_fill = self.time[self.indmin:self.indmax]
        if len(self.option_price) > 0:
            option_price = numpy.array(map(float, self.option_price[self.stock_bump]))
            self.option_price_fill = option_price[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.option_price_fill))
            minYLimlist.append(min(self.option_price_fill))
            if not self.viewFill:
                self.line1.set_data(self.time_span_fill, self.option_price_fill)
        if len(self.delta) > 0:
            delta = numpy.array(map(float, self.delta[self.stock_bump]))
            self.delta_fill = delta[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.delta_fill))
            minYLimlist.append(min(self.delta_fill))
            if not self.viewFill:
                self.line2.set_data(self.time_span_fill, self.delta_fill)
        if len(self.gamma) > 0:
            gamma = numpy.array(map(float, self.gamma[self.stock_bump]))
            self.gamma_fill = gamma[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.gamma_fill))
            minYLimlist.append(min(self.gamma_fill))
            if not self.viewFill:
                self.line3.set_data(self.time_span_fill, self.gamma_fill)
        if len(self.theta) > 0:
            theta = numpy.array(map(float, self.theta[self.time_bump]))
            self.theta_fill = theta[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.theta_fill))
            minYLimlist.append(min(self.theta_fill))
            if not self.viewFill:
                self.line4.set_data(self.time_span_fill, self.theta_fill)
        if len(self.rho) > 0:
            rho = numpy.array(map(float, self.rho[self.rate_bump]))
            self.rho_fill = rho[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.rho_fill))
            minYLimlist.append(min(self.rho_fill))
            if not self.viewFill:
                self.line5.set_data(self.time_span_fill, self.rho_fill)
        if len(self.vega) > 0:
            vega = numpy.array(map(float, self.vega[self.volitile_bump]))
            self.vega_fill = vega[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.vega_fill))
            minYLimlist.append(min(self.vega_fill))
            if not self.viewFill:
                self.line6.set_data(self.time_span_fill, self.vega_fill)
        if len(self.risidual) > 0:
            risidual = numpy.array(map(float, self.risidual[self.stock_bump]))
            self.risidual_fill = risidual[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.risidual_fill))
            minYLimlist.append(min(self.risidual_fill))
            if not self.viewFill:
                self.line7.set_data(self.time_span_fill, self.risidual_fill)

        if len(maxYLimlist) > 0:
            maxYLim = max(maxYLimlist)
        else:
            maxYLim = 1
        if len(minYLimlist) > 0:
            minYLim = min(minYLimlist)
        else:
            minYLim = 0

        self.axes2.set_xlim(self.time_span_fill[0]-1, self.time_span_fill[-1]+1)
        self.axes2.set_ylim(minYLim, maxYLim)
        if not self.viewFill:
            self.canvas.draw()
        else:
            self.Plot_Data()

    def Build_Panel(self):
        self.panel = wx.Panel(self)

        # Create Figure and canvas objects
        self.fig = Figure((6.0, 4.0))
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.axes = self.fig.add_subplot(111)

        # setup slider-widgets for controlling GUI
        self.sliderPanel = wx.Panel(self.panel)
        self.stockSlider_label = wx.StaticText(self.sliderPanel, -1, "Stock Price: ")
        self.stockSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, 
            pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
        # self.stockSlider.SetTickFreq(9, 1)
        self.rateSlider_label = wx.StaticText(self.sliderPanel, -1, "Interest Rate: ")
        self.rateSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, 
            pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
        self.rateSlider.SetTickFreq(1, 1)
        self.timeStepSlider_label = wx.StaticText(self.sliderPanel, -1, "Time Step: ")
        self.timeStepSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, 
            pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
        self.timeStepSlider.SetTickFreq(1, 1)

        self.Bind(wx.EVT_SLIDER, self.onStockSlider, self.stockSlider)
        self.Bind(wx.EVT_SLIDER, self.onRateSlider, self.rateSlider)
        self.Bind(wx.EVT_SLIDER, self.ontimeStepSlider, self.timeStepSlider)        

        # setup options-widgets for controlling graphs
        self.callRadio = wx.RadioButton(self.panel, label="Call options", pos=(10, 10))
        self.putRadio = wx.RadioButton(self.panel, label="Put options", pos=(10, 30))
        self.callRadio.SetValue(True)        
        self.spaceKeeper = wx.StaticText(self.panel, -1, '')
        self.optionPriceCheck = wx.CheckBox(self.panel, label="view Option Price", pos=(20, 20))
        self.deltaCheck = wx.CheckBox(self.panel, label="show Delta", pos=(20, 20))
        self.gammaCheck = wx.CheckBox(self.panel, label="show Gamma", pos=(20, 20))
        self.rhoCheck = wx.CheckBox(self.panel, label="show Rho", pos=(20, 20))
        self.thetaCheck = wx.CheckBox(self.panel, label="show Theta", pos=(20, 20))
        self.fillCheck = wx.CheckBox(self.panel, label="show fill feature", pos=(20, 20))
        self.risidualCheck = wx.CheckBox(self.panel, label="Show Residual", pos=(20, 20))
        self.differenceCheck = wx.CheckBox(self.panel, label="Show Difference", pos=(20, 20))
        self.effectCheck = wx.CheckBox(self.panel, label="Show Greek's effect on option price", pos=(20, 20))
        self.effectCheck.SetValue(True)

        self.Bind(wx.EVT_RADIOBUTTON, self.onCallRadio, self.callRadio)
        self.Bind(wx.EVT_RADIOBUTTON, self.onPutRadio, self.putRadio)
        self.Bind(wx.EVT_CHECKBOX, self.onOptionPrice, self.optionPriceCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onDelta, self.deltaCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onGamma, self.gammaCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onRho, self.rhoCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onTheta, self.thetaCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onRisidual, self.risidualCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onDifferenceCheck, self.differenceCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onShowEffects, self.effectCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onShowFillEffect, self.fillCheck)

        # Create the navigation toolbar, tied to the canvas
        self.toolbar = NavigationToolbar(self.canvas)

        ####################
        # Layout with sizers
        ####################
        flags = wx.ALIGN_LEFT | wx.ALL | wx.ALIGN_CENTER_VERTICAL
        self.sizer = wx.BoxSizer(wx.VERTICAL)

        self.hboxMainBlock = wx.BoxSizer(wx.HORIZONTAL)
        self.vboxOptions = wx.BoxSizer(wx.VERTICAL)
        self.hboxSliders = wx.BoxSizer(wx.HORIZONTAL)
        self.flexiGridSizer = wx.FlexGridSizer(4, 2, 3, 10)

        # adds border around sliders to group related widgets
        self.vboxOptions.AddSpacer(10)
        self.sliderStaticBox = wx.StaticBox(self.sliderPanel, -1, 'Bump Sliders')
        self.sliderBorder = wx.StaticBoxSizer(self.sliderStaticBox, orient=wx.VERTICAL)
        self.flexiGridSizer.AddMany([(self.stockSlider_label), (self.stockSlider, 1, wx.ALL), 
            (self.rateSlider_label), (self.rateSlider, 1, wx.EXPAND), (self.timeStepSlider_label), (self.timeStepSlider, 1, wx.EXPAND)])
        self.sliderBorder.Add(self.flexiGridSizer, 1, wx.ALL, 5)
        self.sliderPanel.SetSizer(self.sliderBorder)
        self.vboxOptions.Add(self.sliderPanel, 0, flag=wx.ALIGN_LEFT|wx.ALL)

        # add border for type of option price
        self.optionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Option Price Type'), orient=wx.VERTICAL)
        self.flexiOptions = wx.FlexGridSizer(3, 1, 3, 10)
        self.flexiOptions.AddMany([(self.callRadio, 1, wx.EXPAND), 
            (self.putRadio, 1, wx.EXPAND), (self.optionPriceCheck, 1, wx.EXPAND)])            
        self.optionsBorder.Add(self.flexiOptions, 1, wx.ALL, 5)
        self.vboxOptions.Add(self.optionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW)
        
        # add border for greeks
        self.greekOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Greek effect Options'), orient=wx.VERTICAL)
        self.flexiOptions2 = wx.FlexGridSizer(6, 1, 3, 10)
        self.flexiOptions2.AddMany([(self.deltaCheck, 1, wx.EXPAND), (self.gammaCheck, 1, wx.EXPAND), 
            (self.rhoCheck, 1, wx.EXPAND), (self.thetaCheck, 1, wx.EXPAND), (self.risidualCheck, 1, wx.EXPAND)])
        self.greekOptionsBorder.Add(self.flexiOptions2, 1, wx.ALL, 5)
        self.vboxOptions.Add(self.greekOptionsBorder, 1, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW)
        #self.vboxOptions.AddSpacer(5)
        
        # add border for other checkable options
        self.otherOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Extra Options'), orient=wx.VERTICAL)
        self.flexiOptions3 = wx.FlexGridSizer(3, 1, 3, 10)
        self.flexiOptions3.AddMany([(self.fillCheck, 1, wx.EXPAND), (self.differenceCheck, 1, wx.EXPAND), 
            (self.effectCheck, 1, wx.EXPAND)])
        self.otherOptionsBorder.Add(self.flexiOptions3, 1, wx.ALL, 5)
        self.vboxOptions.Add(self.otherOptionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW)
        self.vboxOptions.AddSpacer(5)

        self.hboxMainBlock.Add(self.vboxOptions, 0, flag=flags)
        self.hboxMainBlock.Add(self.canvas, 1, flag=wx.ALIGN_RIGHT|wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
        self.sizer.Add(self.hboxMainBlock, 1, wx.ALL|wx.EXPAND)

        self.sizer.Add(self.toolbar, 0, wx.ALL|wx.ALIGN_RIGHT)
        self.sizer.AddSpacer(1)

        self.canvas.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent)
        self.Bind(wx.EVT_CLOSE, self.onExit)

        self.panel.SetSizer(self.sizer)
        self.sizer.Fit(self)
        self.Center()

    def Build_Menus(self):
        """ build menus """
        MENU_EXIT = wx.NewId()
        MENU_OPEN = wx.NewId()
        MENU_SAVE = wx.NewId()
        MENU_PRINT = wx.NewId()
        MENU_PSETUP = wx.NewId()
        MENU_PREVIEW =wx.NewId()
        MENU_CLIPB =wx.NewId()
        MENU_VIEW_GRID = wx.NewId()
        MENU_HELP =wx.NewId()
        MENU_BASIC = wx.NewId()
        MENU_ADVANCE = wx.NewId()
        MENU_LEGEND = wx.NewId()
        MENU_3D = wx.NewId()
        MENU_ABOUT = wx.NewId()

        menuBar = wx.MenuBar()

        f0 = wx.Menu()
        importItem = wx.MenuItem(f0, MENU_OPEN, "&Import\tCtrl+I")
        f0.AppendItem(importItem)  
        f0.Append(MENU_SAVE,   "&Export",   "Save Image of Plot")
        f0.AppendSeparator()
        printMenu = wx.Menu()
        printMenu.Append(MENU_PSETUP, "Page Setup...",    "Printer Setup")
        printMenu.Append(MENU_PREVIEW,"Print Preview...", "Print Preview")
        printItem = wx.MenuItem(printMenu, MENU_PRINT,  "Print\tCtrl+P")
        printMenu.AppendItem(printItem)
        f0.AppendMenu(-1, '&Print', printMenu)
        f0.AppendSeparator()
        exitItem = wx.MenuItem(f0, MENU_EXIT, 'E&xit\tCtrl+Q')
        f0.AppendItem(exitItem)
        menuBar.Append(f0,     "&File")

        f1 = wx.Menu()
        f1.Append(MENU_BASIC, '&Basic', "Basic View(2D)")
        f1.Append(MENU_ADVANCE, '&Advanced-2D', "Advanced View(2D)")
        f1.Append(MENU_3D, 'A&dvanced-3D', "Advanced View(3D)")

        optionsMenu = wx.Menu()
        viewGridItem = wx.MenuItem(optionsMenu, MENU_VIEW_GRID, 'View &Grid\tCtrl+G')
        optionsMenu.AppendItem(viewGridItem)
        viewLegendItem = wx.MenuItem(optionsMenu, MENU_LEGEND, 'View &Legend\tCtrl+L')
        optionsMenu.AppendItem(viewLegendItem)
        f1.AppendMenu(-1, "&Options", optionsMenu)

        menuBar.Append(f1, "&View")

        f2 = wx.Menu()
        f2.Append(MENU_HELP, "Quick &Reference",  "Quick Reference")
        f2.Append(MENU_ABOUT, "&About",  "About this interface")
        menuBar.Append(f2, "&Help")

        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.onImport,       id=MENU_OPEN)
        self.Bind(wx.EVT_MENU, self.onPrint,        id=MENU_PRINT)
        self.Bind(wx.EVT_MENU, self.onPrinterSetup, id=MENU_PSETUP)
        self.Bind(wx.EVT_MENU, self.onPrinterPreview, id=MENU_PREVIEW)
        self.Bind(wx.EVT_MENU, self.onClipboard,    id=MENU_CLIPB)
        self.Bind(wx.EVT_MENU, self.onExport,       id=MENU_SAVE)
        self.Bind(wx.EVT_MENU, self.onExit ,        id=MENU_EXIT)
        self.Bind(wx.EVT_MENU, self.onViewGrid,     id=MENU_VIEW_GRID)
        self.Bind(wx.EVT_MENU, self.onViewLegend,     id=MENU_LEGEND)
        self.Bind(wx.EVT_MENU, self.onHelp,         id=MENU_HELP)
        self.Bind(wx.EVT_MENU, self.onAbout,         id=MENU_ABOUT)
        self.Bind(wx.EVT_MENU, self.onBasicView,    id=MENU_BASIC)
        self.Bind(wx.EVT_MENU, self.onAdvancedView, id=MENU_ADVANCE)
        self.Bind(wx.EVT_MENU, self.onAdvanced3DView, id=MENU_3D)

    """ Menu event methods """
    def onViewLegend(self, event=None):
        if self.viewLegend:
            self.viewLegend = False
            self.Plot_Data()
        else:
            self.viewLegend = True
            # use proxy artist
            plot_op = Line2D([], [], linewidth=3, color="black") 
            plot_delta = Line2D([], [], linewidth=3, color="royalblue") 
            plot_gamma = Line2D([], [], linewidth=3, color="cyan") 
            plot_theta = Line2D([], [], linewidth=3, color="green") 
            plot_rho = Line2D([], [], linewidth=3, color="darkorange") 
            plot_risidual = Line2D([], [], linewidth=3, color="purple")

            # Shink current axis by 15%
            box = self.axes.get_position()
            self.axes.set_position([box.x0, box.y0, box.width * 0.88, box.height])
            # Put a legend to the right of the current axis
            self.axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'],
                loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})

            if self.current_view == 1:
                box = self.axes2.get_position()
                self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height])
                # Put a legend to the right of the current axis
                self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})
            self.canvas.draw()

    def onBasicView(self, event=None):
        self.current_view = 0
        # show sliders panel
        self.sliderPanel.Enable()
        self.toolbar.Enable()
        self.fillCheck.Enable()
        self.panel.Layout()
        self.Plot_Data()

    def onAdvancedView(self, event=None):
        self.current_view = 1
        # show sliders panel
        self.sliderPanel.Enable()
        self.toolbar.Enable()
        self.fillCheck.Enable()
        self.panel.Layout()
        self.Plot_Data()

    def onAdvanced3DView(self, event=None):
        self.current_view = 2
        # hide slider panel since will not be used
        self.sliderPanel.Disable()
        self.toolbar.Disable()
        self.fillCheck.Disable()
        self.panel.Layout()   
        self.Plot_Data()

    def onPrinterSetup(self,event=None):
        self.canvas.Printer_Setup(event=event)

    def onPrinterPreview(self,event=None):
        self.canvas.Printer_Preview(event=event)

    def onPrint(self,event=None):
        self.canvas.Printer_Print(event=event)

    def onClipboard(self,event=None):
        self.canvas.Copy_to_Clipboard(event=event)

    def onKeyEvent(self,event=None):
        """ capture and act upon keystroke events """
        if event == None: return
        key = event.GetKeyCode()
        if (key < wx.WXK_SPACE or  key > 255):  return

        if (event.ControlDown() and chr(key)=='C'): # Ctrl-C
            self.onClipboard(event=event)
        if (event.ControlDown() and chr(key)=='P'): # Ctrl-P
            self.onPrinterPreview(event=event)

    def onHelp(self, event=None):
        dlg = wx.MessageDialog(self, self.help_msg, "Quick Reference", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onAbout(self, event=None):
        dlg = wx.MessageDialog(self, self.about_msg, "About", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onViewGrid(self, event=None):
        if self.viewGrid:
            self.viewGrid = False
        else:
            self.viewGrid = True
        for a in self.fig.axes:
            a.grid(self.viewGrid)
        self.canvas.draw()

    def onExport(self,event=None):
        """ save figure image to file"""
        file_choices = "PNG (*.png)|*.png|" \
                       "JPEG (*.jpg)|*.jpg|" \
                       "BMP (*.bmp)|*.bmp"

        thisdir  = os.getcwd()

        dlg = wx.FileDialog(self, message='Save Plot Figure as...',
                            defaultDir = thisdir, defaultFile='plot.png',
                            wildcard=file_choices, style=wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path,dpi=300)
            if (path.find(thisdir) ==  0):
                path = path[len(thisdir)+1:]
            print('Saved plot to %s' % path)

    def onImport(self, event=None):
        """ Import csv file of option prices and greeks """
        file_choices = "SETTINGS (*.settings)|*.settings"
        thisdir  = ''.join(os.getcwd()+'/data')

        # import output file
        dlg = wx.FileDialog(self, message='Import option prices and greeks (Outputs)',
                            defaultDir = thisdir, defaultFile='data.settings',
                            wildcard=file_choices, style=wx.OPEN)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            projectDir = path.rsplit('/', 1)[0]
            #projectDir = path.rsplit('\\', 1)[0]
            self.reInitialiseData()
            
            # this also involves reading in all the data
            self.number_bumps = self.fileReader.loadSettingsFile(path, projectDir, self.statusbar)
            print('Opened settings file at %s' % path)
        else:
            dlg = wx.MessageDialog(self, "Failed to import the correct settings file.", "Complication", wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

        # populate data
        self.strike_price = self.fileReader.getStrikePrice()
        self.stock_price = self.fileReader.getStockPrice()
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked())
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), self.vegaCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked())

        self.onBasicView()

    def onExit(self,event=None):
        dlg = wx.MessageDialog(None, 'Are you sure to exit?', 'Confirm', wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION)
        ret = dlg.ShowModal()
        if ret == wx.ID_YES:
            self.Destroy()

    """ GUI event methods """
    def onShowFillEffect(self, event=None):
        if self.fillCheck.IsChecked():
            if self.differenceCheck.IsChecked():
                self.differenceCheck.SetValue(False)
                # reload and replot data
                self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
                    self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
                    self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
                #    self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
                    self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
                    self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
                    self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
            
            self.viewFill = True
        else:
            self.viewFill = False
        self.Plot_Data()

    def onCallRadio(self, event=None):
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), 
            self.optionPriceCheck.IsChecked())
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onPutRadio(self, event=None):
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), 
            self.optionPriceCheck.IsChecked())
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data() 

    def onOptionPrice(self, event=None):
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), 
                self.optionPriceCheck.IsChecked())
        self.Plot_Data()

    def onDelta(self, event=None):
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onGamma(self, event=None):
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())

        self.Plot_Data()

    def onRho(self, event=None):
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onTheta(self, event=None):
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onVega(self, event=None):
        self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
            self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onRisidual(self, event=None):
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())

        # print(self.risidual)
        self.Plot_Data()

    def onShowEffects(self, event=None):
        if not self.effectCheck.IsChecked():
            warning_msg = """
                This setting will plot the value of the greeks, but not terms of the option price. This means that the greek graphs will no-longer be comparable. You will still be able to plot the greeks against each other though.

                Do you want to continue?
            """
            dlg = wx.MessageDialog(self, warning_msg, "Take Note", wx.YES_NO | wx.ICON_INFORMATION)
            ret = dlg.ShowModal()
            if ret == wx.ID_NO:
                dlg.Destroy()
                self.effectCheck.SetValue(True)
                return
            dlg.Destroy()
            self.differenceCheck.Disable()
            self.fillCheck.Disable()
            self.optionPriceCheck.SetValue(False)
            self.onOptionPrice()
            self.optionPriceCheck.Disable()
        else:
            self.differenceCheck.Enable()
            self.optionPriceCheck.Enable()
            if self.current_view != 2:
                self.fillCheck.Enable()

        # reload and replot data
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())

        self.Plot_Data()

    def onDifferenceCheck(self, event=None):
        if self.fillCheck.IsChecked():    
            self.fillCheck.SetValue(False)
            self.viewFill = False

        # reload and replot data
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onStockSlider(self, event=None):
        self.statusbar.SetStatusText("Stock price bump: "+str(self.stockSlider.GetValue()))
        self.stock_bump = self.stockSlider.GetValue()-1
        self.Plot_Data()

    def onRateSlider(self, event=None):
        self.statusbar.SetStatusText("Interest Rate bump: "+str(self.rateSlider.GetValue()))
        self.rate_bump = self.rateSlider.GetValue()-1
        self.Plot_Data()

    def onVolatilSlider(self, event=None):
        self.statusbar.SetStatusText("Volatility bump: "+str(self.volatilSlider.GetValue()))
        self.volitile_bump = self.volatilSlider.GetValue()-1
        self.Plot_Data()

    def ontimeStepSlider(self, event=None):
        self.statusbar.SetStatusText("Time step bump: "+str(self.timeStepSlider.GetValue()))
        self.time_bump = self.timeStepSlider.GetValue()-1
        self.Plot_Data()
        self.Plot_Data()

    """ Graph plotting methods """
    def clearPlots(self):
        """ Clear all graphs and plots for next draw """
        for a in self.fig.axes:
            self.fig.delaxes(a)

    def Plotter_2D_general(self, axes):
        # plot option price graph
        temp_option_price = []
        if len(self.option_price) > 0:
            temp_option_price = numpy.array(map(float, self.option_price[self.stock_bump]))
        if len(self.option_price) > 0:
            axes.plot(self.time, self.option_price[self.stock_bump], color='black')
        
        # stagger plot effects of greeks 
        temp_delta = []
        temp_gamma = []
        temp_theta = []
        temp_rho = []
        temp_risidual = []
        if len(self.delta) > 0:
            temp_delta = numpy.array(self.delta[self.stock_bump])
        if len(self.gamma) > 0:
            temp_gamma = numpy.array(self.gamma[self.stock_bump])
        if len(self.rho) > 0:
            temp_rho = numpy.array(self.rho[self.rate_bump])
        if len(self.theta) > 0:
            temp_theta = numpy.array(self.theta[self.time_bump])
        if len(self.risidual) > 0:
            temp_risidual = numpy.array(self.risidual[self.stock_bump])

        if not self.differenceCheck.IsChecked() and len(temp_option_price) > 0:
            for t in self.time:
                greeks_below = []
                greeks_above = []  # above/below option price
                if t < 30:
                    # sort arrays
                    if len(temp_delta) > 0:
                        if temp_delta[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_delta[t:t+2], 'delta'])
                        else:
                            greeks_below.append([temp_delta[t:t+2], 'delta'])
                    if len(temp_gamma) > 0:
                        if temp_gamma[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_gamma[t:t+2], 'gamma'])
                        else:
                            greeks_below.append([temp_gamma[t:t+2], 'gamma'])
                    if len(temp_theta) > 0:
                        if temp_theta[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_theta[t:t+2], 'theta'])
                        else:
                            greeks_below.append([temp_theta[t:t+2], 'theta'])
                    if len(temp_rho) > 0:
                        if temp_rho[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_rho[t:t+2], 'rho'])
                        else:
                            greeks_below.append([temp_rho[t:t+2], 'rho'])
                    if len(temp_risidual) > 0:
                        if temp_risidual[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_risidual[t:t+2], 'risidual'])
                        else:
                            greeks_below.append([temp_risidual[t:t+2], 'risidual'])

                    temp_time = numpy.arange(t, t+2, 1)    
                    greeks_above = sorted(greeks_above, key=lambda tup: tup[0][1])
                    greeks_below = sorted(greeks_below, key=lambda tup: tup[0][1], reverse=True)

                    # PLOT stagger greek effects
                    temp_time = numpy.arange(t, t+2, 1)
                    temp1 = numpy.array(temp_option_price[t:t+2])

                    # print(t, greeks_below, greeks_above)
                    for g in greeks_above:
                        # print(t)
                        temp2 = numpy.array([temp_option_price[t], g[0][1]])
                        if self.viewFill and len(self.option_price) > 0:
                            if g[1] == 'delta':
                                axes.fill_between(temp_time, temp2, temp1, color='blue')
                            if g[1] == 'gamma':
                                axes.fill_between(temp_time, temp2, temp1, color='cyan')
                            if g[1] == 'theta':
                                axes.fill_between(temp_time, temp2, temp1, color='green')
                            if g[1] == 'rho':
                                axes.fill_between(temp_time, temp2, temp1, color='darkorange')
                            if g[1] == 'risidual':
                                axes.fill_between(temp_time, temp2, temp1, color='purple')
                        if g[1] == 'delta':
                            axes.plot(temp_time, temp2, label="Delta", color='blue')
                        if g[1] == 'gamma':
                            axes.plot(temp_time, temp2, label="Gamma", color='cyan')
                        if g[1] == 'theta':
                            axes.plot(temp_time, temp2, label="Theta", color='green')
                        if g[1] == 'rho':
                            axes.plot(temp_time, temp2, label="Rho", color='darkorange')
                        if g[1] == 'risidual':
                            axes.plot(temp_time, temp2, label="risidual", color='purple')
                        temp1 = temp2

                    temp1 = numpy.array(temp_option_price[t:t+2])
                    for g in greeks_below:
                        temp2 = numpy.array([temp_option_price[t], g[0][1]])
                        if self.viewFill and len(self.option_price) > 0:
                            if g[1] == 'delta':
                                axes.fill_between(temp_time, temp2, temp1, color='blue')
                            if g[1] == 'gamma':
                                axes.fill_between(temp_time, temp2, temp1, color='cyan')
                            if g[1] == 'theta':
                                axes.fill_between(temp_time, temp2, temp1, color='green')
                            if g[1] == 'rho':
                                axes.fill_between(temp_time, temp2, temp1, color='darkorange')
                            if g[1] == 'risidual':
                                axes.fill_between(temp_time, temp2, temp1, color='purple')
                        if g[1] == 'delta':
                            axes.plot(temp_time, temp2, label="Delta", color='blue')
                        if g[1] == 'gamma':
                            axes.plot(temp_time, temp2, label="Gamma", color='cyan')
                        if g[1] == 'theta':
                            axes.plot(temp_time, temp2, label="Theta", color='green')
                        if g[1] == 'rho':
                            axes.plot(temp_time, temp2, label="Rho", color='darkorange')
                        if g[1] == 'risidual':
                            axes.plot(temp_time, temp2, label="risidual", color='purple')
                        temp1 = temp2
        else:
            # plot difference between greeks and option price
            if len(self.delta) > 0:
                axes.plot(self.delta[self.stock_bump], color='blue')
            if len(self.gamma) > 0:
                axes.plot(self.gamma[self.stock_bump], color='cyan')
            # if len(self.vega) > 0:
            #    axes.plot(self.vega[self.volitile_bump], label="Vega", color='yellow')
            if len(self.theta) > 0:
                axes.plot(self.time, self.theta[self.time_bump], color='green')
            if len(self.rho) > 0:
                axes.plot(self.time, self.rho[self.rate_bump], color='darkorange')
            if len(self.risidual) > 0:
                axes.plot(self.time, self.risidual[self.stock_bump], color='purple')

        if self.viewLegend:
            # use proxy artist
            plot_op = Line2D([], [], linewidth=3, color="black") 
            plot_delta = Line2D([], [], linewidth=3, color="royalblue") 
            plot_gamma = Line2D([], [], linewidth=3, color="cyan") 
            plot_theta = Line2D([], [], linewidth=3, color="green") 
            plot_rho = Line2D([], [], linewidth=3, color="darkorange") 
            plot_risidual = Line2D([], [], linewidth=3, color="purple")

            # Shink current axis by 15%
            box = axes.get_position()
            axes.set_position([box.x0, box.y0, box.width * 0.88, box.height])
            # Put a legend to the right of the current axis
            axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'],
                loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})

    def Plot_Data(self):
        if self.current_view == 1:
            self.Plot_Data_advanced()
        elif self.current_view == 2:
            self.Plot_Data_3D()
        elif self.current_view == 0:            
            """ Basic 2D graph plotter """
            self.clearPlots()
            
            self.axes = self.fig.add_subplot(111) # can use add_axes, but then nav-toolbar would not work
            self.axes.set_xlim(0, 30)
            self.axes.grid(self.viewGrid)

            self.Plotter_2D_general(self.axes)

            # set caption and axes labels
            self.axes.set_xlabel('Time (Daily)')
            if self.effectCheck.IsChecked():
                self.axes.set_ylabel('Price (Rands)')
                if hasattr(self, 'title'):
                    self.title.set_text('Option Prices and breakdown of the effects of Greeks')
                else:
                    self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks')
            else:
                self.axes.set_ylabel('Greek Value')
                if hasattr(self, 'title'):
                    self.title.set_text('Raw Greek values not in terms of option price')
                else:
                    self.title = self.fig.suptitle('Greek values not in terms of option price')

            self.canvas.draw()

    def Plot_Data_advanced(self):
        """ Advanced 2D plotter """
        self.clearPlots()
        self.axes2 = self.fig.add_subplot(212)
        self.axes = self.fig.add_subplot(211, sharex=self.axes2)
        self.axes.set_xlim(0, 30)
        self.axes.grid(self.viewGrid)        
        self.axes2.grid(self.viewGrid)

        self.Plotter_2D_general(self.axes)

        # plot strike price and stock price curve
        if self.strike_price > 0:
            self.axes2.plot([0, 30], [self.strike_price, self.strike_price], label="Strike Price", color='red')

        # plot stock price curve
        temp_stock_price = numpy.array(self.stock_price)
        if len(temp_stock_price) > 0:
            self.axes2.plot(self.time, temp_stock_price, label="Stock Price", color='blue')

        # set limits for x and y axes
        # self.axes2.set_xlim(self.time_span_fill[0], self.time_span_fill[-1])
        # self.axes2.set_ylim(min(p, key=float), max(p, key=float))

        # set caption and axes labels
        self.axes2.set_xlabel('Time (Daily)')
        self.axes2.set_ylabel('Price (Rands)')
        if self.effectCheck.IsChecked():
            self.axes.set_ylabel('Price (Rands)')
            if hasattr(self, 'title'):
                self.title.set_text('Option Prices and breakdown of the effects of Greeks')
            else:
                self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks')
        else:
            self.axes.set_ylabel('Greek Value')
            if hasattr(self, 'title'):
                self.title.set_text('Raw Greek values not in terms of option price')
            else:
                self.title = self.fig.suptitle('Greek values not in terms of option price')

        # set useblit True on gtkagg for enhanced performance
        # self.span = SpanSelector(self.axes, self.onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red'))

        if self.viewLegend:
            # Shink current axis by 15%
            box = self.axes2.get_position()
            self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height])
            # Put a legend to the right of the current axis
            self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})

        self.canvas.draw()

    def Plot_Data_3D(self):
        """ Advanced 3D plotter """
        # plot graphs
        self.clearPlots()
            
        self.axes = self.fig.add_subplot(111, projection='3d') # can use add_axes, but then nav-toolbar would not work
        self.axes.grid(self.viewGrid)

        b = numpy.arange(0, 9, 1)
        X2D, Y2D = numpy.meshgrid(self.time, b)
        Z2D = None
        
        # plot option price surface
        if len(self.option_price) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.option_price]            
            surf = self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, cmap=cm.afmhot, zorder=0.5)  #cm.coolwarm, cm.winter, cm.autumn
            cbar = self.fig.colorbar(surf, shrink=0.5, aspect=5)
            cbar.set_label('Option Price', rotation=90)

            ### TODO - mayavi ###
            # X2D, Y2D = numpy.mgrid[self.time, b]
            # print(X2D)
            # s = mlab.surf(Z2D)
            # mlab.show()

        # plot greek surfaces
        if len(self.delta) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.delta]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='blue')

        if len(self.gamma) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.gamma]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='cyan')
                
        if len(self.theta) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.theta]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='green')
                
        if len(self.rho) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.rho]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='orange')
                
        # if len(self.vega) > 0:
        #     Z2D = [[float(string) for string in inner] for inner in self.vega]
        #     self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
        #         antialiased=False, alpha=0.75, color='aqua')

        if len(self.risidual) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.risidual]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='rosybrown')
        
        if Z2D != None:
            # cset1 = self.axes.contourf(X2D, Y2D, Z2D, zdir='z', offset=300, cmap=cm.afmhot)
            self.axes.contourf(X2D, Y2D, Z2D, zdir='x', offset=0, cmap=cm.coolwarm)
            self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=-0.3, cmap=cm.winter)
            # cset = self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=10, cmap=cm.afmhot)
            # cbar = self.fig.colorbar(cset1, shrink=0.7, aspect=3)
            # cbar = self.fig.colorbar(cset2, shrink=0.7, aspect=3)
            # cbar = self.fig.colorbar(cset3, shrink=0.5, aspect=5)
            # cbar.set_label('Option Proce', rotation=90)

        # set captions and axis labels
        self.axes.set_xlabel('Time (Days)')
        self.axes.set_xlim(0, 35)
        self.axes.set_ylabel('Bump Size')
        #~ self.axes.set_ylim(-3, 8)
        # self.axes.set_zlabel('Price (Rands)')
        # ~ self.axes.set_zlim(-100, 100)

        if self.effectCheck.IsChecked():
            if self.differenceCheck.IsChecked():
                self.axes.set_zlabel('Greek Value')
            else:
                self.axes.set_zlabel('Price (Rands)')
            if hasattr(self, 'title'):
                self.title.set_text('Option Prices and breakdown of the effects of Greeks')
            else:
                self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks')
        else:
            self.axes.set_zlabel('Greek Value')
            if hasattr(self, 'title'):
                self.title.set_text('Raw Greek values not in terms of option price')
            else:
                self.title = self.fig.suptitle('Greek values not in terms of option price')

        self.canvas.draw()
示例#3
0
class PanelGraph(wx.Panel):
    def __init__(self, parent, figure=None):
        wx.Panel.__init__(self, parent, id=-1, style=wx.SUNKEN_BORDER | wx.TAB_TRAVERSAL)
        
        self.figure = figure
        self.figure.set_size_inches(90, 90)
        self.canvas = Canvas(self, -1, figure)
        self.SetColor( (255,255,255) )
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas,1,wx.EXPAND|wx.ALL, 0)
        self.SetSizer(sizer)

    def SetColor(self, rgbtuple=None):
        """Set figure and canvas colours to be the same."""
        if rgbtuple is None:
            rgbtuple = wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ).Get()
        clr = [c/255. for c in rgbtuple]
        self.figure.set_facecolor(clr)
        self.figure.set_edgecolor(clr)
        self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))

    def Save_image(self):
        """ save figure image to file"""
        file_choices = "PNG (*.png)|*.png|" \
                       "PS (*.ps)|*.ps|" \
                       "EPS (*.eps)|*.eps|" \
                       "BMP (*.bmp)|*.bmp"
        
        standardPath = wx.StandardPaths.Get()
        save_destination = standardPath.GetDocumentsDir()

        dlg = wx.FileDialog(self, message=_(u"Enregistrer le graphe sous..."),
                            defaultDir = save_destination, defaultFile="graphe.png",
                            wildcard=file_choices, style=wx.FD_SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path, dpi=300)
            message = _(u"Le graphe a été sauvegardé avec succès")
            dlg = wx.MessageDialog(self, message, _(u"Sauvegarde"), wx.OK | wx.ICON_INFORMATION)
            dlg.ShowModal()
            dlg.Destroy()
                
    def Clipboard_image(self):
        self.canvas.Copy_to_Clipboard()
        message = _(u"Le graphe a été envoyé dans le presse-papiers.")
        dlg = wx.MessageDialog(self, message, _(u"Presse-papiers"), wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def Imprimer_image(self):
        # Enregistrement de l'image dans repertoire Temp
        self.canvas.print_figure(UTILS_Fichiers.GetRepTemp(fichier="grapheTemp.png"), dpi=300)
        # Création du PDF
        from reportlab.pdfgen import canvas as canvasPDF
        from reportlab.lib.pagesizes import A4
        hauteur, largeur = A4
        cheminFichier = UTILS_Fichiers.GetRepTemp(fichier="grapheTemp.pdf")
        if sys.platform.startswith("win") : cheminFichier = cheminFichier.replace("/", "\\")
        c = canvasPDF.Canvas(cheminFichier, pagesize=(largeur, hauteur), pageCompression = 1)
        img = c.drawImage(UTILS_Fichiers.GetRepTemp(fichier="grapheTemp.png"), 0, 0, width=largeur, height=hauteur, preserveAspectRatio=True)
        c.save()
        FonctionsPerso.LanceFichierExterne(cheminFichier)
示例#4
0
class BarChartGraphic(wx.Panel):
    """ This module accepts data, creates a BarChart from it, and places that BarChart in the CLipboard. """
    def __init__(self, parent, pos=(10, 10)):
        """ Initialize a panel for drawing the BarChart.  This panel can be hidden. """
        # Initialize a Panel
        wx.Panel.__init__(self, parent, pos=pos)
        # Create a PyPlot figure
        self.figure = plt.figure(figsize=(7, 9))
        # Create a MatPlotLib FigureCanvas based on the Panel and the Figure
        self.canvas = FigureCanvas(self, -1, self.figure)

    def plot(self, title, data, dataLabels):
        """ Create a BarChart.
               title        Title for the BarChart
               data         List of data values for the BarChart
               dataLabels   Matching list of data labels for the BarChart
            This module limits the BarChart to 15 bars max. """
        # Clear the Figure (in case we use the same BarChartGraphic to create multiple BarCharts)
        self.figure.clf()
        # The length of data is the number of bars we need
        numBars = len(data)
        # Define the colors to be used in the BarChart
        # If we're running stand-alone ...
        if __name__ == '__main__':
            # ... use generic colors
            colors = [
                '#FF0000', '#00FF00', '#0000FF', '#666600', '#FF00FF',
                '#00FFFF', '#440000', '#004400', '#000044'
            ]
            #            colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (0.5, 0.5, 0), (1, 0, 1), (0, 1, 1)]
            # There are no Colors for Keywords when running stand-alone
            colorsForKeywords = {}
        # If we're running inside Transana ...
        else:
            # ... import Transana's Global Values ...
            import TransanaGlobal
            # ... and use Transana's defined color scheme
            colorList = TransanaGlobal.getColorDefs(
                TransanaGlobal.configData.colorConfigFilename)[:-1]
            # Initialize the Colors list
            colors = []
            # Populate the colors list.
            for colorName, colorDef in colorList:
                # MatPlotLib uses a 0 .. 1 scale rather than a 0 .. 255 scale for RGB colors!
                colors.append((colorDef[0] / 255.0, colorDef[1] / 255.0,
                               colorDef[2] / 255.0))
            # Get the color definitions for all keywords in Transana
            colorsForKeywords = DBInterface.dict_of_keyword_colors()

        # If we have more data points that will fit, we should truncate the number of bars
        maxBars = 30
        if numBars > maxBars:
            # Reduce data to the first 15 points
            data = data[:maxBars]
            # Reduce the data labels to the first 15 labels
            dataLabels = dataLabels[:maxBars]
            # Reduce the number of bars to be displayed to maxBars
            numBars = maxBars
        # X values for the bars are simple integers for bar number
        xValues = range(numBars)
        # Set the bar width to allow space between bars
        width = .85

        # Create a MatPlotLib SubPlot
        ax = self.figure.add_subplot(111)
        # Define the BarChart Bars in the figure
        rects1 = ax.bar(xValues, data, width)

        # Add the Chart Title
        ax.set_title(title)
        # If we're running stand-alone ...
        if __name__ == '__main__':
            # Add the Y axis label
            ax.set_ylabel('Frequency')
        else:
            # Add the Y axis label
            ax.set_ylabel(_('Frequency'))
        # Set X axis tick marks for each bar
        ax.set_xticks(xValues)
        # Add the bar labels
        lbls = ax.set_xticklabels(dataLabels, rotation=90)  # 35  65

        # Initialize the color list position indicator
        colorIndx = 0
        # For each bar ...
        for x in range(numBars):
            # If there's a color defined for the Keyword ...
            if dataLabels[x] in colorsForKeywords.keys():
                # ... use that color
                color = colorsForKeywords[dataLabels[x]]['colorDef']
            # If there's no color defined ...
            else:
                # ... use the next color from the color list
                color = colors[colorIndx]
                # Increment or reset the color index
                if colorIndx >= len(colors) - 1:
                    colorIndx = 0
                else:
                    colorIndx += 1
            # ... define the bar color
            rects1[x].set_color(color)
            # ... make the label color match the bar color
            lbls[x].set_color(color)
        # Give the graph small inside margins
        plt.margins(0.05)
        # Adjust the bottom margin to make room for bar labels
        plt.subplots_adjust(bottom=0.5)  # 0.2  0.4
        # Draw the BarChart
        self.canvas.draw()
        # Copy the BarChart to the Clipboard
        self.canvas.Copy_to_Clipboard()
示例#5
0
class t_C_MatPlot(My_Control_Class):
    def __init__(self, *args, **kwargs):
        My_Control_Class.__init__(self, *args, **kwargs)

        # *************************************************************
        # Create the panel with the plot controls
        # *************************************************************
        self.Panel = wx.Panel(self.Dock)
        self.CB_Grid = wx.CheckBox(self.Panel, -1, "Grid", pos=(0, 5))
        self.CP_Grid = wx.ColourPickerCtrl(self.Panel, -1, pos=(40, 1))
        wx.StaticText(self.Panel, -1, "BackGround-", pos=(70, 5))
        self.CP_BG = wx.ColourPickerCtrl(self.Panel, -1, pos=(130, 1))
        self.CB_Axis = wx.CheckBox(self.Panel, -1, "Axis", pos=(160, 5))
        self.CB_Legend = wx.CheckBox(self.Panel, -1, "Legend", pos=(210, 5))
        self.CB_Polar = wx.CheckBox(self.Panel, -1, "Low Res", pos=(275, 5))
        self.CB_FFT = wx.CheckBox(self.Panel, -1, "FFT", pos=(335, 5))

        bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_BUTTON, (16, 16))
        self.Button_ClipBoard = wx.BitmapButton(self.Panel,
                                                -1,
                                                bmp,
                                                pos=(375, 0))
        self.Button_ClipBoard.SetToolTipString('Copy to ClipBoard')

        bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_BUTTON,
                                       (16, 16))
        self.Button_Image = wx.BitmapButton(self.Panel, -1, bmp, pos=(405, 0))
        self.Button_Image.SetToolTipString('Save as PNG-image')

        if self.Test:
            self.Spin = wx.SpinCtrl(self.Panel,
                                    wx.ID_ANY,
                                    min=1,
                                    max=5,
                                    pos=(435, 2),
                                    size=(40, 20))
            self.Spin.SetToolTipString('Select Demo')

        # background color of the not used part of the button bar
        self.Dock.SetBackgroundColour(self.Panel.GetBackgroundColour())
        # *************************************************************

        # *************************************************************
        # *************************************************************
        # These parameters must be set before the figure is created
        # EASIER to set these parameters from rcParams, than from rc,
        # because you can use deep nested properties
        #rc ('figure.subplot', 'left' = 0.5)  ## not accepted
        rcParams['figure.subplot.top'] = 0.95
        rcParams['figure.subplot.bottom'] = 0.05
        rcParams['figure.subplot.left'] = 0.1
        rcParams['figure.subplot.right'] = 0.97

        self.figure = Figure()
        self.Canvas = FigureCanvas(self.Dock, -1, self.figure)
        self.axes = self.figure.add_subplot(111)
        self.axes_2 = None
        self.lx = None
        # *************************************************************

        # *************************************************************
        # Try to reload the settings, otherwise set defaults
        # *************************************************************
        self.Legends = ('signal 1', 'signal 2')
        self.SignalsX = []
        self.SignalsY = []
        self.Pseudo_Color = False
        if self.Test and self.Ini:
            print('piep1')
            self.Ini.Section = 'MatPlot'
            #line = self.Ini.Read ( 'Pars', '' )
            self.Load_Settings(self.Ini)

        if self.Test:
            self.MatPlot_Example(self.Spin.GetValue())
        else:
            self.MatPlot_Redraw()
        # *************************************************************

        # *************************************************************
        # *************************************************************
        Sizer = wx.BoxSizer(wx.VERTICAL)
        Sizer.Add(self.Canvas, 1, wx.EXPAND)
        Sizer.Add(self.Panel, 0)
        self.Dock.SetSizer(Sizer)
        #Dock.Fit()

        # We need this for Ubuntu, and even then it works limited
        self.Dock.Bind(wx.EVT_SIZE, self._OnSize)
        # *************************************************************

        # *************************************************************
        # *************************************************************
        self.Dock.Bind(wx.EVT_COLOURPICKER_CHANGED, self.MatPlot_OnPolar,
                       self.CP_Grid)
        self.Dock.Bind(wx.EVT_COLOURPICKER_CHANGED, self.MatPlot_OnSet_CBs,
                       self.CP_BG)
        self.Dock.Bind(wx.EVT_CHECKBOX, self.MatPlot_OnSet_CBs, self.CB_Grid)
        self.Dock.Bind(wx.EVT_CHECKBOX, self.MatPlot_OnSet_CBs, self.CB_Axis)
        self.Dock.Bind(wx.EVT_CHECKBOX, self.MatPlot_OnSet_CBs, self.CB_Legend)
        self.Dock.Bind(wx.EVT_CHECKBOX, self.MatPlot_OnPolar, self.CB_Polar)
        self.Dock.Bind(wx.EVT_CHECKBOX, self.MatPlot_OnFFT, self.CB_FFT)
        self.Button_Image.Bind(wx.EVT_BUTTON, self.MatPlot_OnSaveImage,
                               self.Button_Image)
        self.Button_ClipBoard.Bind(wx.EVT_BUTTON, self.MatPlot_OnCopyClipBoard,
                                   self.Button_ClipBoard)

        if self.Test:
            self.Spin.Bind(wx.EVT_SPINCTRL, self.MatPlot_OnSpinEvent,
                           self.Spin)
            self.Dock.Bind(wx.EVT_CLOSE, self.MatPlot_OnClose)

        #if not ( self.connect ) :
        self.Dock.connect = self.Canvas.mpl_connect('motion_notify_event',
                                                    self.MatPlot_OnMotion)
        # *************************************************************

    # *************************************************************
    # We need this for Ubuntu, and even then it works limited
    # *************************************************************
    def _OnSize(self, event):
        event.Skip()
        wx.CallAfter(self.MatPlot_Redraw)

    # *************************************************************
    # *************************************************************
    def Calculate(self):
        # input might be one of the following:
        #   1:  <array>
        #   2:  list = [ <array>, [ <signal name>,  <signal color>, <linewidth> ] ]
        #
        # array might be one of the following:
        #   A: a 1-dimensional array  ==>  y(x), x=equidistant
        #   B: a 2-dimensional array, with second dimension = 2  ==>  y = f(x)
        #   C: a 2-dimensional array, with second dimension >> 6  ==> z = f(x,y)

        # we can either use signal, which is the input channel that has changed
        # or use the Bricks input channels, so we can use all of them at once

        self.SignalsX = []
        self.SignalsY = []
        self.Legends = []

        # for test purposes, we don't have a brick but Test_Inputs
        try:
            Inputs = self.Brick.In
        except:
            Inputs = self.Test_Inputs

        for s, IVV in enumerate(Inputs[1:]):
            if IVV != None:
                #print 'MatPlot',s,len(IVV)
                if not ( operator.isSequenceType ( IVV ) ) or \
                   isinstance ( IVV, ndarray ):
                    IVV = eval('[IVV]')
                    #print 'no sequence'

                # determine the number of arrays
                # if exactly 2, special case: x,y pairs
                NA = 0
                for IV in IVV:
                    if isinstance(IV, ndarray):
                        NA += 1
                    else:
                        break

                #print 'NA',NA,IVV[0].shape

                # process all signals
                self.Pseudo_Color = False
                if IVV[0].ndim == 2:
                    self.Pseudo_Color = True
                    self.SignalsX.append(IVV[0])

                elif NA == 1:
                    L = len(IVV[0])
                    self.SignalsX.append(linspace(0, L - 1, L))
                    self.SignalsY.append(IVV[0])

                elif NA == 2:
                    self.SignalsX.append(IVV[0])
                    self.SignalsY.append(IVV[1])

                else:
                    self.SignalsX.append(IVV[0])
                    for i, IV in enumerate(IVV[1:NA]):
                        self.SignalsY.append(IV)

                # add legends
                if NA == 1:
                    if (len(IVV) > NA) and (len(IVV[NA]) > 0):
                        self.Legends.append(IVV[NA][0])
                    else:
                        self.Legends.append('Signal 1')
                for i, IV in enumerate(IVV[1:NA]):
                    if (len(IVV) > NA) and (len(IVV[NA]) > i):
                        self.Legends.append(IVV[NA][i])
                    else:
                        self.Legends.append('Signal ' + str(i + 1))

        #print 'Legends',self.Legends
        self.MatPlot_ReCreate_Plot()
        #print 'MatPlot recreated'

    # *************************************************************
    # *************************************************************
    def MatPlot_ReCreate_Plot(self):
        # BUG, "hold" doesn't work in polar, therefore create a new figure

        # helps sometimes .... for polar plot
        ## LUKT NIET MEER rcParams [ 'grid.color' ] = self.Color_2_MatPlot ( self.CP_Grid.GetColour () )

        self.figure.clear()
        self.lx = None

        if not (self.Pseudo_Color):
            self.CB_Polar.SetLabel('-Polar')

            if self.CB_FFT.GetValue(): config = 212
            else: config = 111
            self.axes = self.figure.add_subplot(config,
                                                polar=self.CB_Polar.GetValue())
            for i, SX in enumerate(self.SignalsY):
                self.axes.plot(
                    self.SignalsX[0],
                    self.SignalsY[i],
                )

            if self.CB_FFT.GetValue():
                self.axes_2 = self.figure.add_subplot(
                    211, polar=self.CB_Polar.GetValue())
                for i, SX in enumerate(self.SignalsY):
                    self.axes_2.psd(
                        self.SignalsY[i],
                        512,
                        1,
                        #detrend = mlab.detrend_linear,  #doesn't work
                        #detrend = mlab.detrend_mean,    #doesn't work
                        detrend=mlab.detrend_none,
                        #window = mlab.window_none )     #weird scaling
                        window=mlab.window_hanning)
                    # doesn't work:
                    # self.axes_2.xlabel = 'aap'
                    # self.axes_2.axis ( 0, 0, 50, -50)
            else:
                self.axes_2 = None

        else:  # Pseudo color
            self.CB_FFT.Hide()
            self.CB_Polar.SetLabel('-Low Res')
            self.axes = self.figure.add_subplot(111)

            if self.CB_Polar.GetValue():
                cmap = cm.get_cmap('jet', 10)  # 10 discrete colors
            else:
                cmap = cm.jet
            #cmap = cm.gray
            # IMPORTANT, setting the size explictly,
            # prevents rescaling which sometimes occurs when crosshair is drawn
            s = self.SignalsX[0].shape
            try:  # SignalsX might not be available yet
                im = self.axes.imshow(self.SignalsX[0],
                                      cmap=cmap,
                                      extent=(0, s[0], 0, s[1]))

                #im.set_interpolation ( 'nearest' )    # and there are a lot more !!
                #im.set_interpolation ( 'bicubic' )
                im.set_interpolation('bilinear')
                self.figure.colorbar(im)
            except:
                pass

        self.axes.hold(True)  # needed for measurement cursor
        if self.axes_2: self.axes_2.hold(True)
        self.MatPlot_Redraw()

    # *************************************************************
    # *************************************************************
    def MatPlot_Redraw(self):
        color = self.CP_BG.GetColour()
        color = self.Color_2_MatPlot(color)
        self.axes.set_axis_bgcolor(color)
        if self.axes_2: self.axes_2.set_axis_bgcolor(color)
        self.figure.set_facecolor(color)
        self.figure.set_edgecolor(color)

        if self.CB_Axis.GetValue():
            self.axes.set_axis_on()
            if self.axes_2: self.axes_2.set_axis_on()
        else:
            self.axes.set_axis_off()
            if self.axes_2: self.axes_2.set_axis_off()

        color = self.CP_Grid.GetColour()
        color = self.Color_2_MatPlot(color)
        self.axes.grid(self.CB_Grid.GetValue())
        if self.axes_2: self.axes_2.grid(self.CB_Grid.GetValue())
        # setting the grid color sometimes generates an exception
        # this seems to happen completely random ????
        try:
            if self.CB_Grid.GetValue():
                self.axes.grid(color=color)
                if self.axes_2: self.axes_2.grid(color=color)
        except:
            pass

        # Polar doesn't support legend (use figlegend)
        if self.Pseudo_Color or not (self.CB_Polar.GetValue()):
            if self.CB_Legend.GetValue():
                self.axes.legend(self.Legends)
            else:
                self.axes.legend_ = None
        # FFT plot: no legend
        if self.axes_2:
            self.axes_2.legend_ = None

        self.Canvas.draw()

    # *************************************************************
    # create an example image
    # *************************************************************
    def MatPlot_Example(self, Example):
        self.Test_Inputs = [None]
        if Example == 1:  # Sine
            x = arange(0.0, 3.0, 0.01)
            y = sin(2 * pi * x)

        elif Example == 2:  # SPIRAL
            t = arange(0, 10 * pi, 0.1)
            x = t * sin(t)
            y = t * cos(t)

        elif Example == 3:  # CARDIOID
            t = arange(0, 2 * pi, 0.1)
            x = (1 + cos(t)) * cos(t)
            y = (1 + cos(t)) * sin(t)

        elif Example == 4:  # SPIROGRAPH
            phi = linspace(0, 4, 100)
            #r=sin(phi*pi) #
            r = sin(cos(tan(phi)))
            x = phi
            y = 20 * r

        elif Example == 5:  # Pseudo Color

            def _func(x, y):
                return (1 - x / 2 + x**5 + y**3) * exp(-x**2 - y**2)

            dx, dy = 0.05, 0.05
            x = arange(-3.0, 3.0, dx)
            y = arange(-3.0, 3.0, dy)
            X, Y = meshgrid(x, y)
            self.Test_Inputs.append(_func(X, Y))

        if len(self.Test_Inputs) == 1:
            temp = []
            temp.append(x)
            temp.append(y)
            self.Test_Inputs.append(temp)

        self.Calculate()

    # *************************************************************
    # *************************************************************
    def MatPlot_OnMotion(self, event):
        if self.CB_Polar.GetValue() and not (self.Pseudo_Color): return

        x, y = event.x, event.y
        # check if within an "axes" but not in a "bar-axes"
        if event.inaxes and isinstance(event.inaxes, matplotlib.axes.Subplot):
            x, y = event.xdata, event.ydata

            if not (self.lx):
                self.minx, self.maxx = event.inaxes.get_xlim()
                self.miny, self.maxy = event.inaxes.get_ylim()
                """
        self.lx, = self.axes.plot ( ( self.minx, self.maxx ), ( y, y ), 'k-' )  # the horiz line
        self.ly, = self.axes.plot ( ( x, x ), ( self.miny, self.maxy ), 'k-' )  # the vert line
        self.meas_txt = self.axes.text ( 0.02, 0.02, 'x=%1.2f, y=%1.2f'% ( x, y ),
                                         transform = self.axes.transAxes )
        """
                self.lx, = event.inaxes.plot((self.minx, self.maxx), (y, y),
                                             'k-')  # the horiz line
                self.ly, = event.inaxes.plot((x, x), (self.miny, self.maxy),
                                             'k-')  # the vert line
                self.meas_txt = event.inaxes.text(
                    0.02,
                    0.02,
                    'x=%1.2f, y=%1.2f' % (x, y),
                    transform=event.inaxes.transAxes)
            else:
                # update the crosshair positions
                self.lx.set_data((self.minx, self.maxx), (y, y))
                self.ly.set_data((x, x), (self.miny, self.maxy))
                self.meas_txt.set_text('x=%1.2f, y=%1.2f' % (x, y))

        else:
            # Hide the cross hair
            if self.lx:
                self.lx.set_data((x, x), (y, y))
                self.ly.set_data((x, x), (y, y))
                self.meas_txt.set_text('')
                self.lx = None

        self.Canvas.draw()

    # *************************************************************
    # *************************************************************
    def MatPlot_OnSet_CBs(self, event):
        self.MatPlot_Redraw()

    # *************************************************************
    # *************************************************************
    def MatPlot_OnPolar(self, event):
        if self.CB_Polar.GetValue(): self.CB_FFT.Hide()
        else: self.CB_FFT.Show()
        self.MatPlot_ReCreate_Plot()

    # *************************************************************
    # *************************************************************
    def MatPlot_OnFFT(self, event):
        if self.CB_FFT.GetValue(): self.CB_Polar.Hide()
        else: self.CB_Polar.Show()
        self.MatPlot_ReCreate_Plot()

    # *************************************************************
    # *************************************************************
    def MatPlot_OnSpinEvent(self, event):
        Example = event.GetInt()
        self.MatPlot_Example(Example)

    # *************************************************************
    # *************************************************************
    def MatPlot_OnCopyClipBoard(self, event):
        #canvas = FigureCanvasWxAgg(...)
        self.Canvas.Copy_to_Clipboard(event=event)

    # *************************************************************
    # *************************************************************
    def MatPlot_OnSaveImage(self, event):
        file = Ask_File_For_Save(os.getcwd(),
                                 FileTypes='*.png',
                                 Title='Save Plot as PNG-image')
        if file:
            self.figure.savefig(file)

    # *************************************************************
    # Set Grid color of all backgrounds
    # Doing this gives huges problems,
    # therefor we accept that in the polar
    # *************************************************************
    """
  def OnGridColor ( self, event ) :
    rcParams [ 'grid.color' ] = self.Color_2_MatPlot ( self.CP_Grid.GetColour () )

    # Because we need to reload the resources,
    # we force it by recreating to the total plot
    self.Sizer.Remove ( self.Canvas )
    self.figure = Figure ()
    self.Canvas = FigureCanvas ( self.Dock, -1, self.figure )
    self.lx = None
    self.Sizer.Prepend ( self.Canvas, 1, wx.EXPAND )
    self.Sizer.Layout ()
    self.MatPlot_Example ( self.Spin.GetValue () )
  """

    # *************************************************************
    # MatPlot accepts RGB colors in relative range 0..1,
    # alpha blend is also not accepted
    # *************************************************************
    def Color_2_MatPlot(self, color):
        # if already in MatPlot format, just return the same value
        if isinstance(color, float) or isinstance(color[0], float):
            return color
        # else limit to 3 elements in the range 0.0 ... 1.0
        kleur = []
        for c in color[:3]:
            kleur.append(c / 255.0)
        return kleur

    # *************************************************************
    # MatPlot accepts RGB colors in relative range 0..1,
    # alpha blend is also not accepted
    # *************************************************************
    def MatPlot_2_Color(self, color):
        # if already in normal format, just return the same value
        if isinstance(color, wx.Color):
            return color

        if isinstance(color, basestring):
            try:
                color = float(color)
            except:
                return color  # named color probably
        if isinstance(color, float):
            i = int(color * 255)
            kleur = [i, i, i]
        else:
            kleur = []
            if isinstance(color[0], float):
                for c in color[:3]:
                    kleur.append(int(255 * c))
            else:
                kleur = color[:3]
        kleur = wx.Color(*kleur)
        return kleur

    # *************************************************************
    # *************************************************************
    def MatPlot_OnClose(self, event):
        if self.Ini and self.Test:
            self.Ini.Section = 'MatPlot'
            self.Ini.Write('Pos', self.Dock.GetPosition())
            self.Ini.Write('Size', self.Dock.GetSize())
            self.Save_Settings(self.Ini)
        event.Skip()

    # *************************************************************
    # *************************************************************
    def Save_Settings(self, ini, key=None):
        if ini:
            line = []
            line.append(tuple(self.CP_BG.GetColour()))
            line.append(tuple(self.CP_Grid.GetColour()))
            line.append(self.CB_Grid.GetValue())
            line.append(self.CB_Axis.GetValue())
            line.append(self.CB_Legend.GetValue())
            line.append(self.CB_Polar.GetValue())
            line.append(self.CB_FFT.GetValue())
            if self.Test:
                line.append(self.Spin.GetValue())
            if not (key):
                key = 'CS_'
            v3print('MatPlot SAVE', key, '=', line)
            line = ini.Write(key, line)

    # *************************************************************
    # *************************************************************
    def Load_Settings(self, ini, key=None):
        #print 'llkwp',line
        if not (key):
            key = 'CS_'
        line = ini.Read(key, '')
        if line:
            self.CP_BG.SetColour(line[0])
            self.CP_Grid.SetColour(line[1])
            self.CB_Grid.SetValue(line[2])
            self.CB_Axis.SetValue(line[3])
            self.CB_Legend.SetValue(line[4])
            self.CB_Polar.SetValue(line[5])
            self.CB_FFT.SetValue(line[6])
            if self.Test:
                self.Spin.SetValue(line[7])
        self.MatPlot_ReCreate_Plot()
示例#6
0
class PlotPanel(wx.Panel):
    ''' Base class for the plotting in GenX - all the basic functionallity
        should be implemented in this class. The plots should be derived from
        this class. These classes should implement an update method to update
        the plots.
    '''
    def __init__(self, parent, id = -1, color = None, dpi = None
            , style = wx.NO_FULL_REPAINT_ON_RESIZE|wx.EXPAND|wx.ALL
            , config = None, config_name = '', **kwargs):

        wx.Panel.__init__(self,parent, id = id, style = style, **kwargs)

        self.parent = parent
        self.callback_window = self
        self.config = config
        self.config_name = config_name
        self.figure = Figure(None,dpi)
        self.canvas = FigureCanvasWxAgg(self, -1, self.figure)
        self.canvas.SetExtraStyle(wx.EXPAND)
        self.SetColor(color)
        self.Bind(wx.EVT_IDLE, self._onIdle)
        self.Bind(wx.EVT_SIZE, self._onSize)
        self._resizeflag = True
        self.print_size = (15./2.54, 12./2.54)
        #self._SetSize()

        # Flags and bindings for zooming
        self.zoom = False
        self.zooming = False
        self.scale = 'linear'
        self.autoscale = True


        self.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnLeftMouseButtonDown)
        self.canvas.Bind(wx.EVT_LEFT_UP, self.OnLeftMouseButtonUp)
        self.canvas.Bind(wx.EVT_MOTION, self.OnMouseMove)
        self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDblClick)
        self.canvas.Bind(wx.EVT_RIGHT_UP, self.OnContextMenu)

        cursor = wx.StockCursor(wx.CURSOR_CROSS)
        self.canvas.SetCursor(cursor)
        self.old_scale_state = True
        self.ax = None

        # Init printout stuff
        self.fig_printer = FigurePrinter(self)

        # Create the drawing bitmap
        self.bitmap =wx.EmptyBitmap(1, 1)
#        DEBUG_MSG("__init__() - bitmap w:%d h:%d" % (w,h), 2, self)
        self._isDrawn = False

    def SetColor(self, rgbtuple=None):
        ''' Set the figure and canvas color to be the same '''
        if not rgbtuple:
            rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
        col = [c/255. for c in rgbtuple]
        self.figure.set_facecolor(col)
        self.figure.set_edgecolor(col)
        self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))

    def _onSize(self, evt):
        self._resizeflag = True
        self._SetSize()
        #self.canvas.draw(repaint = False)

    def _onIdle(self, evt):
        if self._resizeflag:
            self._resizeflag = False
            self._SetSize()
            #self.canvas.gui_repaint(drawDC = wx.PaintDC(self))


    def _SetSize(self, pixels = None):
        ''' This method can be called to force the Plot to be a desired
            size which defaults to the ClientSize of the Panel.
        '''
        if not pixels:
            pixels = self.GetClientSize()

        self.canvas.SetSize(pixels)
        #self.figure.set_size_inches(pixels[0]/self.figure.get_dpi()
        #, pixels[1]/self.figure.get_dpi())

    def ReadConfig(self):
        '''ReadConfig(self) --> None

        Reads in the config file
        '''
        bool_items = ['zoom', 'autoscale']
        bool_func = [self.SetZoom, self.SetAutoScale]

        if not self.config:
            return


        vals = []
        for index in range(len(bool_items)):
            try:
                val = self.config.get_boolean(self.config_name,\
                        bool_items[index])
            except io.OptionError as e:
                print('Could not locate option %s.%s'\
                %(self.config_name, bool_items[index]))
                vals.append(None)
            else:
                vals.append(val)

        try:
            scale = self.config.get(self.config_name, 'y scale')
            string_sucess = True
        except io.OptionError as e:
            string_sucess = False
            print('Could not locate option %s.%s'\
            %(self.config_name, 'scale'))
        else:
            self.SetYScale(scale)

        # This is done due to that the zoom and autoscale has to read
        # before any commands are issued in order not to overwrite
        # the config
        [bool_func[i](vals[i]) for i in range(len(vals)) if vals[i]]


    def WriteConfig(self):
        '''WriteConfig(self) --> None

        Writes the current settings to the config file
        '''
        if self.config:
            self.config.set(self.config_name, 'zoom', self.GetZoom())
            self.config.set(self.config_name, 'autoscale', self.GetAutoScale())
            self.config.set(self.config_name, 'y scale', self.GetYScale())

    def SetZoom(self, active = False):
        '''
        set the zoomstate
        '''
        #if not self.zoom_sel:
            #self.zoom_sel = RectangleSelector(self.ax,\
            # self.box_select_callback, drawtype='box',useblit=False)
        #print help(self.zoom_sel.ignore)

        if active:
            #self.zoom_sel.ignore = lambda x: False
            self.zoom = True
            cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER)
            self.canvas.SetCursor(cursor)
            if self.callback_window:
                evt = state_changed(zoomstate = True,\
                        yscale = self.GetYScale(), autoscale = self.autoscale)
                wx.PostEvent(self.callback_window, evt)
            if self.ax:
                #self.ax.set_autoscale_on(False)
                self.old_scale_state = self.GetAutoScale()
                self.SetAutoScale(False)

        else:
            #self.zoom_sel.ignore = lambda x: True
            self.zoom = False
            cursor = wx.StockCursor(wx.CURSOR_CROSS)
            self.canvas.SetCursor(cursor)
            if self.callback_window:
                evt = state_changed(zoomstate = False,\
                    yscale = self.GetYScale(), autoscale = self.autoscale)
                wx.PostEvent(self.callback_window, evt)
            if self.ax:
                #self.ax.set_autoscale_on(self.autoscale)
                self.SetAutoScale(self.old_scale_state)
        self.WriteConfig()

    def GetZoom(self):
        '''GetZoom(self) --> state [bool]
        Returns the zoom state of the plot panel.
        True = zoom active
        False = zoom inactive
        '''
        return self.zoom

    def SetAutoScale(self, state):
        '''SetAutoScale(self, state) --> None

        Sets autoscale of the main axes wheter or not it should autoscale
        when plotting
        '''
        #self.ax.set_autoscale_on(state)
        self.autoscale = state
        self.WriteConfig()
        evt = state_changed(zoomstate = self.GetZoom(),\
                        yscale = self.GetYScale(), autoscale = self.autoscale)
        wx.PostEvent(self.callback_window, evt)


    def GetAutoScale(self):
        '''GetAutoScale(self) --> state [bool]

        Returns the autoscale state, true if the plots is automatically
        scaled for each plot command.
        '''
        return self.autoscale

    def AutoScale(self, force = False):
        '''AutoScale(self) --> None

        A log safe way to autoscale the plots - the ordinary axis tight
        does not work for negative log data. This works!
        '''
        if not (self.autoscale or force):
            return
        # If nothing is plotted no autoscale use defaults...
        if sum([len(line.get_ydata()) > 0 for line in self.ax.lines]) == 0:
            self.ax.set_xlim(0, 1)
            self.ax.set_ylim(1e-3, 1.0)
            return
        if self.scale == 'log':
            #print 'log scaling'
            # Find the lowest possible value of all the y-values that are
            #greater than zero. check so that y data contain data before min
            # is applied
            tmp = [line.get_ydata().compress(line.get_ydata() > 0.0).min()\
                   for line in self.ax.lines if array(line.get_ydata() > 0.0).sum() > 0]
            if len(tmp) > 0:
                ymin = min(tmp)
            else:
                ymin = 1e-3
            tmp = [line.get_ydata().compress(line.get_ydata() > 0.0).max()\
                   for line in self.ax.lines if array(line.get_ydata() > 0.0).sum() > 0]
            if len(tmp) > 0:
                ymax = max(tmp)
            else:
                ymax = 1
        else:
            ymin = min([array(line.get_ydata()).min()\
                     for line in self.ax.lines if len(line.get_ydata()) > 0])
            ymax = max([array(line.get_ydata()).max()\
                   for line in self.ax.lines if len(line.get_ydata()) > 0])
        tmp = [array(line.get_xdata()).min()\
                    for line in self.ax.lines if len(line.get_ydata()) > 0]
        if len(tmp) > 0:
            xmin = min(tmp)
        else:
            xmin = 0
        tmp = [array(line.get_xdata()).max()\
                    for line in self.ax.lines if len(line.get_ydata()) > 0]
        if len(tmp) > 0:
            xmax = max(tmp)
        else:
            xmax = 1
        # Set the limits
        #print 'Autoscaling to: ', ymin, ymax
        self.ax.set_xlim(xmin, xmax)
        self.ax.set_ylim(ymin*(1-sign(ymin)*0.05), ymax*(1+sign(ymax)*0.05))
        #self.ax.set_yscale(self.scale)
        self.flush_plot()

    def SetYScale(self, scalestring):
        ''' SetYScale(self, scalestring) --> None

        Sets the y-scale of the main plotting axes. Currently accepts
        'log' or 'lin'.
        '''
        if self.ax:
            if scalestring == 'log':
                self.scale = 'log'
                self.AutoScale(force = True)
                try:
                    self.ax.set_yscale('log')
                except OverflowError:
                    self.AutoScale(force = True)
            elif scalestring == 'linear' or scalestring == 'lin':
                self.scale = 'linear'
                self.ax.set_yscale('linear')
                self.AutoScale(force = True)
            else:
                raise ValueError('Not allowed scaling')
            self.flush_plot()
            evt = state_changed(zoomstate = self.GetZoom(),\
                        yscale = self.GetYScale(), autoscale = self.autoscale)
            wx.PostEvent(self.callback_window, evt)
            self.WriteConfig()

    def GetYScale(self):
        '''GetYScale(self) --> String

        Returns the current y-scale in use. Currently the string
        'log' or 'linear'. If the axes does not exist it returns None.
        '''
        if self.ax:
            return self.ax.get_yscale()
        else:
            return None


    def CopyToClipboard(self, event = None):
        '''CopyToClipboard(self, event) --> None

        Copy the plot to the clipboard.
        '''
        self.canvas.Copy_to_Clipboard(event = event)

    def PrintSetup(self, event = None):
        '''PrintSetup(self) --> None

        Sets up the printer. Creates a dialog box
        '''
        self.fig_printer.pageSetup()

    def PrintPreview(self, event = None):
        '''PrintPreview(self) --> None

        Prints a preview on screen.
        '''
        self.fig_printer.previewFigure(self.figure)

    def Print(self, event= None):
        '''Print(self) --> None

        Print the figure.
        '''
        self.fig_printer.printFigure(self.figure)


    def SetCallbackWindow(self, window):
        '''SetCallbackWindow(self, window) --> None

        Sets the callback window that should recieve the events from
        picking.
        '''

        self.callback_window = window

    def OnLeftDblClick(self, event):
        if self.ax and self.zoom:
            tmp = self.GetAutoScale()
            self.SetAutoScale(True)
            self.AutoScale()
            self.SetAutoScale(tmp)
            #self.AutoScale()
            #self.flush_plot()
            #self.ax.set_autoscale_on(False)

    def OnLeftMouseButtonDown(self, event):
        self.start_pos = event.GetPosition()
        #print 'Left Mouse button pressed ', self.ax.transData.inverse_xy_tup(self.start_pos)
        class Point:
            pass
        p = Point()
        p.x, p.y = self.start_pos
        size = self.canvas.GetClientSize()
        p.y = (size.height - p.y)
        if self.zoom and self.ax:
            if mat_ver > zoom_ver:
                in_axes = self.ax.in_axes(p)
            else:
                in_axes = self.ax.in_axes(*self.start_pos)
            if in_axes:
                self.zooming = True
                self.cur_rect = None
                self.canvas.CaptureMouse()
            else:
                self.zooming = False
        elif self.ax:
            size = self.canvas.GetClientSize()
            if mat_ver > zoom_ver:
                xy = self.ax.transData.inverted().transform(\
                    array([self.start_pos[0], size.height-self.start_pos[1]])\
                    [newaxis,:])
                x, y = xy[0,0], xy[0,1]
            else:
                x, y = self.ax.transData.inverse_xy_tup(\
                    (self.start_pos[0], size.height - self.start_pos[1]))
            if self.callback_window:
                evt = plot_position(text = '(%.3e, %.3e)'%(x, y))
                wx.PostEvent(self.callback_window, evt)
            #print x,y


    def OnMouseMove(self, event):
        if self.zooming and event.Dragging() and event.LeftIsDown():
            self.cur_pos = event.GetPosition()
            #print 'Mouse Move ', self.ax.transData.inverse_xy_tup(self.cur_pos)
            class Point:
                pass
            p = Point()
            p.x, p.y = self.cur_pos
            size = self.canvas.GetClientSize()
            p.y = (size.height - p.y)
            if mat_ver > zoom_ver:
                in_axes = self.ax.in_axes(p)
            else:
                in_axes = self.ax.in_axes(*self.start_pos)
            if in_axes:
                new_rect = (min(self.start_pos[0], self.cur_pos[0]),
                            min(self.start_pos[1], self.cur_pos[1]),
                        abs(self.cur_pos[0] - self.start_pos[0]),
                        abs(self.cur_pos[1] - self.start_pos[1]))
                self._DrawAndErase(new_rect, self.cur_rect)
                self.cur_rect = new_rect
        #event.Skip()

    def OnLeftMouseButtonUp(self, event):
        if self.canvas.HasCapture():
            #print 'Left Mouse button up'
            self.canvas.ReleaseMouse()
            if self.zooming and self.cur_rect:
                # Note: The coordinte system for matplotlib have a different
                # direction of the y-axis and a different origin!
                size = self.canvas.GetClientSize()
                if mat_ver > zoom_ver:
                    start = self.ax.transData.inverted().transform(\
                    array([self.start_pos[0], size.height-self.start_pos[1]])[newaxis,:])
                    end = self.ax.transData.inverted().transform(\
                    array([self.cur_pos[0], size.height-self.cur_pos[1]])[newaxis, :])
                    xend, yend = end[0,0], end[0,1]
                    xstart, ystart = start[0,0], start[0,1]
                else:
                    xstart, ystart = self.ax.transData.inverse_xy_tup(\
                        (self.start_pos[0], size.height-self.start_pos[1]))
                    xend, yend = self.ax.transData.inverse_xy_tup(\
                        (self.cur_pos[0], size.height-self.cur_pos[1]))

                #print xstart, xend
                #print ystart, yend
                self.ax.set_xlim(min(xstart,xend), max(xstart,xend))
                self.ax.set_ylim(min(ystart,yend), max(ystart,yend))
                self.flush_plot()
            self.zooming = False

    def _DrawAndErase(self, box_to_draw, box_to_erase = None):
        '''_DrawAndErase(self, box_to_draw, box_to_erase = None) --> None
        '''
        dc = wx.ClientDC(self.canvas)
        # dc.BeginDrawing()
        dc.SetPen(wx.Pen(wx.WHITE, 1, wx.DOT))
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
        dc.SetLogicalFunction(wx.XOR)
        if box_to_erase:
            dc.DrawRectangle(*box_to_erase)
        dc.DrawRectangle(*box_to_draw)
        # dc.EndDrawing()

    def OnContextMenu(self, event):
        '''OnContextMenu(self, event) --> None

        Callback to show the popmenu for the plot which allows various
        settings to be made.
        '''
        menu = wx.Menu()

        zoomID = wx.NewId()
        menu.AppendCheckItem(zoomID, "Zoom")
        menu.Check(zoomID, self.GetZoom())
        def OnZoom(event):
            self.SetZoom(not self.GetZoom())
        self.Bind(wx.EVT_MENU, OnZoom, id = zoomID)

        zoomallID = wx.NewId()
        menu.Append(zoomallID, 'Zoom All')
        def zoomall(event):
            tmp = self.GetAutoScale()
            self.SetAutoScale(True)
            self.AutoScale()
            self.SetAutoScale(tmp)
            #self.flush_plot()
        self.Bind(wx.EVT_MENU, zoomall, id = zoomallID)

        copyID = wx.NewId()
        menu.Append(copyID, "Copy")
        def copy(event):
            self.CopyToClipboard()
        self.Bind(wx.EVT_MENU, copy, id = copyID)

        yscalemenu = wx.Menu()
        logID = wx.NewId()
        linID = wx.NewId()
        yscalemenu.AppendRadioItem(logID, "log")
        yscalemenu.AppendRadioItem(linID, "linear")
        menu.AppendMenu(-1, "y-scale", yscalemenu)
        if self.GetYScale() == 'log':
            yscalemenu.Check(logID, True)
        else:
            yscalemenu.Check(linID, True)

        def yscale_log(event):
            if self.ax:
                self.SetYScale('log')
                self.AutoScale()
                self.flush_plot()
        def yscale_lin(event):
            if self.ax:
                self.SetYScale('lin')
                self.AutoScale()
                self.flush_plot()
        self.Bind(wx.EVT_MENU, yscale_log, id = logID)
        self.Bind(wx.EVT_MENU, yscale_lin, id = linID)

        autoscaleID = wx.NewId()
        menu.AppendCheckItem(autoscaleID, "Autoscale")
        menu.Check(autoscaleID, self.GetAutoScale())
        def OnAutoScale(event):
            self.SetAutoScale(not self.GetAutoScale())
        self.Bind(wx.EVT_MENU, OnAutoScale, id = autoscaleID)

        # Time to show the menu
        self.PopupMenu(menu)

        menu.Destroy()

    def flush_plot(self):
        #self._SetSize()
        #self.canvas.gui_repaint(drawDC = wx.PaintDC(self))
        #self.ax.set_yscale(self.scale)
        self.canvas.draw()

    def update(self, data):
        pass