class PageThree(tk.Frame): """Frame showing Data View and chop capabilities """ def __init__(self, parent, controller, **kwargs): tk.Frame.__init__(self, parent) # call class parent """ Initialize data members """ self.DA = DA self.isSafeToUpdate = False self.numViews = 2 self.deactList = list() self.DVconfig = controller.DVconfig """ Create label for frame """ #label = tk.Label(self, text="Data View", font=LARGE_FONT) #label.pack(pady=10,padx=10) """ Create button to go back to other frame """ #button1 = ttk.Button(self, text="Back to Home", # command=lambda: controller.show_frame(StartPage)) #button1.pack() """ Add menu item to load data """ filemenu = controller.filemenu filemenu.insert_command(index=1,label="Load", command=self.load) self.addMainFigure() # Add main figure area to frame self.addDataWindow() # Add widgets for setting data window self.addDataView() # Add widgets for setting data view self.addChop() # Add chop button self.addStat() # Add stat button def addDeactivateList(self, listLike) : """ Keep a list of deactivate-able widgets """ if isinstance(listLike, list) or isinstance(listLike, tuple) : for item in listLike : self.deactList.append(item) else : self.deactList.append(listLike) def deactivateWidgets(self) : for widget in self.deactList : widget.configure(state='disabled') def activateWidgets(self) : if not self.DA.isLoaded : return DataNotLoaded() for widget in self.deactList : widget.configure(state='normal') def addDataView(self) : """ Add widgets that control the view """ self.viewList = list(('No Data','No Data')) """ Add View Widget Sub-Frames """ self.dataViewSubFrameList = list() # list of "subframes" for frameNum in range(0,self.numViews) : subFrame = viewWidgetGroupFrame(self, label="Data View "+str(frameNum)) subFrame.setEventHandler(self.viewChangeTrace) subFrame.pack() self.dataViewSubFrameList.append(subFrame) """ Data View Index Selection """ self.altIdxSel = tk.StringVar(self) self.altIdxSel.set("No data") # default value """ self.altIdxSelW = tk.OptionMenu(self, self.altIdxSel, "No Data" ) self.altIdxSelW.configure(state="disabled") self.altIdxSelW.pack() self.altIdxSel.trace('w', self.viewChangeTrace) # set up event self.addDeactivateList(self.altIdxSelW) """ def addDataWindow(self) : """ Data Window Size Widget """ self.dataWindowSizeWidgetLabel = tk.Label(self, text='View Size') self.dataWindowSizeWidgetLabel.pack() self.dataWindowSizeWidget = tk.Scale(self, from_=1, to=10, resolution=1, orient="horizontal") self.dataWindowSizeWidget.bind("<ButtonRelease-1>", self.updateEvent) self.dataWindowSizeWidget.bind("<Button1-Motion>", self.updateEvent) self.dataWindowSizeWidget.pack(fill=tk.X,expand=1) """ Data Window Start Widget """ self.dataWindowStartWidgetLabel = tk.Label(self, text='View Start') self.dataWindowStartWidgetLabel.pack() self.dataWindowStartWidget = tk.Scale(self, from_=0, to=10, resolution=1, orient="horizontal") self.dataWindowStartWidget.bind("<ButtonRelease-1>", self.updateEvent) self.dataWindowStartWidget.bind("<Button1-Motion>", self.updateEvent) self.dataWindowStartWidget.pack(fill=tk.X,expand=1) def addMainFigure(self) : """ Add main figure area """ self.fig = plt.figure(figsize=(5,4), dpi=100) self.ax = self.fig.add_subplot(111) self.ax.set_title('No data') self.fig.canvas.draw() self.canvas = FigureCanvas(self.fig, self) """ Set up callback from canvas draw events, i.e. pan/zoom """ #self.cid1 = self.fig.canvas.mpl_connect('draw_event', self.updateFromCavas) #self.cid1 = self.fig.canvas.mpl_connect('button_release_event', self.updateFromCavas) #TODO animation self.canvas.draw() self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True) def addChop(self) : chopBW = tk.Button(self, text="Chop", command=self.doChop) chopBW.pack() self.chopButtonW = chopBW def addStat(self) : statBW = tk.Button(self, text="Stats", command=self.doStat) statBW.pack() self.statButtonW = statBW def postLoad(self) : """ Things to run after loading a new DataAnalyser object. """ debug("postLoad: get current view from DA...") viewList = self.DA.getView() # retrieve the default view after load debug("postLoad: get labels from DA...") self.updateLabels() # get new data types from data loaded self.setAltIndex('index') self.setView(viewList) # configure GUI to reflect new data self.isSafeToUpdate = True debug("postLoad: isSafeToUpdate:"+str(self.isSafeToUpdate)) """ now, set the window """ #TODO use data values instead of index values limitDict=self.DA.getIndexLimits() maxSize, minVal = ( limitDict['max'] , limitDict['min'] ) #print( "DEBUG: postLoad: maxSize: "+str(maxSize) ) #print( "DEBUG: postLoad: minValue: "+str(minVal) ) self.setWindow( minVal=minVal, start=0, maxSize=maxSize, size=int(maxSize/2)) # reset the GUI window self.updateEvent(None) # update GUI def setWindow(self, minVal=0, start=0, maxSize=10, size=10) : """ set the GUI values that correspond to the window """ debug("DEBUG: setWindow: %s, start: %s, maxSize: %s, size: %s" ,minVal, start, maxSize, size ) self.dataWindowSizeWidget.config(from_=1, to=maxSize-start+1) self.dataWindowSizeWidget.set(size) self.dataWindowStartWidget.config(from_=minVal, to=maxSize-size+1) self.dataWindowStartWidget.set(start) def load(self, *args, **kwargs) : """ catch all load method Currently, the only implemented mode is CSV file data. """ self.isSafeToUpdate = False name = filedialog.askopenfilename() self.loadFileData(path=name, *args, **kwargs) def loadFileData(self, path=None, *args, **kwargs) : """ Show a dialog to select a file and load it. """ if path is None: raise TypeError("loadFileData: path option is required") print("Got filename:" +path) loadData(path, *args, **kwargs) self.postLoad() def updateLabels(self) : """ Update labels from the DataAnalyser object Call whenever DA is loaded/changed. """ #print("DEBUG: updateLabels: isSafeToUpdate:", self.isSafeToUpdate) if not self.DA.isLoaded : return DataNotLoaded() newLabels = DA.getLabels() #debug("DEBUG: got label list from DA: "+str(newLabels)) for viewSubFrame in self.dataViewSubFrameList: viewSubFrame.setOptionsList(newLabels) """ re-enable widgets """ self.activateWidgets() def updateFromCavas(self, event) : """ Called when view is changed using figure canvas area. """ """ Get the figure axis limits """ figMinX, figMaxX = self.ax.get_xlim() debug('Got interval from MPL axis:'+str((figMinX,figMaxX))) """ Set the current window to match """ #TODO def viewChangeTrace(self, *args): """View is changed, make proper updates downward.""" debug("viewChange: isSafeToUpdate:"+str(self.isSafeToUpdate)) if not self.isSafeToUpdate : #print("DEBUG: viewChangeTrace: not safe, returning") return """Do other updates""" self.updateEvent(None) def setView(self, viewList) : """ Set the GUI representation of the current data view Takes a "view" object and sets the GUI so that it matches. """ self.isSafeToUpdate = False self.viewList = viewList for view,subFrame in zip(viewList,self.dataViewSubFrameList) : debug("DataViewApp: setView: "+str(view)) subFrame.disable() subFrame.setView(view) subFrame.enable() def setAltIndex(self, newIdx): """ Set the GUI presentation of alt index """ self.isSafeToUpdate = False self.altIdxSel.set(newIdx) def updateEvent(self, event): """ Change/Update data view when user requests a change. Call this whenever the user makes a change to view values. """ debug("updateEvent: called, event:"+str(event)) if not self.DA.isLoaded : return DataNotLoaded() DA = self.DA """ Set window from interface settings """ newWinSize = self.dataWindowSizeWidget.get() newWinStart = self.dataWindowStartWidget.get() limitDict=self.DA.getIndexLimits() debug("DEBUG: updateEvent: got limits: "+str(limitDict)) maxSize, minVal = ( limitDict['max'] , limitDict['min'] ) self.setWindow( minVal=minVal, start=newWinStart, maxSize=maxSize, size=newWinSize ) """ Set views from interface settings """ newViewList = list() for subFrame in self.dataViewSubFrameList : newView = subFrame.getView() debug("updateEvent: newView: "+str(newView)) if newView is not None : """If view frame returns None, don't add to list.""" newViewList.append(newView) """ set index """ try : pass #DA.setAltIndexColumn(self.altIdxSel.get()) #TODO except Exception as e: warn('updateEvent: Failed to set altnernate index, ignoring selection') print(e) else : """ just leave it set to index """ pass DA.setView( viewList=newViewList, windowStart=newWinStart, windowSize=newWinSize, windowType='index' ) """Redraw the plot""" dfList = self.DA.getViewData() #print("DEBUG: updateEvent: got updated data:", df.colums.tolist()) ax = self.ax ax.clear() xlabelList, ylabelList = list(), list() for df in dfList : """draw all df data as x,y data""" (xlabel, ylabel) = df.columns.tolist() ax.plot(df[xlabel].values, df[ylabel].values, 'o-') """store labels""" xlabelList.append(xlabel) ylabelList.append(ylabel) """Set labels""" newXlabel, newYlabel = str(), str() xlabelOverride = self.DVconfig.get('xlabel') ylabelOverride = self.DVconfig.get('ylabel') """Remember, configer doesn't hold native objects""" debug("Plotting: xlabelOverride: %s" % xlabelOverride) debug("Plotting: xlabelOverride eq None: %s" % (xlabelOverride == None)) if (xlabelOverride == None) or (ylabelOverride == None) : """Write the labels for all data""" debug("Plotting: Label overrides OFF") sep = "\n" newXlabel = sep.join( xlabelList ) newYlabel = sep.join( ylabelList ) debug("new xlabel: %s" % newXlabel) else : """the labels""" debug("Plotting: Label overrides ON") newXlabel = xlabelOverride newYlabel = ylabelOverride ax.set_xlabel(newXlabel) ax.set_ylabel(newYlabel) self.fig.canvas.draw() """ Show Statistics """ #self.showStats() def showStats(self): """ Get and report statsistics for the current view """ quantiles = self.DVconfig.get('statQuantiles') statsList = self.DA.getStats( quantiles ) dirpath = self.DVconfig.get('saveCDFDir') prefix = self.DVconfig.get('statFilePrefix') for statDF in statsList : fmt = self.DVconfig.get('statFileFmt') cols = ','.join(map(str,statDF.columns)) start,end = self.DA.getStartEnd() filename = prefix + "_{},{}-{}".format(cols,start,end) + fmt pathname = os.path.join( dirpath , filename ) statDF.to_csv(pathname) for stats in statsList: print("Data View Statistics:") print(stats) def doChop(self) : self.saveViewPlot() directory=pathlib.PurePath(os.path.curdir) chopConf = self.DVconfig.get('chopOpts') debug('chopConf:'+str(chopConf)) debug('dict(chopConf):'+str(dict(chopConf))) self.DA.chop(dirpath=directory, **dict(chopConf)) def saveViewPlot(self) : fig = self.fig # Get figure start,end = self.DA.getStartEnd() # Get view range dirpath = self.DVconfig.get('savePlotDir') prefix = self.DVconfig.get('savePlotPrefix') viewList = self.DA.getView() viewStr = ','.join(map(lambda x: ','.join(map(str,x)) if isinstance(x,tuple) else str(x), viewList)) filename = prefix + "_{vl},{start}-{end}".format( start=start,end=end, vl=viewStr ) + ".pdf" pathname = os.path.join( dirpath , filename ) fig.savefig(pathname) # Save plot def doStat(self) : """ Do actions for "stats" button """ # First, show stats on STDOUT self.showStats() # Then, save the current view plot self.saveViewPlot() # Next, make a CDF plot for all the visible data num_bins = self.DVconfig.get('saveCDFbins') cdfInfoLst = self.DA.getCDFall(num_bins=num_bins) # get CDF info from DA prefix = self.DVconfig.get('saveCDFprefix') dirpath = self.DVconfig.get('saveCDFDir') for cdfInfoT in cdfInfoLst : i = cdfInfoLst.index(cdfInfoT) label, cdf, counts, bin_edges = cdfInfoT start,end = self.DA.getStartEnd() filename = prefix +"_{},{}-{},{}.pdf".format(label,start,end,i) pathname = os.path.join( dirpath , filename ) fig = plt.figure() # mk new fig plt.plot(bin_edges[1:], cdf/cdf[-1]) plt.xlabel("{} values".format(label)) plt.ylabel("Normalized Cumulative Sum (CDF)".format()) fig.savefig(pathname)
if __name__ == '__main__': ncf = netcdf_file('KTLX_20100510_22Z.nc') data = ncf.variables['Reflectivity'] lats = ncf.variables['lat'] lons = ncf.variables['lon'] stormcells = storm_loader('polygons.shp') win = tk.Tk() fig = Figure() canvas = FigureCanvas(fig, master=win) ax = fig.add_subplot(1, 1, 1) raddisp = RadarDisplay(ax, lats, lons) raddisp.update_display(data[0]) fig.colorbar(raddisp.im) polycolls = Stormcells(ax, stormcells) linecoll = Tracks(ax) # Turn on the first frame's polygons polycolls.toggle_polygons(0, True) ax.autoscale(True) ctrl_sys = ControlSys(fig, raddisp, data, polycolls, linecoll, stormcells) win.wm_title("Embedding with Tk") canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) canvas.show() tk.mainloop()
class CanvasForGraphs: def __init__(self, root, frame, master_class, figure, axis_id=None, poppedout_id=None, direction="x"): # Save the variables self.root = root self.frame = frame self.master_class = master_class self.figure = figure self.axis_id = axis_id self.poppedout_id = poppedout_id self.direction = direction # Create the frame, canvas and toolbar self.initiate_frameGraph() # Make the canvas available to the master class so we can draw_idle() it if poppedout_id == None: self.master_class.Canvas[axis_id] = self.Canvas if poppedout_id != None: self.root.canvasPoppedOut.append(self.Canvas) #----------- Frame ---------- def initiate_frameGraph(self): # Configure frame that holds the canvas tk.Grid.rowconfigure(self.frame, 0, weight=1) tk.Grid.columnconfigure(self.frame, 0, weight=1) # Create frame for graph elements self.frame_canvas = ttk.Frame(self.frame) self.frame_canvas.grid(row=0, column=0, padx=(0, 0), pady=(0, 0), stick='NSEW') # Configure the frame that holds the figure and toolbar if self.direction == "x": tk.Grid.rowconfigure(self.frame_canvas, 0, weight=1) tk.Grid.rowconfigure(self.frame_canvas, 1, weight=0) tk.Grid.columnconfigure(self.frame_canvas, 0, weight=1) if self.direction == "y": tk.Grid.columnconfigure(self.frame_canvas, 0, weight=0) tk.Grid.columnconfigure(self.frame_canvas, 1, weight=1) tk.Grid.rowconfigure(self.frame_canvas, 0, weight=1) # Add the canvas and the toolbar self.initiate_canvas() self.initiate_toolbar() #----------- Canvas ----------- def initiate_canvas(self): # Add the figure to a Canvas self.Canvas = FigureCanvas(self.figure, self.frame_canvas) self.Canvas.get_tk_widget().configure(background=self.root.color['bg']) self.figure.patch.set_facecolor(self.root.color['bg']) self.Canvas.draw() self.widget = self.Canvas.get_tk_widget() if self.direction == "x": self.widget.grid(row=0, column=0, stick='NSEW') if self.direction == "y": self.widget.grid(row=0, column=1, stick='NSEW') #----------- Toolbar ----------- def initiate_toolbar(self): # Add a toolbar to the canvas self.toolbar = CustomToolbar(self.root, self.Canvas, self.frame_canvas, self.master_class, self.axis_id, self.poppedout_id, self.direction) self.toolbar.config(background=self.root.color['bg']) self.toolbar.update()