Esempio n. 1
0
class Analyze(wx.Panel):
     def __init__(self,parent):
         wx.Panel.__init__(self, parent)
         self.figure = Figure()
         self.canv = FigCanvas(self,-1, self.figure)
         self.toolbar = NavigationToolbar(self.canv)
         self.toolbar.Hide()
         
         self.home = wx.lib.buttons.GenBitmapButton(self, -1, wx.Bitmap('icons/home.jpg'))
         self.Bind(wx.EVT_BUTTON, self.Home, self.home)
         
         self.pan = wx.lib.buttons.GenBitmapButton(self, -1, wx.Bitmap('icons/pan.png'))
         self.Bind(wx.EVT_BUTTON, self.Pan, self.pan)
         
         self.zoom = wx.lib.buttons.GenBitmapButton(self, -1, wx.Bitmap('icons/zoom.jpg'))
         self.Bind(wx.EVT_BUTTON, self.Zoom, self.zoom)
         
         self.plot = wx.lib.buttons.GenBitmapButton(self, -1, wx.Bitmap('icons/plot.png'))
         self.Bind(wx.EVT_BUTTON, self.Plot_a, self.plot)
         
         self.process = wx.lib.buttons.GenBitmapButton(self, -1, wx.Bitmap('icons/processing.png'))
         self.Bind(wx.EVT_BUTTON, self.Processing, self.process)
         
         self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
         self.hbox1.Add(self.home, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
         self.hbox1.Add(self.pan, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
         self.hbox1.Add(self.zoom, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
         self.hbox1.Add(self.plot, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
         self.hbox1.Add(self.process, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
         
         self.vbox = wx.BoxSizer(wx.VERTICAL)
         self.vbox.Add(self.canv, 1, flag=wx.LEFT | wx.TOP | wx.GROW)        
         self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_CENTER | wx.TOP)
         self.SetSizer(self.vbox)
         
     def Home(self,e):
         self.toolbar.home()
         
     def Pan(self,e):
         self.toolbar.pan()
     
     def Zoom(self,e):
         self.toolbar.zoom()
     
     def Plot_a(self,e):
         data = [np.random.random() for i in range(25)]
         
         ax = self.figure.add_subplot(111)
         ax.hold(False)
         ax.plot(data, '*-')
         self.canv.draw()
     
     def Processing(self,e):
         print "run process"
Esempio n. 2
0
File: ui.py Progetto: sm-g/genetic
class PlotPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.figure = plt.figure()

        self.canvas = FigureCanvas(self, -1, self.figure)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()

    def plot(self):
        data = [random() for _ in range(25)]
        ax = self.figure.add_subplot(111, projection='3d')
        ax.hold(False)
        ax.plot(data, data, data, '*-')
        self.canvas.draw()
Esempio n. 3
0
class p1(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.figure = plt.figure()

        self.canvas = FigureCanvas(self, -1, self.figure)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()

    def plot(self):
        ''' plot some random stuff '''
        data = [random.random() for i in range(25)]
        ax = self.figure.add_subplot(111)
        #ax.hold(False)
        ax.plot(data, '*-')
        self.canvas.draw()
Esempio n. 4
0
class MainWindow(wx.Frame):

    # Constructor
    def __init__(self):
        wx.Frame.__init__(self, parent = None, title = "PyStrEmbed-1")
        self.SetBackgroundColour('white')



        ### MENU BAR
        menuBar  = wx.MenuBar()

        fileMenu = wx.Menu()
        menuBar.Append(fileMenu, "&File")
        fileOpen = fileMenu.Append(wx.ID_OPEN, "&Open", "Open file")
        fileSave = fileMenu.Append(wx.ID_SAVE, "&Save", "Save file")
        fileSaveAs = fileMenu.Append(wx.ID_SAVEAS, "&Save as", "Save file as")
        fileClose = fileMenu.Append(wx.ID_CLOSE, "&Close", "Close file")
        fileExit = fileMenu.Append(wx.ID_EXIT, "&Exit", "Exit program")

        partMenu = wx.Menu()
        menuBar.Append(partMenu, "&Parts")

        geomMenu = wx.Menu()
        menuBar.Append(geomMenu, "&Geometry")

        lattMenu = wx.Menu()
        menuBar.Append(lattMenu, "&Lattice")

        abtMenu   = wx.Menu()
        menuBar.Append(abtMenu,  "&About")
        menuAbout = abtMenu.Append(wx.ID_ABOUT,"&About", "About PyStrEmbed-1")

        self.SetMenuBar(menuBar)



        # Bindings for menu items
        self.Bind(wx.EVT_MENU, self.OnFileOpen,      fileOpen)
        self.Bind(wx.EVT_MENU, self.DoNothingDialog, fileSave)
        self.Bind(wx.EVT_MENU, self.DoNothingDialog, fileSaveAs)
        self.Bind(wx.EVT_MENU, self.OnExit,  fileClose)
        self.Bind(wx.EVT_MENU, self.OnExit,  fileExit)
        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)



        ### TOOLBAR
        # Main window toolbar with assembly operations
        self.tb = wx.ToolBar(self, style = wx.TB_NODIVIDER | wx.TB_FLAT)
        self.SetToolBar(self.tb)
        self.tb.SetToolBitmapSize((40,40))
        self.tb.SetBackgroundColour('white')
        # File tools
        self.fileOpenTool  = self.tb.AddTool(wx.ID_ANY, 'Open',  wx.Bitmap("Images/fileopen.bmp"),  bmpDisabled = wx.NullBitmap,
                                   shortHelp = 'File open',  longHelp = 'File open')
        self.exitTool      = self.tb.AddTool(wx.ID_ANY, 'Exit', wx.Bitmap("Images/fileclose.bmp"), bmpDisabled = wx.NullBitmap,
                                   shortHelp = 'Exit', longHelp = 'Exit')
        self.tb.AddSeparator()
        # Assembly tools
        self.insertLeftTool   = self.tb.AddTool(wx.ID_ANY, 'Insert node to left', wx.Bitmap("Images/insertleft1.bmp"), bmpDisabled = wx.NullBitmap,
                                 shortHelp = 'Insert left', longHelp = 'Insert left')
        self.insertRightTool  = self.tb.AddTool(wx.ID_ANY, 'Insert node to right', wx.Bitmap("Images/insertright1.bmp"), bmpDisabled = wx.NullBitmap,
                                 shortHelp = 'Insert right', longHelp = 'Insert right')
        self.adoptTool        = self.tb.AddTool(wx.ID_ANY, 'Adopt node', wx.Bitmap("Images/adopt1.bmp"), bmpDisabled = wx.NullBitmap,
                                 shortHelp = 'Adopt',  longHelp = 'Adopt')
        self.aggregateTool    = self.tb.AddTool(wx.ID_ANY, 'Aggregate nodes', wx.Bitmap("Images/aggregate1.bmp"), bmpDisabled = wx.NullBitmap,
                                 shortHelp = 'Aggregate',   longHelp = 'Aggregate')
        self.disaggregateTool = self.tb.AddTool(wx.ID_ANY, 'Disaggregate nodes', wx.Bitmap("Images/disaggregate1.bmp"), bmpDisabled = wx.NullBitmap,
                                 shortHelp = 'Disaggregate', longHelp = 'Disaggregate')
        self.tb.Realize()



        # Bind toolbar tools to actions
        self.Bind(wx.EVT_TOOL, self.OnFileOpen, self.fileOpenTool)
        self.Bind(wx.EVT_TOOL, self.OnExit,     self.exitTool)

        self.Bind(wx.EVT_TOOL, self.DoNothingDialog, self.insertLeftTool)
        self.Bind(wx.EVT_TOOL, self.DoNothingDialog, self.insertRightTool)
        self.Bind(wx.EVT_TOOL, self.DoNothingDialog, self.adoptTool)
        self.Bind(wx.EVT_TOOL, self.DoNothingDialog, self.aggregateTool)
        self.Bind(wx.EVT_TOOL, self.DoNothingDialog, self.disaggregateTool)



        ### STATUS BAR
        # Status bar
        self.statbar = self.CreateStatusBar()
        self.statbar.SetBackgroundColour('white')
        # Update status bar with window size on (a) first showing and (b) resizing
        self.Bind(wx.EVT_SIZE, self.OnResize, self)



        # Create main panel
        self.InitMainPanel()



    def InitMainPanel(self):

        ### MAIN PANEL
        #
        # Create main panel to contain everything
        self.panel = wx.Panel(self)
        self.box   = wx.BoxSizer(wx.VERTICAL)

        # Create FlexGridSizer to have 3 panes
        # 2nd and 3rd arguments are hgap and vgap b/t panes (cosmetic)
        self.grid = wx.FlexGridSizer(cols = 3, rows = 2, hgap = 10, vgap = 10)

        self.part_header = wx.StaticText(self.panel, label = "Parts view")
        self.geom_header = wx.StaticText(self.panel, label = "Geometry view")
        self.latt_header = wx.StaticText(self.panel, label = "Lattice view")

        self.panel_style = wx.SIMPLE_BORDER
        self.part_panel = wx.Panel(self.panel, style = self.panel_style)
        self.geom_panel = wx.Panel(self.panel, style = self.panel_style)
        self.latt_panel = wx.Panel(self.panel, style = self.panel_style)

        self.part_sizer = wx.BoxSizer(wx.VERTICAL)
        self.latt_sizer = wx.BoxSizer(wx.VERTICAL)
        
        # Some special setup for geometry sizer (grid)
        self.image_cols = 2
        self.geom_sizer = wx.GridSizer(cols = self.image_cols, rows = 0, hgap = 5, vgap = 5)
        # Defines tightness of images in grid (i.e. produces blank border)
        self.geom_tight = 0.7


        # PARTS VIEW SETUP
        # Custom tree ctrl implementation
        self.treeStyle = (ctc.TR_MULTIPLE | ctc.TR_EDIT_LABELS | ctc.TR_HAS_BUTTONS)
        self.partTree_ctc = ctc.CustomTreeCtrl(self.part_panel, agwStyle = self.treeStyle)
        self.partTree_ctc.SetBackgroundColour('white')
        self.part_sizer.Add(self.partTree_ctc, 1, wx.EXPAND)



        # GEOMETRY VIEW SETUP
        # Set up image-view grid, where "rows = 0" means the sizer updates dynamically
        # according to the number of elements it holds
#        self.geom_sizer.Add(self.image_grid, 1, wx.EXPAND)

        # Binding for toggling of part/assembly images
        # though toggle buttons not yet realised
        self.Bind(wx.EVT_TOGGLEBUTTON, self.ImageToggled)
        
        self.no_image_ass  = 'Images/noimage_ass.png'
        self.no_image_part = 'Images/noimage_part.png'



        # LATTICE VIEW SETUP
        # Set up matplotlib FigureCanvas with toolbar for zooming and movement
        self.latt_figure = mpl.figure.Figure()
        self.latt_canvas = FigureCanvas(self.latt_panel, -1, self.latt_figure)
        self.latt_axes   = self.latt_figure.add_subplot(111)
        self.latt_canvas.Hide()

        # Realize but hide, to be shown later when file loaded/data updated
        self.latt_tb = NavigationToolbar(self.latt_canvas)
#        self.latt_tb.Realize()
        self.latt_tb.Hide()

        self.latt_sizer.Add(self.latt_canvas, 1, wx.EXPAND | wx.ALIGN_BOTTOM | wx.ALL, border = 5)
        self.latt_sizer.Add(self.latt_tb, 0, wx.EXPAND)

        self.selected_colour = 'blue'
        


        # OVERALL SIZERS SETUP
        self.part_panel.SetSizer(self.part_sizer)
        self.geom_panel.SetSizer(self.geom_sizer)
        self.latt_panel.SetSizer(self.latt_sizer)

        self.grid.AddMany([(self.part_header), (self.geom_header), (self.latt_header),
                           (self.part_panel, 1, wx.EXPAND), (self.geom_panel, 1, wx.EXPAND), (self.latt_panel, 1, wx.EXPAND)])

        # Set all grid elements to "growable" upon resizing
        # Flags (second argument is proportional size)
        self.grid.AddGrowableRow(1,0)
        self.grid.AddGrowableCol(0,3)
        self.grid.AddGrowableCol(1,2)
        self.grid.AddGrowableCol(2,3)

        # Set sizer for/update main panel
        self.box.Add(self.grid, 1, wx.ALL | wx.EXPAND, 5)
        self.panel.SetSizer(self.box)



    def GetFilename(self, dialog_text = "Open file", starter = None, ender = None):

        ### General file-open method; takes list of file extensions as argument
        ### and can be used for specific file names ("starter", string)
        ### or types ("ender", string or list)

        # Convert "ender" to list if only one element
        if isinstance(ender, str):
            ender = [ender]

        # Check that only one kwarg is present
        # Create text for file dialog
        if starter is not None and ender is None:
            file_open_text = starter.upper() + " files (" + starter.lower() + "*)|" + starter.lower() + "*"
        elif starter is None and ender is not None:
            file_open_text = [el.upper() + " files (*." + el.lower() + ")|*." + el.lower() for el in ender]
            file_open_text = "|".join(file_open_text)
        else:
            raise ValueError("Requires starter or ender only")

        # Create file dialog
        fileDialog = wx.FileDialog(self, dialog_text, "", "",
                                   file_open_text,
                                   wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        fileDialog.ShowModal()
        filename = fileDialog.GetPath()
        fileDialog.Destroy()

        # Return file name, ignoring rest of path
        return filename



    def DisplayPartsList(self):

        # Create root node...
        root_id  = self.assembly.tree.root
        root_tag = self.assembly.tree.get_node(root_id).tag

        # Exception handler if file loaded previously
        try:
            self.partTree_ctc.DeleteAllItems()
        except:
            pass
        ctc_root_item = self.partTree_ctc.AddRoot(text = root_tag, ct_type = 1)
        self.ctc_dict[root_id] = ctc_root_item
        self.ctc_dict_inv[ctc_root_item] = root_id

        # ...then all others
        # Assumes treelib ordering ensures parents are defined before children
        for el in self.assembly.tree_dict:
            if el != root_id:
                parent_id = self.assembly.tree.parent(el).identifier
                ctc_parent = self.ctc_dict[parent_id]
                ctc_text = self.assembly.part_dict[self.assembly.tree_dict[el]]
                ctc_item = self.partTree_ctc.AppendItem(ctc_parent, text = ctc_text, ct_type = 1)
                self.ctc_dict[el] = ctc_item
                self.ctc_dict_inv[ctc_item] = el
        
        # Binding for checking of list items
        self.Bind(ctc.EVT_TREE_ITEM_CHECKED, self.TreeItemChecked)
        self.Bind(ctc.EVT_TREE_SEL_CHANGED,  self.TreeItemSelected)

        self.partTree_ctc.ExpandAll()
        


    def TreeItemChecked(self, event):
        
        def ScaleImage(img):
            # Resize image to geometry panel
            # NEEDS IMPROVEMENT TO BE MORE GENERAL (IN TERMS OF ASPECT RATIO)
            p_w, p_h   = self.geom_panel.GetSize()
            h          = img.GetHeight()
            w          = img.GetWidth()
            
            w_new = p_w*self.geom_tight/self.image_cols
            h_new = w_new*h/w
            img = img.Scale(w_new, h_new)

            return img
        
        
        
        # Get checked item and search for corresponding image
        #
        item = event.GetItem()
        id_  = self.ctc_dict_inv[item]
        
        self.selected_items = self.partTree_ctc.GetSelections()

        if item.IsChecked():
            # Get image
            if id_ in self.assembly.leaf_ids:
                img = self.assembly.tree_dict[id_]
                img = os.path.join('Images', img + '.png')
                if os.path.isfile(img):
                    img = wx.Image(img, wx.BITMAP_TYPE_ANY)
                else:
                    img = wx.Image(self.no_image_part, wx.BITMAP_TYPE_ANY)
            else:
                img = wx.Image(self.no_image_ass, wx.BITMAP_TYPE_ANY)
                
            # Create/add button in geom_panel
            # 
            # Includes rescaling to panel
            img = ScaleImage(img)
            button = wx.BitmapToggleButton(self.geom_panel, id_, wx.Bitmap(img))
            button.SetBackgroundColour('white')
            self.geom_sizer.Add(button, 0, wx.EXPAND)
            
            # Update global list and dict
            #
            # Data is list, i.e. same format as "selected_items"
            # but ctc lacks "get selections" method for checked items
            self.checked_items.append(item)
            self.button_dict[id_] = button
            self.button_dict_inv[button] = id_
            
            # Toggle if already selected elsewhere
            if self.ctc_dict[id_] in self.selected_items:
                button.SetValue(True)
            else:
                pass
            
        else:
            # Remove button from geom_panel
            obj = self.button_dict[id_]
            obj.Destroy()
            
            # Update global list and dict
            self.checked_items.remove(item)
            self.button_dict.pop(id_)
            self.button_dict_inv.pop(obj)
           
        # Update image sizer
        self.geom_sizer.Layout()
            


    def TreeItemSelected(self, event):
        
        # Get selected item and update global list of items
        #
        # Using GetSelection rather than maintaining list of items
        # as with checked items b/c releasing ctrl key during multiple
        # selection means not all selections are tracked easily
        self.selected_items = self.partTree_ctc.GetSelections()
        
        self.UpdateToggledImages()
        self.UpdateLatticeSelections()



    def ImageToggled(self, event):
        
        id_ = event.GetId()
        self.UpdateListSelections(id_)
        
        self.UpdateLatticeSelections()

        

    def UpdateListSelections(self, id_):
        
        # Select/deselect parts list item
        item = self.ctc_dict[id_]
        if item in self.selected_items:
            self.selected_items.remove(item)
        else:
            self.selected_items.append(item)
        
        # With "select = True", SelectItem toggles state if multiple selections enabled
        self.partTree_ctc.SelectItem(self.ctc_dict[id_], select = True)



    def UpdateLatticeSelections(self):
        
        # Update colour of selected items
        #
        # Set all back to default colour first
        for node in self.assembly.g.nodes():
            self.assembly.g.nodes[node]['colour'] = self.assembly.default_colour
        # Then selected nodes
        for item in self.selected_items:
            id_ = self.ctc_dict_inv[item]
            self.assembly.g.nodes[id_]['colour'] = self.selected_colour
        
        # Redraw lattice
        self.DisplayLattice()


    
    def UpdateToggledImages(self):
        
        for id_, button in self.button_dict.items():
            button.SetValue(False)
        
        for item in self.selected_items:
            id_    = self.ctc_dict_inv[item]
            if id_ in self.button_dict:
                button = self.button_dict[id_]
                button.SetValue(True)
            else:
                pass
        


    def DisplayLattice(self):

        # Get node positions, colour map, labels
        pos         = nx.get_node_attributes(self.assembly.g, 'pos')
        colour_map  = [self.assembly.g.nodes[el]['colour'] for el in self.assembly.g.nodes]
#        node_labels = nx.get_node_attributes(self.assembly.g, 'label')
        
        # Draw to lattice panel figure
        try:
            self.latt_axes.clear()
        except:
            pass
        nx.draw(self.assembly.g, pos, node_color = colour_map, with_labels = True, ax = self.latt_axes)
#        nx.draw_networkx_labels(self.assembly.g, pos, labels = node_labels, ax = self.latt_axes)

        # Minimise white space around plot in panel
        self.latt_figure.subplots_adjust(left = 0.01, bottom = 0.01, right = 0.99, top = 0.99)

        # Show lattice figure
        self.latt_canvas.draw()
        self.latt_canvas.Show()
        self.latt_tb.Show()

        # Update lattice panel layout
        self.latt_panel.Layout()



    def DoNothingDialog(self, event):

        nowt = wx.MessageDialog(self, "Functionality to be added", "Do nothing dialog", wx.OK)
        # Create modal dialogue that stops process
        nowt.ShowModal()
        nowt.Destroy()



    def OnFileOpen(self, event):

#        # Delete if exists from previous file load
#        # TO BE COMPLETED FOR VERSION 1-2
#        try:
#            del self.assembly
#        except AttributeError:
#            pass
        
        # Get STEP filename
        self.open_filename = self.GetFilename(ender = ["stp", "step"]).split("\\")[-1]

        # Load data, create nodes and edges, etc.
        self.assembly = StepParse()
        self.assembly.load_step(self.open_filename)
        self.assembly.create_tree()

        # Checked and selected items lists, shared b/t all views
        self.checked_items  = []
        self.selected_items = []

        # Toggle buttons
        self.button_dict     = {}
        self.button_dict_inv = {}
        
        # Write interactive parts list using WX customtreectrl, from treelib nodes
        self.ctc_dict     = {}
        self.ctc_dict_inv = {}



        # Show parts list and lattice
        self.DisplayPartsList()
        
        # Clear geometry window if necessary
        try:
            self.geom_sizer.Clear(True)
        except:
            pass    
        
        # Clear lattice plot if necessary
        try:
            self.latt_axes.clear()
        except:
            pass
        
        # Display lattice
        self.DisplayLattice()



    def OnInsertLeft(self, event):
        pass



    def OnInsertRight(self, event):
        pass



    def OnAdopt(self, event):

        pass



    def OnAggregate(self, event):

        pass



    def OnDisaggregate(self, event):

        pass



    def OnAbout(self, event):

        # Show program info
        abt_text = """StrEmbed-5-1: A user interface for manipulation of design configurations\n
            Copyright (C) 2019 Hugh Patrick Rice\n
            This program is free software: you can redistribute it and/or modify
            it under the terms of the GNU General Public License as published by
            the Free Software Foundation, either version 3 of the License, or
            (at your option) any later version.\n
            This program is distributed in the hope that it will be useful,
            but WITHOUT ANY WARRANTY; without even the implied warranty of
            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
            GNU General Public License for more details.\n
            You should have received a copy of the GNU General Public License
            along with this program. If not, see <https://www.gnu.org/licenses/>."""
 
        abt = wx.MessageDialog(self, abt_text, 'About StrEmbed-5-1', wx.OK)
        abt.ShowModal()         # Shows dialogue that stops process (modal)
        abt.Destroy()



    def OnExit(self, event):

        self.Close(True)        # Close program



    def OnResize(self, event):

        # Display window size in status bar
        self.statbar.SetStatusText("Window size = " + format(self.GetSize()))
        event.Skip()
Esempio n. 5
0
class PlotView:
    def __init__(self, panel):

        self.figure = plt.figure()
        self.axes = self.figure.add_subplot(111)

        self.axes.grid()

        self.axes.margins(0)
        self.canvas = FigureCanvas(panel, -1, self.figure)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()

    def add_padding_to_plot(self,
                            left=None,
                            bottom=None,
                            right=None,
                            top=None,
                            wspace=None,
                            hspace=None):
        """
        Adjust the location of the plot. Parameters must be floats
        :param left:
        :param bottom:
        :param right:
        :param top:
        :param wspace:
        :param hspace:
        :return:
        """
        # self.figure.tight_layout() is also another possible way to do this
        self.figure.subplots_adjust(left=left,
                                    bottom=bottom,
                                    right=right,
                                    top=top,
                                    wspace=wspace,
                                    hspace=hspace)

    def display_legend(self, location='upper right'):
        """
        Taken from http://matplotlib.org/api/figure_api.html
        'best'         : 0,
        'upper right'  : 1,
        'upper left'   : 2,
        'lower left'   : 3,
        'lower right'  : 4,
        'right'        : 5,
        'center left'  : 6,
        'center right' : 7,
        'lower center' : 8,
        'upper center' : 9,
        'center'       : 10,
        """
        self.axes.legend(loc=location)
        self.redraw()

    def redraw(self):
        """
        Call after adding all desired features to the graph
        :return:
        """
        self.canvas.draw()

    def rotate_x_axis_label(self, angle=45):
        """
        Rotates the x-axis labels
        Must be called before redrawing to have effect
        :param angle: angle of rotation
        :return:
        """
        for label in self.axes.xaxis.get_ticklabels():
            label.set_rotation(angle)

    def set_axis_label(self, x="", y=""):
        self.axes.set_xlabel(x)
        self.axes.set_ylabel(y)

    def set_legend(self, labels, location=0):
        """
        :param labels: type([string])
        :param location: type(int)
        :return:
        """
        self.axes.legend(labels, loc=location)

    def set_title(self, title):
        self.axes.set_title(str(title))

    def set_x_axis_label_font_size(self, font_size=10):
        """
        Must be called before redrawing to have effect
        :param font_size:
        :return:
        """
        for label in self.axes.xaxis.get_ticklabels():
            label.set_fontsize(font_size)
Esempio n. 6
0
class SRMWindow(wx.Frame):

    #########################Init Funcions#############################

    def __init__(self,
                 spreading_rate_path,
                 parent=None,
                 starting_sz="",
                 fontsize=8,
                 dpi=200):
        """Constructor"""
        #call init of super class
        default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP
        wx.Frame.__init__(self,
                          parent,
                          title="Spreading Rate Model %s" % parent.__version__,
                          style=default_style,
                          size=(400 * 2, 300 * 2))
        self.Bind(wx.EVT_CLOSE, self.on_close_main)

        self.parent = parent
        self.dpi = dpi
        self.spreading_rate_path = spreading_rate_path

        self.panel = wx.Panel(self, -1, size=(400 * 2, 300 * 2))

        #Populate UI and Menu
        self.init_UI()
        self.create_menu()

        self.sz = starting_sz
        try:
            self.open_srm()
        except:
            self.srm = None

        self.update()

    def init_UI(self):
        spacing = 10

        #---------------------------------Make ListCtrl for SR---------------------------------------------------#

        self.logger = EditableListCtrl(self.panel,
                                       ID=wx.ID_ANY,
                                       size=(300, 300),
                                       style=wx.LC_REPORT)
        self.logger.InsertColumn(0, 'End Age', width=150)
        self.logger.InsertColumn(1, 'Half Rate', width=150)
        #        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_click_listctrl, self.logger)
        #        self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK,self.on_right_click_listctrl,self.logger)
        #        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_select_measurement, self.logger)

        #-----------------------------Make DropDown Box and Update-----------------------------------------------#

        sz_sizer = wx.StaticBoxSizer(
            wx.StaticBox(self.panel, wx.ID_ANY, "Choose Spreading Zone"),
            wx.VERTICAL)

        self.sz_box = wx.ComboBox(self.panel,
                                  id=wx.ID_ANY,
                                  size=(150, 25),
                                  choices=[],
                                  style=wx.CB_DROPDOWN | wx.TE_PROCESS_ENTER)
        self.Bind(wx.EVT_COMBOBOX, self.on_select_sz, self.sz_box)
        self.Bind(wx.EVT_TEXT_ENTER, self.on_enter_sz, self.sz_box)

        add_rate_sizer = wx.StaticBoxSizer(
            wx.StaticBox(self.panel, wx.ID_ANY, "Add Rate to Model"),
            wx.HORIZONTAL)
        self.add_end_age_box = wx.TextCtrl(self.panel,
                                           id=wx.ID_ANY,
                                           size=(50, 25))
        self.add_half_rate_box = wx.TextCtrl(self.panel,
                                             id=wx.ID_ANY,
                                             size=(50, 25))
        self.add_rate_btn = wx.Button(self.panel,
                                      id=wx.ID_ANY,
                                      label='Add Rate',
                                      size=(50, 25))
        self.Bind(wx.EVT_BUTTON, self.on_add_rate_btn, self.add_rate_btn)
        add_rate_sizer.AddMany([
            (self.add_end_age_box, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL
             | wx.LEFT | wx.BOTTOM | wx.EXPAND, spacing),
            (self.add_half_rate_box, 1, wx.ALIGN_LEFT
             | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.BOTTOM | wx.EXPAND,
             spacing),
            (self.add_rate_btn, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL
             | wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, spacing),
        ])

        update_delete_sizer = wx.BoxSizer(wx.HORIZONTAL)
        delete_btn = wx.Button(self.panel,
                               id=wx.ID_ANY,
                               label='Delete Selected',
                               size=(75, 25))
        self.Bind(wx.EVT_BUTTON, self.on_delete_btn, delete_btn)

        update_button = wx.Button(self.panel,
                                  id=wx.ID_ANY,
                                  label='Save and Update',
                                  size=(75, 25))
        self.Bind(wx.EVT_BUTTON, self.on_update_button, update_button)
        update_delete_sizer.AddMany([
            (update_button, 1,
             wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.EXPAND,
             spacing),
            (delete_btn, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT
             | wx.RIGHT | wx.EXPAND, spacing)
        ])

        sz_sizer.AddMany([
            (self.sz_box, 2, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL
             | wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, spacing),
            (add_rate_sizer, 3, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL
             | wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, spacing),
            (update_delete_sizer, 2, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL
             | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM | wx.EXPAND, spacing)
        ])

        #-------------------------------------Make Figure----------------------------------------------------------#

        self.fig = Figure((2, 2), dpi=self.dpi)
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.toolbar = NavigationToolbar(self.canvas)
        self.ax = self.fig.add_subplot(111)
        psk.remove_axis_lines_and_ticks(self.ax)
        self.toolbar.Hide()
        self.plot_setting = "Zoom"
        self.toolbar.zoom()
        self.canvas.Bind(wx.EVT_MIDDLE_DOWN, self.on_middle_click_plot)

        #----------------------------------Build UI and Fit--------------------------------------------------------#

        side_bar_sizer = wx.BoxSizer(wx.VERTICAL)
        side_bar_sizer.AddMany([
            (sz_sizer, 1, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.LEFT | wx.RIGHT
             | wx.BOTTOM | wx.TOP | wx.EXPAND, spacing),
            (self.canvas, 8, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.LEFT | wx.RIGHT
             | wx.BOTTOM | wx.EXPAND, spacing)
        ])

        outer_sizer = wx.BoxSizer(wx.HORIZONTAL)
        outer_sizer.AddMany([
            (self.logger, 1, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.EXPAND),
            (side_bar_sizer, 3, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.EXPAND)
        ])

        self.panel.SetSizerAndFit(outer_sizer)

    def create_menu(self):
        """
        Generates Menu
        """

        self.menubar = wx.MenuBar()

        #-----------------
        # File Menu
        #-----------------

        menu_file = wx.Menu()

        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "&Exit\tCtrl-Q", "Exit")
        self.Bind(wx.EVT_MENU, self.on_close_main, m_exit)

        #-----------------

        self.menubar.Append(menu_file, "&File")
        self.SetMenuBar(self.menubar)

    #########################Update UI Funcions#############################

    def update_self_and_parent(self):
        utl.write_sr_model_file(self.srm, self.spreading_rate_path)
        try:
            srf, _ = sk.generate_spreading_rate_model(self.spreading_rate_path)
            self.parent.sr_box.SetValue(
                "%.1f" % (srf(self.parent.dsk_row["sz_name"],
                              (self.parent.dsk_row["age_min"] +
                               self.parent.dsk_row["age_max"]) / 2)))
        except (AttributeError, KeyError) as e:
            pass

        self.update()
        self.parent.update_synth = True
        self.parent.update(-1)

    def update(self):  #Populates Logger and makes plot

        if self.parent.spreading_rate_path != self.spreading_rate_path:
            self.spreading_rate_path = self.parent.spreading_rate_path
            self.open_srm()

        if self.spreading_rate_path == None: return

        self.logger.DeleteAllItems()
        points = [[], []]
        if self.sz in self.srm.keys():
            prev_age = 0
            for i, (end_age, half_rate) in enumerate(self.srm[self.sz]):
                self.logger.InsertItem(i, "%.3f" % end_age)
                self.logger.SetItem(i, 1, "%.3f" % half_rate)

                if end_age > 1e3: end_age = prev_age + 10
                if i == 0 and end_age > 10: prev_age = end_age - 10
                if prev_age == 0 and end_age <= 0: prev_age = end_age - 10
                points[0].append(prev_age)
                points[0].append(end_age)
                points[1].append(half_rate)
                points[1].append(half_rate)
                prev_age = end_age

        self.ax.clear()

        self.ax.plot(points[0], points[1], 'k-')

        self.canvas.draw()

    def on_close_main(self, event):
        self.parent.srmw_open = False
        self.Destroy()

    ###################Button and Dropdown Functions#########################

    def on_select_sz(self, event):
        self.sz = self.sz_box.GetValue()
        self.update()

    def on_enter_sz(self, event):
        sz_tmp = self.sz_box.GetValue()
        if sz_tmp in sz_box.GetItems():
            self.sz = sz_tmp
        else:
            if self.srm != None and self.parent.user_warning(
                    "Spreading Zone provided not in spreading rate model would you like to add to model?"
            ):
                self.sz = sz_tmp
                self.srm[self.sz] = [1e10, 40]
            else:
                self.sz_box.SetValue("")
                self.sz = None
        self.update()

    def on_update_button(
            self, event):  #Saves the edits and calls update on self and parent

        new_sz_srm = []
        for i in range(self.logger.GetItemCount()):
            try:
                new_sz_srm.append([
                    float(self.logger.GetItemText(i, 0)),
                    float(self.logger.GetItemText(i, 1))
                ])
            except ValueError:
                self.parent.user_warning(
                    "Half Rate and Age to add must be numbers got %s,%s instead"
                    % (self.logger.GetItemText(
                        i, 0), self.logger.GetItemText(i, 1)))
                return
        self.srm[self.sz] = new_sz_srm

        self.update_self_and_parent()

    def on_add_rate_btn(self, event):

        try:
            new_end_age, new_half_rate = float(
                self.add_end_age_box.GetValue()), float(
                    self.add_half_rate_box.GetValue())
        except ValueError:
            self.parent.user_warning(
                "Half Rate and Age to add must be numbers got %s,%s instead" %
                (str(new_end_age), str(new_half_rate)))
            return

        try:
            if new_end_age in np.array(self.srm[self.sz])[:, 0]:
                self.srm[self.sz] = [
                    [new_end_age, new_half_rate] if self.srm[self.sz][i][0]
                    == new_end_age else self.srm[self.sz][i]
                    for i in range(len(self.srm[self.sz]))
                ]
            else:
                self.srm[self.sz] += [[new_end_age, new_half_rate]]
            self.srm[self.sz].sort(key=cmp_to_key(lambda x, y: x[0] - y[0]))
        except (KeyError, IndexError) as e:
            self.srm[self.sz] = [[new_end_age, new_half_rate]]

        self.update_self_and_parent()

    def on_delete_btn(self, event):

        next_i, del_idxs = self.logger.GetNextSelected(-1), []
        if next_i == -1: return
        while next_i != -1:
            del_idxs.append(next_i)
            next_i = self.logger.GetNextSelected(next_i)

        new_sz_srm = []
        for i in range(self.logger.GetItemCount()):
            if i in del_idxs: continue  #Skip deleted data
            try:
                new_sz_srm.append([
                    float(self.logger.GetItemText(i, 0)),
                    float(self.logger.GetItemText(i, 1))
                ])
            except ValueError:
                self.parent.user_warning(
                    "Half Rate and Age to add must be numbers got %s,%s instead"
                    % (self.logger.GetItemText(
                        i, 0), self.logger.GetItemText(i, 1)))
                return

        self.srm[self.sz] = new_sz_srm

        self.update_self_and_parent()

    ###########################Figure Funcions###############################

    def on_middle_click_plot(self, event):
        if event.LeftIsDown() or event.ButtonDClick():
            event.Skip()
            return
        elif self.plot_setting == "Zoom":
            self.plot_setting = "Pan"
            self.toolbar.pan('off')
        elif self.plot_setting == "Pan":
            self.plot_setting = "Zoom"
            self.toolbar.zoom()
        event.Skip()

    ###########################Utility Funcions###############################

    def open_srm(self):
        self.srm = utl.open_sr_model_file(self.spreading_rate_path)
        self.sz_box.SetItems([""] + sorted(list(self.srm.keys())))
        self.sz_box.SetValue(self.sz)
Esempio n. 7
0
class InterpretationEditorFrame(wx.Frame):

    #########################Init Funcions#############################

    def __init__(self,parent):
        """Constructor"""
        #set parent and resolution
        self.parent = parent
        self.GUI_RESOLUTION=self.parent.GUI_RESOLUTION
        #call init of super class
        default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP
        wx.Frame.__init__(self, self.parent, title="Interpretation Editor version:%s"%CURRENT_VERSION,style=default_style, size=(675*self.GUI_RESOLUTION,425*self.GUI_RESOLUTION))
        self.Bind(wx.EVT_CLOSE, self.on_close_edit_window)
        #setup wx help provider class to give help messages
        provider = wx.SimpleHelpProvider()
        wx.HelpProvider.Set(provider)
        self.helper = wx.ContextHelp(doNow=False)
        #make the Panel
        self.panel = wx.Panel(self,-1,size=(700*self.GUI_RESOLUTION,450*self.GUI_RESOLUTION))
        #set icon
        self.SetIcon(self.parent.icon)
#        icon = wx.Icon()
#        icon_path = os.path.join(IMG_DIRECTORY, 'PmagPy.ico')
#        if os.path.exists(icon_path):
#            icon.CopyFromBitmap(wx.Bitmap(icon_path), wx.BITMAP_TYPE_ANY)
#            self.SetIcon(icon)
        self.specimens_list=self.parent.specimens
        self.current_fit_index = None
        self.search_query = ""
        self.font_type = self.parent.font_type
        #build UI and menu
        self.init_UI()
        self.create_menu()
        #update with stuff
        self.on_select_level_name(None)

    def init_UI(self):
        """
        Builds User Interface for the interpretation Editor
        """

        #set fonts
        FONT_WEIGHT=1
        if sys.platform.startswith('win'): FONT_WEIGHT=-1
        font1 = wx.Font(9+FONT_WEIGHT, wx.SWISS, wx.NORMAL, wx.NORMAL, False, self.font_type)
        font2 = wx.Font(12+FONT_WEIGHT, wx.SWISS, wx.NORMAL, wx.NORMAL, False, self.font_type)

        #if you're on mac do some funny stuff to make it look okay
        is_mac = False
        if sys.platform.startswith("darwin"):
            is_mac = True

        self.search_bar = wx.SearchCtrl(self.panel, size=(350*self.GUI_RESOLUTION,25) ,style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB | wx.TE_NOHIDESEL)
        self.Bind(wx.EVT_TEXT_ENTER, self.on_enter_search_bar,self.search_bar)
        self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.on_enter_search_bar,self.search_bar)
        self.search_bar.SetHelpText(dieh.search_help)
#        self.Bind(wx.EVT_TEXT, self.on_complete_search_bar,self.search_bar)

        #build logger
        self.logger = wx.ListCtrl(self.panel, -1, size=(100*self.GUI_RESOLUTION,475*self.GUI_RESOLUTION),style=wx.LC_REPORT)
        self.logger.SetFont(font1)
        self.logger.InsertColumn(0, 'specimen',width=75*self.GUI_RESOLUTION)
        self.logger.InsertColumn(1, 'fit name',width=65*self.GUI_RESOLUTION)
        self.logger.InsertColumn(2, 'max',width=55*self.GUI_RESOLUTION)
        self.logger.InsertColumn(3, 'min',width=55*self.GUI_RESOLUTION)
        self.logger.InsertColumn(4, 'n',width=25*self.GUI_RESOLUTION)
        self.logger.InsertColumn(5, 'fit type',width=60*self.GUI_RESOLUTION)
        self.logger.InsertColumn(6, 'dec',width=45*self.GUI_RESOLUTION)
        self.logger.InsertColumn(7, 'inc',width=45*self.GUI_RESOLUTION)
        self.logger.InsertColumn(8, 'mad',width=45*self.GUI_RESOLUTION)
        self.logger.InsertColumn(9, 'dang',width=45*self.GUI_RESOLUTION)
        self.logger.InsertColumn(10, 'a95',width=45*self.GUI_RESOLUTION)
        self.logger.InsertColumn(11, 'K',width=45*self.GUI_RESOLUTION)
        self.logger.InsertColumn(12, 'R',width=45*self.GUI_RESOLUTION)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnClick_listctrl, self.logger)
        self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK,self.OnRightClickListctrl,self.logger)
        self.logger.SetHelpText(dieh.logger_help)

        #set fit attributes boxsizers
        self.display_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "display options"), wx.HORIZONTAL)
        self.name_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "fit name/color"), wx.VERTICAL)
        self.bounds_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "fit bounds"), wx.VERTICAL)
        self.buttons_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY), wx.VERTICAL)

        #logger display selection box
        UPPER_LEVEL = self.parent.level_box.GetValue()
        if UPPER_LEVEL=='sample':
            name_choices = self.parent.samples
        if UPPER_LEVEL=='site':
            name_choices = self.parent.sites
        if UPPER_LEVEL=='location':
            name_choices = self.parent.locations
        if UPPER_LEVEL=='study':
            name_choices = ['this study']

        self.level_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=UPPER_LEVEL, choices=['sample','site','location','study'], style=wx.CB_DROPDOWN|wx.TE_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.on_select_high_level,self.level_box)
        self.level_box.SetHelpText(dieh.level_box_help)

        self.level_names = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=self.parent.level_names.GetValue(), choices=name_choices, style=wx.CB_DROPDOWN|wx.TE_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.on_select_level_name,self.level_names)
        self.level_names.SetHelpText(dieh.level_names_help)

        #mean type and plot display boxes
        self.mean_type_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=self.parent.mean_type_box.GetValue(), choices=['Fisher','Fisher by polarity','None'], style=wx.CB_DROPDOWN|wx.TE_READONLY, name="high_type")
        self.Bind(wx.EVT_COMBOBOX, self.on_select_mean_type_box,self.mean_type_box)
        self.mean_type_box.SetHelpText(dieh.mean_type_help)

        self.mean_fit_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=self.parent.mean_fit, choices=(['None','All'] + self.parent.fit_list), style=wx.CB_DROPDOWN|wx.TE_READONLY, name="high_type")
        self.Bind(wx.EVT_COMBOBOX, self.on_select_mean_fit_box,self.mean_fit_box)
        self.mean_fit_box.SetHelpText(dieh.mean_fit_help)

        #show box
        if UPPER_LEVEL == "study" or UPPER_LEVEL == "location":
            show_box_choices = ['specimens','samples','sites']
        if UPPER_LEVEL == "site":
            show_box_choices = ['specimens','samples']
        if UPPER_LEVEL == "sample":
            show_box_choices = ['specimens']

        self.show_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value='specimens', choices=show_box_choices, style=wx.CB_DROPDOWN|wx.TE_READONLY,name="high_elements")
        self.Bind(wx.EVT_COMBOBOX, self.on_select_show_box,self.show_box)
        self.show_box.SetHelpText(dieh.show_help)

        #coordinates box
        self.coordinates_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), choices=self.parent.coordinate_list, value=self.parent.coordinates_box.GetValue(), style=wx.CB_DROPDOWN|wx.TE_READONLY, name="coordinates")
        self.Bind(wx.EVT_COMBOBOX, self.on_select_coordinates,self.coordinates_box)
        self.coordinates_box.SetHelpText(dieh.coordinates_box_help)

        #bounds select boxes
        self.tmin_box = wx.ComboBox(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), choices=[''] + self.parent.T_list, style=wx.CB_DROPDOWN|wx.TE_READONLY, name="lower bound")
        self.tmin_box.SetHelpText(dieh.tmin_box_help)

        self.tmax_box = wx.ComboBox(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), choices=[''] + self.parent.T_list, style=wx.CB_DROPDOWN|wx.TE_READONLY, name="upper bound")
        self.tmax_box.SetHelpText(dieh.tmax_box_help)

        #color box
        self.color_dict = self.parent.color_dict
        self.color_box = wx.ComboBox(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), choices=[''] + sorted(self.color_dict.keys()), style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER, name="color")
        self.Bind(wx.EVT_TEXT_ENTER, self.add_new_color, self.color_box)
        self.color_box.SetHelpText(dieh.color_box_help)

        #name box
        self.name_box = wx.TextCtrl(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), name="name")
        self.name_box.SetHelpText(dieh.name_box_help)

        #more mac stuff
        h_size_buttons,button_spacing = 25,5.5
        if is_mac: h_size_buttons,button_spacing = 18,0.

        #buttons
        self.add_all_button = wx.Button(self.panel, id=-1, label='add new fit to all specimens',size=(160*self.GUI_RESOLUTION,h_size_buttons))
        self.add_all_button.SetFont(font1)
        self.Bind(wx.EVT_BUTTON, self.add_fit_to_all, self.add_all_button)
        self.add_all_button.SetHelpText(dieh.add_all_help)

        self.add_fit_button = wx.Button(self.panel, id=-1, label='add fit to highlighted specimens',size=(160*self.GUI_RESOLUTION,h_size_buttons))
        self.add_fit_button.SetFont(font1)
        self.Bind(wx.EVT_BUTTON, self.add_highlighted_fits, self.add_fit_button)
        self.add_fit_button.SetHelpText(dieh.add_fit_btn_help)

        self.delete_fit_button = wx.Button(self.panel, id=-1, label='delete highlighted fits',size=(160*self.GUI_RESOLUTION,h_size_buttons))
        self.delete_fit_button.SetFont(font1)
        self.Bind(wx.EVT_BUTTON, self.delete_highlighted_fits, self.delete_fit_button)
        self.delete_fit_button.SetHelpText(dieh.delete_fit_btn_help)

        self.apply_changes_button = wx.Button(self.panel, id=-1, label='apply changes to highlighted fits',size=(160*self.GUI_RESOLUTION,h_size_buttons))
        self.apply_changes_button.SetFont(font1)
        self.Bind(wx.EVT_BUTTON, self.apply_changes, self.apply_changes_button)
        self.apply_changes_button.SetHelpText(dieh.apply_changes_help)

        #windows
        display_window_0 = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION)
        display_window_1 = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION)
        display_window_2 = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION)
        name_window = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION)
        bounds_window = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION)
        buttons1_window = wx.GridSizer(4, 1, 5*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION)
        display_window_0.AddMany( [(self.coordinates_box, wx.ALIGN_LEFT),
                                   (self.show_box, wx.ALIGN_LEFT)] )
        display_window_1.AddMany( [(self.level_box, wx.ALIGN_LEFT),
                                   (self.level_names, wx.ALIGN_LEFT)] )
        display_window_2.AddMany( [(self.mean_type_box, wx.ALIGN_LEFT),
                                   (self.mean_fit_box, wx.ALIGN_LEFT)] )
        name_window.AddMany( [(self.name_box, wx.ALIGN_LEFT),
                                (self.color_box, wx.ALIGN_LEFT)] )
        bounds_window.AddMany( [(self.tmin_box, wx.ALIGN_LEFT),
                                (self.tmax_box, wx.ALIGN_LEFT)] )
        buttons1_window.AddMany( [(self.add_fit_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0),
                                  (self.add_all_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0),
                                  (self.delete_fit_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0),
                                  (self.apply_changes_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0)])
        self.display_sizer.Add(display_window_0, 1, wx.TOP|wx.EXPAND, 8)
        self.display_sizer.Add(display_window_1, 1, wx.TOP | wx.LEFT|wx.EXPAND, 8)
        self.display_sizer.Add(display_window_2, 1, wx.TOP | wx.LEFT|wx.EXPAND, 8)
        self.name_sizer.Add(name_window, 1, wx.TOP, 5.5)
        self.bounds_sizer.Add(bounds_window, 1, wx.TOP, 5.5)
        self.buttons_sizer.Add(buttons1_window, 1, wx.TOP, 0)

        #duplicate high levels plot
        self.fig = Figure((2.5*self.GUI_RESOLUTION, 2.5*self.GUI_RESOLUTION), dpi=100)
        self.canvas = FigCanvas(self.panel, -1, self.fig, )
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()
        self.toolbar.zoom()
        self.high_EA_setting = "Zoom"
        self.canvas.Bind(wx.EVT_LEFT_DCLICK,self.on_equalarea_high_select)
        self.canvas.Bind(wx.EVT_MOTION,self.on_change_high_mouse_cursor)
        self.canvas.Bind(wx.EVT_MIDDLE_DOWN,self.home_high_equalarea)
        self.canvas.Bind(wx.EVT_RIGHT_DOWN,self.pan_zoom_high_equalarea)
        self.canvas.SetHelpText(dieh.eqarea_help)

        self.eqarea = self.fig.add_subplot(111)
        draw_net(self.eqarea)

        #Higher Level Statistics Box
        self.stats_sizer = wx.StaticBoxSizer( wx.StaticBox( self.panel, wx.ID_ANY,"mean statistics"  ), wx.VERTICAL)

        for parameter in ['mean_type','dec','inc','alpha95','K','R','n_lines','n_planes']:
            COMMAND="self.%s_window=wx.TextCtrl(self.panel,style=wx.TE_CENTER|wx.TE_READONLY,size=(100*self.GUI_RESOLUTION,25))"%parameter
            exec(COMMAND)
            COMMAND="self.%s_window.SetBackgroundColour(wx.WHITE)"%parameter
            exec(COMMAND)
            COMMAND="self.%s_window.SetFont(font2)"%parameter
            exec(COMMAND)
            COMMAND="self.%s_outer_window = wx.GridSizer(1,2,5*self.GUI_RESOLUTION,15*self.GUI_RESOLUTION)"%parameter
            exec(COMMAND)
            COMMAND="""self.%s_outer_window.AddMany([
                    (wx.StaticText(self.panel,label='%s',style=wx.TE_CENTER),wx.EXPAND),
                    (self.%s_window, wx.EXPAND)])"""%(parameter,parameter,parameter)
            exec(COMMAND)
            COMMAND="self.stats_sizer.Add(self.%s_outer_window, 1, wx.ALIGN_LEFT|wx.EXPAND, 0)"%parameter
            exec(COMMAND)

        self.switch_stats_button = wx.SpinButton(self.panel, id=wx.ID_ANY, style=wx.SP_HORIZONTAL|wx.SP_ARROW_KEYS|wx.SP_WRAP, name="change stats")
        self.Bind(wx.EVT_SPIN, self.on_select_stats_button,self.switch_stats_button)
        self.switch_stats_button.SetHelpText(dieh.switch_stats_btn_help)

        #construct panel
        hbox0 = wx.BoxSizer(wx.HORIZONTAL)
        hbox0.Add(self.name_sizer,flag=wx.ALIGN_TOP|wx.EXPAND,border=8)
        hbox0.Add(self.bounds_sizer,flag=wx.ALIGN_TOP|wx.EXPAND,border=8)

        vbox0 = wx.BoxSizer(wx.VERTICAL)
        vbox0.Add(hbox0,flag=wx.ALIGN_TOP,border=8)
        vbox0.Add(self.buttons_sizer,flag=wx.ALIGN_TOP,border=8)

        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        hbox1.Add(vbox0,flag=wx.ALIGN_TOP,border=8)
        hbox1.Add(self.stats_sizer,flag=wx.ALIGN_TOP,border=8)
        hbox1.Add(self.switch_stats_button,flag=wx.ALIGN_TOP|wx.EXPAND,border=8)

        vbox1 = wx.BoxSizer(wx.VERTICAL)
        vbox1.Add(self.display_sizer,flag=wx.ALIGN_TOP,border=8)
        vbox1.Add(hbox1,flag=wx.ALIGN_TOP,border=8)
        vbox1.Add(self.canvas,proportion=1,flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,border=8)

        vbox2 = wx.BoxSizer(wx.VERTICAL)
        vbox2.Add(self.search_bar,proportion=.5,flag=wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.EXPAND, border=8)
        vbox2.Add(self.logger,proportion=1,flag=wx.ALIGN_LEFT|wx.EXPAND,border=8)

        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        hbox2.Add(vbox2,proportion=1,flag=wx.ALIGN_LEFT|wx.EXPAND)
        hbox2.Add(vbox1,flag=wx.ALIGN_TOP|wx.EXPAND)

        self.panel.SetSizerAndFit(hbox2)
        hbox2.Fit(self)

    def create_menu(self):

        menubar = wx.MenuBar()

        #--------------------------------------------------------------------

        menu_file = wx.Menu()

        m_change_WD = menu_file.Append(-1, "Change Working Directory\tCtrl-W","")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_change_working_directory, m_change_WD)

        m_make_MagIC_results_tables = menu_file.Append(-1, "&Save MagIC pmag tables\tCtrl-Shift-S", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_make_MagIC_results_tables, m_make_MagIC_results_tables)

        submenu_save_plots = wx.Menu()

        m_save_high_level = submenu_save_plots.Append(-1, "&Save high level plot", "")
        self.Bind(wx.EVT_MENU, self.parent.on_save_high_level, m_save_high_level,"Eq")

        m_new_sub_plots = menu_file.AppendSubMenu(submenu_save_plots, "&Save plot")

        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "E&xit\tCtrl-Q", "Exit")
        self.Bind(wx.EVT_MENU, self.on_close_edit_window, m_exit)

        #--------------------------------------------------------------------

        menu_Analysis = wx.Menu()

        submenu_criteria = wx.Menu()

        m_change_criteria_file = submenu_criteria.Append(-1, "&Change acceptance criteria", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_change_criteria, m_change_criteria_file)

        m_import_criteria_file =  submenu_criteria.Append(-1, "&Import criteria file", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_criteria_file, m_import_criteria_file)

        m_new_sub = menu_Analysis.AppendSubMenu(submenu_criteria, "Acceptance criteria")

        m_import_LSQ = menu_Analysis.Append(-1, "&Import Interpretations from LSQ file\tCtrl-L", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_read_from_LSQ, m_import_LSQ)

        m_previous_interpretation = menu_Analysis.Append(-1, "&Import previous interpretations from a redo file\tCtrl-R", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_previous_interpretation, m_previous_interpretation)

        m_save_interpretation = menu_Analysis.Append(-1, "&Save current interpretations to a redo file\tCtrl-S", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_save_interpretation, m_save_interpretation)

        #--------------------------------------------------------------------

        menu_Tools = wx.Menu()

        m_view_VGP = menu_Tools.Append(-1, "&View VGPs\tCtrl-Shift-V", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_view_vgps, m_view_VGP)

        #--------------------------------------------------------------------

        menu_Help = wx.Menu()

        m_help = menu_Help.Append(-1, "&Usage and Tips\tCtrl-H", "")
        self.Bind(wx.EVT_MENU, self.on_menu_help, m_help)

        m_cookbook = menu_Help.Append(-1, "&PmagPy Cookbook\tCtrl-Shift-W", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_cookbook, m_cookbook)

        m_docs = menu_Help.Append(-1, "&Open Docs\tCtrl-Shift-H", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_docs, m_docs)

        m_git = menu_Help.Append(-1, "&Github Page\tCtrl-Shift-G", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_git, m_git)

        m_debug = menu_Help.Append(-1, "&Open Debugger\tCtrl-Shift-D", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_debug, m_debug)

        #--------------------------------------------------------------------

        menu_edit = wx.Menu()

        m_new = menu_edit.Append(-1, "&New interpretation\tCtrl-N", "")
        self.Bind(wx.EVT_MENU, self.parent.on_btn_add_fit, m_new)

        m_delete = menu_edit.Append(-1, "&Delete interpretation\tCtrl-D", "")
        self.Bind(wx.EVT_MENU, self.parent.on_btn_delete_fit, m_delete)

        m_next_interp = menu_edit.Append(-1, "&Next interpretation\tCtrl-Up", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_next_interp, m_next_interp)

        m_previous_interp = menu_edit.Append(-1, "&Previous interpretation\tCtrl-Down", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_prev_interp, m_previous_interp)

        m_next_specimen = menu_edit.Append(-1, "&Next Specimen\tCtrl-Right", "")
        self.Bind(wx.EVT_MENU, self.parent.on_next_button, m_next_specimen)

        m_previous_specimen = menu_edit.Append(-1, "&Previous Specimen\tCtrl-Left", "")
        self.Bind(wx.EVT_MENU, self.parent.on_prev_button, m_previous_specimen)

        menu_coordinates = wx.Menu()

        m_speci = menu_coordinates.Append(-1, "&Specimen Coordinates\tCtrl-P", "")
        self.Bind(wx.EVT_MENU, self.parent.on_menu_change_speci_coord, m_speci)
        if "geographic" in self.parent.coordinate_list:
            m_geo = menu_coordinates.Append(-1, "&Geographic Coordinates\tCtrl-G", "")
            self.Bind(wx.EVT_MENU, self.parent.on_menu_change_geo_coord, m_geo)
        if "tilt-corrected" in self.parent.coordinate_list:
            m_tilt = menu_coordinates.Append(-1, "&Tilt-Corrected Coordinates\tCtrl-T", "")
            self.Bind(wx.EVT_MENU, self.parent.on_menu_change_tilt_coord, m_tilt)

        m_coords = menu_edit.AppendSubMenu(menu_coordinates, "&Coordinate Systems")

        #--------------------------------------------------------------------

        #self.menubar.Append(menu_preferences, "& Preferences")
        menubar.Append(menu_file, "&File")
        menubar.Append(menu_edit, "&Edit")
        menubar.Append(menu_Analysis, "&Analysis")
        menubar.Append(menu_Tools, "&Tools")
        menubar.Append(menu_Help, "&Help")
        self.SetMenuBar(menubar)

    ################################Logger Functions##################################

    def update_editor(self):
        """
        updates the logger and plot on the interpretation editor window
        """

        self.fit_list = []
        self.search_choices = []
        for specimen in self.specimens_list:
            if specimen not in self.parent.pmag_results_data['specimens']: continue
            self.fit_list += [(fit,specimen) for fit in self.parent.pmag_results_data['specimens'][specimen]]

        self.logger.DeleteAllItems()
        offset = 0
        for i in range(len(self.fit_list)):
            i -= offset
            v = self.update_logger_entry(i)
            if v == "s": offset += 1

    def update_logger_entry(self,i):
        """
        helper function that given a index in this objects fit_list parameter inserts a entry at that index
        @param: i -> index in fit_list to find the (specimen_name,fit object) tup that determines all the data for this logger entry.
        """
        if i < len(self.fit_list):
            tup = self.fit_list[i]
        elif i < self.logger.GetItemCount():
            self.logger.DeleteItem(i)
            return
        else: return

        coordinate_system = self.parent.COORDINATE_SYSTEM
        fit = tup[0]
        pars = fit.get(coordinate_system)
        fmin,fmax,n,ftype,dec,inc,mad,dang,a95,sk,sr2 = "","","","","","","","","","",""

        specimen = tup[1]
        if coordinate_system=='geographic':
            block_key = 'zijdblock_geo'
        elif coordinate_system=='tilt-corrected':
            block_key = 'zijdblock_tilt'
        else:
            block_key = 'zijdblock'

        name = fit.name
        if pars == {} and self.parent.Data[specimen][block_key] != []:
            fit.put(specimen, coordinate_system, self.parent.get_PCA_parameters(specimen,fit,fit.tmin,fit.tmax,coordinate_system,fit.PCA_type))
            pars = fit.get(coordinate_system)
        if self.parent.Data[specimen][block_key]==[]:
            spars = fit.get('specimen')
            fmin = fit.tmin
            fmax = fit.tmax
            if 'specimen_n' in list(spars.keys()): n = str(spars['specimen_n'])
            else: n = 'No Data'
            if 'calculation_type' in list(spars.keys()): ftype = spars['calculation_type']
            else: ftype = 'No Data'
            dec = 'No Data'
            inc = 'No Data'
            mad = 'No Data'
            dang = 'No Data'
            a95 = 'No Data'
            sk = 'No Data'
            sr2 = 'No Data'
        else:
            if 'measurement_step_min' in list(pars.keys()): fmin = str(fit.tmin)
            else: fmin = "N/A"
            if 'measurement_step_max' in list(pars.keys()): fmax = str(fit.tmax)
            else: fmax = "N/A"
            if 'specimen_n' in list(pars.keys()): n = str(pars['specimen_n'])
            else: n = "N/A"
            if 'calculation_type' in list(pars.keys()): ftype = pars['calculation_type']
            else: ftype = "N/A"
            if 'specimen_dec' in list(pars.keys()): dec = "%.1f"%pars['specimen_dec']
            else: dec = "N/A"
            if 'specimen_inc' in list(pars.keys()): inc = "%.1f"%pars['specimen_inc']
            else: inc = "N/A"
            if 'specimen_mad' in list(pars.keys()): mad = "%.1f"%pars['specimen_mad']
            else: mad = "N/A"
            if 'specimen_dang' in list(pars.keys()): dang = "%.1f"%pars['specimen_dang']
            else: dang = "N/A"
            if 'specimen_alpha95' in list(pars.keys()): a95 = "%.1f"%pars['specimen_alpha95']
            else: a95 = "N/A"
            if 'specimen_k' in list(pars.keys()): sk = "%.1f"%pars['specimen_k']
            else: sk = "N/A"
            if 'specimen_r' in list(pars.keys()): sr2 = "%.1f"%pars['specimen_r']
            else: sr2 = "N/A"

        if self.search_query != "":
            entry = (specimen+name+fmin+fmax+n+ftype+dec+inc+mad+dang+a95+sk+sr2).replace(" ","").lower()
            if self.search_query not in entry:
                self.fit_list.pop(i)
                if i < self.logger.GetItemCount():
                    self.logger.DeleteItem(i)
                return "s"
        for e in (specimen,name,fmin,fmax,n,ftype,dec,inc,mad,dang,a95,sk,sr2):
            if e not in self.search_choices:
                self.search_choices.append(e)

        if i < self.logger.GetItemCount():
            self.logger.DeleteItem(i)
        self.logger.InsertItem(i, str(specimen))
        self.logger.SetItem(i, 1, name)
        self.logger.SetItem(i, 2, fmin)
        self.logger.SetItem(i, 3, fmax)
        self.logger.SetItem(i, 4, n)
        self.logger.SetItem(i, 5, ftype)
        self.logger.SetItem(i, 6, dec)
        self.logger.SetItem(i, 7, inc)
        self.logger.SetItem(i, 8, mad)
        self.logger.SetItem(i, 9, dang)
        self.logger.SetItem(i, 10, a95)
        self.logger.SetItem(i, 11, sk)
        self.logger.SetItem(i, 12, sr2)
        self.logger.SetItemBackgroundColour(i,"WHITE")
        a,b = False,False
        if fit in self.parent.bad_fits:
            self.logger.SetItemBackgroundColour(i,"red")
            b = True
        if self.parent.current_fit == fit:
            self.logger.SetItemBackgroundColour(i,"LIGHT BLUE")
            self.logger_focus(i)
            self.current_fit_index = i
            a = True
        if a and b:
            self.logger.SetItemBackgroundColour(i,"red")

    def update_current_fit_data(self):
        """
        updates the current_fit of the parent Zeq_GUI entry in the case of it's data being changed
        """
        if self.current_fit_index:
            self.update_logger_entry(self.current_fit_index)

    def change_selected(self,new_fit):
        """
        updates passed in fit or index as current fit for the editor (does not affect parent),
        if no parameters are passed in it sets first fit as current
        @param: new_fit -> fit object to highlight as selected
        """
        if len(self.fit_list)==0: return
        if self.search_query and self.parent.current_fit not in [x[0] for x in self.fit_list]: return
        if self.current_fit_index == None:
            if not self.parent.current_fit: return
            for i,(fit,specimen) in enumerate(self.fit_list):
                if fit == self.parent.current_fit:
                    self.current_fit_index = i
                    break
        i = 0
        if isinstance(new_fit, Fit):
            for i, (fit,speci) in enumerate(self.fit_list):
                if fit == new_fit:
                    break
        elif type(new_fit) is int:
            i = new_fit
        elif new_fit != None:
            print(('cannot select fit of type: ' + str(type(new_fit))))
        if self.current_fit_index != None and \
        len(self.fit_list) > 0 and \
        self.fit_list[self.current_fit_index][0] in self.parent.bad_fits:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"")
        else:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"WHITE")
        self.current_fit_index = i
        if self.fit_list[self.current_fit_index][0] in self.parent.bad_fits:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"red")
        else:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"LIGHT BLUE")

    def logger_focus(self,i,focus_shift=16):
        """
        focuses the logger on an index 12 entries below i
        @param: i -> index to focus on
        """
        if self.logger.GetItemCount()-1 > i+focus_shift:
            i += focus_shift
        else:
            i = self.logger.GetItemCount()-1
        self.logger.Focus(i)

    def OnClick_listctrl(self, event):
        """
        Edits the logger and the Zeq_GUI parent object to select the fit that was newly selected by a double click
        @param: event -> wx.ListCtrlEvent that triggered this function
        """
        i = event.GetIndex()
        if self.parent.current_fit == self.fit_list[i][0]: return
        self.parent.initialize_CART_rot(self.fit_list[i][1])
        si = self.parent.specimens.index(self.fit_list[i][1])
        self.parent.specimens_box.SetSelection(si)
        self.parent.select_specimen(self.fit_list[i][1])
        self.change_selected(i)
        fi = 0
        while (self.parent.s == self.fit_list[i][1] and i >= 0): i,fi = (i-1,fi+1)
        self.parent.update_fit_box()
        self.parent.fit_box.SetSelection(fi-1)
        self.parent.update_selection()

    def OnRightClickListctrl(self, event):
        """
        Edits the logger and the Zeq_GUI parent object so that the selected interpretation is now marked as bad
        @param: event -> wx.ListCtrlEvent that triggered this function
        """
        i = event.GetIndex()
        fit,spec = self.fit_list[i][0],self.fit_list[i][1]
        if fit in self.parent.bad_fits:
            if not self.parent.mark_fit_good(fit,spec=spec): return
            if i == self.current_fit_index:
                self.logger.SetItemBackgroundColour(i,"LIGHT BLUE")
            else:
                self.logger.SetItemBackgroundColour(i,"WHITE")
        else:
            if not self.parent.mark_fit_bad(fit): return
            if i == self.current_fit_index:
                self.logger.SetItemBackgroundColour(i,"red")
            else:
                self.logger.SetItemBackgroundColour(i,"red")
        self.parent.calculate_high_levels_data()
        self.parent.plot_high_levels_data()
        self.logger_focus(i)

    ##################################Search Bar Functions###############################

    def on_enter_search_bar(self,event):
        self.search_query = self.search_bar.GetValue().replace(" ","").lower()
        self.update_editor()

