class BoxPlotPanel(FigureCanvasWxAgg): def __init__(self, parent, points, **kwargs): ''' points -- a dictionary mapping x axis values to lists of values to plot ''' self.figure = Figure() FigureCanvasWxAgg.__init__(self, parent, -1, self.figure, **kwargs) self.canvas = self.figure.canvas self.SetMinSize((100,100)) self.figure.set_facecolor((1,1,1)) self.figure.set_edgecolor((1,1,1)) self.canvas.SetBackgroundColour('white') self.navtoolbar = None self.setpoints(points) def setpoints(self, points): ''' Updates the data to be plotted and redraws the plot. points - list of array samples, where each sample will be plotted as a separate box plot against the same y axis ''' self.xlabels = [] self.points = [] ignored = 0 for label, values in sorted(points.items()): if type(label) in [tuple, list]: self.xlabels += [','.join([str(l) for l in label])] else: self.xlabels += [label] self.points += [np.array(values).astype('f')[~ np.isnan(values)]] ignored += len(np.array(values)[np.isnan(values)]) if not hasattr(self, 'subplot'): self.subplot = self.figure.add_subplot(111) self.subplot.clear() # nothing to plot? if len(self.points)==0: logging.warn('No data to plot.') return self.subplot.boxplot(self.points, sym='k.') if len(self.points) > 1: self.figure.autofmt_xdate() self.subplot.set_xticklabels(self.xlabels) self.reset_toolbar() if ignored == 0: logging.info('Boxplot: Plotted %s points.'%(sum(map(len, self.points)))) else: logging.warn('Boxplot: Plotted %s points. Ignored %s NaNs.' %(sum(map(len, self.points)), ignored)) def set_x_axis_label(self, label): self.subplot.set_xlabel(label) def set_y_axis_label(self, label): self.subplot.set_ylabel(label) def get_point_lists(self): return self.points def get_xlabels(self): return self.xlabels def get_toolbar(self): if not self.navtoolbar: self.navtoolbar = NavigationToolbar(self.canvas) self.navtoolbar.DeleteToolByPos(6) return self.navtoolbar def reset_toolbar(self): # Cheat since there is no way reset if self.navtoolbar: self.navtoolbar._nav_stack.clear() self.navtoolbar.push_current()
class SuperPosition(wx.Frame): """main user interface for super position""" def __init__(self, parent=None, files=[],*args, **kwargs): wx.Frame.__init__(self, parent, -1, size = (800, 600)) self.files = files self.Options = GraphOptions(self,extended=False) self.createMenu() self.setWindow() self.createPanel() self.createList() self.draw_figure() def createMenu(self): """create menu bar""" self.menubar = wx.MenuBar() self.fileMenu = wx.Menu() self.plotMenu = wx.Menu( ) qms = self.fileMenu.Append(wx.ID_ANY, '&Save Plot') qec = self.fileMenu.Append(wx.ID_ANY, '&Save Data') self.Bind(wx.EVT_MENU, self.OnSaveData, qec) self.fileMenu.AppendSeparator() subtract = self.plotMenu.Append(100, "Subtract Plots") self.Bind(wx.EVT_MENU, self.OnSubtract, subtract) mean = self.plotMenu.Append(wx.ID_ANY, "Average Plots") self.Bind(wx.EVT_MENU, self.OnMean, mean) self.plotMenu.AppendSeparator() self.showLegend = self.plotMenu.Append(wx.ID_ANY,"Show &Legend",kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, self.OnUpdatePlot, self.showLegend) self.showLegend.Check(True) pltoptions = self.plotMenu.Append(wx.ID_ANY, "&Plot Options") self.Bind(wx.EVT_MENU,self.OnPlotOptions, pltoptions) qme = self.fileMenu.Append(wx.ID_EXIT, '&Quit') self.Bind(wx.EVT_MENU, self.OnQuit, qme) self.Bind(wx.EVT_MENU,self.OnSavePlot,qms) self.menubar.Append(self.fileMenu, '&File') self.menubar.Append(self.plotMenu, '&Plot') self.SetMenuBar(self.menubar) def setWindow(self): """create main panel""" self.SetTitle("SMP Superposition Viewer") self.SetMinSize((600,400)) self.Centre() self.Maximize() self.Show() def createPanel(self): self.panelPlot = wx.Panel(self) self.panelPlot.SetFocus() self.list = ulc.UltimateListCtrl(self.panelPlot, agwStyle=wx.LC_REPORT|wx.LC_VRULES|wx.LC_HRULES|wx.LC_SINGLE_SEL|ulc.ULC_HAS_VARIABLE_ROW_HEIGHT) self.dpi = 100 self.fig = Figure((5.0, 4.0), dpi=self.dpi) self.canvas = FigCanvas(self.panelPlot, -1, self.fig) self.axes = self.fig.add_subplot(111) self.plot_toolbar = NavigationToolbar(self.canvas) self.plot_toolbar.DeleteToolByPos(8) #delete save, subplot and spacer from tool bar self.plot_toolbar.DeleteToolByPos(7) self.plot_toolbar.DeleteToolByPos(6) vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(self.canvas, 10, wx.LEFT | wx.TOP | wx.GROW) vbox.Add(self.plot_toolbar, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) vbox.Add(self.list,3, wx.LEFT | wx.TOP | wx.GROW) self.panelPlot.SetSizer(vbox) vbox.Fit(self) def createList(self): """List Elements""" #colums self.list.InsertColumn(0,"File Name") self.list.InsertColumn(1,"active") self.list.InsertColumn(2,"Offset x [mm]") self.list.InsertColumn(3,"Offset y [N]") self.list.InsertColumn(4, "x Stretch Factor") self.list.InsertColumn(5,"Smooth") self.list.InsertColumn(6,"Color") self.list.InsertColumn(7,"Style") self.list.InsertColumn(8,"Width") self.list.SetColumnWidth(0,500) self.list.SetColumnWidth(1,-2) self.list.SetColumnWidth(2,150) self.list.SetColumnWidth(3,150) self.list.SetColumnWidth(5,150) #entries for item in self.files: self.addItem(item) def addItem(self,item): colors=["blue","black","green","red","yellow","orange","pink","purple","brown", "gray","darkblue","silver","darkgreen","darkred","gold"] styles=["-","-.",":","steps","--","_"] #create elements i = self.list.GetItemCount() index = self.list.InsertStringItem(i, item.filename) box = wx.CheckBox(self.list) box.SetValue(True) dx = FloatSpin(self.list,-1,value=- item.surface,min_val=-500.000,max_val=500.000,increment=1,digits=2) dy = FloatSpin(self.list,-1,value=0.000,min_val=-50.00,max_val=50.00,increment=0.01,digits=2) stretch = FloatSpin(self.list,-1,value=1,min_val=0.5,max_val=1.5,increment=0.001,digits=3) smooth = wx.SpinCtrl(self.list,-1,min=0,max=2000,initial=200) color = wx.ComboBox(self.list, -1, choices=colors, style=wx.CB_READONLY,value=colors[i%len(colors)]) style = wx.ComboBox(self.list, -1, choices=styles, style=wx.CB_READONLY,value="-") width = wx.SpinCtrl(self.list, -1,name="Width",initial=1,min=1,max=10) #append elements to files properties item.index = index item.box = box item.dx = dx item.dy = dy item.stretch = stretch item.smooth = smooth item.color = color item.style = style item.width = width #append elements to list self.list.SetItemWindow(index,1,item.box,expand=True) self.list.SetItemWindow(index,2,item.dx,expand=True) self.list.SetItemWindow(index,3,item.dy,expand=True) self.list.SetItemWindow(index,4,item.stretch,expand=True) self.list.SetItemWindow(index,5,item.smooth,expand=True) self.list.SetItemWindow(index,6,item.color,expand=True) self.list.SetItemWindow(index,7,item.style,expand=True) self.list.SetItemWindow(index,8,item.width,expand=True) #set events to update plot self.Bind(wx.EVT_CHECKBOX, self.OnUpdatePlot, item.box) self.Bind(wx.EVT_SPINCTRL, self.OnUpdatePlot, item.dx) self.Bind(wx.EVT_SPINCTRL, self.OnUpdatePlot, item.dy) self.Bind(wx.EVT_SPINCTRL, self.OnUpdatePlot, item.stretch) self.Bind(wx.EVT_SPINCTRL, self.OnUpdatePlot, item.smooth) self.Bind(wx.EVT_COMBOBOX, self.OnUpdatePlot, item.color) self.Bind(wx.EVT_COMBOBOX, self.OnUpdatePlot, item.style) self.Bind(wx.EVT_SPINCTRL, self.OnUpdatePlot, item.width) def draw_figure(self,autozoom=False): """draw active files""" self.setPlotOptions(autozoom) active = 0 for i in range(len(self.files)): current = self.files[i] if current.box.GetValue(): active += 1 x,y = self.adaptData(current) self.axes.plot(x, y, color = current.color.GetValue(), linestyle = current.style.GetValue(), linewidth = current.width.GetValue(), label = basename(current.filename) ) self.canvas.draw() self.plotMenu.Enable(100,active >= 2) def setPlotOptions(self, autozoom=False): if autozoom: xlim = self.axes.get_xlim() ylim = self.axes.get_ylim() self.axes.clear() self.axes.set_xlim(xlim) self.axes.set_ylim(ylim) else: self.axes.clear() if not self.Options.auto_x: self.axes.set_xlim(self.Options.xlim[0],self.Options.xlim[1]) if not self.Options.auto_y: self.axes.set_ylim(self.Options.ylim[0],self.Options.ylim[1]) if not self.Options.auto_yticks: self.axes.yaxis.set_major_locator(MaxNLocator(self.Options.yticks)) if not self.Options.auto_xticks: self.axes.xaxis.set_major_locator(MaxNLocator(self.Options.xticks)) self.axes.grid(True) self.axes.tick_params(labeltop=self.Options.mirrorx,labelright=self.Options.mirrory) self.axes.set_xlabel(self.Options.xlabel) self.axes.set_ylabel(self.Options.ylabel) self.axes.set_title("SMP Super Position Viewer") if self.showLegend.IsChecked(): print "show legend" self.axes.legend(loc = "upper left") def OnUpdatePlot(self,e): self.draw_figure(True) def OnAddItem(self,e): files = openFile() if files != None: for entry in files: item = smp.Pnt(entry) self.addItem(item) self.drawPlot() def OnSavePlot(self,e): """Save Plot Event""" file_choices = "PNG (*.png)|*.PNG" filename = "_SuperPos.png" dlg = wx.FileDialog( self, message = "Save Plot as...", defaultDir = os.getcwd(), defaultFile = filename, wildcard = file_choices, style = wx.SAVE|wx.OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path, dpi=self.dpi) dlg.Destroy() def OnSaveData(self,e): wx.MessageBox('Not implemented yet', 'Info', wx.OK | wx.ICON_INFORMATION) lines = self.axes.lines """ data = [] for line in lines: data.append(line.get_data()) np.savetxt(fname = "/home/grimm/Desktop/test.txt", X = np.array(data), fmt = '%.18e', delimiter = '\t', newline = '\n', header = '# Automatic written file from SMP SUper Position Viewer', comments='# ') """ def OnPlotOptions(self,e): self.Options.Show() def OnSubtract(self,e): choices = [] files = [] for entry in self.files: if entry.box.GetValue(): choices.append(os.path.basename(entry.filename)) files.append(entry) dlg = wx.SingleChoiceDialog(parent = self, message = "select reference", caption = "Subtract Plots", choices = choices, ) if dlg.ShowModal() == wx.ID_OK: ref = files[dlg.GetSelection()] files.pop(dlg.GetSelection()) xref, yref = self.adaptData(ref) fref = interp1d(xref,yref) xref_min = np.min(xref) xref_max = np.max(xref) for entry in files: xsub, ysub = self.adaptData(entry) fsub = interp1d(xsub,ysub) xsub_min = np.min(xsub) xsub_max = np.max(xsub) if xsub_min >= xref_min: xmin = xsub_min else: xmin = xref_min if xsub_max >= xref_max: xmax = xref_max else: xmax = xsub_max x_new = np.arange(xmin,xmax,0.1) f_ref = fref(x_new) f_sub = fsub(x_new) y_new = f_ref - f_sub rsme = calc.rsme(f_ref, f_sub) self.axes.plot(x_new, y_new, linestyle = "--", color = entry.color.GetValue(), label = basename(entry.filename) + " - " + basename(ref.filename) + ", rsme = %0.3g" %rsme) self.axes.legend(loc = "upper left") self.axes.autoscale(False) self.canvas.draw() dlg.Destroy() def OnMean(self,e): #get prepared data data = [] for entry in self.files: if entry.box.GetValue(): data.append(self.adaptData(entry)) #find common range xmins = [] xmaxs = [] for entry in data: xmins.append(entry[0][0]) xmaxs.append(entry[0][-1]) xmin = np.amax(xmins) xmax = np.amin(xmaxs) x_new = np.arange(xmin,xmax,0.004) y_new = [] #interpolate data to get same number of data points for entry in data: fint = interp1d(entry[0],entry[1]) y_new.append(fint(x_new)) y_new = np.transpose(np.array(y_new)) y_mean = np.mean(y_new,1) #plot average self.setPlotOptions() self.axes.plot(x_new, y_mean, linestyle = "-", color = "r", label = "mean") self.canvas.draw() def adaptData(self, pnt): x_corrected = (calc.downsample(pnt.data[:,0],pnt.smooth.GetValue()) + pnt.dx.GetValue()) * pnt.stretch.GetValue() y_corrected = calc.downsample(pnt.data[:,1],pnt.smooth.GetValue()) + pnt.dy.GetValue() return x_corrected,y_corrected def OnQuit(self,e): self.Destroy()