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()
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)
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()