#    def on_complete_search_bar(self,event):
#        self.search_bar.AutoComplete(self.search_choices)

    ###################################ComboBox Functions################################

    def update_bounds_boxes(self,B_list):
        self.tmin_box.SetItems(B_list)
        self.tmax_box.SetItems(B_list)

    def add_new_color(self,event):
        new_color = self.color_box.GetValue()
        if ':' in new_color:
            color_list = new_color.split(':')
            color_name = color_list[0]
            if len(color_list[1])==7 and color_list[1].startswith('#'):
                for c in color_list[1][1:]:
                    if ord(c) < 48 or ord(c) > 70:
                        self.parent.user_warning('invalid hex color must be of form #0F0F0F');return
                color_val = color_list[1]
            elif '(' in color_list[1] and ')' in color_list[1]:
                color_val = list(map(eval, tuple(color_list[1].strip('( )').split(','))))
                for val in color_val:
                    if val > 1 or val < 0: self.parent.user_warning("invalid RGB sequence"); return
            else: self.parent.user_warning("colors must be given as a valid hex color or rgb tuple"); return
        else:
            self.parent.user_warning("New colors must be passed in as $colorname:$colorval where $colorval is a valid hex color or rgb tuple"); return
        self.color_dict[color_name] = color_val
        #clear old box
        self.color_box.Clear()
        #update fit box
        self.color_box.SetItems([''] + sorted(self.color_dict.keys()))

    def on_select_coordinates(self,event):
        self.parent.coordinates_box.SetStringSelection(self.coordinates_box.GetStringSelection())
        self.parent.onSelect_coordinates(event)

    def on_select_show_box(self,event):
        """
        Changes the type of mean shown on the high levels mean plot so that single dots represent one of whatever the value of this box is.
        @param: event -> the wx.COMBOBOXEVENT that triggered this function
        """
        self.parent.UPPER_LEVEL_SHOW=self.show_box.GetValue()
        self.parent.calculate_high_levels_data()
        self.parent.plot_high_levels_data()


    def on_select_high_level(self,event,called_by_parent=False):
        """
        alters the possible entries in level_names combobox to give the user selections for which specimen interpretations to display in the logger
        @param: event -> the wx.COMBOBOXEVENT that triggered this function
        """
        UPPER_LEVEL=self.level_box.GetValue()

        if UPPER_LEVEL=='sample':
            self.level_names.SetItems(self.parent.samples)
            self.level_names.SetStringSelection(self.parent.Data_hierarchy['sample_of_specimen'][self.parent.s])

        if UPPER_LEVEL=='site':
            self.level_names.SetItems(self.parent.sites)
            self.level_names.SetStringSelection(self.parent.Data_hierarchy['site_of_specimen'][self.parent.s])

        if UPPER_LEVEL=='location':
            self.level_names.SetItems(self.parent.locations)
            self.level_names.SetStringSelection(self.parent.Data_hierarchy['location_of_specimen'][self.parent.s])

        if UPPER_LEVEL=='study':
            self.level_names.SetItems(['this study'])
            self.level_names.SetStringSelection('this study')

        if not called_by_parent:
            self.parent.level_box.SetStringSelection(UPPER_LEVEL)
            self.parent.onSelect_high_level(event,True)

        self.on_select_level_name(event)

    def on_select_level_name(self,event,called_by_parent=False):
        """
        change this objects specimens_list to control which specimen interpretatoins are displayed in this objects logger
        @param: event -> the wx.ComboBoxEvent that triggered this function
        """
        high_level_name=str(self.level_names.GetValue())

        if self.level_box.GetValue()=='sample':
            self.specimens_list=self.parent.Data_hierarchy['samples'][high_level_name]['specimens']
        elif self.level_box.GetValue()=='site':
            self.specimens_list=self.parent.Data_hierarchy['sites'][high_level_name]['specimens']
        elif self.level_box.GetValue()=='location':
            self.specimens_list=self.parent.Data_hierarchy['locations'][high_level_name]['specimens']
        elif self.level_box.GetValue()=='study':
            self.specimens_list=self.parent.Data_hierarchy['study']['this study']['specimens']

        if not called_by_parent:
            self.parent.level_names.SetStringSelection(high_level_name)
            self.parent.onSelect_level_name(event,True)

        self.specimens_list.sort(key=spec_key_func)
        self.update_editor()

    def on_select_mean_type_box(self, event):
        """
        set parent Zeq_GUI to reflect change in this box and change the
        @param: event -> the wx.ComboBoxEvent that triggered this function
        """
        new_mean_type = self.mean_type_box.GetValue()
        if new_mean_type == "None":
            self.parent.clear_high_level_pars()
        self.parent.mean_type_box.SetStringSelection(new_mean_type)
        self.parent.onSelect_mean_type_box(event)

    def on_select_mean_fit_box(self, event):
        """
        set parent Zeq_GUI to reflect the change in this box then replot the high level means plot
        @param: event -> the wx.COMBOBOXEVENT that triggered this function
        """
        new_mean_fit = self.mean_fit_box.GetValue()
        self.parent.mean_fit_box.SetStringSelection(new_mean_fit)
        self.parent.onSelect_mean_fit_box(event)

    ###################################Button Functions##################################

    def on_select_stats_button(self,event):
        """

        """
        i = self.switch_stats_button.GetValue()
        self.parent.switch_stats_button.SetValue(i)
        self.parent.update_high_level_stats()

    def add_highlighted_fits(self, evnet):
        """
        adds a new interpretation to each specimen highlighted in logger if multiple interpretations are highlighted of the same specimen only one new interpretation is added
        @param: event -> the wx.ButtonEvent that triggered this function
        """

        specimens = []
        next_i = self.logger.GetNextSelected(-1)
        if next_i == -1: return
        while next_i != -1:
            fit,specimen = self.fit_list[next_i]
            if specimen in specimens:
                next_i = self.logger.GetNextSelected(next_i)
                continue
            else: specimens.append(specimen)
            next_i = self.logger.GetNextSelected(next_i)

        for specimen in specimens:
            self.add_fit_to_specimen(specimen)

        self.update_editor()
        self.parent.update_selection()

    def add_fit_to_all(self,event):
        for specimen in self.parent.specimens:
            self.add_fit_to_specimen(specimen)

        self.update_editor()
        self.parent.update_selection()

    def add_fit_to_specimen(self,specimen):
        if specimen not in self.parent.pmag_results_data['specimens']:
            self.parent.pmag_results_data['specimens'][specimen] = []

        new_name = self.name_box.GetLineText(0)
        new_color = self.color_box.GetValue()
        new_tmin = self.tmin_box.GetValue()
        new_tmax = self.tmax_box.GetValue()

        if not new_name:
            next_fit = str(len(self.parent.pmag_results_data['specimens'][specimen]) + 1)
            while ("Fit " + next_fit) in [x.name for x in self.parent.pmag_results_data['specimens'][specimen]]:
                next_fit = str(int(next_fit) + 1)
            new_name = ("Fit " + next_fit)
        if not new_color:
            next_fit = str(len(self.parent.pmag_results_data['specimens'][specimen]) + 1)
            new_color = self.parent.colors[(int(next_fit)-1) % len(self.parent.colors)]
        else: new_color = self.color_dict[new_color]
        if not new_tmin: new_tmin = None
        if not new_tmax: new_tmax = None

        if new_name in [x.name for x in self.parent.pmag_results_data['specimens'][specimen]]:
            print(('-E- interpretation called ' + new_name + ' already exsists for specimen ' + specimen))
            return

        self.parent.add_fit(specimen, new_name, new_tmin, new_tmax, color=new_color,suppress_warnings=True)

    def delete_highlighted_fits(self, event):
        """
        iterates through all highlighted fits in the logger of this object and removes them from the logger and the Zeq_GUI parent object
        @param: event -> the wx.ButtonEvent that triggered this function
        """

        next_i = -1
        deleted_items = []
        while True:
            next_i = self.logger.GetNextSelected(next_i)
            if next_i == -1:
                break
            deleted_items.append(next_i)
        deleted_items.sort(reverse=True)
        for item in deleted_items:
            self.delete_entry(index=item)
        self.parent.update_selection()

    def delete_entry(self, fit = None, index = None):
        """
        deletes the single item from the logger of this object that corrisponds to either the passed in fit or index. Note this function mutaits the logger of this object if deleting more than one entry be sure to pass items to delete in from highest index to lowest or else odd things can happen.
        @param: fit -> Fit object to delete from this objects logger
        @param: index -> integer index of the entry to delete from this objects logger
        """
        if type(index) == int and not fit:
            fit,specimen = self.fit_list[index]
        if fit and type(index) == int:
            for i, (f,s) in enumerate(self.fit_list):
                if fit == f:
                    index,specimen = i,s
                    break

        if index == self.current_fit_index: self.current_fit_index = None
        if fit not in self.parent.pmag_results_data['specimens'][specimen]:
            print(("cannot remove item (entry #: " + str(index) + ") as it doesn't exist, this is a dumb bug contact devs"))
            self.logger.DeleteItem(index)
            return
        self.parent.pmag_results_data['specimens'][specimen].remove(fit)
        del self.fit_list[index]
        self.logger.DeleteItem(index)

    def apply_changes(self, event):
        """
        applies the changes in the various attribute boxes of this object to all highlighted fit objects in the logger, these changes are reflected both in this object and in the Zeq_GUI parent object.
        @param: event -> the wx.ButtonEvent that triggered this function
        """

        new_name = self.name_box.GetLineText(0)
        new_color = self.color_box.GetValue()
        new_tmin = self.tmin_box.GetValue()
        new_tmax = self.tmax_box.GetValue()

        next_i = -1
        changed_i = []
        while True:
            next_i = self.logger.GetNextSelected(next_i)
            if next_i == -1:
                break
            specimen = self.fit_list[next_i][1]
            fit = self.fit_list[next_i][0]
            if new_name:
                if new_name not in [x.name for x in self.parent.pmag_results_data['specimens'][specimen]]: fit.name = new_name
            if new_color:
                fit.color = self.color_dict[new_color]
            #testing
            not_both = True
            if new_tmin and new_tmax:
                if fit == self.parent.current_fit:
                    self.parent.tmin_box.SetStringSelection(new_tmin)
                    self.parent.tmax_box.SetStringSelection(new_tmax)
                fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,new_tmin,new_tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type))
                not_both = False
            if new_tmin and not_both:
                if fit == self.parent.current_fit:
                    self.parent.tmin_box.SetStringSelection(new_tmin)
                fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,new_tmin,fit.tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type))
            if new_tmax and not_both:
                if fit == self.parent.current_fit:
                    self.parent.tmax_box.SetStringSelection(new_tmax)
                fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,fit.tmin,new_tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type))
            changed_i.append(next_i)

        offset = 0
        for i in changed_i:
            i -= offset
            v = self.update_logger_entry(i)
            if v == "s":
                offset += 1

        self.parent.update_selection()

    ###################################Canvas Functions##################################

    def scatter(self,*args,**kwargs):
#        args_corrected = self.eqarea.transAxes.transform(vstack(args).T)
#        x,y = args_corrected.T
        return self.eqarea.scatter(*args,**kwargs)

    def plot(self,*args,**kwargs):
#        args_corrected = self.eqarea.transAxes.transform(vstack(args).T)
#        x,y = args_corrected.T
        return self.eqarea.plot(*args,**kwargs)

    def write(self,text):
        return self.eqarea.text(-1.2,1.15,text,{'family':self.font_type, 'fontsize':10*self.GUI_RESOLUTION, 'style':'normal','va':'center', 'ha':'left' })

    def draw_net(self):
        draw_net(self.eqarea)

    def draw(self):
        self.toolbar.home()
        self.eqarea.set_xlim(-1., 1.)
        self.eqarea.set_ylim(-1., 1.)
        self.eqarea.axes.set_aspect('equal')
        self.eqarea.axis('off')
        self.canvas.draw()

    def pan_zoom_high_equalarea(self,event):
        """
        Uses the toolbar for the canvas to change the function from zoom to pan or pan to zoom
        @param: event -> the wx.MouseEvent that triggered this funciton
        """
        if event.LeftIsDown() or event.ButtonDClick():
            return
        elif self.high_EA_setting == "Zoom":
            self.high_EA_setting = "Pan"
            try: self.toolbar.pan('off')
            except TypeError: pass
        elif self.high_EA_setting == "Pan":
            self.high_EA_setting = "Zoom"
            try: self.toolbar.zoom()
            except TypeError: pass
        else:
            self.high_EA_setting = "Zoom"
            try: self.toolbar.zoom()
            except TypeError: pass

    def home_high_equalarea(self,event):
        """
        returns high equal area to it's original position
        @param: event -> the wx.MouseEvent that triggered the call of this function
        @alters: toolbar setting
        """
        self.toolbar.home()

    def on_change_high_mouse_cursor(self,event):
        """
        If mouse is over data point making it selectable change the shape of the cursor
        @param: event -> the wx Mouseevent for that click
        """
        if self.show_box.GetValue() != "specimens": return
        if not self.parent.high_EA_xdata or not self.parent.high_EA_ydata: return
        pos=event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos[1] = height - pos[1]
        xpick_data,ypick_data = pos
        xdata_org = self.parent.high_EA_xdata
        ydata_org = self.parent.high_EA_ydata
        data_corrected = self.eqarea.transData.transform(vstack([xdata_org,ydata_org]).T)
        xdata,ydata = data_corrected.T
        xdata = list(map(float,xdata))
        ydata = list(map(float,ydata))
        e = 4e0

        if self.high_EA_setting == "Zoom":
            self.canvas.SetCursor(wx.Cursor(wx.CURSOR_CROSS))
        else:
            self.canvas.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
        for i,(x,y) in enumerate(zip(xdata,ydata)):
            if 0 < sqrt((x-xpick_data)**2. + (y-ypick_data)**2.) < e:
                self.canvas.SetCursor(wx.Cursor(wx.CURSOR_HAND))
                break
        event.Skip()

    def on_equalarea_high_select(self,event):
        self.parent.on_equalarea_high_select(event,fig = self.eqarea, canvas = self.canvas)

    ###############################Menu Functions######################################

    def on_menu_help(self,event):
        """
        Toggles the GUI's help mode which allows user to click on any part of the dialog and get help
        @param: event -> wx.MenuEvent that triggers this function
        """
        self.helper.BeginContextHelp(None)

    ###############################Window Functions######################################

    def on_close_edit_window(self, event):
        """
        the function that is triggered on the close of the interpretation editor window
        @param: event -> wx.WindowEvent that triggered this function
        """

        self.parent.ie_open = False
        self.Destroy()
Esempio n. 8
0
class p1(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        self.figure = plt.figure()
        self.figure.set_size_inches(12, 6)
        self.canvas = FigureCanvasWxAgg(self, -1, self.figure)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()

    def onOpen(self):
        dialog = wx.FileDialog(self,
                               "Otwieranie pliku",
                               style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)

        if dialog.ShowModal() == wx.ID_CANCEL:
            return

        path = dialog.GetPath()
        print(path)
        return path

    def plot1a(self, a):
        plik = p1.onOpen(self)
        plt.clf()
        df = pd.read_csv(plik, names=['value'], header=0)
        model = pmdarima.auto_arima(
            df.value,
            start_p=1,
            start_q=1,
            test='adf',  # use Trueadftest to find optimal 'd'
            max_p=3,
            max_q=3,  # maximum p and q
            m=7,  # frequency of series
            d=None,  # let model determine 'd'
            seasonal=True,  # No Seasonality
            start_P=0,
            D=0,
            trace=True,
            error_action='ignore',
            suppress_warnings=True,
            stepwise=True)
        print(model.summary())
        n_periods = a
        fc, confint = model.predict(n_periods=n_periods, return_conf_int=True)

        def forecast_accuracy(forecast, actual):
            mape = np.mean(np.abs(forecast - actual) / np.abs(actual))
            mae = np.mean(np.abs(forecast - actual))  # MAE
            mpe = np.mean((forecast - actual) / actual)  # MPE
            rmse = np.mean((forecast - actual)**2)**.5  # RMSE
            print("mae:", mae, "mpe:", mpe, "rmse:", rmse, "mape:", mape)
            return ({'mae': mae, 'mpe': mpe, 'rmse': rmse})

        def mean_absolute_percentage_error(y_true, y_pred):
            y_true, y_pred = np.array(y_true), np.array(y_pred)
            return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

        mape = mean_absolute_percentage_error(df.values, fc)

        print("MAPE", mape)
        forecast_accuracy(fc, df.values)
        index_of_fc = np.arange(len(df.value), len(df.value) + n_periods)
        df2 = pd.DataFrame({'Przewidzana wartosc': fc})
        df1 = df2.head(a)
        f = open("Przewidywanie_Arima.txt", "w")
        f.write(str(df1))
        f.close()
        print(df1)
        fc_series = pd.Series(fc, index=index_of_fc)
        lower_series = pd.Series(confint[:, 0], index=index_of_fc)
        upper_series = pd.Series(confint[:, 1], index=index_of_fc)

        plt.plot(df.value)
        plt.xticks(np.arange(0, len(df.value), 30), rotation=90)
        plt.plot(fc_series, color='darkgreen')
        plt.fill_between(lower_series.index,
                         lower_series,
                         upper_series,
                         color='k',
                         alpha=0.15)
        plt.ylabel("liczba graczy online")
        plt.title("ARIMA")
        plt.subplots_adjust(bottom=0.20)
        plt.plot()
        self.canvas.draw()

    def porownanie(self):
        plt.clf()
        plik = p1.onOpen(self)
        data = pd.read_csv(plik)

        data.describe()

        with open(plik) as csvfile:
            row_count = sum(1 for row in csvfile)
            print(row_count if row_count else 'Empty')

        data['DateTime'] = pd.to_datetime(data['DateTime'])
        data['DateTime'] = data['DateTime'].map(dt.datetime.toordinal)

        X = data['DateTime'].values.reshape(-1, 1)
        Y = data['Players'].values.reshape(-1, 1)

        X_train, X_test, y_train, y_test = train_test_split(X,
                                                            Y,
                                                            test_size=0.2,
                                                            random_state=0)

        regressor = LinearRegression()
        regressor.fit(X_train, y_train)  # training the algorithm

        # To retrieve the intercept:
        print(regressor.intercept_)
        # For retrieving the slope:
        print(regressor.coef_)

        y_pred = regressor.predict(X_test)
        df = pd.DataFrame({
            'Wartosci aktualne': y_test.flatten(),
            'Wartosci przewidziane': y_pred.flatten()
        })
        df1 = df.head(10)
        df1.to_csv(r'Regresja_przewidziane_wartosci.csv')
        print(df1)

        def MAPE(forecast, actual):
            mape = np.mean(np.abs(forecast - actual) / np.abs(actual)) * 100
            return mape

        mae1 = metrics.mean_absolute_error(y_test, y_pred)
        mse1 = metrics.mean_squared_error(y_test, y_pred)
        rmse1 = np.sqrt(metrics.mean_squared_error(y_test, y_pred))
        mape1 = MAPE(y_pred, y_test)

        df2 = pd.read_csv(plik)
        relp = os.path.relpath(plik)
        if relp == 'Bloodstained_data.csv':
            model = SARIMAX(df2['Players'],
                            order=(2, 0, 1),
                            seasonal_order=(2, 0, 0, 7),
                            trend='n')
        elif relp == 'Resident_data.csv':
            model = SARIMAX(df2['Players'],
                            order=(2, 0, 0),
                            seasonal_order=(1, 0, 1, 7),
                            trend='n')
        elif relp == 'Divinity2_data.csv':
            model = SARIMAX(df2['Players'],
                            order=(1, 0, 0),
                            seasonal_order=(2, 0, 0, 7),
                            trend='n')
        elif relp == 'Hellblade_data.csv':
            model = SARIMAX(df2['Players'],
                            order=(2, 0, 1),
                            seasonal_order=(1, 0, 1, 7),
                            trend='n')
        elif relp == 'Plague_data.csv':
            model = SARIMAX(df2['Players'],
                            order=(3, 0, 0),
                            seasonal_order=(1, 0, 0, 7),
                            trend='n')
        elif relp == 'DragonDogma_data.csv':
            model = SARIMAX(df2['Players'],
                            order=(3, 0, 2),
                            seasonal_order=(2, 0, 0, 7),
                            trend='n')

        res = model.fit()
        print(res.summary())

        nauka = res.predict(start=0, end=(row_count - 2), Dynamic=True)
        df3 = pd.DataFrame({
            'Wartosci aktualne': df2['Players'],
            'Wartosci przewidziane': nauka
        })
        df3H = df3.tail(10)
        df3H.to_csv(r'Arima_przewidziane_wartosci.csv')

        mae2 = metrics.mean_absolute_error(df2['Players'], nauka)
        mse2 = metrics.mean_squared_error(df2['Players'], nauka)
        rmse2 = np.sqrt(metrics.mean_squared_error(df2['Players'], nauka))
        mape2 = MAPE(nauka, df2['Players'])

        print(mae1, mse1, rmse1, mape1)
        print(mae2, mse2, rmse2, mape2)
        if mape2 < mape1:
            wynik = 'Dla danej probki model ARIMA jest lepszym modelem'
        elif mape2 > mape1:
            wynik = 'Dla danej probki regresja liniowa jest lepszym modelem'

        f = open("Porownanie_Algorytmow.txt", "w")
        f.write("Regresja liniowa:\nRMSE: {} MSE: {} MAE: {} \nMAPE: {}\n\n".
                format(rmse1, mse1, mae1, mape1))
        f.write("ARIMA:\nRMSE: {} MSE: {} MAE: {} \nMAPE: {}".format(
            rmse2, mse2, mae2, mape2))
        f.write("\n {}".format(wynik))
        f.close()

        plt.plot(df3)
        plt.yticks([])
        plt.plot(nauka, color="red", label='predykcja')
        plt.ylabel("Ilosc osob online")
        plt.xlabel("Dni od premiery gry")
        self.canvas.draw()

    def textMinin(self):
        plt.clf()
        plik = p1.onOpen(self)
        review = pd.read_csv(plik)

        # tworzenie oznaczenia recenzji o zlym  wydzwieku (ocena < 5)
        review["is_bad_review"] = review["recomend"].apply(
            lambda x: 1 if x == "Not Recommended" else 0)
        # wybieranie tylko potrzebych kolumn
        review = review[["review", "is_bad_review"]]
        # zamiana danych w kolumnie "review" na string
        review['review'] = review['review'].astype(str)

        review.head()

        # Podzial danych na probke
        #review = review.sample(frac = 0.3, replace = False, random_state=42)

        # obrabianie danych
        def get_wordnet_pos(pos_tag):
            if pos_tag.startswith('J'):
                return wordnet.ADJ
            elif pos_tag.startswith('V'):
                return wordnet.VERB
            elif pos_tag.startswith('N'):
                return wordnet.NOUN
            elif pos_tag.startswith('R'):
                return wordnet.ADV
            else:
                return wordnet.NOUN

        def clean_text(text):
            # male litery
            text = text.lower()
            # tokenizacja i usuwanie interpunkcji
            text = [word.strip(string.punctuation) for word in text.split(" ")]
            # usuwanie slow zawierajacych cyfry
            text = [
                word for word in text if not any(c.isdigit() for c in word)
            ]
            # usuwanie "stop" slow ('the', 'a' ,'this')
            stop = stopwords.words('english')
            text = [x for x in text if x not in stop]
            # usuwanie pustych tokenow
            text = [t for t in text if len(t) > 0]
            # oznaczanie slow POS (rzeczownik,przymiotnik,itd)
            pos_tags = pos_tag(text)
            # lemmanizacja tekstu (odmieniona forma do bezokolicznika, jesli istnieje)
            text = [
                WordNetLemmatizer().lemmatize(t[0], get_wordnet_pos(t[1]))
                for t in pos_tags
            ]
            # usuwanie slow jednoliterowych
            text = [t for t in text if len(t) > 1]
            # fuzja tekstu
            text = " ".join(text)
            return (text)

        review["review_clean"] = review["review"].apply(
            lambda x: clean_text(x))

        # uzycie Vader do sprawdzenia nastroju slow do odroznienia negatywnych od pozytywnych
        sid = SentimentIntensityAnalyzer()
        review["sentiments"] = review["review"].apply(
            lambda x: sid.polarity_scores(x))
        review = pd.concat([
            review.drop(['sentiments'], axis=1), review['sentiments'].apply(
                pd.Series)
        ],
                           axis=1)

        # liczba liter
        review["nb_chars"] = review["review"].apply(lambda x: len(x))

        # liczba slow
        review["nb_words"] = review["review"].apply(
            lambda x: len(x.split(" ")))

        # reprezentacja wektorowa kazdej recenzji

        documents = [
            TaggedDocument(doc, [i]) for i, doc in enumerate(
                review["review_clean"].apply(lambda x: x.split(" ")))
        ]

        # trening Doc2Vec
        model = Doc2Vec(documents,
                        vector_size=5,
                        window=2,
                        min_count=1,
                        workers=4)

        # przetwarzanie danych do danych wektorowych (Wymagane w Doc2Vec)
        doc2vec_df = review["review_clean"].apply(
            lambda x: model.infer_vector(x.split(" "))).apply(pd.Series)
        doc2vec_df.columns = [
            "doc2vec_vector_" + str(x) for x in doc2vec_df.columns
        ]
        review = pd.concat([review, doc2vec_df], axis=1)

        # dodawanie wartosci TF-IDF dla kazdego slowa
        tfidf = TfidfVectorizer(min_df=10)
        tfidf_result = tfidf.fit_transform(review["review_clean"]).toarray()
        tfidf_df = pd.DataFrame(tfidf_result,
                                columns=tfidf.get_feature_names())
        tfidf_df.columns = ["word_" + str(x) for x in tfidf_df.columns]
        tfidf_df.index = review.index
        review = pd.concat([review, tfidf_df], axis=1)

        # pokazanie dystrybucji procentowej dobrych do zlych recenzji
        f = open("wyniki recenzji.txt", "w")
        print('dystrybucja dobrych do zlych recenzji:')
        print(review["is_bad_review"].value_counts(normalize=True))
        f.write('dystrybucja dobrych do zlych recenzji:\n')
        f.write(str(review["is_bad_review"].value_counts(normalize=True)))
        f.close()

        def show_wordcloud(data, title=None):
            wordcloud = WordCloud(background_color='white',
                                  max_words=200,
                                  max_font_size=40,
                                  scale=3,
                                  random_state=42).generate(str(data))

            fig = plt.figure(1, figsize=(20, 20))
            plt.axis('off')
            if title:
                fig.suptitle(title, fontsize=20)
                fig.subplots_adjust(top=2.3)
            plt.imshow(wordcloud)
            self.canvas.draw()

        show_wordcloud(review["review"])
        # wypisanie 10 najbardziej pozytywnych recenzji
        print('wypisanie 10 najbardziej pozytywnych recenzji:')

        print(review[review["nb_words"] >= 5].sort_values(
            "pos", ascending=False)[["review", "pos"]].head(10))
        f = open("wyniki recenzji.txt", "a")
        f.write('\nwypisanie 10 najbardziej pozytywnych recenzji:\n')
        f.write(
            str(review[review["nb_words"] >= 5].sort_values(
                "pos", ascending=False)[["review", "pos"]].head(10)))
        f.close()
Esempio n. 9
0
class RightGraph(wx.Panel):
    def __init__(self, parent, statusbar):
        wx.Panel.__init__(self, parent, wx.ID_ANY)
        self.statusbar = statusbar

        self.fig = Figure((7.0, 6.0))
        self.canvas = FigCanvas(self, -1, self.fig)
        self.fig.patch.set_facecolor(colorBackgroundGraph)

        self.ax = self.fig.add_subplot(111)
        self.ax.set_ylabel("Intensity (a.u.)", fontdict=font)
        self.ax.set_xlabel(r'2$\theta$ (deg.)', fontdict=font)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()
        self.canvas.toolbar.zoom()
        self.toolbar.Disable()

        self.ly = self.ax.axvline(color='r', lw=0.0)  # the vert line
        self.lx = self.ax.axhline(color='r', lw=0.0)  # the horiz line

        if not hasattr(self, "UnzoomID"):
            self.UnzoomID = wx.NewId()
            self.CheckedGridId = wx.NewId()
            self.CursorId = wx.NewId()
            self.Bind(wx.EVT_MENU, self.OnUnzoom, id=self.UnzoomID)
            self.Bind(wx.EVT_MENU, self.CheckedGrid, id=self.CheckedGridId)
            self.Bind(wx.EVT_MENU, self.CursorMove, id=self.CursorId)
        """build the menu"""
        self.menu = wx.Menu()
        self.item_unzoom = self.menu.Append(self.UnzoomID, "Unzoom")
        self.item_grid = self.menu.Append(self.CheckedGridId,
                                          "Show/Hide grid",
                                          kind=wx.ITEM_CHECK)
        self.item_cursor = self.menu.Append(self.CursorId,
                                            "Show/Hide cursor",
                                            kind=wx.ITEM_CHECK)
        self.item_unzoom.Enable(False)
        self.item_grid.Enable(False)
        self.item_cursor.Enable(False)

        self.connect = self.canvas.mpl_connect
        self.disconnect = self.canvas.mpl_disconnect

        self.update_zoom = self.connect('motion_notify_event',
                                        self.MouseOnGraph)
        self.update_coord = self.connect('motion_notify_event',
                                         self.on_update_coordinate)
        self.disconnect(self.update_zoom)
        self.disconnect(self.update_coord)

        self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)

        self.c_data = ""
        self.c_fit = ""
        self.c_live = ""
        self.l_data = ""
        self.l_fit = ""
        self.l_live = ""

        mastersizer = wx.BoxSizer(wx.VERTICAL)
        mastersizer.Add(self.canvas, 1, wx.EXPAND)
        mastersizer.Add(self.toolbar, 0, wx.EXPAND)

        pub.subscribe(self.OnDrawGraph, pubsub_Draw_XRD)
        pub.subscribe(self.OnDrawGraphLive, pubsub_Draw_Fit_Live_XRD)
        pub.subscribe(self.onFit, pubsub_OnFit_Graph)
        pub.subscribe(self.on_color, pubsub_Graph_change_color_style)

        self.on_color()

        self.SetSizer(mastersizer)
        self.Layout()
        self.Fit()

    def on_color(self):
        a = P4Rm()
        self.c_data = a.DefaultDict['c_data']
        self.c_fit = a.DefaultDict['c_fit']
        self.c_live = a.DefaultDict['c_fit_live']
        self.l_data = a.DefaultDict['l_data']
        self.l_fit = a.DefaultDict['l_fit']
        self.l_live = a.DefaultDict['l_fit_live']
        self.c_bkg = a.DefaultDict['c_graph_background']

    def OnDrawGraph(self, b=None):
        a = P4Rm()
        self.ax.clear()
        if b == 1:
            self.ax.semilogy(2 * a.ParamDict['th'] * 180 / np.pi,
                             a.ParamDict['Iobs'], 'o-k')
        elif b == 2:
            self.ax.set_xlim([0, 1])
            self.ax.set_ylim([0, 1])
            self.ax.clear()
        else:
            a = P4Rm()
            xx = 2 * a.ParamDict['th'] * 180 / np.pi
            Iobs_len = len(a.ParamDict['Iobs'])
            I_i_len = len(a.ParamDict['I_i'])
            if Iobs_len == I_i_len:
                I_val = a.ParamDict['I_i']
            else:
                I_val = a.ParamDictbackup['I_i']
            self.ax.semilogy(xx,
                             a.ParamDict['Iobs'],
                             color=self.c_data,
                             ls=self.l_data,
                             marker='o')
            self.ax.semilogy(xx, I_val, color=self.c_fit, ls=self.l_fit)
            middle = int(len(a.ParamDict['th']) / 2)
            self.ly = self.ax.axvline(x=xx[middle], color='r', lw=0.0)
            self.lx = self.ax.axhline(color='r', lw=0.0)  # the horiz line
        self.ax.set_ylabel("Intensity (a.u.)", fontdict=font)
        self.ax.set_xlabel(r'2$\theta$ (deg.)', fontdict=font)
        if LooseVersion(matplotlib_vers) < LooseVersion("2.0.0"):
            self.ax.set_axis_bgcolor(self.c_bkg)
        else:
            self.ax.set_facecolor(self.c_bkg)
        self.CheckedGrid()
        self.CursorMove()

    def OnDrawGraphLive(self, val=None):
        a = P4Rm()
        if val != []:
            P4Rm.ParamDict['I_fit'] = val
        self.ax.clear()
        self.ax.semilogy(a.ParamDict['th4live'],
                         a.ParamDict['Iobs'],
                         color=self.c_data,
                         ls=self.l_data,
                         marker='o')
        self.ax.semilogy(a.ParamDict['th4live'],
                         a.ParamDict['I_fit'],
                         color=self.c_live,
                         ls=self.l_live)
        self.ax.set_ylabel("Intensity (a.u.)", fontdict=font)
        self.ax.set_xlabel(r'2$\theta$ (deg.)', fontdict=font)
        self.canvas.draw()

    def onFit(self, b=None):
        if b == 1:
            self.update_zoom = self.connect('motion_notify_event',
                                            self.MouseOnGraph)
            self.update_coord = self.connect('motion_notify_event',
                                             self.on_update_coordinate)
            self.item_unzoom.Enable(True)
            self.item_grid.Enable(True)
            self.item_cursor.Enable(True)
        else:
            self.disconnect(self.update_zoom)
            self.disconnect(self.update_coord)

            self.menu.Check(self.CursorId, check=False)
            self.item_unzoom.Enable(False)
            self.item_grid.Enable(False)
            self.item_cursor.Enable(False)
            self.ly.set_linewidth(0)
            self.lx.set_linewidth(0)

    def MouseOnGraph(self, event):
        a = P4Rm()
        if a.fitlive == 1:
            return
        if event.inaxes != None:
            if a.ParamDict['Iobs'] != "":
                xlim = self.ax.get_xlim()
                xlim_min = xlim[0] * np.pi / (2 * 180)
                xlim_max = xlim[1] * np.pi / (2 * 180)
                itemindex = where((a.ParamDictbackup['th'] > xlim_min)
                                  & (a.ParamDictbackup['th'] < xlim_max))
                t1 = itemindex[0][0]
                t2 = itemindex[0][-1]
                P4Rm.ParamDict['th'] = a.ParamDictbackup['th'][t1:t2]
                P4Rm.ParamDict['Iobs'] = a.ParamDictbackup['Iobs'][t1:t2]
                P4Rm.ParamDict['th4live'] = 2 * a.ParamDict['th'] * 180 / np.pi

    def OnRightDown(self, event):
        a = P4Rm()
        if a.fitlive == 1:
            return
        else:
            self.PopupMenu(self.menu)

    def OnUnzoom(self, event=None):
        self.canvas.toolbar.home()
        P4Rm.zoomOn = 0
        a = P4Rm()
        P4Rm.ParamDict['th'] = a.ParamDictbackup['th']
        P4Rm.ParamDict['Iobs'] = a.ParamDictbackup['Iobs']
        P4Rm.ParamDict['th4live'] = 2 * a.ParamDict['th'] * 180 / np.pi
        pub.sendMessage(pubsub_Re_Read_field_paramters_panel)
        self.CheckedGrid()
        self.CursorMove()

    def CheckedGrid(self, event=None):
        if self.menu.IsChecked(self.CheckedGridId) is True:
            self.ax.grid(True, color='gray')
        elif self.menu.IsChecked(self.CheckedGridId) is False:
            self.ax.grid(False)
        self.canvas.draw()

    def CursorMove(self, event=None):
        if self.menu.IsChecked(self.CursorId) is True:
            self.ly.set_linewidth(1)
            self.lx.set_linewidth(1)
        elif self.menu.IsChecked(self.CursorId) is False:
            self.ly.set_linewidth(0)
            self.lx.set_linewidth(0)

    def on_update_coordinate(self, event):
        if event.inaxes is None:
            self.statusbar.SetStatusText(u"", 1)
            self.statusbar.SetStatusText(u"", 2)
            return
        else:
            x, y = event.xdata, event.ydata
            self.ly.set_xdata(x)
            self.lx.set_ydata(y)
            xfloat = round(float(x), 4)
            yfloat = round(float(y), 8)
            self.statusbar.SetStatusText(u"x = " + str(xfloat), 1)
            self.statusbar.SetStatusText(u"y = " + str(yfloat), 2)
            self.canvas.draw()
Esempio n. 10
0
class ChartPanelBase(wx.Panel):
	"""
	Panel that contains a matplotlib plotting window, used for displaying an image.
	The image can be right clicked to bring up a context menu allowing copying, pasting and saving of the image.
	The image can be panned by holding the left mouse button and moving the mouse,
	and zoomed in and out using the scrollwheel on the mouse.
	"""

	def __init__(
			self,
			parent: wx.Window,
			fig,
			ax,
			id: wx.WindowID = wx.ID_ANY,
			pos: wx.Point = wx.DefaultPosition,
			size: wx.Sixe = wx.DefaultSize,
			style=0,
			name: str = wx.PanelNameStr
			):
		"""
		:param parent: The parent window.
		:type parent: wx.Window
		:param fig:
		:type fig:
		:param ax:
		:type ax:
		:param id: An identifier for the panel. wx.ID_ANY is taken to mean a default.
		:type id: wx.WindowID, optional
		:param pos: The panel position. The value ::wxDefaultPosition indicates a default position,
		:type pos: wx.Point, optional
			chosen by either the windowing system or wxWidgets, depending on platform.
		:param size: The panel size. The value ::wxDefaultSize indicates a default size, chosen by
		:type size: wx.Size, optional
			either the windowing system or wxWidgets, depending on platform.
		:param style: The window style. See wxPanel.
		:type style: int, optional
		:param name: Window name.
		:type name: str, optional
		"""

		wx.Panel.__init__(self, parent, id, pos, size, style | wx.TAB_TRAVERSAL, name)

		self.fig = fig
		self.ax = ax

		self.canvas = FigureCanvas(self, wx.ID_ANY, self.fig)
		self._do_layout()

		self.toolbar = NavigationToolbar(self.canvas)
		self.toolbar.Hide()

		self.Bind(wx.EVT_SIZE, self.on_size_change, self)
		self.Bind(wx.EVT_MAXIMIZE, self.on_size_change)

	def setup_ylim_refresher(self, y_data, x_data):
		"""
		Setup the function for updating the ylim whenever the xlim changes.s

		:param y_data:
		:type y_data:
		:param x_data:
		:type x_data:
		"""

		def update_ylim(*args):
			# print(str(*args).startswith("MPL MouseEvent")) # Pan

			# Zoom, Pan
			if ((str(*args).startswith("XPanAxesSubplot") and self.canvas.toolbar._active != "PAN")
				or (str(*args).startswith("MPL MouseEvent") and self.canvas.toolbar._active != "ZOOM")):
				# print("updated xlims: ", axes.get_xlim())
				min_x_index = (numpy.abs(x_data - self.ax.get_xlim()[0])).argmin()
				max_x_index = (numpy.abs(x_data - self.ax.get_xlim()[1])).argmin()
				# print(min_x_index, max_x_index)

				y_vals_for_range = numpy.take(y_data, [idx for idx in range(min_x_index, max_x_index)])
				# print(max(y_vals_for_range))
				self.ax.set_ylim(bottom=0, top=max(y_vals_for_range) * 1.1)
				self.fig.canvas.draw()
				# print("x-val: {}, y-val:{}
				self.size_change()

		self.ax.callbacks.connect('xlim_changed', update_ylim)
		self.fig.canvas.callbacks.connect("button_release_event", update_ylim)

	def _do_layout(self):
		# begin wxGlade: ChromatogramPanel.__do_layout
		sizer = wx.FlexGridSizer(1, 2, 0, 0)
		sizer.Add(self.canvas, 1, wx.EXPAND, 0)
		self.SetSizer(sizer)
		sizer.Fit(self)
		self.Layout()

	def reset_view(self, *_):
		"""
		Reset the view of the chart
		"""

		self.canvas.toolbar.home()
		self.canvas.draw_idle()

	def previous_view(self, *_):
		"""
		Go to the previous view of the chart
		"""

		self.canvas.toolbar.back()

	def zoom(self, enable: bool = True):
		"""
		Enable the Zoom tool
		"""

		if enable or (not enable and self.canvas.toolbar._active == "ZOOM"):
			self.canvas.toolbar.zoom()
		self.canvas.Refresh()

	def pan(self, enable: bool = True):
		"""
		Enable the Pan tool
		"""

		if enable or (not enable and self.canvas.toolbar._active == "PAN"):
			self.canvas.toolbar.pan()
		self.canvas.Refresh()

	def configure_borders(self, event=None):
		"""
		Open the 'Configure Borders' dialog
		"""

		self.border_config = border_config(self, self.fig)
		self.border_config.Show()

		if event:
			event.Skip()

	def constrain_zoom(self, key="x"):
		"""
		Constrain zoom to the x axis only

		:param key:
		:type key:
		:return:
		:rtype:
		"""

		def press_zoom(self, event):
			event.key = key
			NavigationToolbar.press_zoom(self, event)

		self.fig.canvas.toolbar.press_zoom = types.MethodType(press_zoom, self.fig.canvas.toolbar)

	# Other Toolbar Options
	# Save chromatogram as image: save_figure(self, *args)
	# set_cursor(self, cursor)
	# Set the current cursor to one of the :class:`Cursors` enums values.

	# If required by the backend, this method should trigger an update in
	# the backend event loop after the cursor is set, as this method may be
	# called e.g. before a long-running task during which the GUI is not
	# updated.
	# set_history_buttons(self)
	# Enable or disable the back/forward button.
	# forward(self, *args)
	# move forward in the view lim stack.
	# print(axes.get_ylim())
	# end of class ChromatogramPanel

	def size_change(self):
		"""
		Internal function that runs whenever the window is resized
		"""

		# self.canvas.SetMinSize(self.GetSize())
		self.canvas.SetSize(self.GetSize())
		self.Refresh()
		self.canvas.draw()
		self.canvas.Refresh()

		# if event.ClassName == "wxSizeEvent":
		# 	event.Skip()

	def on_size_change(self, event):
		"""
		Event handler for size change events
		"""

		self.size_change()
		# event.Skip()

	def setup_scrollwheel_zooming(self, scale: float = 1.1):
		"""
		Allow zooming of the chart with the scrollwheel

		:param scale:
		:type scale:
		"""

		def zoom_factory(ax, base_scale: float = 1.1):

			def zoom_fun(event):
				# get the current x and y limits
				cur_xlim = ax.get_xlim()
				cur_ylim = ax.get_ylim()
				cur_xrange = (cur_xlim[1] - cur_xlim[0]) * .5
				cur_yrange = (cur_ylim[1] - cur_ylim[0]) * .5
				xdata = event.xdata  # get event x location
				ydata = event.ydata  # get event y location
				if event.button == 'up':
					# deal with zoom in
					scale_factor = 1 / base_scale
				elif event.button == 'down':
					# deal with zoom out
					scale_factor = base_scale
				else:
					# deal with something that should never happen
					scale_factor = 1
					print(event.button)
				# set new limits
				ax.set_xlim([xdata - cur_xrange * scale_factor, xdata + cur_xrange * scale_factor])
				ax.set_ylim([ydata - cur_yrange * scale_factor, ydata + cur_yrange * scale_factor])
				self.canvas.draw()  # force re-draw

			fig = ax.get_figure()  # get the figure of interest
			# attach the call back
			fig.canvas.mpl_connect('scroll_event', zoom_fun)

			# return the function
			return zoom_fun

		self.__zoom_factory = zoom_factory(self.ax, base_scale=scale)
Esempio n. 11
0
class graphManager(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=u"ReGenesis", pos=wx.DefaultPosition,
                          size=wx.Size(MAXWIDTH, MAXHEIGHT),
                          style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER |
                                                            wx.MAXIMIZE_BOX))
        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        self.sizer = wx.BoxSizer(wx.VERTICAL)

        self.renderer = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
        self.sizer.Add(self.renderer, 1, wx.EXPAND | wx.ALL, 5)


        # toolbar
        self.toolbar = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
        self.toolbar.SetMinSize(wx.Size(1200, 40))
        self.toolbar.SetMaxSize(wx.Size(1200,40))
        self.toolbarSizer = wx.BoxSizer(wx.HORIZONTAL)

        # adding buttons
        self.homeButton = wx.Button(self.toolbar, wx.ID_ANY, u"Reset", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.homeButton, 0, wx.ALL, 5)

        self.backButton = wx.Button(self.toolbar, wx.ID_ANY, u"Undo", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.backButton, 0, wx.ALL, 5)

        self.forwardButton = wx.Button(self.toolbar, wx.ID_ANY, u"Redo", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.forwardButton, 0, wx.ALL, 5)

        self.panButton = wx.Button(self.toolbar, wx.ID_ANY, u"Pan", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.panButton, 0, wx.ALL, 5)

        self.zoomButton = wx.Button(self.toolbar, wx.ID_ANY, u"Zoom", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.zoomButton, 0, wx.ALL, 5)

        self.appearanceButton = wx.Button(self.toolbar, wx.ID_ANY, u"Edit Appearance", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.appearanceButton, 0, wx.ALL, 5)

        self.saveButton = wx.Button(self.toolbar, wx.ID_ANY, u"Save", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.saveButton, 0, wx.ALL, 5)

        self.loadButton = wx.Button(self.toolbar, wx.ID_ANY, u"Load", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.loadButton, 0, wx.ALL, 5)

        self.exportButton = wx.Button(self.toolbar, wx.ID_ANY, u"Export", wx.DefaultPosition, wx.DefaultSize, 0)
        self.toolbarSizer.Add(self.exportButton, 0, wx.ALL, 5)



        self.toolbar.SetSizer(self.toolbarSizer)
        self.toolbar.Layout()
        self.toolbarSizer.Fit(self.toolbar)
        self.sizer.Add(self.toolbar, 1, wx.EXPAND | wx.ALL, 5)

        self.SetSizer(self.sizer)
        self.Layout()
        self.MenuBar = wx.MenuBar(0)

        #new graph menu options
        self.newGraph = wx.Menu()
        self.newPCA = wx.MenuItem(self.newGraph, wx.ID_ANY, u"PCA Graph", wx.EmptyString, wx.ITEM_NORMAL)
        self.newGraph.Append(self.newPCA)

        self.newAdmixture = wx.MenuItem(self.newGraph, wx.ID_ANY, u"Admixture Graph", wx.EmptyString, wx.ITEM_NORMAL)
        self.newGraph.Append(self.newAdmixture)

        self.MenuBar.Append(self.newGraph, u"New Graph")



        #Manage Graphs Menu
        self.manageGraphs = wx.Menu()

        self.saveGraph = wx.MenuItem(self.manageGraphs, wx.ID_ANY, u"Save", wx.EmptyString, wx.ITEM_NORMAL)
        self.manageGraphs.Append(self.saveGraph)

        self.loadGraph = wx.MenuItem(self.manageGraphs, wx.ID_ANY, u"Load", wx.EmptyString, wx.ITEM_NORMAL)
        self.manageGraphs.Append(self.loadGraph)

        self.exportGraph = wx.MenuItem(self.manageGraphs, wx.ID_ANY, u"Export", wx.EmptyString, wx.ITEM_NORMAL)
        self.manageGraphs.Append(self.exportGraph)

        self.MenuBar.Append(self.manageGraphs, u"Manage Graphs")

        self.SetMenuBar(self.MenuBar)

        self.Centre(wx.BOTH)





        # Connect Events
        # New graph events
        self.Bind(wx.EVT_MENU, self.newPCAOnMenuSelection, id=self.newPCA.GetId())
        self.Bind(wx.EVT_MENU, self.newAdmixtureOnMenuSelection, id=self.newAdmixture.GetId())

        # Manage graph events
        self.Bind(wx.EVT_MENU, self.saveGraphOnMenuSelection, id=self.saveGraph.GetId())
        self.Bind(wx.EVT_MENU, self.loadGraphOnMenuSelection, id=self.loadGraph.GetId())
        self.Bind(wx.EVT_MENU, self.exportGraphOnMenuSelection, id=self.exportGraph.GetId())

        # Toolbar Events

        self.saveButton.Bind(wx.EVT_BUTTON, self.saveGraphOnMenuSelection)
        self.loadButton.Bind(wx.EVT_BUTTON, self.loadGraphOnMenuSelection)
        self.exportButton.Bind(wx.EVT_BUTTON, self.onExportButtonClick)
        self.zoomButton.Bind(wx.EVT_BUTTON, self.onZoomButtonClick)
        self.appearanceButton.Bind(wx.EVT_BUTTON, self.onAppearanceButtonClick)
        self.homeButton.Bind(wx.EVT_BUTTON, self.onHomeButtonClick)
        self.panButton.Bind(wx.EVT_BUTTON, self.onPanButtonClick)
        self.forwardButton.Bind(wx.EVT_BUTTON, self.onForwardButtonClick)
        self.backButton.Bind(wx.EVT_BUTTON, self.onBackButtonClick)

        # Variable to store which graph type is currently loaded for saving  purposes
        self.graphType = None

    def __del__(self):
        pass

    def createFigure(self):
        """
               Creates figure or clears figure and adds a new subplot to the figure.


        """
        # checking if figure exists to avoid reinitializing

        if not hasattr(self, 'figure'):
            self.figure = mpl.figure.Figure(figsize=(FIGUREWIDTH, FIGUREHEIGHT), dpi=FIGUREDPI)

        else:
            self.figure.clf()

        # add subplot to newly created/cleared figure

        self.axes = self.figure.add_subplot(111)

    def showGraph(self):
        """
            Produces key and canvas.

        """
        self.axes.legend()
        self.canvas = FigureCanvas(self.renderer, wx.ID_ANY, self.figure)

        # Initialises navToolbar instance to use built in functions for custom toolbar
        if not hasattr(self, "navToolbar"):
            locale = wx.Locale(wx.LANGUAGE_ENGLISH)
            self.navToolbar = NavigationToolbar(self.canvas)
            self.navToolbar.Hide()

    def CreatePCAPlot(self, data):
        """
        Creates pca graph and draws it.
        """
        self.graph = pcaGraph(data)
        pcaData = self.graph.findPcaData(True)
        self.plotPcaData(pcaData)

    def CreateAdmixturePlot(self, data):
        """
        Creates admixture graph and draws it.
        """
        self.graph = admixGraph(data)
        admixData = self.graph.genDataDictionary()
        self.plotAdmixData(admixData)

    def plotPcaData(self, pcaData):
        """
        Plots PCA data to figure.
        """


        pcaAppearance.groupNames = self.graph.getGroups()
        pcaAppearance.groupColours = self.graph.getColours()
        pcaAppearance.groupShapes = self.graph.getShapes()
        pcaAppearance.groupSizes = self.graph.getSize()
        pcaAppearance.title = self.graph.getTitle()
        pcaAppearance.hasGrid = self.graph.getHasGrid()
        pcaAppearance.hasLabels = self.graph.getHasLabels()

        self.createFigure()

        for group in pcaData:
            x = pcaData[group]['x']
            y = pcaData[group]['y']
            # getting the colours of the groups
            colourList = self.graph.getColours()
            # getting the shapes of the groups
            shapeList = self.graph.getShapes()
            #getting the sizes of the groups
            sizeList = self.graph.getSize()
            #getting the title of the graph
            title = self.graph.getTitle()

            hasGrid = self.graph.getHasGrid()
            hasLabels = self.graph.getHasLabels()

            # plotting the graph
            self.axes.scatter(x, y, label=group, s=sizeList[group], color=colourList[group], marker=shapeList[group])
        self.axes.set_title(title)
        if(hasGrid):
            self.axes.grid()

        if(hasLabels):
            self.axes.set_xlabel(self.graph.getXLabel())
            self.axes.set_ylabel(self.graph.getYLabel())
        self.showGraph()

        return


    def plotAdmixData(self, admixData):
        """
        Plots admixture data to figure.
        """

        groups = list(admixData.keys())
        ancestryLabels = list(admixData[groups[0]].keys())
        individualCount = 0
        groupCenters = []

        # creating figure
        self.createFigure()

        fullRatios = []

        self.axes.set_xticklabels([])
        for group in admixData:

            ratios = []

            for ancestry in admixData[group]:
                anc = admixData[group][ancestry]
                ratios.append(anc)
            numAncestries = len(ratios)
            numIndividuals = len(ratios[0])

            # Normalising ratios so they add up to 1
            tempRatios = list(zip(*ratios))
            sums = list(map(sum, tempRatios))
            for ancestry in ratios:
                for i in range(len(ancestry)):
                    ancestry[i] /= sums[i]

            # storing values used for separating groups at presentation

            groupCenters.append(individualCount + (numIndividuals/2))
            individualCount += numIndividuals
            self.axes.axvline(individualCount, color='w')

            if len(fullRatios) > 0:
                for i in range(len(fullRatios)):
                    fullRatios[i].extend(ratios[i])
            else:
                fullRatios = ratios


        # plotting bars
        indexes = [i for i in range(individualCount)]
        self.axes.bar(indexes, fullRatios[0], 1, label=ancestryLabels[0])
        # barBottom keeps track of the current height of each bar so subsequent bars can be plotted above
        barBottom = [0 for i in range(individualCount)]
        for i in range(0, numAncestries - 1):

            # increasing height of barBottom
            barBottom = [x + y for x, y in zip(barBottom, fullRatios[i])]
            self.axes.bar(indexes, fullRatios[i + 1], 1, bottom=barBottom, label=ancestryLabels[i + 1])

        # setting labels for better readability
        self.axes.set_xticks(groupCenters)
        self.axes.set_xticklabels(groups)

        self.showGraph()

    # Event Handlers
    def newPCAOnMenuSelection(self, event):
        """
        Event handler for new PCA menu selection.
        """
        self.child = pcaCreator(self)
        self.Disable()
        self.child.ShowModal()
        if self.child.result == "CANCEL":
            event.Skip()
        elif self.child.result == "CONFIRM":
            self.CreatePCAPlot(self.child._dataDict)


    def newAdmixtureOnMenuSelection(self, event):
        """
        Event handler for new Admixture menu selection.
        """
        self.child = admixCreator(self)
        self.Disable()
        self.child.ShowModal()
        if self.child.result == "CANCEL":
            event.Skip()
        elif self.child.result == "CONFIRM":
            self.CreateAdmixturePlot(self.child._dataDict)

    def saveGraphOnMenuSelection(self, event):
        """
        Event handler for save Graph menu selection.
        """
        with wx.FileDialog(self, "Save Graph file", wildcard="Regenesis Graph File files (*.rgf)|*.rgf",
                           style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # save the current contents in the file
            pathname = fileDialog.GetPath()
            try:
                with open(pathname, 'w', encoding='utf-8') as file:
                    self.doSaveData(file)
            except IOError:
                wx.LogError("Cannot save current data in file '%s'." % pathname)

    def doSaveData(self, f):
        """
        Saves project state to file.
        """
        # find dictionary of values to plot
        if self.graph.getGraphType() == 'admix':
            data = self.graph.getSaveFileData()
            # Add a graph type key to the data dict
            data.update({"GraphType" : 'admix'})
        elif self.graph.getGraphType() == 'pca':
            data = self.graph.getSaveFileData()
            # Add a graph type key to the data dict
            data.update({"GraphType" : "pca"})
        json.dump(data, f, ensure_ascii=False)
        f.close()

    def loadGraphOnMenuSelection(self, event):

        """
        Event handler for load Graph menu selection.
        """
            # otherwise ask the user what new file to open
        with wx.FileDialog(self, "Load Graph file", wildcard="Regenesis Graph File files (*.rgf)|*.rgf",
                           style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Proceed loading the file chosen by the user
            pathname = fileDialog.GetPath()
            try:
                with open(pathname, 'r') as file:
                    self.doLoadData(file)
            except IOError:
                wx.LogError("Cannot open file '%s'." % file)

    def doLoadData(self,f):
        """
        Loads project state from file.
        """
        data = json.load(f)
        if data.get("GraphType") == 'admix':
            # Delete the Graph Type key from the data dict
            del data["GraphType"]
            self.CreateAdmixturePlot(data)
        elif data.get("GraphType") == 'pca':
            # Delete the Graph Type key from the data dict
            del data["GraphType"]
            self.CreatePCAPlot(data)
        f.close()

    def exportGraphOnMenuSelection(self, event):
        """
        Exports graph as image.
        """
        self.navToolbar.save_figure()

    def onZoomButtonClick(self, event):
        """
        Activates zoom mode on graph.
        """
        self.navToolbar.zoom()

    def onAppearanceButtonClick(self, event):
        """
        Opens appearance editor.
        """
        if self.graph.getGraphType() == 'pca':
            self.child = pcaAppearance(self)
            self.Disable()
            self.child.ShowModal()
        else:
            msgDlg = wx.MessageDialog(parent=self, message="Appearance editing functionality for admixture graph still to come in future releases",
                                      caption="Edit Admixture graph appearance", style=wx.ICON_INFORMATION)
            val = msgDlg.ShowModal()
            msgDlg.Show()


        if self.child.result == "CANCEL":
            event.Skip()
        elif self.child.result == "CONFIRM":

            if self.graph.getGraphType() == 'pca':
                #re-plotting the graph with the newly chosen colours
                newColours = self.child.GetColours()
                self.graph.setColours(newColours)

                #re-plotting the graph with the newly chosen shape
                newShapes = self.child.GetShapes()
                self.graph.setShapes(newShapes)

                #re-plotting the graph with the new group size
                newSize = self.child.GetSize()
                self.graph.setSize(newSize)

                #re-plotting graph with new title
                newTitle = self.child.GetTitle()
                self.graph.setTitle(newTitle)

                #re-plotting graph with grid settings
                grid = self.child.GetHasGrid()
                self.graph.setHasGrid(grid)

                #re-plotting graph with labels settings
                labels = self.child.GetHasLabels()
                self.graph.setHasLabels(labels)

                pcaData = self.graph.findPcaData(False)
                self.plotPcaData(pcaData)
                #self.CreatePCAPlot(self.child._dataDict)

        elif self.graph.getGraphType() == "admix":
            wx.MessageDialog(None, "Admixture Appearance editing to b")

    def onHomeButtonClick(self, event):
        """
        Resets graph panning and zooming
        """
        self.navToolbar.home()

    def onPanButtonClick(self, event):
        """
        Activates Pan mode on graph.
        """
        self.navToolbar.pan()

    def onConfigureButtonClick(self, event):
        self.navToolbar.configure_subplots()

    def onBackButtonClick(self, event):
        """
        Undoes latest panning or zooming change.
        """
        self.navToolbar.back()

    def onForwardButtonClick(self, event):
        """
        Redoes latest undone panning or zooming change.
        """
        self.navToolbar.forward()

    def onExportButtonClick(self, event):
        """
        Exports graph as image.
        """
        self.navToolbar.save_figure()
Esempio n. 12
0
class TVWindow(wx.Frame):

    #########################Init Funcions#############################

    def __init__(self,
                 parent=None,
                 dpi=200,
                 geoid=Geodesic.WGS84,
                 resolution="10m"):
        """Constructor"""
        #call init of super class
        default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP
        wx.Frame.__init__(self,
                          parent,
                          title="Track Viewer %s" % parent.__version__,
                          style=default_style,
                          size=(400 * 2, 300 * 2))
        self.Bind(wx.EVT_CLOSE, self.on_close_main)

        self.parent = parent
        try:
            self.center_lon = self.parent.dsk_row["inter_lon"]
        except AttributeError:
            self.center_lon = 180
        self.dpi = dpi
        self.grd_file = None
        self.geo_tiff_paths = []
        self.geoid = geoid
        self.resolution = resolution

        self.panel = wx.Panel(self, -1, size=(400 * 2, 300 * 2))

        #Populate UI and Menu
        self.init_UI()
        self.create_menu()
        self.configure()

        self.update()

    def init_UI(self):
        spacing = 10

        #----------------Build Directory and File Buttons-----------------

        #        grd_sizer = wx.BoxSizer(wx.HORIZONTAL)
        #        self.grd_path = wx.TextCtrl(self.panel, id=-1, size=(100,25), style=wx.TE_READONLY)
        #        self.change_grd_btn = buttons.GenButton(self.panel, id=-1, label="Add Grid",size=(176, 29))
        #        self.change_grd_btn.InitColours()
        #        self.Bind(wx.EVT_BUTTON, self.on_change_grd_btn, self.change_grd_btn)
        #        grd_sizer.Add(self.change_grd_btn, wx.ALIGN_LEFT)
        #        grd_sizer.AddSpacer(20)
        #        grd_sizer.Add(self.grd_path,wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)

        #------------------------------------Make DropDown Box-----------------------------------------------------#

        latlon_sizer = wx.StaticBoxSizer(
            wx.StaticBox(self.panel, wx.ID_ANY, "Choose Gravity Window"),
            wx.VERTICAL)
        proj_sizer = wx.StaticBoxSizer(
            wx.StaticBox(self.panel, wx.ID_ANY, "Choose Projection"),
            wx.VERTICAL)
        down_sample_sizer = wx.StaticBoxSizer(
            wx.StaticBox(self.panel, wx.ID_ANY, "Choose Downsample Factor"),
            wx.HORIZONTAL)

        projs = [
            "Mercator", "Mollweide", "North Polar Stereographic",
            "South Polar Stereographic"
        ]
        self.proj_box = wx.ComboBox(self.panel,
                                    id=wx.ID_ANY,
                                    size=(100, 25),
                                    value=projs[0],
                                    choices=projs,
                                    style=wx.CB_DROPDOWN | wx.TE_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.on_select_proj, self.proj_box)

        self.max_lat_box = wx.TextCtrl(self.panel,
                                       id=wx.ID_ANY | wx.TE_CENTRE,
                                       size=(25, 25))
        self.min_lat_box = wx.TextCtrl(self.panel,
                                       id=wx.ID_ANY | wx.TE_CENTRE,
                                       size=(25, 25))
        self.max_lon_box = wx.TextCtrl(self.panel,
                                       id=wx.ID_ANY | wx.TE_CENTRE,
                                       size=(25, 25))
        self.min_lon_box = wx.TextCtrl(self.panel,
                                       id=wx.ID_ANY | wx.TE_CENTRE,
                                       size=(25, 25))
        self.down_sample_box = wx.TextCtrl(self.panel,
                                           id=wx.ID_ANY | wx.TE_CENTRE,
                                           size=(50, 25))
        self.re_render_button = wx.Button(self.panel,
                                          id=wx.ID_ANY,
                                          label='Refresh Figure',
                                          size=(50, 25))
        self.Bind(wx.EVT_BUTTON, self.on_re_render_button,
                  self.re_render_button)

        #Projection sizer
        proj_sizer.Add(self.proj_box, 1,
                       wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.EXPAND | wx.ALL,
                       spacing)

        #Lat-Lon Sizer
        lat_sizer = wx.BoxSizer(wx.HORIZONTAL)
        lat_sizer.AddMany([
            (self.min_lat_box, 1,
             wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.EXPAND | wx.ALL, spacing),
            (self.max_lat_box, 1,
             wx.ALIGN_RIGHT | wx.ALIGN_TOP | wx.EXPAND | wx.ALL, spacing)
        ])
        lon_sizer = wx.BoxSizer(wx.HORIZONTAL)
        lon_sizer.AddMany([
            (self.min_lon_box, 1,
             wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.EXPAND | wx.ALL, spacing),
            (self.max_lon_box, 1,
             wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM | wx.EXPAND | wx.ALL, spacing)
        ])
        latlon_sizer.AddMany([
            (lat_sizer, 1, wx.ALIGN_TOP | wx.EXPAND, spacing),
            (lon_sizer, 1, wx.ALIGN_BOTTOM | wx.EXPAND, spacing)
        ])

        #Downsample sizer with downsample box and refresh button
        down_sample_sizer.AddMany([
            (self.re_render_button, 1,
             wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.EXPAND | wx.ALL, spacing),
            (self.down_sample_box, 1,
             wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM | wx.EXPAND | wx.ALL, spacing)
        ])

        #Combine projection and downsample sizers
        proj_ds_sizer = wx.BoxSizer(wx.VERTICAL)
        proj_ds_sizer.AddMany([
            (proj_sizer, 1, wx.ALIGN_TOP | wx.EXPAND, spacing),
            (down_sample_sizer, 1, wx.ALIGN_BOTTOM | wx.EXPAND, spacing)
        ])

        #Combine all in final sizer
        all_txt_btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        all_txt_btn_sizer.AddMany([
            (proj_ds_sizer, 1, wx.ALIGN_LEFT | wx.EXPAND, spacing),
            (latlon_sizer, 1, wx.ALIGN_RIGHT | wx.EXPAND, spacing)
        ])

        #-------------------------------------Make Figure----------------------------------------------------------#

        self.fig = Figure((2, 2), dpi=self.dpi)
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.toolbar = NavigationToolbar(self.canvas)
        self.ax = self.fig.add_subplot(111)
        psk.remove_axis_lines_and_ticks(self.ax)
        self.toolbar.Hide()
        self.plot_setting = "Zoom"
        self.toolbar.zoom()
        self.canvas.Bind(wx.EVT_MIDDLE_DOWN, self.on_middle_click_plot)
        self.canvas.Bind(wx.EVT_MOTION, self.on_move_mouse_plot)
        self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.on_select_dleft_click)

        #----------------------------------Build UI and Fit--------------------------------------------------------#

        outer_sizer = wx.BoxSizer(wx.VERTICAL)
        outer_sizer.AddMany(
            [  #(grd_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND|wx.LEFT|wx.RIGHT,spacing),
                (all_txt_btn_sizer, 1,
                 wx.ALIGN_CENTER | wx.ALIGN_TOP | wx.EXPAND),
                (self.canvas, 10, wx.ALIGN_CENTER | wx.ALIGN_TOP | wx.EXPAND)
            ])

        self.panel.SetSizerAndFit(outer_sizer)

    def create_menu(self):
        """
        Generates Menu
        """

        self.menubar = wx.MenuBar()

        #-----------------
        # File Menu
        #-----------------

        menu_file = wx.Menu()

        m_tiff = menu_file.Append(-1, "&Add GeoTiff\tCtrl-O", "AddTiff")
        self.Bind(wx.EVT_MENU, self.on_add_tiff, m_tiff)

        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "&Exit\tCtrl-Q", "Exit")
        self.Bind(wx.EVT_MENU, self.on_close_main, m_exit)

        #-----------------

        self.menubar.Append(menu_file, "&File")
        self.SetMenuBar(self.menubar)

    def configure(self):
        try:
            dsk_row = self.parent.dsk_row
            TRACKSELECTED = isinstance(dsk_row, type(None))
        except:
            TRACKSELECTED = False
        if TRACKSELECTED:  #Set up default values
            self.min_lat_box.SetValue("%.1f" % dsk_row["inter_lat"] - 10)
            self.max_lat_box.SetValue("%.1f" % dsk_row["inter_lat"] + 10)
            self.min_lon_box.SetValue("%.1f" % dsk_row["inter_lon"] - 10)
            self.max_lon_box.SetValue("%.1f" % dsk_row["inter_lon"] + 10)
        else:  # TODO
            self.min_lat_box.SetValue("%.1f" % -20.)
            self.max_lat_box.SetValue("%.1f" % 30.)
            self.min_lon_box.SetValue("%.1f" % 190.)
            self.max_lon_box.SetValue("%.1f" % 250.)
        self.down_sample_box.SetValue("%.0f" % 50.)
        self.window = [None, None, None, None]
        self.down_sample_factor = None

    #########################Update UI Funcions#############################

    def update(self):  #Populates Logger and makes plot
        self.make_map()
        self.plot_gravity()
        self.plot_tracks()
        self.plot_sites()

        self.canvas.draw()

    def on_close_main(self, event):
        self.parent.tvw_open = False
        self.Destroy()

    ###################Button and Dropdown Functions#########################

#    def on_change_grd_btn(self,event):
#        dlg = wx.FileDialog(
#            self, message="Choose Grid File",
#            defaultDir=self.parent.WD,
#            defaultFile="",
#            wildcard="Grid Files (*.grd,*.nc,*.ncf)|*.grd;*.nc;*.ncf|All Files (*.*)|*.*",
#            style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST
#            )
#        if dlg.ShowModal() == wx.ID_OK:
#            self.grd_file = dlg.GetPath()
#            self.grd_path.SetValue(self.grd_file)
#            self.update()
#            dlg.Destroy()
#        else: dlg.Destroy()

    def on_select_proj(self, event):
        self.update()

    def on_re_render_button(self, event):
        self.plot_gravity()

    ###########################Figure Funcions###############################

    def on_middle_click_plot(self, event):
        if event.LeftIsDown() or event.ButtonDClick():
            event.Skip()
            return
        elif self.plot_setting == "Zoom":
            self.plot_setting = "Pan"
            self.toolbar.pan('off')
        elif self.plot_setting == "Pan":
            self.plot_setting = "Zoom"
            self.toolbar.zoom()
        event.Skip()

    def on_move_mouse_plot(self, event):
        try:
            dsk_row = self.parent.dsk_row
        except AttributeError:
            event.Skip()
            return
        pos = event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos = [pos[0], height - pos[1]]
        pos = self.ax.transData.inverted().transform(pos)
        lonlat = ccrs.PlateCarree().transform_point(*pos, self.proj)
        self.plot_tracer_on_self_and_parent(dsk_row, lonlat)
        self.parent.canvas.draw()
        self.canvas.draw()
        event.Skip()

    def on_select_dleft_click(self, event):
        try:
            dsk_row = self.parent.dsk_row
        except AttributeError:
            event.Skip()
            return

        pos = event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos = [pos[0], height - pos[1]]
        pos = self.ax.transData.inverted().transform(pos)

        lonlat = ccrs.PlateCarree().transform_point(*pos, self.proj)
        proj_locs = utl.calc_projected_distance(dsk_row['inter_lon'],
                                                dsk_row['inter_lat'],
                                                [lonlat[0]], [lonlat[1]],
                                                dsk_row['strike'])
        self.parent.set_new_intercept(proj_locs.iloc[0]["dist"])
        self.parent.update(event)
        self.update()

    ##########################Additional Plotting and Backend Functions################

    def on_parent_select_track(self):
        self.center_lon = self.parent.dsk_row["inter_lon"]
        self.update()

    def on_add_tiff(self, event):
        dlg = wx.FileDialog(
            self,
            message="Choose GeoTiff File",
            defaultDir=self.parent.WD,
            wildcard="Tiff Files (*.tiff)|*.tiff|All Files (*.*)|*.*",
            style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        if dlg.ShowModal() == wx.ID_OK:
            self.geo_tiff_paths.append(dlg.GetPath())
            self.update()
            dlg.Destroy()
        else:
            dlg.Destroy()

    def make_map(self):
        #set basemap
        try:
            self.fig.delaxes(self.ax)
        except AttributeError:
            pass
        #TODO: ADD TRANSVERSE MERCATOR AT STRIKE AS OPTION
        if self.proj_box.GetValue() == 'North Polar Stereographic':
            self.proj = ccrs.NorthPolarStereo(
                central_longitude=self.center_lon,
                true_scale_latitude=None,
                globe=None)
            self.ax = self.fig.add_subplot(111, projection=self.proj)
            pgeo.make_circular_ax(self.ax)
        elif self.proj_box.GetValue() == 'South Polar Stereographic':
            self.proj = ccrs.SouthPolarStereo(
                central_longitude=self.center_lon,
                true_scale_latitude=None,
                globe=None)
            self.ax = self.fig.add_subplot(111, projection=self.proj)
            pgeo.make_circular_ax(self.ax)
        elif self.proj_box.GetValue() == 'Mercator':
            self.proj = ccrs.Mercator(central_longitude=self.center_lon)
            self.ax = self.fig.add_subplot(111, projection=self.proj)
            path = mpath.Path(
                np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]))
            self.ax.set_boundary(path, transform=self.ax.transAxes)
        elif self.proj_box.GetValue() == 'Mollweide':
            self.proj = ccrs.Mollweide(central_longitude=self.center_lon,
                                       globe=None)
            self.ax = self.fig.add_subplot(111, projection=self.proj)
#            path = mpath.Path(np.array([[0.05,0.05],[0.95,0.05],[0.95,0.95],[0.05,0.95],[0.05,0.05]]))
#            self.ax.set_boundary(path, transform=self.fig.transFigure)
        else:
            self.parent.user_warning("Projection %s not supported" %
                                     str(self.proj_box.GetValue()))
            return

        self.ax.set_xticks(np.arange(0, 370, 10.), crs=ccrs.PlateCarree())
        self.ax.set_yticks(np.arange(-80, 90, 10.), crs=ccrs.PlateCarree())
        self.ax.tick_params(grid_linewidth=.5,
                            grid_linestyle=":",
                            color="k",
                            labelsize=8)
        lon_formatter = LongitudeFormatter(zero_direction_label=True)
        lat_formatter = LatitudeFormatter()
        self.ax.xaxis.set_major_formatter(lon_formatter)
        self.ax.yaxis.set_major_formatter(lat_formatter)
        #        self.ax.gridlines(color='grey', alpha=0.5, linestyle='--',linewidth=.5)
        land = cfeature.NaturalEarthFeature('physical',
                                            'land',
                                            '110m',
                                            edgecolor="black",
                                            facecolor="",
                                            linewidth=2)
        self.ax.add_feature(land)

#        if self.proj_box.GetValue() == 'Mercator': self.ax.gridlines(color='black', alpha=0.4, linestyle='--', draw_labels=True)

    def plot_gravity(self):
        #        try: TRACKSELECTED = self.parent.dsk_row!=None
        #        except: TRACKSELECTED = False
        #        if not TRACKSELECTED: self.parent.user_warning("No track selected, skipping gravity plotting"); return

        new_window = [
            float(self.min_lon_box.GetValue()),
            float(self.max_lon_box.GetValue()),
            float(self.min_lat_box.GetValue()),
            float(self.max_lat_box.GetValue())
        ]
        new_down_sample_factor = float(self.down_sample_box.GetValue())
        if new_window == self.window and new_down_sample_factor == self.down_sample_factor:
            return
        else:
            self.window, self.down_sample_factor = new_window, new_down_sample_factor

        with wx.BusyInfo("Refreshing Gravity Grid", parent=self):
            #            wx.Yield()
            all_lons, all_lats, all_grav = pg.get_sandwell(
                self.window, self.down_sample_factor)
            #            self.ax.imshow(all_grav,cmap="viridis",alpha=.75,transform=ccrs.PlateCarree(),zorder=0,extent=self.window,origin="lower")
            fcm = self.ax.contourf(all_lons,
                                   all_lats,
                                   all_grav,
                                   60,
                                   cmap="viridis",
                                   alpha=.75,
                                   transform=ccrs.PlateCarree(),
                                   zorder=0)
            self.ax.set_extent(self.window, crs=ccrs.PlateCarree())

    def plot_tracks(self):
        try:
            dsk_row = self.parent.dsk_row
            dsk_data = self.parent.deskew_df[self.parent.deskew_df["sz_name"]
                                             == dsk_row["sz_name"]]
        except AttributeError:
            return
        #        projected_distances = utl.calc_projected_distance(dsk_row['inter_lon'],dsk_row['inter_lat'],mag_data['lon'].tolist(),mag_data['lat'].tolist(),dsk_row['strike'])
        #        dis = max(abs(projected_distances["dist"]))*1000
        #        geodict1 = Geodesic.WGS84.Direct(dsk_row['inter_lat'],dsk_row['inter_lon'],dsk_row['strike']-90,dis)
        #        geodict2 = Geodesic.WGS84.Direct(dsk_row['inter_lat'],dsk_row['inter_lon'],dsk_row['strike']+90,dis)
        self.ax.plot([geodict1["lon2"], geodict2["lon2"]],
                     [geodict1["lat2"], geodict2["lat2"]],
                     transform=ccrs.Geodetic(),
                     color="black",
                     linewidth=1,
                     linestyle='--')

        for j, (i, row) in enumerate(dsk_data.iterrows()):
            # Read in deskewed profile
            # This is hard-coded now. It will be updated to take a list of profiles in the future
            if not os.path.isfile(infile):
                self.parent.user_warning("Data file %s could not be found" %
                                         infile)
            dskd = utl.open_mag_file(
                os.path.join(row['data_dir'], row["comp_name"]))

            # Define the angle along which to project
            perp = row["strike"] - 180
            lon = dskd["lon"]
            lat = dskd["lat"]
            mag = sk.phase_shift_data(dskd["mag"].tolist(), row["phase_shift"])

            # Find distance to project
            if row["track_type"] == 'ship':
                pcol = '#000000'
                scle = 0.2 * 1e3
            if row["track_type"] == 'aero':
                if 'Ed' in row["comp_name"]:
                    pcol = 'purple'
                else:
                    pcol = 'darkorchid'
                scle = 0.5 * 1e3

            # Project amplitude onto map
            mlats, mlons = [], []
            for i in range(len(mag)):
                gdsc = self.geoid.Direct(lat[i], lon[i], perp, mag[i] * scle)
                mlons.append(gdsc['lon2'])
                mlats.append(gdsc['lat2'])

            # Plot map elements
            deskew_tracks.append(
                self.ax.plot(utl.convert_to_0_360(lon),
                             lat,
                             '--',
                             linewidth=1.0,
                             transform=ccrs.PlateCarree(),
                             color=pcol,
                             zorder=990))
            deskew_tracks.append(
                self.ax.plot(utl.convert_to_0_360(mlons),
                             mlats,
                             '-',
                             linewidth=1.0,
                             transform=ccrs.PlateCarree(),
                             color=pcol,
                             zorder=1000))
            deskew_fill.append(
                self.ax.fill_between(utl.convert_to_0_360(
                    np.array(mlons)[mag > 0]),
                                     np.array(mlats)[mag > 0],
                                     lat[mag > 0],
                                     transform=ccrs.PlateCarree(),
                                     alpha=0.5,
                                     color=pcol))

    def plot_sites(self):
        pass  #should plot present site locations of tracks

    def plot_tracer_on_self_and_parent(self, dsk_row, lonlat):
        proj_locs = utl.calc_projected_distance(dsk_row['inter_lon'],
                                                dsk_row['inter_lat'],
                                                [lonlat[0]], [lonlat[1]],
                                                dsk_row['strike'])
        self.plot_tracer_point(dsk_row,
                               proj_locs.iloc[0]["dist"],
                               color="red",
                               marker="o",
                               s=10)
        self.parent.plot_tracer_point(proj_locs.iloc[0]["dist"],
                                      linestyle='--',
                                      color='red',
                                      alpha=.5)

    def plot_tracer_point(self, dsk_row, dis, **kwargs):
        try:
            self.point_on_track.remove()
        except (AttributeError, ValueError) as e:
            pass
        geodict = Geodesic.WGS84.Direct(dsk_row['inter_lat'],
                                        dsk_row['inter_lon'],
                                        dsk_row['strike'] - 90, dis * 1000)
        self.point_on_track = self.ax.scatter(geodict["lon2"],
                                              geodict["lat2"],
                                              transform=ccrs.Geodetic(),
                                              **kwargs)
Esempio n. 13
0
class ChartPanelBase(wx.Panel):
    def __init__(self,
                 parent,
                 fig,
                 ax,
                 id=wx.ID_ANY,
                 pos=wx.DefaultPosition,
                 size=wx.DefaultSize,
                 style=0,
                 name="ChartPanelBase"):
        """
		:param parent: The parent window.
		:type parent: wx.Window
		:param fig: The figure to plot on
		:type fig: :class:`matplotlib.figure.Figure`
		:param ax: The axes to plot on
		:type ax: :class:`matplotlib.axes.Axes`
		:param id: An identifier for the panel. wx.ID_ANY is taken to mean a default.
		:type id: wx.WindowID, optional
		:param pos: The panel position. The value wx.DefaultPosition indicates a default position,
		chosen by either the windowing system or wxWidgets, depending on platform.
		:type pos: wx.Point, optional
		:param size: The panel size. The value wx.DefaultSize indicates a default size, chosen by
		either the windowing system or wxWidgets, depending on platform.
		:type size: wx.Size, optional
		:param style: The window style. See wx.Panel.
		:type style: int, optional
		:param name: Window name.
		:type name: str, optional
		"""

        wx.Panel.__init__(self, parent, id, pos, size,
                          style | wx.TAB_TRAVERSAL, name)

        self.fig = fig
        self.ax = ax

        self.canvas = FigureCanvas(self, wx.ID_ANY, self.fig)
        self._do_layout()

        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()

        self.Bind(wx.EVT_SIZE, self.on_size_change, self)
        self.Bind(wx.EVT_MAXIMIZE, self.on_size_change)

    def setup_ylim_refresher(self, y_data, x_data):

        # def on_xlims_change(ax):
        def update_ylim(*args):
            # print(*args)
            # print(str(*args).startswith("MPL MouseEvent")) # Pan
            if (str(*args).startswith("XPanAxesSubplot")
                    and self.current_canvas_mode != "PAN") or (
                        str(*args).startswith("MPL MouseEvent")
                        and self.current_canvas_mode != "ZOOM"):

                self.do_rescale_y(x_data, y_data)

        self.ax.callbacks.connect('xlim_changed', update_ylim)
        self.fig.canvas.callbacks.connect("button_release_event", update_ylim)

    @property
    def current_canvas_mode(self):
        """
		Returns the current mode of the canvas. Either "PAN", "ZOOM" or None.
		"PAN" means the canvas is in pan mode.
		"ZOOM" means the canvas is in zoom mode.
		None means the canvas is not in either mode. This state can be used for custom selection events
			(e.g. click somewhere and something happens)
		
		:return: The current canvas mode
		:rtype: str or None
		"""

        return self.canvas.toolbar._active

    def _do_layout(self):
        # begin wxGlade: ChromatogramPanel.__do_layout
        sizer = wx.FlexGridSizer(1, 2, 0, 0)
        sizer.Add(self.canvas, 1, wx.EXPAND, 0)
        self.SetSizer(sizer)
        sizer.Fit(self)
        self.Layout()

    def reset_view(self, *_):
        self.canvas.toolbar.home()
        self.canvas.draw_idle()

    def previous_view(self, *_):
        self.canvas.toolbar.back()

    def rescale_y(self, *_):
        pass

    def rescale_x(self, *_):
        pass

    def do_rescale_x(self, x_data):
        ylim = self.ax.get_ylim()
        self.ax.set_xlim(x_data[0], x_data[-1])

        self.fig.canvas.draw()

        self.ax.set_ylim(*ylim)
        self.size_change()

    def get_current_x_index_range(self, x_data):
        min_x_index = (numpy.abs(x_data - self.ax.get_xlim()[0])).argmin()
        max_x_index = (numpy.abs(x_data - self.ax.get_xlim()[1])).argmin()

        return min_x_index, max_x_index

    def do_rescale_y(self, x_data, y_data):
        min_x_index, max_x_index = self.get_current_x_index_range(x_data)

        y_vals_for_range = numpy.take(
            y_data, [idx for idx in range(min_x_index, max_x_index)])

        self.ax.set_ylim(bottom=0, top=max(y_vals_for_range) * 1.1)
        self.fig.canvas.draw()
        self.size_change()

    def zoom(self, enable=True):
        if self.check_mode("ZOOM", enable):
            self.canvas.toolbar.zoom()
        self.canvas.Refresh()

    def pan(self, enable=True):
        if self.check_mode("PAN", enable):
            self.canvas.toolbar.pan()
        self.canvas.Refresh()

    def check_mode(self, mode, enable=True):
        return (enable and self.current_canvas_mode != mode) \
         or (not enable and self.current_canvas_mode == mode)

    def configure_borders(self, _):
        self.border_config = border_config.border_config(self, self.fig)
        self.border_config.Show()

    def constrain_zoom(self, key="x"):
        # Constrain zoom to x axis only
        # From https://stackoverflow.com/questions/16705452/matplotlib-forcing-pan-zoom-to-constrain-to-x-axes
        def press_zoom(self, event):
            event.key = key
            NavigationToolbar.press_zoom(self, event)

        self.fig.canvas.toolbar.press_zoom = types.MethodType(
            press_zoom, self.fig.canvas.toolbar)

    # Other Toolbar Options
    # Save chromatogram as image: save_figure(self, *args)
    # set_cursor(self, cursor)
    # Set the current cursor to one of the :class:`Cursors` enums values.

    # If required by the backend, this method should trigger an update in
    # the backend event loop after the cursor is set, as this method may be
    # called e.g. before a long-running task during which the GUI is not
    # updated.
    # set_history_buttons(self)
    # Enable or disable the back/forward button.
    # forward(self, *args)
    # move forward in the view lim stack.
    # print(axes.get_ylim())
    # end of class ChromatogramPanel

    def size_change(self):
        # code to run whenever window resized
        # self.canvas.SetMinSize(self.GetSize())
        self.canvas.SetSize(self.GetSize())
        self.fig.tight_layout()
        self.Refresh()
        self.canvas.draw()
        self.canvas.Refresh()

        # if event.ClassName == "wxSizeEvent":
        # 	event.Skip()

    def on_size_change(self, _):
        self.size_change()
        # event.Skip()

    def setup_scrollwheel_zooming(self, scale=1.5):
        # https://stackoverflow.com/a/11562898/3092681
        def zoom_factory(ax, base_scale=2.):
            def zoom_fun(event):
                # get the current x and y limits
                cur_xlim = ax.get_xlim()
                cur_ylim = ax.get_ylim()
                cur_xrange = (cur_xlim[1] - cur_xlim[0]) * .5
                cur_yrange = (cur_ylim[1] - cur_ylim[0]) * .5
                xdata = event.xdata  # get event x location
                ydata = event.ydata  # get event y location
                if event.button == 'up':
                    # deal with zoom in
                    scale_factor = 1 / base_scale
                elif event.button == 'down':
                    # deal with zoom out
                    scale_factor = base_scale
                else:
                    # deal with something that should never happen
                    scale_factor = 1
                    print(event.button)
                # set new limits
                ax.set_xlim([
                    xdata - cur_xrange * scale_factor,
                    xdata + cur_xrange * scale_factor
                ])
                ax.set_ylim([
                    ydata - cur_yrange * scale_factor,
                    ydata + cur_yrange * scale_factor
                ])
                self.canvas.draw()  # force re-draw

            fig = ax.get_figure()  # get the figure of interest
            # attach the call back
            fig.canvas.mpl_connect('scroll_event', zoom_fun)

            # return the function
            return zoom_fun

        self.__zoom_factory = zoom_factory(self.ax, base_scale=scale)

    def show_message(self, message):
        self.ax.text(0.5,
                     0.5,
                     message,
                     horizontalalignment="center",
                     fontsize='11',
                     transform=self.ax.transAxes)
        self.canvas.draw()

    def clear(self):
        self.ax.clear()
        self.fig.subplots_adjust(left=0.1, bottom=0.125, top=0.9, right=0.97)
        self.canvas.draw()
Esempio n. 14
0
class SkwLatWindow(wx.Frame):

    #########################Init Funcions#############################

    def __init__(self, parent=None, dpi=200, fontsize=6):
        """Constructor"""
        #call init of super class
        default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP
        wx.Frame.__init__(self,
                          parent,
                          title="Skewness by Latitude %s" % parent.__version__,
                          style=default_style)
        self.Bind(wx.EVT_CLOSE, self.on_close_main)

        self.parent = parent
        self.dpi = dpi
        self.fontsize = fontsize

        #        self.panel = wx.Panel(self, wx.ID_ANY)
        self.scrolled_panel = wx.lib.scrolledpanel.ScrolledPanel(
            self, wx.ID_ANY)  # make the Panel

        #Populate UI and Menu
        self.init_UI()
        self.create_menu()

        self.scrolled_panel.SetAutoLayout(True)
        self.scrolled_panel.SetupScrolling()  # endable scrolling

        self.update()

    def init_UI(self):
        spacing, vpadding, hpadding = 0., .01, .15

        #------------------------------------Make DropDown Box-----------------------------------------------------#

        sz_names_sizer = wx.StaticBoxSizer(
            wx.StaticBox(self.scrolled_panel, wx.ID_ANY, "Spreading Zone"),
            wx.HORIZONTAL)

        try:
            sz_names = self.parent.deskew_df["sz_name"].drop_duplicates(
            ).tolist()
            self.maximum_profiles = max([
                len(self.parent.deskew_df[self.parent.deskew_df["sz_name"] ==
                                          sz_name]) for sz_name in sz_names
            ])
        except AttributeError:
            sz_names, self.maximum_profiles = [""], 6
        self.sz_names_box = wx.ComboBox(self.scrolled_panel,
                                        id=wx.ID_ANY,
                                        size=(300, 50),
                                        value=sz_names[0],
                                        choices=sz_names,
                                        style=wx.CB_DROPDOWN | wx.TE_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.on_select_sz, self.sz_names_box)

        self.show_synth_button = wx.CheckBox(self.scrolled_panel,
                                             id=wx.ID_ANY,
                                             label="Plot Synthetic",
                                             size=(300, 50))
        self.Bind(wx.EVT_CHECKBOX, self.on_show_synth_button,
                  self.show_synth_button)

        sz_names_sizer.AddMany([
            (self.sz_names_box, 0, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL
             | wx.ALIGN_LEFT | wx.EXPAND | wx.ALL, spacing),
            (self.show_synth_button, 0, wx.ALIGN_CENTER
             | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
             spacing)
        ])
        #        self.panel.SetSizerAndFit(sz_names_sizer)

        #-------------------------------------Make Figure----------------------------------------------------------#

        canvas_sizer = wx.BoxSizer(wx.VERTICAL)

        self.fig = Figure((2., 1. * self.maximum_profiles), dpi=self.dpi)
        self.fig.subplots_adjust(top=1. - vpadding,
                                 right=1. - hpadding,
                                 left=hpadding,
                                 bottom=vpadding,
                                 wspace=.0,
                                 hspace=.0)
        self.canvas = FigCanvas(self.scrolled_panel, wx.ID_ANY, self.fig)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()
        self.plot_setting = "Zoom"
        self.toolbar.zoom()
        self.canvas.Bind(wx.EVT_MIDDLE_DOWN, self.on_middle_click_plot)
        self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.on_select_dleft_click)

        canvas_sizer.AddMany([
            (sz_names_sizer, 0,
             wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL,
             spacing),
            (self.canvas, 1,
             wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL,
             spacing)
        ])

        #----------------------------------Build UI and Fit--------------------------------------------------------#

        self.scrolled_panel.SetSizerAndFit(canvas_sizer)

#        outer_sizer = wx.BoxSizer(wx.VERTICAL)
#        outer_sizer.AddMany([(self.panel,1,wx.ALIGN_CENTER|wx.EXPAND),
#                            (self.scrolled_panel,2,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND)])

#        self.SetSizer(outer_sizer)
#        outer_sizer.Fit(self)

    def create_menu(self):
        """
        Generates Menu
        """

        self.menubar = wx.MenuBar()

        #-----------------
        # File Menu
        #-----------------

        menu_file = wx.Menu()

        submenu_save_plots = wx.Menu()

        m_save_plot = submenu_save_plots.Append(-1, "&Save Plot", "")
        self.Bind(wx.EVT_MENU, self.on_save_plot, m_save_plot, "save-plot")

        m_new_sub_plots = menu_file.Append(-1, "&Save Result",
                                           submenu_save_plots)

        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "&Exit\tCtrl-Q", "Exit")
        self.Bind(wx.EVT_MENU, self.on_close_main, m_exit)

        #-----------------

        self.menubar.Append(menu_file, "&File")
        self.SetMenuBar(self.menubar)

    #########################Update UI Funcions#############################

    def update(self):  #Populates Logger and makes plot
        self.fig.clear()
        self.plot_skewnesses_by_lat()
        self.canvas.draw()

    def on_save_plot(self, event):
        self.toolbar.save_figure()

    def on_close_main(self, event):
        self.parent.skw_lat_open = False
        self.Destroy()

    ##########################ComboBox Funcions##############################

    def on_select_sz(self, event):
        self.update()

    def on_show_synth_button(self, event):
        self.update()

    ###########################Figure Funcions###############################

    def on_middle_click_plot(self, event):
        if event.LeftIsDown() or event.ButtonDClick():
            event.Skip()
            return
        elif self.plot_setting == "Zoom":
            self.plot_setting = "Pan"
            self.toolbar.pan('off')
        elif self.plot_setting == "Pan":
            self.plot_setting = "Zoom"
            self.toolbar.zoom()
        event.Skip()

    def on_select_dleft_click(self, event):
        pass
#        try: dsk_df = self.parent.deskew_df
#        except AttributeError: event.Skip(); return

#        pos=event.GetPosition()
#        width, height = self.canvas.get_width_height()
#        pos = [pos[0],height-pos[1]]
#        pos = self.ax.transData.inverted().transform(pos)

#        min_dis,min_row = np.inf,None
#        ylim = self.ax.get_ylim()
#        for i,row in dsk_df.iterrows():
#            dis = ((row["inter_lat"]-pos[0])/ylim[0])**2 + ((row["aei"]-pos[1])/ylim[1])**2
#            if dis < min_dis:
#                min_dis = dis
#                min_row = row

#        self.parent.track_box.SetValue(min_row["comp_name"])
#        self.parent.on_select_track(event)

##########################Additional Plotting and Backend Functions################

    def on_parent_select_track(self):
        pass

    def plot_skewnesses_by_lat(self, clip_on=True):

        try:
            sz_name = self.sz_names_box.GetValue()
            rows = self.parent.deskew_df[self.parent.deskew_df["sz_name"] ==
                                         sz_name]
            rows.sort_values("inter_lat", inplace=True, ascending=False)
        except (AttributeError, KeyError) as e:
            print("Spreading Zone %s not found in deskew file" %
                  str(self.sz_names_box.GetValue()))
            return
        try:
            xlims = self.parent.ax.get_xlim()
            ylims = self.parent.ax.get_ylim()
        except AttributeError:
            xlims, ylims = (-300, 300), (-150, 150)
        axs = self.fig.subplots(self.maximum_profiles,
                                1,
                                sharex=True,
                                sharey=True)
        #        for ax in axs:
        #            ax.set_facecolor("grey")
        axs = axs[:len(rows)]

        for j, (ax, (i, row)) in enumerate(zip(axs, rows.iterrows())):
            print(j, row["comp_name"], xlims, ylims)
            ax.set_anchor('W')

            psk.remove_axis_lines_and_ticks(ax)

            min_proj_dis, max_proj_dis = psk.plot_skewness_data(
                row,
                float(row['phase_shift']),
                ax,
                picker=True,
                clip_on=clip_on,
                xlims=xlims,
                flip=True)

            ax.annotate(
                r"%s" % row['comp_name'] + "\n" +
                r"%.1f$^\circ$N,%.1f$^\circ$E" % (float(
                    row['inter_lat']), utl.convert_to_0_360(row['inter_lon'])),
                xy=(-.215, .5),
                xycoords="axes fraction",
                fontsize=self.fontsize,
                va="center",
                ha="left")
            ax.annotate(r"$\theta$=%.1f" % float(row['phase_shift']) + "\n" +
                        r"$e_a$=%.1f" % float(row['aei']),
                        xy=(1.15, .5),
                        xycoords="axes fraction",
                        fontsize=self.fontsize,
                        va="center",
                        ha="right")
            #            ax.set_ylabel(r"$\theta$=%.1f"%float(row['phase_shift'])+"\n"+r"$e_a$=%.1f"%float(row['aei']),rotation=0,fontsize=self.fontsize)
            ax.yaxis.set_label_coords(1.05, .45)
            ax.patch.set_alpha(0.0)
            #            ax.format_coord = format_coord

            if self.show_synth_button.GetValue():
                try:
                    ax.plot(self.parent.dis_synth,
                            self.parent.synth,
                            'r-',
                            alpha=.4,
                            zorder=1)
                except (AttributeError, IndexError):
                    print(
                        "No synthetic found to render in skewness by latitude window"
                    )

        scale = np.sqrt(sum(np.array(xlims)**2))
        if not scale < 20 or scale > 3000:
            ax.set_xlim(xlims)
            ax.set_ylim(ylims)

        if self.parent.spreading_rate_path != None:
            psk.plot_chron_span_on_axes(
                sz_name,
                self.fig.get_axes(),
                rows[['age_min', 'age_max']].iloc[0],
                spreading_rate_path=self.parent.spreading_rate_path)

#        self.fig.subplots_adjust(hspace=.0) #remove space between subplot axes

        self.canvas.draw()
Esempio n. 15
0
class RTPWindow(wx.Frame):

    #########################Init Funcions#############################

    def __init__(self,parent=None,dpi=100,geoid=Geodesic.WGS84,resolution="50m",center_lon=0.,fontsize=8, verbose=False):
        """Constructor"""
        #call init of super class
        default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP
        wx.Frame.__init__(self, parent, title="Pole Plot %s"%parent.__version__,style=default_style, size=(600*2,600*2))
        self.Bind(wx.EVT_CLOSE, self.on_close_main)

        self.parent=parent
        if not pymax_found: self.parent.user_warning("PyRot module PyMax not found, pole plot viewer will not be usable"); self.on_close_window(-1)
        else: self.parent.rtp_open=True
        self.center_lon = center_lon
        self.dpi = dpi
        self.geoid = geoid
        self.resolution = resolution
        self.fontsize = fontsize
        self.verbose = verbose
        self.poles_to_plot = []

        self.panel = wx.Panel(self,-1,size=(400*2,300*2))

        #Populate UI and Menu
        self.init_UI()
        self.create_menu()
        self.configure()

        self.update()

    def init_UI(self):
        spacing = 10

        #------------------------------------Make DropDown Box-----------------------------------------------------#

        latlon_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Window Boundaries"), wx.VERTICAL)
        proj_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Choose Projection"), wx.VERTICAL)
        refresh_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Refresh Figure"), wx.HORIZONTAL)

        projs = ["North Polar Stereographic","South Polar Stereographic","Orthographic"]
        self.proj_box = wx.ComboBox(self.panel, id=wx.ID_ANY,size=(100, 25), value=projs[0], choices=projs, style=wx.CB_DROPDOWN|wx.TE_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.on_select_proj,self.proj_box)

        self.max_lat_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25))
        self.min_lat_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25))
        self.max_lon_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25))
        self.min_lon_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25))
#        self.down_sample_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))\

        self.re_render_button = wx.Button(self.panel, id=wx.ID_ANY, label='Refresh Figure',size=(50,25))
        self.Bind(wx.EVT_BUTTON, self.on_re_render_button, self.re_render_button)
        self.add_pole_button = wx.Button(self.panel, id=wx.ID_ANY, label='Add Pole',size=(50,25))
        self.Bind(wx.EVT_BUTTON, self.on_add_pole_button, self.add_pole_button)

        #Projection sizer
        proj_sizer.Add(self.proj_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)

        #Lat-Lon Sizer
        lat_sizer = wx.BoxSizer(wx.HORIZONTAL)
        lat_sizer.AddMany([(self.min_lat_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                           (self.max_lat_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)])
        lon_sizer = wx.BoxSizer(wx.HORIZONTAL)
        lon_sizer.AddMany([(self.min_lon_box, 1, wx.ALIGN_LEFT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing),
                           (self.max_lon_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing)])
        latlon_sizer.AddMany([(lat_sizer, 1, wx.ALIGN_TOP|wx.EXPAND, spacing),
                              (lon_sizer, 1, wx.ALIGN_BOTTOM|wx.EXPAND, spacing)])

        #Downsample sizer with downsample box and refresh button
        refresh_sizer.AddMany([(self.re_render_button, 1, wx.ALIGN_LEFT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing),
                               (self.add_pole_button, 1, wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing)])

        #Combine projection and downsample sizers
        proj_ds_sizer = wx.BoxSizer(wx.VERTICAL)
        proj_ds_sizer.AddMany([(proj_sizer, 1, wx.ALIGN_TOP|wx.EXPAND, spacing),
                               (refresh_sizer, 1, wx.ALIGN_BOTTOM|wx.EXPAND, spacing)])

        #Combine all in final sizer
        all_txt_btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        all_txt_btn_sizer.AddMany([(proj_ds_sizer, 1, wx.ALIGN_LEFT|wx.EXPAND, spacing),
                                   (latlon_sizer, 1, wx.ALIGN_RIGHT|wx.EXPAND, spacing)])

        #-------------------------------------Make Figure----------------------------------------------------------#

        self.fig = Figure((2, 2), dpi=self.dpi)
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.toolbar = NavigationToolbar(self.canvas)
        self.ax = self.fig.add_subplot(111)
        psk.remove_axis_lines_and_ticks(self.ax)
        self.toolbar.Hide()
        self.plot_setting = "Zoom"
        self.toolbar.zoom()
        self.canvas.Bind(wx.EVT_MIDDLE_DOWN,self.on_middle_click_plot)
#        self.canvas.Bind(wx.EVT_MOTION,self.on_move_mouse_plot)
        self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.on_select_dleft_click)
        self.canvas.Bind(wx.EVT_RIGHT_DCLICK, self.on_select_dright_click)

        #----------------------------------Build UI and Fit--------------------------------------------------------#

        outer_sizer = wx.BoxSizer(wx.VERTICAL)
        outer_sizer.AddMany([#(grd_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND|wx.LEFT|wx.RIGHT,spacing),
                             (all_txt_btn_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND),
                             (self.canvas,10,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND)])

        self.panel.SetSizerAndFit(outer_sizer)

    def create_menu(self):
        """
        Generates Menu
        """

        self.menubar = wx.MenuBar()

        #-----------------
        # File Menu
        #-----------------

        menu_file = wx.Menu()

        m_import_poles = menu_file.Append(-1, "&Import Poles From CSV", "ImportPoles")
        self.Bind(wx.EVT_MENU, self.on_import_poles, m_import_poles)

        menu_file.AppendSeparator()
        submenu_save_plots = wx.Menu()

        m_save_plot = submenu_save_plots.Append(-1, "&Save Plot", "")
        self.Bind(wx.EVT_MENU, self.on_save_plot, m_save_plot,"save-plot")

        m_new_sub_plots = menu_file.Append(-1, "&Save Result", submenu_save_plots)

        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "&Exit\tCtrl-Q", "Exit")
        self.Bind(wx.EVT_MENU, self.on_close_main, m_exit)

        #-----------------
        # Edit Menu
        #-----------------

        menu_edit = wx.Menu()

        self.m_remove_pole = menu_edit.Append(-1, "&Remove Last Pole\tCtrl-Z", "RemovePole")
        self.Bind(wx.EVT_MENU, self.on_remove_pole, self.m_remove_pole)

        self.m_remove_all_poles = menu_edit.Append(-1, "&Remove All Poles\tCtrl-Z", "RemovePolesAll")
        self.Bind(wx.EVT_MENU, self.on_remove_all_poles, self.m_remove_all_poles)

        self.m_add_strike_unc = menu_edit.AppendCheckItem(-1, "&Add Strike Uncertainty\tCtrl-R", "CalcStrikes")
        self.Bind(wx.EVT_MENU, self.on_add_strike_unc, self.m_add_strike_unc)

        self.m_solve_askw = menu_edit.AppendCheckItem(-1, "&Solve for Anomalous Skewness\tCtrl-A-R", "SolveAskw")
        self.Bind(wx.EVT_MENU, self.on_solve_askw, self.m_solve_askw)

        #-----------------
        # View Menu
        #-----------------

        menu_view = wx.Menu()

        self.m_show_lunes = menu_view.AppendCheckItem(-1, "&Show Lunes", "ShowLunes")
        self.m_show_lunes.Check()
        self.Bind(wx.EVT_MENU, self.on_show_lunes, self.m_show_lunes)

        self.m_show_pole = menu_view.AppendCheckItem(-1, "&Show Pole", "ShowPole")
#        self.m_show_pole.Check()
        self.Bind(wx.EVT_MENU, self.on_show_pole, self.m_show_pole)

        self.m_show_a95 = menu_view.AppendCheckItem(-1, "&Show A95", "ShowA95")
        self.m_show_a95.Check()
        self.Bind(wx.EVT_MENU, self.on_show_a95, self.m_show_a95)

        self.m_show_selected = menu_view.AppendCheckItem(-1, "&Show Selected", "ShowSelected")
        self.m_show_selected.Check()
        self.Bind(wx.EVT_MENU, self.on_show_selected, self.m_show_selected)

        #-----------------

        self.menubar.Append(menu_file, "&File")
        self.menubar.Append(menu_edit, "&Edit")
        self.menubar.Append(menu_view, "&View")
        self.SetMenuBar(self.menubar)

    def configure(self):
        self.min_lat_box.SetValue("%.1f"%60.)
        self.max_lat_box.SetValue("%.1f"%90.)
        self.min_lon_box.SetValue("%.1f"%-180.)
        self.max_lon_box.SetValue("%.1f"%180.)
        self.window = [None,None,None,None]

    #########################Update UI Funcions#############################

    def update(self): #Populates Logger and makes plot
        self.make_map() #Make Background Map

        if self.m_show_pole.IsChecked():

            if len(self.parent.deskew_df[self.parent.deskew_df["track_type"]=="ship"]) > 0:
                self.parent.save_max_file(".tmp.max",ship_only=True) #Save tmp max file to disk for debugging purposes and to more easily punch data into format using previous functions
                comment,header,ship_data = pymax.read_max_file(".tmp.max") #Read max file
                if len(ship_data["phs"])>2: #If more than 2 profiles (even-determined) invert ship
                    (plat,plon,pmag,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(ship_data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment)
                    s1_ship = np.sqrt(chisq/dof)*ship_data["phs"][0][1][1] #ship 1sigma
                else: s1_ship = 0
            else: ship_data,s1_ship = {"phs":[["none",[0.,0.]]]},0

            if len(self.parent.deskew_df[self.parent.deskew_df["track_type"]=="aero"]) > 0:
                self.parent.save_max_file(".tmp.max",aero_only=True) #Do same for aero only data
                comment,header,aero_data = pymax.read_max_file(".tmp.max")
                if len(aero_data["phs"])>2:
                    (plat,plon,pmag,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(aero_data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment)
                    s1_aero = np.sqrt(chisq/dof)*aero_data["phs"][0][1][1]
                else: s1_aero = 0
            else: aero_data,s1_aero = {"phs":[["none",[0.,0.]]]},0

            self.parent.save_max_file(".tmp.max") #now read all data and change s1 to match above
            comment,header,data = pymax.read_max_file(".tmp.max")
            if len(data["phs"])==0: return
            for i in range(len(data["phs"])):
                if len(ship_data["phs"]) > 0 and data["phs"][i][1][1]==ship_data["phs"][0][1][1]:
                    data["phs"][i][1][1] = s1_ship
                elif len(aero_data["phs"]) > 0 and data["phs"][i][1][1]==aero_data["phs"][0][1][1]:
                    data["phs"][i][1][1] = s1_aero

            if self.m_solve_askw.IsChecked(): (plat,plon,pmag,askw,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment, solve_anom_skew=self.m_solve_askw.IsChecked())
            else: (plat,plon,pmag,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment, solve_anom_skew=self.m_solve_askw.IsChecked())
            if self.m_add_strike_unc.IsChecked(): #If strike unc is to be included calculate it!!!
                (maj_se,min_se,phi) = cs.calc_strikes_and_add_err(self.parent.deskew_path,mlat=plat,mlon=plon,ma=maj_se,mb=min_se,mphi=phi,geoid=self.geoid,outfile=".tmp_dsk_cs",filter_by_quality=False,visualize=False,convergence_level=1e-5)
                os.remove(".tmp_dsk_cs")

            #write pole coordinates and 1sigmas to plot for user
            if phi<0: phi = phi+180
            elif phi>180: phi = phi%180
            if self.m_show_a95.IsChecked():
                f_factor = f.ppf(.95,2,dof)
                print(f_factor)
                maj_se,min_se = maj_se*np.sqrt(f_factor),min_se*np.sqrt(f_factor)
            if self.m_solve_askw.IsChecked(): self.ax.annotate(r"%.1f$^\circ$N, %.1f$^\circ$E"%(plat,plon)+"\n"+r"%.1f$^\circ$, %.1f$^\circ$, N%.1fE"%(maj_se,min_se,phi)+"\n"+"Anom. Skw. = %.1f"%askw+"\n"+r"$\chi^2_\nu$ = %.2f"%(chisq/dof)+"\n"+r"$1\sigma_{aero}$=%.1f"%(s1_aero)+"\n"+r"$1\sigma_{ship}$=%.1f"%(s1_ship),xy=(1-0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,ha='right',va='top')
            else: self.ax.annotate(r"%.1f$^\circ$N, %.1f$^\circ$E"%(plat,plon)+"\n"+r"%.1f$^\circ$, %.1f$^\circ$, N%.1fE"%(maj_se,min_se,phi)+"\n"+r"$\chi^2_\nu$ = %.2f"%(chisq/dof)+"\n"+r"$1\sigma_{aero}$=%.1f"%(s1_aero)+"\n"+r"$1\sigma_{ship}$=%.1f"%(s1_ship),xy=(1-0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,ha='right',va='top')
            #plot inverted pole
            self.ax = psk.plot_pole(plon,plat,phi,np.sqrt(chisq/dof)*maj_se,np.sqrt(chisq/dof)*min_se,m=self.ax, alpha=.5, zorder=10000)
        if self.m_show_lunes.IsChecked():
            #filter deskew_df to only data labeled "good" and plot lunes
            if self.m_solve_askw.IsChecked():
                srf,asf = self.parent.get_srf_asf()
                new_asf = lambda sr: asf(sr)+askw
                self.parent.deskew_df = sk.calc_aei(self.parent.deskew_df,srf,new_asf)
            else:
                self.parent.deskew_df = sk.calc_aei(self.parent.deskew_df,*self.parent.get_srf_asf())
            dsk_to_plot = self.parent.deskew_df[self.parent.deskew_df["quality"]=="g"]
            if self.m_show_selected.IsChecked():
                try: self.ax = psk.plot_lunes(dsk_to_plot,self.ax,idx_selected=self.parent.dsk_idx)
                except AttributeError: self.ax = psk.plot_lunes(dsk_to_plot,self.ax) #catch no selected data case
            else: self.ax = psk.plot_lunes(dsk_to_plot,self.ax)
#            os.remove(".tmp.max") #remove the deskew file on disk

        #plot any additional poles
        for pole_rec in self.poles_to_plot:
            print(pole_rec)
            self.ax = psk.plot_pole(*pole_rec[0],color=pole_rec[1],m=self.ax,zorder=1000)

        #set the map extent to match user input
        print([float(self.min_lon_box.GetValue()),float(self.max_lon_box.GetValue()),float(self.min_lat_box.GetValue()),float(self.max_lat_box.GetValue())])
        self.ax.set_extent([float(self.min_lon_box.GetValue()),float(self.max_lon_box.GetValue()),float(self.min_lat_box.GetValue()),float(self.max_lat_box.GetValue())], ccrs.PlateCarree())

        self.canvas.draw() #rerender

    def on_close_main(self,event):
        self.parent.rtp_open=False
        self.Destroy()

    ############################Menu Funcions################################

    def on_import_poles(self,event):
        dlg = wx.FileDialog(
            self, message="Choose CSV File",
            defaultDir=self.parent.WD,
            wildcard="Files (*.csv)|*.csv|All Files (*.*)|*.*",
            style=wx.FD_OPEN
            )
        if dlg.ShowModal() == wx.ID_OK:
            import_csv=dlg.GetPath()
            df_poles = pd.read_csv(import_csv,sep=None)
        dlg.Destroy()

        uniform_cols = list(map(lambda x: str(x).lower(), df_poles.columns))
        df_poles.columns = uniform_cols
        try:
            lat_col = next(filter(lambda x: x.startswith("lat"), uniform_cols))
            lon_col = next(filter(lambda x: x.startswith("lon"), uniform_cols))
            maj_col = next(filter(lambda x: x.startswith("maj"), uniform_cols))
            min_col = next(filter(lambda x: x.startswith("min"), uniform_cols))
            azi_col = next(filter(lambda x: x.startswith("azi"), uniform_cols))
        except:
            self.parent.user_warning("""Couldn't find a required column. There must be at least 5 columns.
                                        These 5 columns must have labels that start with lat, lon, maj, min, azi
                                        in any order and case insensitive. If more than one column fits these
                                        conditions then the first column is taken.""")
            return
        try: color_col = next(filter(lambda x: "color" in x, uniform_cols))
        except: color_col=None
        for i,row in df_poles.iterrows():
            if isinstance(color_col,type(None)):
                self.parent.user_warning("No Color for Pole (%.1f,%.1f), please specify"%(row[lat_col],row[lon_col]))
                cdlg = wx.ColourDialog(self)
                if cdlg.ShowModal() == wx.ID_OK:
                    color = tuple(np.array(cdlg.GetColourData().GetColour().Get())/255)
                else: color = "tab:blue"
            else: color = row[color_col]
            self.poles_to_plot.append([row[[lon_col,lat_col,azi_col,maj_col,min_col]].values,color])
        self.update()

    def on_save_plot(self,event):
        self.toolbar.save_figure()

    def on_remove_pole(self,event):
        self.poles_to_plot = self.poles_to_plot[:-1]
        self.update()

    def on_remove_all_poles(self,event):
        self.poles_to_plot = []
        self.update()

    def on_add_strike_unc(self,event):
        self.update()

    def on_solve_askw(self,event):
        self.update()

    def on_show_lunes(self,event):
        self.update()

    def on_show_pole(self,event):
        self.update()

    def on_show_a95(self,event):
        self.update()

    def on_show_selected(self,event):
        self.update()

    ###################Button and Dropdown Functions#########################

#    def on_change_grd_btn(self,event):
#        dlg = wx.FileDialog(
#            self, message="Choose Grid File",
#            defaultDir=self.parent.WD,
#            defaultFile="",
#            wildcard="Grid Files (*.grd,*.nc,*.ncf)|*.grd;*.nc;*.ncf|All Files (*.*)|*.*",
#            style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST
#            )
#        if dlg.ShowModal() == wx.ID_OK:
#            self.grd_file = dlg.GetPath()
#            self.grd_path.SetValue(self.grd_file)
#            self.update()
#            dlg.Destroy()
#        else: dlg.Destroy()

    def on_select_proj(self,event):
        self.update()

    def on_re_render_button(self,event):
        self.update()

    def on_add_pole_button(self,event):
        pdlg = PoleDialog(self) #run text entry dialog
        if pdlg.ShowModal() == wx.ID_OK:
            new_pole = [pdlg.lon,pdlg.lat,pdlg.phi,pdlg.a,pdlg.b]
        else: return
        pdlg.Destroy()
        cdata = wx.ColourData()
        cdata.SetChooseFull(True)
#        cdata.SetChooseAlpha(True)
        cdata.SetColour(wx.Colour(255, 0, 0, 128))
        cdlg = wx.ColourDialog(self,cdata)
        if cdlg.ShowModal() == wx.ID_OK:
            new_color = tuple(np.array(cdlg.GetColourData().GetColour().Get())/255)
        else: color = "#00FFFF88"
        if len(new_color)==3 or new_color[3]==1.: new_color =  (new_color[0],new_color[1],new_color[2],.5)
        elif len(new_color)<3:
            raise RuntimeError("If you're looking at this error in the terminal while running SynthMag GUI, you shouldn't be able to get here and something is significantly wrong with the color picker. Contact the dev on github.")
        cdlg.Destroy()
        self.poles_to_plot.append([new_pole,new_color]) #add new pole to list
        self.update() #update figure

    ###########################Figure Funcions###############################

    def on_middle_click_plot(self,event):
        if event.LeftIsDown() or event.ButtonDClick(): event.Skip(); return
        elif self.plot_setting == "Zoom":
            self.plot_setting = "Pan"
            self.toolbar.pan('off')
        elif self.plot_setting == "Pan":
            self.plot_setting = "Zoom"
            self.toolbar.zoom()
        event.Skip()

#    def on_move_mouse_plot(self,event):
#        try: dsk_row = self.parent.dsk_row
#        except AttributeError: event.Skip(); return
#        pos=event.GetPosition()
#        width, height = self.canvas.get_width_height()
#        pos = [pos[0],height-pos[1]]
#        pos = self.ax.transData.inverted().transform(pos)
#        lonlat = ccrs.PlateCarree().transform_point(*pos,self.proj)
#        self.plot_tracer_on_self_and_parent(dsk_row,lonlat)
#        self.parent.canvas.draw()
#        self.canvas.draw()
#        event.Skip()

    def on_select_dleft_click(self,event): #TODO make rtp
        try: self.parent.dsk_row
        except AttributeError: event.Skip(); return

        pos=event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos = [pos[0],height-pos[1]]
        pos = self.ax.transData.inverted().transform(pos)

        plonlat = ccrs.PlateCarree().transform_point(*pos,self.proj)
        srf,asf = self.parent.get_srf_asf()
        reduced_skewness,rel_reduced_amplitude = sk.reduce_dsk_row_to_pole(self.parent.dsk_row,*plonlat,asf,srf)
        self.parent.phase_shift_box.SetValue("%.1f"%reduced_skewness)
        self.parent.deskew_df.at[self.parent.dsk_idx,'phase_shift'] = reduced_skewness
        self.parent.deskew_df.at[self.parent.dsk_idx,'rel_amp'] = rel_reduced_amplitude
        self.parent.dsk_row = self.parent.deskew_df.loc[self.parent.dsk_idx].iloc[0]

        self.parent.update(event)
        self.update()

    def on_select_dright_click(self,event): #TODO make rtp
        try: self.parent.deskew_df
        except AttributeError: event.Skip(); return

        pos=event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos = [pos[0],height-pos[1]]
        pos = self.ax.transData.inverted().transform(pos)

        plonlat = ccrs.PlateCarree().transform_point(*pos,self.proj)
        srf,asf = self.parent.get_srf_asf()
        for i,row in self.parent.deskew_df.iterrows():
            reduced_skewness,rel_reduced_amplitude = sk.reduce_dsk_row_to_pole(row,*plonlat,asf,srf)
            self.parent.deskew_df.at[i,'phase_shift'] = reduced_skewness
            self.parent.deskew_df.at[i,'rel_amp'] = rel_reduced_amplitude
        self.parent.deskew_df = sk.calc_aei(self.parent.deskew_df,srf,asf)
        try: self.parent.dsk_row = self.parent.deskew_df.loc[self.parent.dsk_idx].iloc[0]
        except (AttributeError,KeyError) as e: pass

        self.parent.update(event)
        self.update()

    ##########################Additional Plotting and Backend Functions################

    def on_parent_select_track(self):
        self.update()

    def make_map(self):
        #set basemap
        try: self.fig.delaxes(self.ax)
        except AttributeError: self.parent.user_warning("Unable to remove previous axis and refresh map, raise issue with Dev.")
        #TODO: ADD TRANSVERSE MERCATOR AT STRIKE AS OPTION
        if self.proj_box.GetValue() == 'North Polar Stereographic':
            self.proj = ccrs.NorthPolarStereo(central_longitude=self.center_lon,true_scale_latitude=None,globe=None)
            self.ax = self.fig.add_subplot(111,projection=self.proj)
#            pgeo.make_circular_ax(self.ax)
        elif self.proj_box.GetValue() == 'South Polar Stereographic':
            self.proj = ccrs.SouthPolarStereo(central_longitude=self.center_lon,true_scale_latitude=None,globe=None)
            self.ax = self.fig.add_subplot(111,projection=self.proj)
#            pgeo.make_circular_ax(self.ax)
        elif self.proj_box.GetValue() == 'Orthographic':
            self.proj = ccrs.Orthographic(central_longitude=self.center_lon)
            self.ax = self.fig.add_subplot(111,projection=self.proj)
        else: self.parent.user_warning("Projection %s not supported"%str(self.proj_box.GetValue())); return

#        self.ax.set_xticks(np.arange(0, 370, 10.), crs=ccrs.PlateCarree())
#        self.ax.set_yticks(np.arange(-80, 90, 10.), crs=ccrs.PlateCarree())
#        self.ax.tick_params(grid_linewidth=.5,grid_linestyle=":",color="k",labelsize=8)
#        lon_formatter = LongitudeFormatter(zero_direction_label=True)
#        lat_formatter = LatitudeFormatter()
#        self.ax.xaxis.set_major_formatter(lon_formatter)
#        self.ax.yaxis.set_major_formatter(lat_formatter)
        self.ax.gridlines(color='grey', alpha=0.5, linestyle='--',linewidth=.5)
        land = cfeature.NaturalEarthFeature('physical', 'land', self.resolution, edgecolor="black", facecolor="grey", linewidth=2)
        self.ax.add_feature(land)
Esempio n. 16
0
class LeftGraphBottom(wx.Panel):
    def __init__(self, parent, statusbar):
        wx.Panel.__init__(self, parent)
        self.statusbar = statusbar
        """
        An polygon editor.
        Key-bindings
          't' toggle vertex markers on and off.  When vertex markers are on,
              you can move them, delete them
          'd' delete the vertex under point
          'i' insert a vertex at point.  You must be within epsilon of the
              line connecting two existing vertices
        """
        self.fig = Figure((4.0, 3.0))
        self.canvas = FigCanvas(self, -1, self.fig)
        self.ax = self.fig.add_subplot(111)
        """ subplots_adjust(bottom=0.14): permet d'ajuster la taille du canevas
        en prenant en compte la legende
        sinon la legende est rognee"""
        self.fig.subplots_adjust(bottom=0.20)
        self.ax.set_ylabel("DW", fontdict=font)
        self.ax.set_xlabel("Depth ($\AA$)", fontdict=font)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()
        self.fig.patch.set_facecolor(colorBackgroundGraph)

        self._ind = None  # the active vert
        self.poly = []
        self.line = []
        self.showverts = True
        self.epsilon = 5  # max pixel distance to count as a vertex hit
        self.new_coord = {'indice': 0, 'x': 0, 'y': 0}
        self.modelpv = False

        xs = [-1]
        ys = [-1]
        poly = Polygon(list(zip(xs, ys)),
                       ls='solid',
                       fill=False,
                       closed=False,
                       animated=True)
        self.ax.set_xlim([0, 1])
        self.ax.set_ylim([0, 1])
        self.c_dw = ""
        self.l_dw = ""

        self.canvas.mpl_connect('draw_event', self.draw_callback)
        self.canvas.mpl_connect('button_press_event',
                                self.button_press_callback)
        self.canvas.mpl_connect('button_release_event',
                                self.button_release_callback)
        self.canvas.mpl_connect('motion_notify_event',
                                self.motion_notify_callback)
        self.canvas.mpl_connect('scroll_event', self.scroll_callback)
        self.canvas.mpl_connect('motion_notify_event',
                                self.on_update_coordinate)

        mastersizer = wx.BoxSizer(wx.VERTICAL)
        mastersizer.Add(self.canvas, 1, wx.ALL | wx.EXPAND)
        mastersizer.Add(self.toolbar, 0, wx.ALL)

        pub.subscribe(self.draw_c, pubsub_draw_graph)
        pub.subscribe(self.OnDrawGraph, pubsub_Draw_DW)
        pub.subscribe(self.scale_manual, pubsub_Update_Scale_DW)
        pub.subscribe(self.on_color, pubsub_Graph_change_color_style)

        self.on_color()
        self.draw_c(poly, xs, ys)

        self.SetSizer(mastersizer)
        self.Fit()

    def on_color(self):
        a = P4Rm()
        self.c_dw = a.DefaultDict['c_dw']
        self.l_dw = a.DefaultDict['l_dw']
        self.c_bkg = a.DefaultDict['c_graph_background']

    def OnDrawGraph(self, b=None):
        a = P4Rm()
        self.modelpv = a.modelPv
        self.ax.clear()
        if a.AllDataDict['damaged_depth'] == 0:
            self.ax.text(0.5,
                         0.5,
                         "No Damage",
                         size=30,
                         rotation=0.,
                         ha="center",
                         va="center",
                         bbox=dict(
                             boxstyle="round",
                             ec='red',
                             fc=self.c_dw,
                         ))
            x_dwp = [-1]
            y_dwp = [-1]
            xs = [-1]
            ys = [-1]
            self.ax.set_xticklabels([])
            self.ax.set_yticklabels([])
            self.ax.set_xlim([0, 1])
            self.ax.set_ylim([0, 1])
        else:
            if b != 2:
                x_dwp = a.ParamDict['x_dwp']
                y_dwp = a.ParamDict['DW_shifted']
                xs = deepcopy(a.ParamDict['depth'])
                ys = deepcopy(a.ParamDict['DW_i'])
                P4Rm.DragDrop_DW_x = x_dwp
                P4Rm.DragDrop_DW_y = y_dwp
                ymin = min(ys) - min(ys) * 10 / 100
                ymax = max(ys) + max(ys) * 10 / 100
                self.ax.set_ylim([ymin, ymax])
                if a.ParamDict['x_dwp'] != "":
                    self.ax.set_xlim(
                        [a.ParamDict['depth'][-1], a.ParamDict['depth'][0]])
            elif b == 2:
                x_dwp = [-1]
                y_dwp = [-1]
                xs = [-1]
                ys = [-1]
                self.ax.set_xlim([0, 1])
                self.ax.set_ylim([0, 1])
        poly = Polygon(list(zip(x_dwp, y_dwp)),
                       lw=0,
                       ls='solid',
                       color=self.c_dw,
                       fill=False,
                       closed=False,
                       animated=True)
        if self.modelpv is True:
            P4Rm.ParamDict['dwp_pv_backup'] = a.ParamDict['dwp']
        self.draw_c(poly, xs, ys)

    def draw_c(self, data, x, y):
        self.ax.plot(x, y, color=self.c_dw, lw=2., ls='solid')
        self.ax.set_ylabel("DW", fontdict=font)
        self.ax.set_xlabel("Depth ($\AA$)", fontdict=font)
        if LooseVersion(matplotlib_vers) < LooseVersion("2.0.0"):
            self.ax.set_axis_bgcolor(self.c_bkg)
        else:
            self.ax.set_facecolor(self.c_bkg)
        self.poly = data
        xs, ys = zip(*self.poly.xy)
        self.line = Line2D(xs,
                           ys,
                           lw=0,
                           ls='solid',
                           color=self.c_dw,
                           marker='.',
                           ms=32,
                           markerfacecolor=self.c_dw,
                           markeredgecolor='k',
                           mew=1.0)
        self.ax.add_line(self.line)
        self.ax.add_patch(self.poly)
        self.canvas.SetCursor(Cursor(wx.CURSOR_HAND))
        self.canvas.draw()

    def draw_callback(self, event):
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
        self.ax.draw_artist(self.poly)
        self.ax.draw_artist(self.line)
        self.canvas.blit(self.ax.bbox)

    def get_ind_under_point(self, event):
        'get the index of the vertex under point if within epsilon tolerance'

        # display coords
        xy = np.asarray(self.poly.xy)
        xyt = self.poly.get_transform().transform(xy)
        xt, yt = xyt[:, 0], xyt[:, 1]
        d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)
        indseq = np.nonzero(np.equal(d, np.amin(d)))[0]
        ind = indseq[0]

        if d[ind] >= self.epsilon:
            ind = None
        return ind

    def button_press_callback(self, event):
        'whenever a mouse button is pressed'
        a = P4Rm()
        val = a.xrd_graph_loaded
        if self.canvas.HasCapture():
            self.canvas.ReleaseMouse()
            if not self.showverts:
                return
            if event.inaxes is None:
                return
            if event.button != 1:
                return
            if val == 1:
                self._ind = self.get_ind_under_point(event)
                self.new_coord['indice'] = self._ind

    def button_release_callback(self, event):
        'whenever a mouse button is released'
        a = P4Rm()
        val = a.xrd_graph_loaded
        if self.canvas.HasCapture():
            self.canvas.ReleaseMouse()
        else:
            if not self.showverts:
                return
            if event.button != 1:
                return
            if self.new_coord['indice'] is not None and val == 1:
                a = P4Rm()
                temp_1 = self.new_coord['y']
                temp_2 = self.new_coord['x']
                P4Rm.DragDrop_DW_y[self.new_coord['indice']] = temp_1
                P4Rm.DragDrop_DW_x[self.new_coord['indice']] = temp_2
                if a.AllDataDict['model'] == 0:
                    temp = self.new_coord['y']
                    P4Rm.DragDrop_DW_y[self.new_coord['indice']] = temp
                    temp = [
                        dw * scale for dw, scale in zip(
                            a.DragDrop_DW_y, a.ParamDict['scale_dw'])
                    ]
                    temp = [float(format(value, '.8f')) for value in temp]
                    temp2 = np.concatenate([temp, [a.ParamDict['dw_out']]])
                    P4Rm.ParamDict['dwp'] = deepcopy(temp2)
                    P4Rm.ParamDictbackup['dwp'] = deepcopy(temp2)
                elif a.AllDataDict['model'] == 1:
                    temp = self.new_coord['y']
                    P4Rm.DragDrop_DW_y[self.new_coord['indice']] = temp
                    temp = [
                        dw * scale for dw, scale in zip(
                            a.DragDrop_DW_y, a.ParamDict['scale_dw'])
                    ]
                    temp = [float(format(value, '.8f')) for value in temp]
                    temp2 = np.concatenate([[a.ParamDict['dw_out'][0]], temp,
                                            [a.ParamDict['dw_out'][1]]])
                    P4Rm.ParamDict['dwp'] = deepcopy(temp2)
                    P4Rm.ParamDictbackup['dwp'] = deepcopy(temp2)
                elif a.AllDataDict['model'] == 2:
                    t_temp = a.ParamDict['depth'] + a.ParamDict['z']
                    t = t_temp[0]
                    dwp_temp = range(7)
                    dwp_temp[0] = a.DragDrop_DW_y[0]
                    dwp_temp[1] = 1 - a.DragDrop_DW_x[0] / t
                    dwp_temp[2] = 2 * (-1 + a.ParamDict['dwp'][1] +
                                       a.DragDrop_DW_x[1] / t)
                    dwp_temp[3] = 2 * (1 - a.ParamDict['dwp'][1] -
                                       1 * a.DragDrop_DW_x[2] / t)
                    dwp_temp[4] = a.ParamDict['dwp'][4]
                    dwp_temp[5] = a.ParamDict['dwp'][5]
                    dwp_temp[6] = a.DragDrop_DW_y[3]
                    P4Rm.ParamDict['dwp'] = deepcopy(dwp_temp)
                    P4Rm.ParamDictbackup['dwp'] = deepcopy(dwp_temp)
                    P4Rm.ParamDict['dwp_pv'] = deepcopy(dwp_temp)
                pub.sendMessage(pubsub_Update_Fit_Live)
            self._ind = None

    def scroll_callback(self, event):
        if not event.inaxes:
            return
        a = P4Rm()
        if event.key == 'u' and event.button == 'up':
            temp = a.ParamDict['DW_multiplication'] + 0.01
            P4Rm.ParamDict['DW_multiplication'] = temp
        elif event.key == 'u' and event.button == 'down':
            temp = a.ParamDict['DW_multiplication'] - 0.01
            P4Rm.ParamDict['DW_multiplication'] = temp
        P4Rm.ParamDict['dwp'] = multiply(a.ParamDictbackup['dwp'],
                                         a.ParamDict['DW_multiplication'])
        pub.sendMessage(pubsub_Re_Read_field_paramters_panel, event=event)

    def scale_manual(self, event, val=None):
        a = P4Rm()
        if val is not None:
            P4Rm.ParamDict['DW_multiplication'] = val
        P4Rm.ParamDict['dwp'] = multiply(a.ParamDict['dwp'],
                                         a.ParamDict['DW_multiplication'])
        pub.sendMessage(pubsub_Re_Read_field_paramters_panel, event=event)

    def motion_notify_callback(self, event):
        'on mouse movement'
        a = P4Rm()
        if a.AllDataDict['damaged_depth'] == 0:
            return
        if not self.showverts:
            return
        if self._ind is None:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return

        if self.modelpv is True:
            if self._ind == 0:
                y = event.ydata
                x = event.xdata
            elif self._ind == 1 or self._ind == 2:
                y = a.DragDrop_DW_y[self.new_coord['indice']]
                x = event.xdata
            else:
                x = a.DragDrop_DW_x[self.new_coord['indice']]
                y = event.ydata
        else:
            y = event.ydata
            x = a.DragDrop_DW_x[self.new_coord['indice']]

        self.new_coord['x'] = x
        self.new_coord['y'] = y
        self.poly.xy[self._ind] = x, y
        self.line.set_data(zip(*self.poly.xy))

        self.canvas.restore_region(self.background)
        self.ax.draw_artist(self.poly)
        self.ax.draw_artist(self.line)
        self.canvas.blit(self.ax.bbox)

    def on_update_coordinate(self, event):
        if event.inaxes is None:
            self.statusbar.SetStatusText(u"", 1)
            self.statusbar.SetStatusText(u"", 2)
        else:
            a = P4Rm()
            if not a.AllDataDict['damaged_depth'] == 0:
                x, y = event.xdata, event.ydata
                xfloat = round(float(x), 2)
                yfloat = round(float(y), 2)
                self.statusbar.SetStatusText(u"x = " + str(xfloat), 1)
                self.statusbar.SetStatusText(u"y = " + str(yfloat), 2)
                xy = np.asarray(self.poly.xy)
                xyt = self.poly.get_transform().transform(xy)
                xt, yt = xyt[:, 0], xyt[:, 1]
                d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)
                indseq = np.nonzero(np.equal(d, np.amin(d)))[0]
                ind = indseq[0]

                if d[ind] >= self.epsilon:
                    self.canvas.SetCursor(Cursor(wx.CURSOR_ARROW))
                elif d[ind] <= self.epsilon:
                    self.canvas.SetCursor(Cursor(wx.CURSOR_HAND))
Esempio n. 17
0
class plot1(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, size=(700, 500))
        self.figure = plt.figure()

        self.canvas = FigureCanvas(self, -1, self.figure)
        self.canvas.SetMinSize(wx.Size(1, 1))
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Hide()
        self._init_plots()

    def _init_plots(self):
        self.ax_time = self.figure.add_subplot(111)
        self.ax_freq = self.figure.add_subplot(111)
        self.ax_hist = self.figure.add_subplot(111)

        self.ax_time.plot([], [])
        self.ax_time.set_title("Loaded Data")
        self.ax_time.set_xlabel("Time [s]")
        self.ax_time.set_ylabel("Amplitude [V]")

    def plot(self, data, time, type, rate=None):
        if (type == 1):
            self.ax_time.clear()
            self.ax_freq.clear()
            self.ax_hist.clear()

            y = data
            t = time
            self.ax_time.plot(t, y)

            #set the plot params
            self.ax_time.set_title("Time Series Measurement")
            self.ax_time.set_xlabel("Time [s]")
            self.ax_time.set_ylabel("Voltage [V]")

            #draw the plot
            self.canvas.draw()

        elif (type == 2):
            self.ax_time.clear()
            self.ax_freq.clear()
            self.ax_hist.clear()

            #freq domain
            N = len(data)
            T = 1 / rate
            xf = np.linspace(0.0, 1.0 / (2.0 * T), N // 2)

            # taking the fft
            fftData = np.abs(np.fft.rfft(data))
            # determine the offset
            offset = len(fftData) - len(xf)
            if (offset < 0):
                # pad the data array with zeros
                for i in range(offset):
                    fftData.append[0]
            elif (offset > 0):
                fftData = fftData[:-offset]
            # fftTime = np.fft.rfftfreq(self.chunksize, 1./self.samplerate)
            self.ax_freq.plot(xf, fftData)
            self.ax_freq.set_title("Signal FFT")
            self.ax_freq.set_xlabel("Frequency [Hz]")
            self.ax_freq.set_ylabel("Amplitude |P(f)|")
            self.canvas.draw()
        elif (type == 3):
            self.ax_time.clear()
            self.ax_freq.clear()
            self.ax_hist.clear()

            counts, bins, patches = self.ax_hist.hist(data, 30)
            self.ax_hist.set_title("Signal Histogram")
            self.ax_hist.set_xlabel("Voltage [V]")
            self.ax_hist.set_ylabel("Counts")
            self.canvas.draw()
            #hist
            ''''''

    def OnDelete(self):
        print(">>> closing plots")
        plt.close(self.figure)
Esempio n. 18
0
class PVWindow(wx.Frame):

    #########################Init Funcions#############################

    def __init__(self,parent=None,dpi=100,geoid=Geodesic.WGS84,fontsize=8):
        """Constructor"""
        #call init of super class
        default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP
        wx.Frame.__init__(self, parent, title="Phase Viewer %s"%parent.__version__,style=default_style, size=(400*2,300*2))
        self.Bind(wx.EVT_CLOSE, self.on_close_main)

        self.parent=parent
        self.dpi = dpi
        self.geoid = geoid
        self.fontsize = fontsize
        self.mouse_left_down = False

        self.panel = wx.Panel(self,-1,size=(400*2,300*2))

        #Populate UI and Menu
        self.init_UI()
        self.create_menu()
        self.configure()

        self.update()

    def init_UI(self):
        spacing = 10

        #-----------------------------------------Make SideBar-----------------------------------------------------#

        side_bar_sizer = wx.BoxSizer(wx.VERTICAL)

        #####-------------------------------------Make FilterBox---------------------------------------------------#

        filter_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Filter Options"), wx.VERTICAL)
        highlow_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Highcut/Lowcut"), wx.HORIZONTAL)
        order_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Order"), wx.HORIZONTAL)
        text_input_sizer = wx.BoxSizer(wx.HORIZONTAL)

        null_filter = lambda x,y,z,fs,order: x
        self.filters = {"None":null_filter,"Butterworth Bandpass":sk.butter_bandpass_filter,"Butterworth Lowpass":sk.butter_lowpass_filter}
        list_filters = ["None","Butterworth Bandpass","Butterworth Lowpass"]
        self.filter_type_box = wx.ComboBox(self.panel, id=wx.ID_ANY,size=(200, 25), value=list_filters[0], choices=list_filters, style=wx.CB_DROPDOWN|wx.TE_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.on_select_filter,self.filter_type_box)

        self.lowcut_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))
        self.highcut_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))
        self.order_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))

        order_sizer.Add(self.order_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)
        highlow_sizer.AddMany([(self.lowcut_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                               (self.highcut_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)])
        text_input_sizer.AddMany([(highlow_sizer, 2, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                                  (order_sizer, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)])
        filter_sizer.AddMany([(self.filter_type_box, 1, wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                              (text_input_sizer, 1, wx.ALIGN_CENTER|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing)])

        #####-------------------------------------Make BoundsBox---------------------------------------------------#

        bounds_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Bounds"), wx.HORIZONTAL)
        bounds_diff_sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.low_bound_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))
        self.high_bound_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))
        self.aero_diff_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))

        bounds_sizer.AddMany([(self.low_bound_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                              (self.high_bound_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)])
        bounds_diff_sizer.AddMany([(bounds_sizer, 2, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                                   (self.aero_diff_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)])

        #####-------------------------------------Make UpdateBtn---------------------------------------------------#

        self.update_button = wx.Button(self.panel, id=wx.ID_ANY, label='Update',size=(200,50))
        self.Bind(wx.EVT_BUTTON, self.on_update_button, self.update_button)

        #-------------------------------------Make Figures---------------------------------------------------------#

        self.power_fig = Figure((3, 3), dpi=self.dpi)
        self.power_canvas = FigCanvas(self.panel, -1, self.power_fig)
        self.power_toolbar = NavigationToolbar(self.power_canvas)
#        psk.remove_axis_lines_and_ticks(self.ax)
        self.power_toolbar.Hide()
        self.power_plot_setting = "Zoom"
        self.power_toolbar.zoom()
        self.power_canvas.Bind(wx.EVT_MIDDLE_DOWN,self.on_middle_click_power_plot)

        self.fig = Figure((4, 3), dpi=self.dpi)
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.toolbar = NavigationToolbar(self.canvas)
#        psk.remove_axis_lines_and_ticks(self.ax)
        self.toolbar.Hide()
        self.plot_setting = "Zoom"
        self.toolbar.zoom()
        self.canvas.Bind(wx.EVT_MIDDLE_DOWN,self.on_middle_click_plot)
        self.canvas.Bind(wx.EVT_MOTION,self.on_move_mouse_plot)
        self.canvas.Bind(wx.EVT_LEFT_DOWN, self.on_left_click_down)
        self.canvas.Bind(wx.EVT_LEFT_UP, self.on_left_click_up)
#        self.canvas.Bind(wx.EVT_RIGHT_DCLICK, self.on_select_dright_click)

        #----------------------------------Build UI and Fit--------------------------------------------------------#

        side_bar_sizer.AddMany([(filter_sizer, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                                (bounds_diff_sizer, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                                (self.update_button, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing),
                                (self.power_canvas, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)])

        outer_sizer = wx.BoxSizer(wx.HORIZONTAL)
        outer_sizer.AddMany([#(grd_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND|wx.LEFT|wx.RIGHT,spacing),
                             (side_bar_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND),
                             (self.canvas,10,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND)])

        self.panel.SetSizerAndFit(outer_sizer)

    def create_menu(self):
        """
        Generates Menu
        """

        self.menubar = wx.MenuBar()

        #-----------------
        # File Menu
        #-----------------

        menu_file = wx.Menu()

        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "&Exit\tCtrl-Q", "Exit")
        self.Bind(wx.EVT_MENU, self.on_close_main, m_exit)

        #-----------------

        self.menubar.Append(menu_file, "&File")
        self.SetMenuBar(self.menubar)

    def configure(self):
        self.lowcut_box.SetValue("%.2f"%0.01)
        self.highcut_box.SetValue("%.2f"%0.1)
        self.order_box.SetValue("%d"%3)
        self.low_bound_box.SetValue("%.2f"%(-50.0))
        self.high_bound_box.SetValue("%.2f"%50.0)
        self.aero_diff_box.SetValue("%.1f"%0.0)


    #########################Update UI Funcions#############################

    def update(self):

        self.fig.clear() #clear
        self.power_fig.clear()

        self.draw_figures() #draw

        self.canvas.draw() #rerender
        self.power_canvas.draw()

    def on_close_main(self,event):
        self.parent.pv_open=False
        self.Destroy()

    ###################Button and Dropdown Functions#########################

#    def on_change_grd_btn(self,event):
#        dlg = wx.FileDialog(
#            self, message="Choose Grid File",
#            defaultDir=self.parent.WD,
#            defaultFile="",
#            wildcard="Grid Files (*.grd,*.nc,*.ncf)|*.grd;*.nc;*.ncf|All Files (*.*)|*.*",
#            style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST
#            )
#        if dlg.ShowModal() == wx.ID_OK:
#            self.grd_file = dlg.GetPath()
#            self.grd_path.SetValue(self.grd_file)
#            self.update()
#            dlg.Destroy()
#        else: dlg.Destroy()

    def on_select_filter(self,event):
        self.update()

    def on_update_button(self,event):
        self.update()

    ###########################Figure Funcions###############################

    def on_middle_click_plot(self,event):
        if event.LeftIsDown() or event.ButtonDClick(): event.Skip(); return
        elif self.plot_setting == "Zoom":
            self.plot_setting = "Pan"
            self.toolbar.pan('off')
        elif self.plot_setting == "Pan":
            self.plot_setting = "Pick"
            self.toolbar.pan('off')
            myCursor= wx.StockCursor(wx.CURSOR_IBEAM)
            self.canvas.SetCursor(myCursor)
        elif self.plot_setting == "Pick":
            self.plot_setting = "Zoom"
            self.toolbar.zoom()
        event.Skip()

    def on_middle_click_power_plot(self,event):
        if event.LeftIsDown() or event.ButtonDClick(): event.Skip(); return
        elif self.power_plot_setting == "Zoom":
            self.power_plot_setting = "Pan"
            self.power_toolbar.pan('off')
        elif self.power_plot_setting == "Pan":
            self.power_plot_setting = "Zoom"
            self.power_toolbar.zoom()
        event.Skip()

    def on_move_mouse_plot(self,event):
        pos=event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos = [pos[0],height-pos[1]]
        pos = self.ax0.transData.inverted().transform(pos)

#        self.annotate_point(pos,xy=(1-0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,va='top',ha='right')

        self.plot_tracer_point(pos[0],linestyle='--',color='red',alpha=.5)

        self.canvas.draw()

        event.Skip()

    def on_left_click_down(self,event):
        if self.plot_setting!="Pick": event.Skip(); return
        pos=event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos = [pos[0],height-pos[1]]
        pos = self.ax0.transData.inverted().transform(pos)
        self.tmp_new_bounds = [pos[0],None]
        self.mouse_left_down = True
        event.Skip()

    def on_left_click_up(self,event):
        if self.plot_setting!="Pick": event.Skip(); return
        pos=event.GetPosition()
        width, height = self.canvas.get_width_height()
        pos = [pos[0],height-pos[1]]
        pos = self.ax0.transData.inverted().transform(pos)
        self.tmp_new_bounds[1] = pos[0]
        self.mouse_left_down = False

        if abs(self.tmp_new_bounds[1]-self.tmp_new_bounds[0])>0:
            self.low_bound_box.SetValue("%.1f"%float(min(self.tmp_new_bounds)))
            self.high_bound_box.SetValue("%.1f"%float(max(self.tmp_new_bounds)))

        self.update()

        event.Skip()

    ##########################Additional Plotting and Backend Functions################

    def on_parent_select_track(self):
        self.update()

    def plot_tracer_point(self,x,**kwargs):
        try:
            for tracer in self.tracers:
                tracer.remove()
        except (AttributeError,ValueError) as e: pass
        self.tracers = []
        self.tracers.append(self.ax0.axvline(x,**kwargs))
        self.tracers.append(self.ax1.axvline(x,**kwargs))
        self.tracers.append(self.ax2.axvline(x,**kwargs))
        if self.mouse_left_down:
            myCursor= wx.StockCursor(wx.CURSOR_IBEAM)
            self.canvas.SetCursor(myCursor)
            self.tracers.append(self.ax0.axvspan(min([self.tmp_new_bounds[0],x]),max([self.tmp_new_bounds[0],x]),color="yellow",alpha=.4))
            self.tracers.append(self.ax1.axvspan(min([self.tmp_new_bounds[0],x]),max([self.tmp_new_bounds[0],x]),color="yellow",alpha=.4))
            self.tracers.append(self.ax2.axvspan(min([self.tmp_new_bounds[0],x]),max([self.tmp_new_bounds[0],x]),color="yellow",alpha=.4))

    def draw_figures(self):

        ####################################################Get Values
        dsk_row = self.parent.dsk_row
        track = self.parent.track
        ddis = float(self.parent.samp_dis_box.GetValue())
        if ddis==0: self.parent.user_warning("Synthetic is required for comparision of phase, start by initalilzing a synthetic"); return
        synth_dis = self.parent.dis_synth
        synth_mag = self.parent.synth

        filter_type = self.filter_type_box.GetValue()
        lowcut = float(self.lowcut_box.GetValue())
        highcut = float(self.highcut_box.GetValue())
        order = int(self.order_box.GetValue())

        left_bound = float(self.low_bound_box.GetValue())
        right_bound = float(self.high_bound_box.GetValue())
        aero_diff = float(self.aero_diff_box.GetValue())

        left_idx = np.argmin(np.abs(synth_dis-left_bound))
        right_idx = np.argmin(np.abs(synth_dis-right_bound))
        left_idx,right_idx = min([left_idx,right_idx]),max([left_idx,right_idx])

        bin_range,bin_num = (-180,180),120

        ###################################################Filter Data

        data_path = os.path.join(dsk_row["data_dir"],dsk_row["comp_name"])
        data_df = utl.open_mag_file(data_path)
        projected_distances = utl.calc_projected_distance(dsk_row['inter_lon'],dsk_row['inter_lat'],data_df['lon'].tolist(),data_df['lat'].tolist(),(180+dsk_row['strike'])%360)
        shifted_mag = sk.phase_shift_data(data_df["mag"],dsk_row["phase_shift"])
        if np.any(np.diff(projected_distances["dist"])<0): itshifted_mag = np.interp(-synth_dis,-projected_distances["dist"],shifted_mag)
        else: itshifted_mag = np.interp(synth_dis,projected_distances["dist"],shifted_mag)
        fitshifted_mag = self.filters[filter_type](itshifted_mag,lowcut,highcut,fs=1/ddis,order=order)

        ###################################################Actual Plotting

        outer = gridspec.GridSpec(4, 1)

        ###################################################Axis 0: Magnetic profiles
        self.ax0 = self.fig.add_subplot(outer[0])

        if self.parent.show_other_comp: #Handle Other Aeromag Component

            if dsk_row["track_type"]=="aero":
                if "Ed.lp" in track:
                    other_track = track.replace("Ed.lp","Vd.lp")
                    total_track = track.replace("Ed.lp","Td.lp")
                    other_phase = dsk_row["phase_shift"]-90
                elif "Hd.lp" in track:
                    other_track = track.replace("Hd.lp","Vd.lp")
                    total_track = track.replace("Hd.lp","Td.lp")
                    other_phase = dsk_row["phase_shift"]-90
                elif "Vd.lp" in track:
                    other_track = track.replace("Vd.lp","Ed.lp")
                    total_track = track.replace("Vd.lp","Td.lp")
                    if other_track not in self.parent.deskew_df["comp_name"].tolist(): other_track = track.replace("Vd.lp","Hd.lp")
                    other_phase = dsk_row["phase_shift"]+90
                else: self.parent.user_warning("Improperly named component files should have either Ed.lp, Hd.lp, or Vd.lp got: %s"%track); return
                oth_row = self.parent.deskew_df[self.parent.deskew_df["comp_name"]==other_track].iloc[0]

                oth_data_path = os.path.join(oth_row["data_dir"],oth_row["comp_name"])
                tot_data_path = os.path.join(oth_row["data_dir"],total_track) #Should be in same place

                oth_data_df = utl.open_mag_file(oth_data_path)
                oth_shifted_mag = sk.phase_shift_data(oth_data_df["mag"],other_phase)
                if np.any(np.diff(projected_distances["dist"])<0): oth_itshifted_mag = np.interp(-synth_dis,-projected_distances["dist"],oth_shifted_mag)
                else: oth_itshifted_mag = np.interp(synth_dis,projected_distances["dist"],oth_data_df)
                oth_fitshifted_mag = self.filters[filter_type](oth_itshifted_mag,lowcut,highcut,fs=1/ddis,order=order)
                if filter_type=="None": psk.plot_skewness_data(oth_row,other_phase,self.ax0,xlims=[None,None],color='darkgreen',zorder=2,picker=True,alpha=.7,return_objects=True,flip=True)
                else: self.ax0.plot(synth_dis,oth_fitshifted_mag,color="#299C29",zorder=3,alpha=.6)

                tot_data_df = utl.open_mag_file(tot_data_path)
                if np.any(np.diff(projected_distances["dist"])<0): tot_imag = np.interp(-synth_dis,-projected_distances["dist"],tot_data_df["mag"])
                else: tot_imag = np.interp(synth_dis,projected_distances["dist"],tot_data_df["mag"])
                tot_fimag = self.filters[filter_type](tot_imag,lowcut,highcut,fs=1/ddis,order=order)

        if filter_type=="None": psk.plot_skewness_data(dsk_row,dsk_row["phase_shift"],self.ax0,xlims=[None,None],zorder=3,picker=True,return_objects=True,flip=True)
        else: self.ax0.plot(synth_dis,fitshifted_mag,color="#7F7D7D",zorder=3,alpha=.6)
        self.ax0.plot(self.parent.dis_synth,self.parent.synth,'r-',alpha=.4,zorder=1)
        self.ax0.set_ylabel("Magnetic Profiles")
#        self.ax0.get_xaxis().set_ticklabels([])

        ###################################################Axis 1/2: Phase Angles and Differences

        self.ax1 = self.fig.add_subplot(outer[1], sharex=self.ax0)
        self.ax2 = self.fig.add_subplot(outer[2], sharex=self.ax0)

        ###################################################Calculate: Phase Differences
        trimmed_dis = synth_dis[left_idx:right_idx]
        trimmed_synth = synth_mag[left_idx:right_idx]
        trimmed_fitshifted_mag = fitshifted_mag[left_idx:right_idx]

        al_data = np.angle(hilbert(fitshifted_mag),deg=False)[left_idx:right_idx]
        al_synth = np.angle(hilbert(np.real(synth_mag)),deg=False)[left_idx:right_idx]

        data_synth_diff = phase_diff_func(al_synth,al_data)

        if self.parent.show_other_comp and dsk_row["track_type"]=="aero":
            trimmed_oth_fitshifted_mag = oth_fitshifted_mag[left_idx:right_idx]
            al_oth = np.angle(hilbert(oth_fitshifted_mag),deg=False)[left_idx:right_idx]

            oth_synth_diff = phase_diff_func(al_synth,al_oth)
            oth_data_diff = phase_diff_func(al_oth,al_data)

            if abs(aero_diff) > 0:
                idx = ma.array(np.abs(oth_data_diff)<aero_diff)

                self.ax1.plot((trimmed_dis[~idx]),(np.rad2deg(al_oth[~idx])),color="darkgreen",linestyle=":")

                self.ax2.plot((trimmed_dis[~idx]),(oth_synth_diff[~idx]),color="tab:pink",alpha=.8,linestyle=":")
                self.ax2.plot((trimmed_dis[~idx]),(oth_data_diff[~idx]),color="tab:grey",alpha=.8,linestyle=":")

                self.ax1.plot((trimmed_dis[~idx]),(np.rad2deg(al_data[~idx])),color="k",linestyle=":")
                self.ax1.plot((trimmed_dis[~idx]),(np.rad2deg(al_synth[~idx])),color="r",linestyle=":")

                self.ax2.plot((trimmed_dis[~idx]),(data_synth_diff[~idx]),color="tab:red",alpha=.8,linestyle=":")

#                import pdb; pdb.set_trace()
#                not_trimmed_dis = (trimmed_dis[~idx])
#                not_trimmed_dis[np.diff(~idx,prepend=[0])] = ma.masked
#                not_al_data = (al_data[~idx])
#                not_al_data[np.diff(~idx)] = ma.masked
#                not_al_synth = (al_synth[~idx])
#                not_al_synth[np.diff(~idx)] = ma.masked
#                not_al_oth = (al_oth[~idx])
#                not_al_oth[np.diff(~idx)] = ma.masked
#                not_data_synth_diff = (data_synth_diff[~idx])
#                not_data_synth_diff[np.diff(~idx)] = ma.masked
#                not_oth_synth_diff = (oth_synth_diff[~idx])
#                not_oth_synth_diff[np.diff(~idx)] = ma.masked
#                not_oth_data_diff = (oth_data_diff[~idx])
#                not_oth_data_diff[np.diff(~idx)] = ma.masked
                trimmed_dis = (trimmed_dis[idx])
                al_data = (al_data[idx])
                al_synth = (al_synth[idx])
                al_oth = (al_oth[idx])
                data_synth_diff = (data_synth_diff[idx])
                oth_synth_diff = (oth_synth_diff[idx])
                oth_data_diff = (oth_data_diff[idx])

            self.ax1.plot(trimmed_dis,np.rad2deg(al_oth),color="darkgreen")

            self.ax2.plot(trimmed_dis,oth_synth_diff,color="tab:pink",alpha=.8)
            self.ax2.plot(trimmed_dis,oth_data_diff,color="tab:grey",alpha=.8)

        self.ax1.plot(trimmed_dis,np.rad2deg(al_data),color="k")
        self.ax1.plot(trimmed_dis,np.rad2deg(al_synth),color="r")

        self.ax2.plot(trimmed_dis,data_synth_diff,color="tab:red",alpha=.8)
#        self.ax2.get_xaxis.set_ticklabels
        self.ax0.set_xlim(*self.parent.ax.get_xlim())
        self.ax0.set_ylim(*self.parent.ax.get_ylim())

        self.ax1.set_ylabel("Phase Angles")
        self.ax2.set_ylabel("Phase Differences")


        ###################################################Axis 2.1: Power Spectrum
#        inner = gridspec.GridSpecFromSubplotSpec(1, 2, subplot_spec=outer[2])#, hspace=0.)
#        self.ax2 = self.fig.add_subplot(inner[0])


        ###################################################Axis 2.2: Phase Statistics
        self.ax3 = self.fig.add_subplot(outer[3])

        if self.parent.show_other_comp and dsk_row["track_type"]=="aero":
            self.ax3.hist(oth_synth_diff,range=bin_range,bins=bin_num,color="tab:pink",alpha=.5,zorder=2)
            self.ax3.hist(oth_data_diff,range=bin_range,bins=bin_num,color="tab:grey",alpha=.5,zorder=1)

        self.ax3.hist(data_synth_diff,range=bin_range,bins=bin_num,color="tab:red",alpha=.5,zorder=3)
        self.ax3.axvline(np.median(data_synth_diff),color="k",alpha=.5,zorder=5,linestyle=":")
        self.ax3.axvline(np.mean(data_synth_diff),color="k",alpha=.5,zorder=5)
        self.ax3.axvspan(np.mean(data_synth_diff)-np.std(data_synth_diff),np.mean(data_synth_diff)+np.std(data_synth_diff),color="tab:grey",alpha=.3,zorder=0)

        self.ax3.annotate(r"$\theta_{mean}$ = $%.1f^\circ \pm %.1f^\circ$"%(np.mean(data_synth_diff),np.std(data_synth_diff)) + "\n" + r"$\theta_{median}$ = %.1f$^\circ$"%np.median(data_synth_diff),xy=(0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,va='top',ha='left')

        self.ax3.set_ylabel(r"$\Delta \theta$ Count")

        self.fig.suptitle("%s\n%s\n"%(dsk_row["sz_name"],track))

        ###################################################Power Figure

        N = (right_idx-left_idx) #Length of signal in distance domain
        NW = 3 #following Parker and O'brien '97 and HJ-Gordon '03 we use a time-bandwith product of 6 (Nw is half)
        Ns = 5 #Number of points to use in running average smoothing

        #Handle Distance Domain
#        import pdb; pdb.set_trace()
        Sk_complex, weights, eigenvalues=pmtm(itshifted_mag[left_idx:right_idx], NW=NW, NFFT=N, show=False)
        Sk = np.abs(Sk_complex)**2
        smoothed_tshifted_freq = (np.mean(Sk * np.transpose(weights), axis=0) * ddis)[N//2:][::-1]
#        smoothed_tshifted_freq = np.convolve(smoothed_tshifted_freq, np.ones((Ns,))/Ns, mode='same') #10 point running average smoothing
        tdata_freqs = np.linspace(0.0, 1.0/(2.0*ddis), N-N//2) #0 to Nyquest

        self.power_ax = self.power_fig.add_subplot(111)

        if self.parent.show_other_comp and dsk_row["track_type"]=="aero":
            Sk_complex, weights, eigenvalues=pmtm(oth_itshifted_mag[left_idx:right_idx], NW=NW, NFFT=N, show=False)
            Sk = np.abs(Sk_complex)**2
            oth_smoothed_tshifted_freq = (np.mean(Sk * np.transpose(weights), axis=0) * ddis)[N//2:][::-1]
#            oth_smoothed_tshifted_freq = np.convolve(oth_smoothed_tshifted_freq, np.ones((Ns,))/Ns, mode='same') #10 point running average smoothing
            self.power_ax.semilogy(tdata_freqs, oth_smoothed_tshifted_freq, color="darkgreen")
#            self.power_ax.semilogy(tdata_freqs, oth_smoothed_tshifted_freq+smoothed_tshifted_freq, color="grey")


            Sk_complex, weights, eigenvalues=pmtm(tot_imag[left_idx:right_idx], NW=NW, NFFT=N, show=False)
            Sk = np.abs(Sk_complex)**2
            tot_smoothed_tshifted_freq = (np.mean(Sk * np.transpose(weights), axis=0) * ddis)[N//2:][::-1]
#            tot_smoothed_tshifted_freq = np.convolve(tot_smoothed_tshifted_freq, np.ones((Ns,))/Ns, mode='same') #10 point running average smoothing
            self.power_ax.semilogy(tdata_freqs, tot_smoothed_tshifted_freq, color="tab:orange")

        #Old Numpy Method
#        synth_freqs = np.fft.fftfreq(len(synth_dis[left_idx:right_idx]),ddis)
#        tdata_freqs = np.fft.fftfreq(len(shifted_mag[left_idx:right_idx]),ddis)
#        tshifted_freq = np.fft.fft(shifted_mag[left_idx:right_idx])
#        fitshifted_freq = np.fft.fft(fitshifted_mag[left_idx:right_idx])
#        tsynth_freq = np.fft.fft(synth_mag[left_idx:right_idx])

        self.power_ax.semilogy(tdata_freqs, smoothed_tshifted_freq, color="k",zorder=100)

#        self.power_ax.semilogy(tdata_freqs, np.abs(tshifted_freq), color="k")
#        self.power_ax.plot(synth_freqs, np.abs(fitshifted_freq), color="#7F7D7D")
#        self.power_ax.plot(synth_freqs, np.abs(tsynth_freq), color="r")

        self.power_ax.set_xlim(0.0,0.4)
        self.power_ax.set_ylim(1e-1,1e6)
Esempio n. 19
0
class ImageLabeler(wx.App):
    '''
    The Main Application Class
    '''
    def __init__(self, starting_image=None, image_dir=None, conf_dir=None):

        wx.App.__init__(self)

        self.labeler_dir = labeler.__path__[0]
        self.starting_image = starting_image
        self.image_dir = image_dir

        # Mode that the labeler should use: single or batch
        self.labeler_mode = "single"

        # Frame that will contain image and grid
        self.frame = wx.Frame(None, title='Image Display')

        #What is the display of the monitor
        self.monitor_size = wx.GetDisplaySize()

        # Where does our code live
        self.bin_dir = os.path.dirname(os.path.abspath(__file__))
        self.CanvasPanel = wx.Panel(self.frame,
                                    style=wx.BORDER_SUNKEN | wx.CLOSE_BOX
                                    | wx.SYSTEM_MENU | wx.CAPTION)
        self.CanvasPanel.SetBackgroundColour("dark gray")

        self.frame.Bind(wx.EVT_CLOSE, self.OnFileExit)

        # Intitialise the matplotlib figure
        self.figure = Figure()

        # Create an axes, turn off the labels and add them to the figure
        self.axes = plt.Axes(self.figure, [0, 0, 1, 1])
        self.axes.set_axis_off()
        self.figure.add_axes(self.axes)

        # Add the figure to the wxFigureCanvas
        self.canvas = FigureCanvas(self.CanvasPanel, -1, self.figure)
        self.toolbar = NavigationToolbar(self.canvas)
        self.toolbar.Realize()
        self.toolbar.Hide()

        # What mode is the cursor in: bb,toolbar
        self.cursor_mode = "nobb"

        # Connect the mouse events to their relevant callbacks
        self.canvas.mpl_connect('button_press_event', self.OnLeftDown)
        self.canvas.mpl_connect('button_release_event', self.OnLeftUp)
        self.canvas.mpl_connect('motion_notify_event', self.OnMotion)
        self.canvas.mpl_connect('key_press_event', self.OnKeyDown)

        # Lock to stop the motion event from behaving badly when the mouse isn't pressed
        self.frame.pressed = False

        # Setting up the file menu
        filemenu = wx.Menu()
        menuAbout = filemenu.Append(wx.ID_ABOUT, "&About",
                                    "Information About This Program")
        menuOpenGrid = filemenu.Append(wx.ID_FILE, "&Open Grid",
                                       "Open File Containing Bounding Boxes")
        menuOpenImage = filemenu.Append(wx.ID_OPEN, "&Open Image",
                                        "Open Image File")
        menuSaveGrid = filemenu.Append(wx.ID_SAVE, "&Save Grid",
                                       "Save Bounding Boxes to CSV File")
        menuSaveImage = filemenu.Append(wx.ID_SAVEAS, "&Save Image",
                                        "Save Image")
        menuExit = filemenu.Append(wx.ID_EXIT, "&Exit", "Exit Image Labeler")

        # Setting up the models menu
        configmenu = wx.Menu()
        menuConfigModel = configmenu.Append(wx.ID_ABOUT, "&Models",
                                            "Configure Custom Models")

        # Creating the menubar.
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,
                       "&File")  # Adding the "filemenu" to the MenuBar
        menuBar.Append(configmenu, "&Config")
        self.frame.SetMenuBar(
            menuBar)  # Adding the MenuBar to the Frame content.

        # Set events for menuBar things
        self.frame.Bind(wx.EVT_MENU, self.OnFileAbout, menuAbout)
        self.frame.Bind(wx.EVT_MENU, self.OnFileOpen, menuOpenImage)
        self.frame.Bind(wx.EVT_MENU, self.OnImportGrid, menuOpenGrid)
        self.frame.Bind(wx.EVT_MENU, self.OnFileExit, menuExit)
        self.frame.Bind(wx.EVT_MENU, self.OnSaveGrid, menuSaveGrid)
        self.frame.Bind(wx.EVT_MENU, self.OnSaveImage, menuSaveImage)
        self.frame.Bind(wx.EVT_MENU, self.OnConfigModel, menuConfigModel)

        #Keep track of how many images you have displayed
        self.imagecounter = 0

        #Define where this program should find images
        if self.image_dir == None:
            self.image_dir = os.getcwd()

        # Get list of image files in the image_dir
        self.images_obj = get_list_files(self.image_dir)

        if self.images_obj != None:
            self.labeler_mode = "batch"
        else:
            print(
                "Warning: no images found in image path or current directory.")

        #What image will we be starting on
        if self.starting_image != None:  #use the one specified on the command line.
            self.imagepath = self.starting_image
        elif self.labeler_mode == "single":  #Just use the default application image
            print("Info: Using application default image:",
                  self.labeler_dir + "/image.jpg")
            self.imagepath = self.labeler_dir + "/image.jpg"

        elif self.labeler_mode == "batch":
            print(
                "Info: Starting labeler in batch mode, multiple images detected."
            )
            #in batch mode start with the first image
            self.imagepath = self.images_obj[0]['path']

        # Create Panel to display Bounding Box Coordinates
        self.BBPanel = wx.Panel(self.frame,
                                style=wx.BORDER_SUNKEN | wx.CLOSE_BOX
                                | wx.SYSTEM_MENU | wx.CAPTION)
        self.BBPanel.SetBackgroundColour("dark gray")

        # Create the Grid to Hold the Coordinates
        self.BBGrid = gridlib.Grid(self.BBPanel)
        self.BBGrid.CreateGrid(100, 5)
        self.BBGrid.SetColLabelValue(0, "X1")
        self.BBGrid.SetColLabelValue(1, "Y1")
        self.BBGrid.SetColLabelValue(2, "X2")
        self.BBGrid.SetColLabelValue(3, "Y2")
        self.BBGrid.SetColLabelValue(4, "Label")

        BBsizer = wx.BoxSizer(wx.VERTICAL)
        BBsizer.Add(self.BBGrid, 1, wx.EXPAND | wx.ALL)

        # Do Some things when the mouse clicks inside of the Grid
        self.BBGrid.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnGridLeft)
        # Do some things when delete key is pressed inside of the grid
        self.BBGrid.Bind(wx.EVT_KEY_DOWN, self.OnGridDelete)
        # Get rid of row labels
        self.BBGrid.SetRowLabelSize(0)
        # Set all columns to read only, except the Label column
        set_grid_edit(self)
        #self.BBGrid.EnableEditing(False)

        self.BBPanel.SetSizer(BBsizer)

        # Create Panel for Image Controls
        self.ControlPanel = wx.Panel(self.frame,
                                     style=wx.BORDER_SUNKEN | wx.CLOSE_BOX
                                     | wx.SYSTEM_MENU | wx.CAPTION)
        self.ControlBox = wx.BoxSizer(wx.VERTICAL)
        self.ControlBox.Add(self.ControlPanel)
        self.ControlPanel.SetBackgroundColour("dark gray")

        # Create Buttons to help label image
        self.button_list = []

        self.selected_button = "HOME"

        self.sibut = wx.Button(self.ControlPanel,
                               -1,
                               size=(50, 50),
                               pos=(5, 5),
                               name="zoom")
        zoom_img = wx.Image(self.labeler_dir + '/icons/zoom.png',
                            wx.BITMAP_TYPE_ANY)
        zoom_img = zoom_img.Scale(20, 20)
        self.sibut.SetBitmap(wx.Bitmap(zoom_img))
        self.sibut.Bind(wx.EVT_BUTTON, self.zoom)
        self.button_list.append(self.sibut)

        self.hmbut = wx.Button(self.ControlPanel,
                               -1,
                               size=(50, 50),
                               pos=(60, 5),
                               name="home")
        home_img = wx.Image(self.labeler_dir + '/icons/home.png',
                            wx.BITMAP_TYPE_ANY)
        home_img = home_img.Scale(20, 20)
        self.hmbut.SetBitmap(wx.Bitmap(home_img))
        self.hmbut.Bind(wx.EVT_BUTTON, self.home)
        self.button_list.append(self.hmbut)

        self.hibut = wx.Button(self.ControlPanel,
                               -1,
                               size=(50, 50),
                               pos=(115, 5),
                               name="pan")
        pan_img = wx.Image(self.labeler_dir + '/icons/pan.png',
                           wx.BITMAP_TYPE_ANY)
        pan_img = pan_img.Scale(20, 20)
        self.hibut.SetBitmap(wx.Bitmap(pan_img))
        self.hibut.Bind(wx.EVT_BUTTON, self.pan)
        self.button_list.append(self.hibut)

        self.plotbut = wx.Button(self.ControlPanel,
                                 -1,
                                 size=(50, 50),
                                 pos=(170, 5),
                                 name="bbox")
        box_img = wx.Image(self.labeler_dir + '/icons/bbox.png',
                           wx.BITMAP_TYPE_ANY)
        box_img = box_img.Scale(20, 20)
        self.plotbut.SetBitmap(wx.Bitmap(box_img))
        self.plotbut.Bind(wx.EVT_BUTTON, self.plot)
        self.button_list.append(self.plotbut)

        # Create Panel Controls for Dataset movement
        self.BatchPanel = wx.Panel(self.frame,
                                   style=wx.BORDER_SUNKEN | wx.CLOSE_BOX
                                   | wx.SYSTEM_MENU | wx.CAPTION)
        self.BatchBox = wx.BoxSizer(wx.VERTICAL)
        self.BatchBox.Add(self.BatchPanel)
        self.BatchPanel.SetBackgroundColour("dark gray")

        self.prevbut = wx.Button(self.BatchPanel,
                                 -1,
                                 size=(50, 50),
                                 pos=(7, 5))
        box_img = wx.Image(self.labeler_dir + '/icons/left_arrow.png',
                           wx.BITMAP_TYPE_ANY)
        box_img = box_img.Scale(20, 20)
        self.prevbut.SetBitmap(wx.Bitmap(box_img))
        self.prevbut.Bind(wx.EVT_BUTTON, self.prev)

        self.nextbut = wx.Button(self.BatchPanel,
                                 -1,
                                 size=(50, 50),
                                 pos=(60, 5))
        box_img = wx.Image(self.labeler_dir + '/icons/right_arrow.png',
                           wx.BITMAP_TYPE_ANY)
        box_img = box_img.Scale(20, 20)
        self.nextbut.SetBitmap(wx.Bitmap(box_img))
        self.nextbut.Bind(wx.EVT_BUTTON, self.next)

        if self.labeler_mode == "single":  #Disable button in single mode
            self.nextbut.Disable()
            self.prevbut.Disable()

        # Create Panel for Grid controls
        self.GridControlPanel = wx.Panel(self.frame,
                                         style=wx.BORDER_SUNKEN | wx.CLOSE_BOX
                                         | wx.SYSTEM_MENU | wx.CAPTION)
        self.GridControlBox = wx.BoxSizer(wx.VERTICAL)
        self.GridControlBox.Add(self.GridControlPanel)
        self.GridControlPanel.SetBackgroundColour("dark gray")

        # Button to import csv file with bounding boxes
        self.imbut = wx.Button(self.GridControlPanel,
                               -1,
                               size=(50, 50),
                               pos=(5, 5))
        imp_img = wx.Image(self.labeler_dir + '/icons/import.png',
                           wx.BITMAP_TYPE_ANY)
        imp_img = imp_img.Scale(20, 20)
        self.imbut.SetBitmap(wx.Bitmap(imp_img))
        self.imbut.Bind(wx.EVT_BUTTON, self.OnImportGrid)

        # Button to save grid to csv file
        self.grsavebut = wx.Button(self.GridControlPanel,
                                   -1,
                                   size=(50, 50),
                                   pos=(60, 5))
        save_img = wx.Image(self.labeler_dir + '/icons/filesave.png',
                            wx.BITMAP_TYPE_ANY)
        save_img = save_img.Scale(20, 20)
        self.grsavebut.SetBitmap(wx.Bitmap(save_img))
        self.grsavebut.Bind(wx.EVT_BUTTON, self.save_grid)

        # Button to delete grid and bounding boxes
        self.grdelbut = wx.Button(self.GridControlPanel,
                                  -1,
                                  size=(50, 50),
                                  pos=(115, 5))
        del_img = wx.Image(self.labeler_dir + '/icons/delete_all.png',
                           wx.BITMAP_TYPE_ANY)
        del_img = del_img.Scale(20, 20)
        self.grdelbut.SetBitmap(wx.Bitmap(del_img))
        self.grdelbut.Bind(wx.EVT_BUTTON, self.clear_bb)

        # Are we moving the rectangle or creating a new one
        self.is_moving = False

        # Hold list of rectangle objects
        self.rect_obj_list = []
        self.rect_labels = []

        # A Statusbar i the bottom of the window
        self.frame.CreateStatusBar()
        self.frame.Show(True)

        self.FirstImage()

        # Frame for image transformations
        self.TransFrame = TransFrame(None, self)

        # Frame for image segmentation
        self.SegFrame = SegmentFrame(None, self)

        # Frame for configuring models
        self.ModelFrame = None

    def OnGridLeft(self, event):
        '''
            Action taken when left click happens on grid
        '''
        row = event.GetRow()
        self.selected_rect = row
        self.change_rect_color()
        highlight_row(self, row)

    def OnGridDelete(self, event):
        '''
            Delete row in grid
        '''
        row = self.BBGrid.GetGridCursorRow()
        col = self.BBGrid.GetGridCursorCol()

        if event.GetKeyCode() == wx.WXK_DELETE:
            self.OnDelete()

    def toggle_cursor_mode(self, button, name):
        '''  
            Change cursor_mode between bb and rest toolbar 
            Hides active button
        '''

        for butt in self.button_list:
            if button == butt:
                if name == "home":  # This one doesn't need to be hidden
                    next
                else:
                    butt.Hide()
            else:
                butt.Show()

    def zoom(self, event):
        '''
            Use Matplotlibs zoom tool
        '''
        self.cursor_mode = "nobb"

        self.toggle_cursor_mode(self.sibut, "zoom")
        self.toolbar.zoom()
        # Toggle off other buttons
        if self.selected_button == 'HOME':
            self.toolbar.home()
        elif self.selected_button == 'PAN':
            self.toolbar.pan()
        elif self.selected_button == 'PLOT`':
            self.toolbar.plot()

        self.selected_button = "ZOOM"

    def toggle_off_mode(self):
        ''' 
           Turn off any button that is selected
        '''

        # Toggle off other buttons
        if self.selected_button == 'ZOOM':
            self.toolbar.zoom()
        elif self.selected_button == 'PAN':
            self.toolbar.pan()
        elif self.selected_button == 'PLOT`':
            self.toolbar.plot()
        elif self.selected_button == 'HOME':
            self.toolbar.home()

    def home(self, event):
        '''
            Return view back to original position
        '''
        self.cursor_mode = "nobb"
        self.toggle_cursor_mode(self.hmbut, "home")

        self.toolbar.home()

        # Reset axes so they don't get messed up when zooming
        self.axes.set_xbound(0, self.image_shape[1])
        self.axes.set_ybound(0, self.image_shape[0])

        self.toggle_off_mode()
        self.selected_button = "HOME"

    def pan(self, event):
        '''
            Uses Matplotlibs pan tool
        '''
        self.cursor_mode = "nobb"
        self.toggle_cursor_mode(self.hibut, "pan")
        self.toolbar.pan()

        self.toggle_off_mode()
        self.selected_button = "PAN"

    def plot(self, event):
        '''
            Draw a rectangle on the canvas
        '''
        self.cursor_mode = "bb"
        self.toggle_cursor_mode(self.plotbut, "plot")
        # Set Crosshair as mouse cursor.

        self.toggle_off_mode()
        self.selected_button = "PLOT"

    def next(self, event):
        '''
            Move to next image
        '''
        self.cursor_mode = "nobb"
        self.toggle_cursor_mode(self.nextbut, "next")

        # Find Out which image you are currently on in self.images_obj
        i = 0
        for obj in self.images_obj:
            if obj['path'] == self.imagepath:
                self.cur_obj_num = i
                break
            i += 1

        if self.cur_obj_num + 1 == len(self.images_obj):
            self.user_error("There are no more images left to work on.")
            self.cur_obj_num = 0
            return 0

        self.cur_obj_num += 1

        # Now display the new image
        self.imagepath = self.images_obj[self.cur_obj_num]['path']
        self.NewImage()

    def prev(self, event):
        '''
            Move to previous image
        '''
        self.cursor_mode = "nobb"
        self.toggle_cursor_mode(self.prevbut, "prev")
        # Find Out which image you are currently on in self.images_obj
        i = 0
        for obj in self.images_obj:
            if obj['path'] == self.imagepath:
                self.cur_obj_num = i
                break
            i += 1

        if self.cur_obj_num == 0:
            self.user_error("You are on the first image.")
            return 0

        self.cur_obj_num -= 1

        # Now display the new image
        self.imagepath = self.images_obj[self.cur_obj_num]['path']
        self.NewImage()

    def OnFileExit(self, event):
        '''
            Close every frame in the app.
        '''
        self.frame.Destroy()
        self.TransFrame.Close()
        self.SegFrame.Close()
        if self.ModelFrame != None:
            self.ModelFrame.Close()

    def OnImportGrid(self, event):
        '''
            Choose CSV file with coordinates to import.
        '''
        with wx.FileDialog(self.frame,
                           "Import CSV File",
                           wildcard="*.csv",
                           style=wx.FD_OPEN) as fileDialog:
            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Get Pathname
            pathname = fileDialog.GetPath()

            # Read file into list
            new_coords = import_grid_csv(self, pathname)

            # Loop through coordinates and draw rectangle
            for coord in new_coords:
                self.draw_rect(coord)

            self.canvas.draw()

    def OnConfigModel(self, event):
        self.ModelFrame = ModelFrame(None, self)

    def draw_rect(self, rect):
        if len(rect) > 4:
            x0, y0, x1, y1, label = rect
            self.rect_labels.append(label)
        else:
            x0, y0, x1, y1 = rect
            self.rect_labels.append("")

        x0 = int(x0)
        y0 = int(y0)
        x1 = int(x1)
        y1 = int(y1)

        if x0 < 0:
            x0 = 0
        if x1 < 0:
            x1 = 0
        if y0 < 0:
            y0 = 0
        if y1 < 0:
            y1 = 0

        max_height = self.image_shape[0]
        max_width = self.image_shape[1]

        if x0 > max_width:
            x0 = max_width
        if x1 > max_width:
            x1 = max_width
        if y0 > max_height:
            y0 = max_height
        if y1 > max_height:
            y1 = max_height

        width = int(x1) - int(x0)
        height = int(y1) - int(y0)

        self.rect = Rectangle((int(x0), int(y0)),
                              width,
                              height,
                              facecolor='None',
                              edgecolor='green',
                              linewidth='2')
        self.axes.add_patch(self.rect)
        self.rect_obj_list.append(self.rect)

    def OnSaveGrid(self, event):
        '''
            Choose filename to save a CSV with grid with the coordinates.
        '''
        with wx.FileDialog(self.frame,
                           "Save CSV file",
                           wildcard="*.csv",
                           style=wx.FD_SAVE
                           | wx.FD_OVERWRITE_PROMPT) as fileDialog:
            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Get Pathname
            pathname = fileDialog.GetPath()

            # Write to that file
            write_grid_csv(self, pathname)

    def OnSaveImage(self, event):
        '''
            Choose filename to save the image.
        '''
        with wx.FileDialog(self.frame,
                           "Save an image file",
                           style=wx.FD_SAVE
                           | wx.FD_OVERWRITE_PROMPT) as fileDialog:
            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Get Pathname
            imagepathname = fileDialog.GetPath()

            # Write to that file
            write_image(self, imagepathname)

    def OnFileOpen(self, event):
        ''' 
            Open Dialog so user can select a new image. 
        '''
        # Get the file path you wan to open.
        with wx.FileDialog(self.frame,
                           "Open Image File",
                           wildcard="Image Files *.png|*.jpg",
                           style=wx.FD_OPEN
                           | wx.FD_FILE_MUST_EXIST) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Proceed loading the file chosen by the user
            pathname = fileDialog.GetPath()
            self.imagepath = pathname

            self.NewImage()

    def OnFileAbout(self, event):
        '''
            Display information about the application
        '''
        # A message dialog box with an OK button. wx.OK is a standard ID in wxWidgets.
        dlg = wx.MessageDialog(self.frame, "A GUI for labeling images",
                               "About Image Labeler", wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def OnKeyDown(self, event):
        '''
            Actions to be taken when a key is pressed
        '''
        if event.key == 'delete':
            self.OnDelete()

    def OnLeftDown(self, event):
        '''
            Actions taken when mouse button is pressed
        '''
        # Is the click inside a rectangle?
        found = 0
        current_x = event.xdata
        current_y = event.ydata

        for i in range(len(self.rect_obj_list)):
            rect = self.rect_obj_list[i]
            result = check_inside_rect((current_x, current_y), rect)
            if result == 1:
                self.selected_rect = i
                found += 1

        # We want to select this rectangle, and move it
        if found > 0:
            self.is_moving = True
            self.change_rect_color()
            self.selected_rect_obj = self.rect_obj_list[self.selected_rect]
            self.x0, self.y0 = self.selected_rect_obj.xy
            self.x1 = None
            self.y1 = None
            self.press = self.x0, self.y0, event.xdata, event.ydata
            return 0

        if self.cursor_mode == "nobb":
            return 0

        # If the above is not satisified, it is time to draw a new rectangle
        # Initialise the rectangle
        self.rect = Rectangle((0, 0),
                              1,
                              1,
                              facecolor='None',
                              edgecolor='green',
                              linewidth='2')

        self.x0 = None
        self.y0 = None
        self.x1 = None
        self.y1 = None
        self.axes.add_patch(self.rect)

        # Check the mouse press was actually on the canvas
        if event.xdata is not None and event.ydata is not None:
            # Upon initial press of the mouse record the origin and record the mouse as pressed
            self.frame.pressed = True
            self.rect.set_linestyle('dashed')
            self.x0 = event.xdata
            self.y0 = event.ydata

    def OnMotion(self, event):
        '''
            Action taken when mouse movement happens over the canvas
        '''

        # If a rectangle is selected and needs to be moved
        if self.is_moving == True:
            if event.xdata is not None and event.ydata is not None:
                if self.press is None: return
                self.x0, self.y0, xpress, ypress = self.press
                dx = event.xdata - xpress
                dy = event.ydata - ypress
                self.x1 = self.x0 + dx
                self.y1 = self.y0 + dy
                self.selected_rect_obj.set_x(self.x1)
                self.selected_rect_obj.set_y(self.y1)
                self.selected_rect_obj.figure.canvas.draw()

            return 0
        # If the mouse has been pressed draw an updated rectangle when the mouse is
        # moved so the user can see what the current selection is
        elif self.frame.pressed:

            # Check the mouse was released on the canvas,
            # and if it wasn't then just leave the width and
            # height as the last values set by the motion event
            if event.xdata is not None and event.ydata is not None:
                self.x1 = event.xdata
                self.y1 = event.ydata

            # Set the width and height and draw the rectangle
            self.rect.set_width(self.x1 - self.x0)
            self.rect.set_height(self.y1 - self.y0)
            self.rect.set_xy((self.x0, self.y0))
            self.canvas.draw()

    def OnLeftUp(self, event):
        '''
            Actions taken with mouse button is released
        '''

        # Rectangle has finished moving and objects need to be updated.
        if self.is_moving == True:

            x0 = self.selected_rect_obj.get_bbox().x0
            y0 = self.selected_rect_obj.get_bbox().y0
            x1 = self.selected_rect_obj.get_bbox().x1
            y1 = self.selected_rect_obj.get_bbox().y1

            self.selected_rect_obj.figure.canvas.draw()
            self.is_moving = False

            self.press = None

            # Update Grid with new coordinates
            fill_grid(self)
            return 0
        # A new rectangle is finished being drawn
        elif self.frame.pressed:

            # Upon release draw the rectangle as a solid rectangle
            self.frame.pressed = False
            self.rect.set_linestyle('solid')

            # Check the mouse was released on the canvas, and if it wasn't then
            # just leave the width and height as the last values set by the motion event
            if event.xdata is not None and event.ydata is not None:
                self.x1 = event.xdata
                self.y1 = event.ydata

            # Set the width and height and origin of the bounding rectangle
            self.boundingRectWidth = self.x1 - self.x0
            self.boundingRectHeight = self.y1 - self.y0
            self.bouningRectOrigin = (self.x0, self.y0)

            # Draw the bounding rectangle
            self.rect.set_width(self.boundingRectWidth)
            self.rect.set_height(self.boundingRectHeight)
            self.rect.set_xy((self.x0, self.y0))
            self.canvas.draw()

            # Keep list of rect objects
            self.rect_obj_list.append(self.rect)
            self.rect_labels.append("")

            # Fill the grid with the bounding boxes
            fill_grid(self)

    def NewImage(self):
        '''
            A new image needs to be read in, and various objects need to be cleaned up.
        '''

        # Delete all rectangles from the canvas
        self.clear_bb()
        # Uncheck all transformation boxes
        self.TransFrame.reset_boxes()

        # Clear Rectangle List
        self.rect_obj_list = []
        self.rect_labels = []

        # Read image into original_image and current_image
        self.ReadImage()

        # Refresh the canvas
        self.RefreshImage()

    def ReadImage(self):
        ''' 
            Read image off disk
        '''
        self.original_image = cv2.imread(self.imagepath)

        #Matplotlib is RGB, opencv is BGR
        self.original_image = cv2.cvtColor(self.original_image,
                                           cv2.COLOR_BGR2RGB)
        self.current_image = self.original_image.copy()
        self.image_shape = self.current_image.shape

    def FirstImage(self):
        '''
            The very first image is handled differently
        '''
        # Read image into the original_image and current_image
        self.ReadImage()

        # Set Frame to size of image, plust a little extra
        self.frame.SetSize(
            (self.image_shape[1] + 550, self.image_shape[0] + 200))

        self.set_panels()

        # Display the image on the canvas
        self.img_obj = self.axes.imshow(self.current_image, cmap='gray')
        self.canvas.draw()

    def RefreshImage(self):
        '''
            Display new image to Matplotlib canvas and tiddy up
        '''

        # Set Frame to size of image, plust a little extra
        self.frame.SetSize(
            (self.image_shape[1] + 550, self.image_shape[0] + 200))

        self.set_panels()

        # Display the image on the canvas
        self.img_obj.set_extent(
            (0.0, self.image_shape[1], self.image_shape[0], 0.0))

        self.BasicRefresh()

    def BasicRefresh(self):
        self.img_obj.set_data(self.current_image)
        self.canvas.draw()

    def OnDelete(self):
        ''' 
            Delete the selected rectangle
        '''

        # Don't try to delete if empty
        if len(self.rect_obj_list) < 1:
            self.user_error("There is nothing to delete.")
            return 1

        try:
            self.selected_rect
        except:
            self.user_error("You haven't selected a rectangle yet.")
            return 1

        rectangle = self.rect_obj_list[self.selected_rect]
        # Remove object from list
        self.rect_obj_list.remove(rectangle)
        del self.rect_labels[self.selected_rect]
        # Remove object from canvas
        rectangle.remove()
        # Remove coordinates from grid
        self.BBGrid.DeleteRows(self.selected_rect)
        # redraw the canvas
        self.canvas.draw()

        # clear
        del self.selected_rect

    def change_rect_color(self):
        ''' 
            change the line color of currently selected rectangle
        '''
        # Set selected rectangle line color black
        if len(self.rect_obj_list) < 1:
            return 0

        rect = self.rect_obj_list[self.selected_rect]

        #set everything back to green
        for i in range(len(self.rect_obj_list)):
            rect = self.rect_obj_list[i]
            # Set currently selected rect line as black
            if i == self.selected_rect:
                rect.set_edgecolor('red')
            else:  # Set everything else as green
                rect.set_edgecolor('green')

        # Also highlight row in grid
        highlight_row(self, self.selected_rect)

        self.canvas.draw()

    def clear_bb(self, event=None):
        '''
            Remove all rectangles and empty grid
        '''

        for rectangle in self.rect_obj_list:
            # Remove object from canvas
            rectangle.remove()

        empty_grid(self)

        # Set the list back to empty
        self.rect_obj_list = []
        self.rect_labels = []

        # redraw the canvas
        self.canvas.draw()

    def set_panels(self):
        '''
            Set the size and position of the pannels based on the images size.
        '''

        grid_width = 425
        control_height = 70
        img_pane_max_width = self.monitor_size[0] - grid_width - 10
        img_pane_max_height = self.monitor_size[1] - control_height - 120

        #Set some common sense things in relation to image widths
        if self.image_shape[1] < 525:
            img_pane_width = 525
        elif self.image_shape[1] > img_pane_max_width:
            img_pane_width = img_pane_max_width
        else:
            img_pane_width = self.image_shape[1]

        #Set some common sense things in relation to image height
        if self.image_shape[0] < 525:
            img_pane_height = 525
        elif self.image_shape[0] > img_pane_max_height:
            img_pane_height = img_pane_max_height
        else:
            img_pane_height = self.image_shape[0]

        #Come up with what the frame size should be
        frame_width = img_pane_width + grid_width + 10
        frame_height = img_pane_height + control_height + 90

        self.CanvasPanel.SetPosition((0, 0))
        self.CanvasPanel.SetSize((img_pane_width, img_pane_height))

        self.ControlPanel.SetPosition((0, img_pane_height + 5))
        self.ControlPanel.SetSize((235, control_height))

        self.BatchPanel.SetPosition((240, img_pane_height + 5))
        self.BatchPanel.SetSize((125, control_height))

        self.BBPanel.SetPosition((img_pane_width + 5, 0))
        self.BBPanel.SetSize((grid_width, img_pane_height))

        self.GridControlPanel.SetPosition(
            (img_pane_width + 5, img_pane_height + 5))
        self.GridControlPanel.SetSize((grid_width, control_height))

        #Set Overall frame size
        self.frame.SetSize((frame_width, frame_height))

        self.canvas.SetSize((self.image_shape[1], self.image_shape[0]))

        # Reset axes so they don't get messed up when zooming
        self.axes.set_ybound(0, self.image_shape[0])
        self.axes.set_xbound(0, self.image_shape[1])

    def save_grid(self, event):
        '''
            Save the selected bounding boxes to some file, database,etc 
        '''
        if len(self.rect_obj_list) < 1:
            self.user_error("You haven't selected a single bounding box yet.")
            return 1
        else:
            write_grid_csv(self)
            return 0

    def user_info(self, message):
        wx.MessageBox(message, 'Info', wx.OK)

    def user_error(self, message):
        wx.MessageBox(message, 'Error', wx.ICON_ERROR | wx.OK)