class ScanViewerFrame(wx.Frame): _about = """Scan Viewer, Matt Newville <newville @ cars.uchicago.edu> """ TIME_MSG = 'Point %i/%i, Time Remaining ~ %s ' def __init__(self, parent, dbname=None, server='sqlite', host=None, port=None, user=None, password=None, create=True, **kws): wx.Frame.__init__(self, None, -1, style=FRAMESTYLE) title = "Epics Step Scan Viewer" self.parent = parent self.scandb = getattr(parent, 'scandb', None) if self.scandb is None and dbname is not None: self.scandb = ScanDB(dbname=dbname, server=server, host=host, user=user, password=password, port=port, create=create) self.larch = None self.lgroup = None self.SetTitle(title) self.SetSize((750, 750)) self.SetFont(Font(9)) self.createMainPanel() self.createMenus() self.statusbar = self.CreateStatusBar(2, 0) self.statusbar.SetStatusWidths([-3, -1]) statusbar_fields = ["Initializing....", " "] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) if self.scandb is not None: self.get_info = self.scandb.get_info self.scandb_server = self.scandb.server self.live_scanfile = None self.live_cpt = -1 self.total_npts = 1 self.scantimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onScanTimer, self.scantimer) self.scantimer.Start(50) self.Show() self.Raise() def onScanTimer(self, evt=None, **kws): if self.lgroup is None: return curfile = fix_filename(self.get_info('filename')) sdata = self.scandb.get_scandata() npts = len(sdata[-1].data) if (npts > 2 and npts == self.live_cpt and curfile == self.live_scanfile): # no new data return # filename changed -- scan starting, so update # list of positioners, detectors, etc force_newplot = False if curfile != self.live_scanfile: force_newplot = True self.live_scanfile = curfile self.title.SetLabel(curfile) self.set_column_names(sdata) if npts == self.live_cpt: return time_est = hms(self.get_info('scan_time_estimate', as_int=True)) msg = self.TIME_MSG % (npts, self.total_npts, time_est) self.SetStatusText(msg) self.live_cpt = npts for row in sdata: dat = row.data if self.scandb_server == 'sqlite': dat = json.loads(dat.replace('{', '[').replace('}', ']')) setattr(self.lgroup, fix_varname(row.name), np.array(dat)) if npts > 1: self.onPlot(npts=npts, force_newplot=force_newplot) def set_column_names(self, sdata): """set column names from values read from scandata table""" self.lgroup.array_units = [fix_varname(s.units) for s in sdata] self.total_npts = self.get_info('scan_total_points', as_int=True) self.live_cpt = -1 xcols, ycols, y2cols = [], [], [] for s in sdata: nam = fix_varname(s.name) ycols.append(nam) if s.notes.lower().startswith('pos'): xcols.append(nam) y2cols = ycols[:] + ['1.0', '0.0', ''] xarr_old = self.xarr.GetStringSelection() self.xarr.SetItems(xcols) ix = xcols.index(xarr_old) if xarr_old in xcols else 0 self.xarr.SetSelection(ix) for i in range(2): for j in range(3): yold = self.yarr[i][j].GetStringSelection() idef, cols = 0, y2cols if i == 0 and j == 0: idef, cols = 1, ycols self.yarr[i][j].SetItems(cols) iy = cols.index(yold) if yold in cols else idef self.yarr[i][j].SetSelection(iy) def createMainPanel(self): wx.CallAfter(self.init_larch) mainpanel = wx.Panel(self) mainsizer = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(mainpanel) self.yops = [[],[]] self.yarr = [[],[]] arr_kws= {'choices':[], 'size':(120, -1), 'action':self.onPlot} self.title = SimpleText(panel, 'initializing...', font=Font(13), colour='#880000') self.xarr = add_choice(panel, **arr_kws) for i in range(3): self.yarr[0].append(add_choice(panel, **arr_kws)) self.yarr[1].append(add_choice(panel, **arr_kws)) for opts, sel, wid in ((PRE_OPS, 0, 100), (ARR_OPS, 3, 60), (ARR_OPS, 3, 60)): arr_kws['choices'] = opts arr_kws['size'] = (wid, -1) self.yops[0].append(add_choice(panel, default=sel, **arr_kws)) self.yops[1].append(add_choice(panel, default=sel, **arr_kws)) # place widgets sizer = wx.GridBagSizer(5, 10) sizer.Add(self.title, (0, 1), (1, 6), LCEN, 2) sizer.Add(SimpleText(panel, ' X ='), (1, 0), (1, 1), CEN, 0) sizer.Add(self.xarr, (1, 3), (1, 1), RCEN, 0) ir = 1 for i in range(2): ir += 1 label = ' Y%i =' % (i+1) sizer.Add(SimpleText(panel, label), (ir, 0), (1, 1), CEN, 0) sizer.Add(self.yops[i][0], (ir, 1), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, '[('), (ir, 2), (1, 1), CEN, 0) sizer.Add(self.yarr[i][0], (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yops[i][1], (ir, 4), (1, 1), CEN, 0) sizer.Add(self.yarr[i][1], (ir, 5), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ')'), (ir, 6), (1, 1), LCEN, 0) sizer.Add(self.yops[i][2], (ir, 7), (1, 1), CEN, 0) sizer.Add(self.yarr[i][2], (ir, 8), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ']'), (ir, 9), (1, 1), LCEN, 0) ir += 1 sizer.Add(hline(panel), (ir, 0), (1, 12), CEN|wx.GROW|wx.ALL, 0) pack(panel, sizer) self.plotpanel = PlotPanel(mainpanel, size=(520, 550), axissize=(0.18, 0.18, 0.70, 0.70), fontsize=8) self.plotpanel.messenger = self.write_message self.plotpanel.canvas.figure.set_facecolor((0.98,0.98,0.97)) btnsizer = wx.StdDialogButtonSizer() btnpanel = wx.Panel(mainpanel) btnsizer.Add(add_button(btnpanel, 'Pause', action=self.onPause)) btnsizer.Add(add_button(btnpanel, 'Resume', action=self.onResume)) btnsizer.Add(add_button(btnpanel, 'Abort', action=self.onAbort)) pack(btnpanel, btnsizer) mainsizer.Add(panel, 0, LCEN|wx.EXPAND, 2) mainsizer.Add(self.plotpanel, 1, wx.GROW|wx.ALL, 1) mainsizer.Add(btnpanel, 0, wx.GROW|wx.ALL, 1) pack(mainpanel, mainsizer) return mainpanel def onPause(self, evt=None): self.scandb.set_info('request_command_pause', 1) def onResume(self, evt=None): self.scandb.set_info('request_command_pause', 0) def onAbort(self, evt=None): self.scandb.set_info('request_command_abort', 1) def CreateFitPanel(self, parent): p = panel = wx.Panel(parent) self.fit_model = add_choice(panel, size=(100, -1), choices=('Gaussian', 'Lorentzian', 'Voigt', 'Linear', 'Quadratic', 'Step', 'Rectangle', 'Exponential')) self.fit_bkg = add_choice(panel, size=(100, -1), choices=('None', 'constant', 'linear', 'quadtratic')) self.fit_step = add_choice(panel, size=(100, -1), choices=('linear', 'error function', 'arctan')) self.fit_report = wx.StaticText(panel, -1, "", (180, 200)) sizer = wx.GridBagSizer(10, 4) sizer.Add(SimpleText(p, 'Fit Model: '), (0, 0), (1, 1), LCEN) sizer.Add(self.fit_model, (0, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Background: '), (1, 0), (1, 1), LCEN) sizer.Add(self.fit_bkg, (1, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Step Function Form: '), (2, 0), (1, 1), LCEN) sizer.Add(self.fit_step, (2, 1), (1, 1), LCEN) sizer.Add(add_button(panel, 'Show Fit', size=(100, -1), action=self.onFitPeak), (3, 0), (1, 1), LCEN) sizer.Add(self.fit_report, (0, 2), (4, 2), LCEN, 3) pack(panel, sizer) return panel def CreateXASPanel(self, parent): p = panel = wx.Panel(parent) self.xas_autoe0 = check(panel, default=True, label='auto?') self.xas_autostep = check(panel, default=True, label='auto?') self.xas_op = add_choice(panel, size=(95, -1), choices=('Raw Data', 'Pre-edged', 'Normalized', 'Flattened')) self.xas_e0 = FloatCtrl(panel, value = 0, precision=3, size=(95, -1)) self.xas_step = FloatCtrl(panel, value = 0, precision=3, size=(95, -1)) self.xas_pre1 = FloatCtrl(panel, value=-200, precision=1, size=(95, -1)) self.xas_pre2 = FloatCtrl(panel, value= -30, precision=1, size=(95, -1)) self.xas_nor1 = FloatCtrl(panel, value= 30, precision=1, size=(95, -1)) self.xas_nor2 = FloatCtrl(panel, value= 300, precision=1, size=(95, -1)) self.xas_vict = add_choice(panel, size=(50, -1), choices=('0', '1', '2', '3')) self.xas_nnor = add_choice(panel, size=(50, -1), choices=('0', '1', '2', '3')) self.xas_vict.SetSelection(1) self.xas_nnor.SetSelection(2) sizer = wx.GridBagSizer(10, 4) sizer.Add(SimpleText(p, 'Plot XAS as: '), (0, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'E0 : '), (1, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Edge Step: '), (2, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Pre-edge range: '), (3, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Normalization range: '), (4, 0), (1, 1), LCEN) sizer.Add(self.xas_op, (0, 1), (1, 1), LCEN) sizer.Add(self.xas_e0, (1, 1), (1, 1), LCEN) sizer.Add(self.xas_step, (2, 1), (1, 1), LCEN) sizer.Add(self.xas_pre1, (3, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (3, 2), (1, 1), LCEN) sizer.Add(self.xas_pre2, (3, 3), (1, 1), LCEN) sizer.Add(self.xas_nor1, (4, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (4, 2), (1, 1), LCEN) sizer.Add(self.xas_nor2, (4, 3), (1, 1), LCEN) sizer.Add(self.xas_autoe0, (1, 2), (1, 2), LCEN) sizer.Add(self.xas_autostep, (2, 2), (1, 2), LCEN) sizer.Add(SimpleText(p, 'Victoreen:'), (3, 4), (1, 1), LCEN) sizer.Add(self.xas_vict, (3, 5), (1, 1), LCEN) sizer.Add(SimpleText(p, 'PolyOrder:'), (4, 4), (1, 1), LCEN) sizer.Add(self.xas_nnor, (4, 5), (1, 1), LCEN) pack(panel, sizer) return panel def onFitPeak(self, evt=None): gname = self.groupname if self.dtcorr.IsChecked(): print 'fit needs to dt correct!' dtext = [] model = self.fit_model.GetStringSelection().lower() dtext.append('Fit Model: %s' % model) bkg = self.fit_bkg.GetStringSelection() if bkg == 'None': bkg = None if bkg is None: dtext.append('No Background') else: dtext.append('Background: %s' % bkg) step = self.fit_step.GetStringSelection().lower() if model in ('step', 'rectangle'): dtext.append('Step form: %s' % step) lgroup = getattr(self.larch.symtable, gname) x = lgroup.arr_x y = lgroup.arr_y1 pgroup = fit_peak(x, y, model, background=bkg, step=step, _larch=self.larch) text = fit_report(pgroup.params, _larch=self.larch) dtext.append('Parameters: ') for pname in dir(pgroup.params): par = getattr(pgroup.params, pname) if isParameter(par): ptxt = " %s= %.4f" % (par.name, par.value) if (hasattr(par, 'stderr') and par.stderr is not None): ptxt = "%s(%.4f)" % (ptxt, par.stderr) dtext.append(ptxt) dtext = '\n'.join(dtext) text = fit_report(pgroup.params, _larch=self.larch) self.fit_report.SetLabel(dtext) def xas_process(self, gname, plotopts): """ process (pre-edge/normalize) XAS data from XAS form, overwriting larch group '_y1_' attribute to be plotted """ print 'Process XAS ', gname out = self.xas_op.GetStringSelection().lower() # raw, pre, norm, flat if out.startswith('raw'): return plotopts preopts = {'group': gname, 'e0': None, 'step': None} lgroup = getattr(self.larch.symtable, gname) if self.dtcorr.IsChecked(): print 'need to dt correct!' if not self.xas_autoe0.IsChecked(): xmin, xmax = min(lgroup.arr_x), max(lgroup.arr_x) e0 = self.xas_e0.GetValue() if e0 < xmax and e0 > xmin: preopts['e0'] = e0 if not self.xas_autostep.IsChecked(): preopts['step'] = self.xas_step.GetValue() preopts['pre1'] = self.xas_pre1.GetValue() preopts['pre2'] = self.xas_pre2.GetValue() preopts['norm1'] = self.xas_nor1.GetValue() preopts['norm2'] = self.xas_nor2.GetValue() preopts['nvict'] = self.xas_vict.GetSelection() preopts['nnorm'] = self.xas_nnor.GetSelection() preopts = ", ".join(["%s=%s" %(k, v) for k,v in preopts.items()]) preedge_cmd = "pre_edge(%s._x1_, %s._y1_, %s)" % (gname, gname, preopts) self.larch(preedge_cmd) self.xas_e0.SetValue(lgroup.e0) self.xas_step.SetValue(lgroup.edge_step) if out.startswith('pre'): self.larch('%s._y1_ = %s.norm * %s.edge_step' % (gname, gname, gname)) elif out.startswith('norm'): self.larch('%s._y1_ = %s.norm' % (gname, gname)) elif out.startswith('flat'): self.larch('%s._y1_ = %s.flat' % (gname, gname)) return plotopts def init_larch(self): t0 = time.time() from larch.wxlib import inputhook self.larch = Interpreter() self.larch.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp()) self.larch.symtable.set_symbol('_sys.wx.parent', self) self.larch('%s = group(filename="%s")' % (SCANGROUP, CURSCAN)) self.larch('_sys.localGroup = %s)' % (SCANGROUP)) self.lgroup = getattr(self.larch.symtable, SCANGROUP) self.SetStatusText('ready') self.title.SetLabel('') def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def onPlot(self, evt=None, npts=None, force_newplot=False): """drow plot of newest data""" new_plot = force_newplot or npts < 3 lgroup, gname = self.lgroup, SCANGROUP ix = self.xarr.GetSelection() x = self.xarr.GetStringSelection() xlabel = x popts = {'labelfontsize': 8, 'xlabel': x} try: xunits = lgroup.array_units[ix] xlabel = '%s (%s)' % (xlabel, xunits) except: pass def make_array(wids, iy): gn = SCANGROUP op1 = self.yops[iy][0].GetStringSelection() op2 = self.yops[iy][1].GetStringSelection() op3 = self.yops[iy][2].GetStringSelection() yy1 = self.yarr[iy][0].GetStringSelection() yy2 = self.yarr[iy][1].GetStringSelection() yy3 = self.yarr[iy][2].GetStringSelection() if yy1 in ('0', '1', '', None) or len(yy1) < 0: return '', '' label = yy1 expr = "%s.%s" % (gn, yy1) if yy2 != '': label = "%s%s%s" % (label, op2, yy2) expr = "%s%s%s.%s" % (expr, op2, gn, yy2) if yy3 != '': label = "(%s)%s%s" % (label, op3, yy3) expr = "(%s)%s%s.%s" % (expr, op3, gn, yy3) if op1 != '': label = "%s(%s)" % (op1, label) expr = "%s(%s)" % (op1, expr) return label, expr ylabel, yexpr = make_array(self.yops, 0) if yexpr == '': return self.larch("%s.arr_x = %s.%s" % (gname, gname, x)) self.larch("%s.arr_y1 = %s" % (gname, yexpr)) # print 'onPlot Show Groups ', lgroup # print ' : ', dir(lgroup) # print ' X -> ', x, lgroup.arr_x # print ' Y -> ', yexpr, lgroup.arr_y1 try: npts = min(len(lgroup.arr_x), len(lgroup.arr_y1)) except AttributeError: return y2label, y2expr = make_array(self.yops, 1) if y2expr != '': self.larch("%s.arr_y2 = %s" % (gname, y2expr)) n2pts = npts try: n2pts = min(len(lgroup.arr_x), len(lgroup.arr_y1), len(lgroup.arr_y2)) lgroup.arr_y2 = np.array( lgroup.arr_y2[:n2pts]) except: y2expr = '' npts = n2pts lgroup.arr_y1 = np.array( lgroup.arr_y1[:npts]) lgroup.arr_x = np.array( lgroup.arr_x[:npts]) path, fname = os.path.split(self.live_scanfile) popts.update({'title': fname, 'xlabel': xlabel, 'ylabel': ylabel, 'y2label': y2label}) ppnl = self.plotpanel if new_plot: ppnl.plot(lgroup.arr_x, lgroup.arr_y1, label= "%s: %s" % (fname, ylabel), **popts) if y2expr != '': ppnl.oplot(lgroup.arr_x, lgroup.arr_y2, side='right', label= "%s: %s" % (fname, y2label), **popts) ppnl.canvas.draw() else: ppnl.set_xlabel(xlabel) ppnl.set_ylabel(ylabel) ppnl.update_line(0, lgroup.arr_x, lgroup.arr_y1, draw=True, update_limits=True) ppnl.set_xylims((min(lgroup.arr_x), max(lgroup.arr_x), min(lgroup.arr_y1), max(lgroup.arr_y1))) if y2expr != '': ppnl.set_y2label(y2label) ppnl.update_line(1, lgroup.arr_x, lgroup.arr_y2, side='right', draw=True, update_limits=True) ppnl.set_xylims((min(lgroup.arr_x), max(lgroup.arr_x), min(lgroup.arr_y2), max(lgroup.arr_y2)), side='right') def createMenus(self): self.menubar = wx.MenuBar() # fmenu = wx.Menu() pmenu = wx.Menu() fmenu.AppendSeparator() add_menu(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) self.menubar.Append(fmenu, "&File") fmenu.AppendSeparator() add_menu(self, fmenu, "&Copy\tCtrl+C", "Copy to Clipboard", self.onClipboard) add_menu(self, fmenu, "&Save\tCtrl+S", "Save Figure", self.onSaveFig) add_menu(self, fmenu, "&Print\tCtrl+P", "Print Figure", self.onPrint) add_menu(self, fmenu, "Page Setup", "Print Page Setup", self.onPrintSetup) add_menu(self, fmenu, "Preview", "Print Preview", self.onPrintPreview) # add_menu(self, pmenu, "Configure\tCtrl+K", "Configure Plot", self.onConfigurePlot) add_menu(self, pmenu, "Unzoom\tCtrl+Z", "Unzoom Plot", self.onUnzoom) pmenu.AppendSeparator() add_menu(self, pmenu, "Toggle Legend\tCtrl+L", "Toggle Legend on Plot", self.onToggleLegend) add_menu(self, pmenu, "Toggle Grid\tCtrl+G", "Toggle Grid on Plot", self.onToggleGrid) self.menubar.Append(pmenu, "Plot Options") self.SetMenuBar(self.menubar) def onClipboard(self, evt=None): self.plotpanel.canvas.Copy_to_Clipboard(evt) def onSaveFig(self, evt=None): self.plotpanel.save_figure(event=evt, transparent=True, dpi=300) def onPrint(self, evt=None): self.plotpanel.Print(evet) def onPrintSetup(self, evt=None): self.plotpanel.PrintSetup(evt) def onPrintPreview(self, evt=None): self.plotpanel.PrintPreview(evt) def onConfigurePlot(self, evt=None): self.plotpanel.configure(evt) def onUnzoom(self, evt=None): self.plotpanel.unzoom(evt) def onToggleLegend(self, evt=None): self.plotpanel.toggle_legend(evt) def onToggleGrid(self, evt=None): self.plotpanel.toggle_grid(evt) def onAbout(self,evt): dlg = wx.MessageDialog(self, self._about,"About Epics StepScan", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self,evt): for obj in self.plotters: try: obj.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) del obj self.Destroy()
class Viewer1DXRD(wx.Panel): ''' Frame for housing all 1D XRD viewer widgets ''' label='Viewer' def __init__(self,parent,owner=None,_larch=None): wx.Panel.__init__(self, parent) self.parent = parent self.owner = owner ## Default information self.data_name = [] self.xy_data = [] self.xy_plot = [] self.plotted_data = [] self.xy_scale = [] self.wavelength = None self.xlabel = 'q (A^-1)' self.xunits = ['q','d'] self.cif_name = [] self.cif_data = [] self.cif_plot = [] self.plotted_cif = [] self.x_for_zoom = None self.Panel1DViewer() ############################################## #### PANEL DEFINITIONS def Panel1DViewer(self): ''' Frame for housing all 1D XRD viewer widgets ''' leftside = self.LeftSidePanel(self) rightside = self.RightSidePanel(self) panel1D = wx.BoxSizer(wx.HORIZONTAL) panel1D.Add(leftside,flag=wx.ALL,border=10) panel1D.Add(rightside,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) self.SetSizer(panel1D) def Toolbox(self,panel): ''' Frame for visual toolbox ''' tlbx = wx.StaticBox(self,label='PLOT TOOLBOX') vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) ########################### ## X-Scale hbox_xaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_xaxis = wx.StaticText(self, label='X-SCALE') self.ch_xaxis = wx.Choice(self,choices=self.xunits) self.ch_xaxis.Bind(wx.EVT_CHOICE, self.checkXaxis) hbox_xaxis.Add(ttl_xaxis, flag=wx.RIGHT, border=8) hbox_xaxis.Add(self.ch_xaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_xaxis, flag=wx.ALL, border=10) ########################### ## Y-Scale hbox_yaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_yaxis = wx.StaticText(self, label='Y-SCALE') yscales = ['linear','log'] self.ch_yaxis = wx.Choice(self,choices=yscales) self.ch_yaxis.Bind(wx.EVT_CHOICE, None) hbox_yaxis.Add(ttl_yaxis, flag=wx.RIGHT, border=8) hbox_yaxis.Add(self.ch_yaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_yaxis, flag=wx.ALL, border=10) return vbox def DataBox(self,panel): ''' Frame for data toolbox ''' tlbx = wx.StaticBox(self,label='DATA TOOLBOX') vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) ########################### ## DATA CHOICE self.ch_data = wx.Choice(self,choices=self.data_name) self.ch_data.Bind(wx.EVT_CHOICE, self.onSELECT) vbox.Add(self.ch_data, flag=wx.EXPAND|wx.ALL, border=8) #self.ttl_data = wx.StaticText(self, label='') #vbox.Add(self.ttl_data, flag=wx.EXPAND|wx.ALL, border=8) ########################### # self.ck_bkgd = wx.CheckBox(self,label='BACKGROUND') # self.ck_smth = wx.CheckBox(self,label='SMOOTHING') # # self.ck_bkgd.Bind(wx.EVT_CHECKBOX, None) # self.ck_smth.Bind(wx.EVT_CHECKBOX, None) # # vbox.Add(self.ck_bkgd, flag=wx.ALL, border=8) # vbox.Add(self.ck_smth, flag=wx.ALL, border=8) ########################### ## Scale hbox_scl = wx.BoxSizer(wx.HORIZONTAL) ttl_scl = wx.StaticText(self, label='SCALE Y TO:') self.entr_scale = wx.TextCtrl(self,wx.TE_PROCESS_ENTER) btn_scale = wx.Button(self,label='set') btn_scale.Bind(wx.EVT_BUTTON, self.normalize1Ddata) hbox_scl.Add(ttl_scl, flag=wx.RIGHT, border=8) hbox_scl.Add(self.entr_scale, flag=wx.RIGHT, border=8) hbox_scl.Add(btn_scale, flag=wx.RIGHT, border=8) vbox.Add(hbox_scl, flag=wx.BOTTOM|wx.TOP, border=8) ########################### ## Hide/show and reset hbox_btns = wx.BoxSizer(wx.HORIZONTAL) btn_hide = wx.Button(self,label='hide') btn_reset = wx.Button(self,label='reset') btn_rmv = wx.Button(self,label='remove') btn_hide.Bind(wx.EVT_BUTTON, self.hide1Ddata) btn_reset.Bind(wx.EVT_BUTTON, self.reset1Dscale) btn_rmv.Bind(wx.EVT_BUTTON, self.remove1Ddata) btn_hide.Disable() btn_rmv.Disable() hbox_btns.Add(btn_reset, flag=wx.ALL, border=10) hbox_btns.Add(btn_hide, flag=wx.ALL, border=10) hbox_btns.Add(btn_rmv, flag=wx.ALL, border=10) vbox.Add(hbox_btns, flag=wx.ALL, border=10) return vbox def AddPanel(self,panel): hbox = wx.BoxSizer(wx.HORIZONTAL) btn_data = wx.Button(panel,label='ADD NEW DATA SET') btn_data.Bind(wx.EVT_BUTTON, self.loadXYFILE) btn_cif = wx.Button(panel,label='ADD NEW CIF') btn_cif.Bind(wx.EVT_BUTTON, self.loadCIF) hbox.Add(btn_data, flag=wx.ALL, border=8) hbox.Add(btn_cif, flag=wx.ALL, border=8) return hbox def LeftSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) plttools = self.Toolbox(self) addbtns = self.AddPanel(self) dattools = self.DataBox(self) vbox.Add(plttools,flag=wx.ALL,border=10) vbox.Add(addbtns,flag=wx.ALL,border=10) vbox.Add(dattools,flag=wx.ALL,border=10) return vbox def RightSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) self.plot1DXRD(panel) btnbox = self.QuickButtons(panel) vbox.Add(self.plot1D,proportion=1,flag=wx.ALL|wx.EXPAND,border = 10) vbox.Add(btnbox,flag=wx.ALL|wx.ALIGN_RIGHT,border = 10) return vbox def QuickButtons(self,panel): buttonbox = wx.BoxSizer(wx.HORIZONTAL) btn_img = wx.Button(panel,label='SAVE FIGURE') btn_calib = wx.Button(panel,label='PLOT SETTINGS') btn_integ = wx.Button(panel,label='RESET PLOT') btn_img.Bind(wx.EVT_BUTTON, self.onSAVEfig) btn_calib.Bind(wx.EVT_BUTTON, self.onPLOTset) btn_integ.Bind(wx.EVT_BUTTON, self.onRESETplot) buttonbox.Add(btn_img, flag=wx.ALL, border=8) buttonbox.Add(btn_calib, flag=wx.ALL, border=8) buttonbox.Add(btn_integ, flag=wx.ALL, border=8) return buttonbox ############################################## #### PLOTPANEL FUNCTIONS def plot1DXRD(self,panel): self.plot1D = PlotPanel(panel,size=(1000, 500)) self.plot1D.messenger = self.owner.write_message ## Set defaults for plotting self.plot1D.set_ylabel('Intensity (a.u.)') self.plot1D.cursor_mode = 'zoom' ## trying to get this functionality into our gui ## mkak 2016.11.10 # interactive_legend().show() def onSAVEfig(self,event): self.plot1D.save_figure() def onPLOTset(self,event): self.plot1D.configure() def onRESETplot(self,event): self.plot1D.reset_config() ############################################## #### XRD PLOTTING FUNCTIONS def add1Ddata(self,x,y,name=None,cif=False,wavelength=None): plt_no = len(self.data_name) if cif: if name is None: name = 'cif %i' % plt_no else: name = 'cif: %s' % name else: if name is None: name = 'dataset %i' % plt_no else: name = 'data: %s' % name if wavelength is not None: self.addLAMBDA(wavelength) ## Add to data array lists self.data_name.append(name) self.xy_scale.append(max(y)) self.xy_data.extend([x,y]) ## redefine x,y based on scales self.xy_plot.extend([x,y]) ## Add to plot self.plotted_data.append(self.plot1D.oplot(x,y,label=name,show_legend=True))#,xlabel=self.xlabel)) ## Use correct x-axis units self.checkXaxis(None) self.ch_data.Set(self.data_name) self.ch_data.SetStringSelection(name) ## Update toolbox panel, scale all cif to 1000 if cif is True: self.entr_scale.SetValue('1000') self.normalize1Ddata(None) else: self.entr_scale.SetValue(str(self.xy_scale[plt_no])) def addLAMBDA(self,wavelength,units='m'): ## convert to units A if units == 'm': self.wavelength = wavelength*1e10 elif units == 'cm': self.wavelength = wavelength*1e8 elif units == 'mm': self.wavelength = wavelength*1e7 elif units == 'um': self.wavelength = wavelength*1e4 elif units == 'nm': self.wavelength = wavelength*1e1 else: ## units 'A' self.wavelength = wavelength self.xunits.append(u'2\u03B8') self.ch_xaxis.Set(self.xunits) def normalize1Ddata(self,event): plt_no = self.ch_data.GetSelection() self.xy_scale[plt_no] = float(self.entr_scale.GetValue()) if self.xy_scale[plt_no] <= 0: self.xy_scale[plt_no] = max(self.xy_data[(plt_no*2+1)]) self.entr_scale.SetValue(str(self.xy_scale[plt_no])) y = self.xy_data[(plt_no*2+1)] self.xy_plot[(plt_no*2+1)] = y/np.max(y) * self.xy_scale[plt_no] self.updatePLOT() def remove1Ddata(self,event): ## Needs pop up warning: "Do you really want to delete this data set from plotter? ## Current settings will not be saved." ## mkak 2016.11.10 plt_no = self.ch_data.GetSelection() print('EVENTUALLY, button will remove plot: %s' % self.data_name[plt_no]) ## removing name from list works... do not activate till rest is working ## mkak 2016.11.10 # self.data_name.remove(self.data_name[plt_no]) # self.ch_data.Set(self.data_name) def hide1Ddata(self,event): plt_no = self.ch_data.GetSelection() print('EVENTUALLY, button will hide plot: %s' % self.data_name[plt_no]) def onSELECT(self,event): data_str = self.ch_data.GetString(self.ch_data.GetSelection()) # self.ttl_data.SetLabel('SELECTED: %s' % data_str) plt_no = self.ch_data.GetSelection() self.entr_scale.SetValue(str(self.xy_scale[plt_no])) def checkXaxis(self, event): if self.ch_xaxis.GetSelection() == 2: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_2th(self.xy_data[plt_no*2],self.wavelength) elif self.ch_xaxis.GetSelection() == 1: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_d(self.xy_data[plt_no*2]) else: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = self.xy_data[plt_no*2] if self.ch_xaxis.GetSelection() == 2: self.xlabel = r'$2\Theta$'+r' $(^\circ)$' elif self.ch_xaxis.GetSelection() == 1: self.xlabel = 'd ($\AA$)' else: self.xlabel = 'q (1/$\AA$)' self.plot1D.set_xlabel(self.xlabel) self.updatePLOT() def updatePLOT(self): xmax,xmin,ymax,ymin = None,0,None,0 if len(self.plotted_data) > 0: for plt_no in range(len(self.plotted_data)): i = plt_no*2 j = i+1 x = self.xy_plot[i] y = self.xy_plot[j] if xmax is None or xmax < max(x): xmax = max(x) if xmin > min(x): xmin = min(x) if ymax is None or ymax < max(y): ymax = max(y) if ymin > min(y): ymin = min(y) self.plot1D.update_line(plt_no,x,y) self.unzoom_all() self.plot1D.canvas.draw() if self.ch_xaxis.GetSelection() == 1: xmax = 5 self.plot1D.set_xylims([xmin, xmax, ymin, ymax]) def reset1Dscale(self,event): plt_no = self.ch_data.GetSelection() self.xy_plot[(plt_no*2+1)] = self.xy_data[(plt_no*2+1)] self.plot1D.update_line(plt_no,self.xy_plot[(plt_no*2)], self.xy_plot[(plt_no*2+1)]) self.plot1D.canvas.draw() self.unzoom_all() self.updatePLOT() self.xy_scale[plt_no] = max(self.xy_data[(plt_no*2+1)]) self.entr_scale.SetValue(str(self.xy_scale[plt_no])) ####### BEGIN ####### ## THIS IS DIRECTLY FROM XRDDISPLAY.PY ## mkak 2016.11.11 def unzoom_all(self, event=None): xmid, xrange, xmin, xmax = self._get1Dlims() self._set_xview(xmin, xmax) self.xview_range = None def _get1Dlims(self): xmin, xmax = self.plot1D.axes.get_xlim() xrange = xmax-xmin xmid = (xmax+xmin)/2.0 if self.x_for_zoom is not None: xmid = self.x_for_zoom return (xmid, xrange, xmin, xmax) def _set_xview(self, x1, x2, keep_zoom=False, pan=False): xmin,xmax = self.abs_limits() xrange = x2-x1 x1 = max(xmin,x1) x2 = min(xmax,x2) if pan: if x2 == xmax: x1 = x2-xrange elif x1 == xmin: x2 = x1+xrange if not keep_zoom: self.x_for_zoom = (x1+x2)/2.0 self.plot1D.axes.set_xlim((x1, x2)) self.xview_range = [x1, x2] self.plot1D.canvas.draw() def abs_limits(self): if len(self.data_name) > 0: xmin, xmax = self.xy_plot[0].min(), self.xy_plot[0].max() return xmin,xmax ####### END ####### ############################################## #### XRD FILE OPENING/SAVING def loadXYFILE(self,event): wildcards = 'XRD data file (*.xy)|*.xy|All files (*.*)|*.*' dlg = wx.FileDialog(self, message='Choose 1D XRD data file', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.FD_OPEN) path, read = None, False if dlg.ShowModal() == wx.ID_OK: read = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if read: try: x,y = xy_file_reader(path) self.add1Ddata(x,y,name=os.path.split(path)[-1]) except: print('incorrect xy file format: %s' % os.path.split(path)[-1]) def saveXYFILE(self,event): wildcards = 'XRD data file (*.xy)|*.xy|All files (*.*)|*.*' dlg = wx.FileDialog(self, 'Save data as...', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.SAVE|wx.OVERWRITE_PROMPT) path, save = None, False if dlg.ShowModal() == wx.ID_OK: save = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if save: ## mkak 2016.11.16 print('need to write something to save data - like pyFAI does?') def loadCIF(self,event): wildcards = 'XRD cifile (*.cif)|*.cif|All files (*.*)|*.*' dlg = wx.FileDialog(self, message='Choose CIF', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.FD_OPEN) path, read = None, False if dlg.ShowModal() == wx.ID_OK: read = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if read: cifile = os.path.split(path)[-1] try: cif = xu.materials.Crystal.fromCIF(path) except: print('incorrect file format: %s' % os.path.split(path)[-1]) return ## generate hkl list hkllist = [] maxhkl = 8 for i in range(-maxhkl,maxhkl+1): for j in range(-maxhkl,maxhkl+1): for k in range(-maxhkl,maxhkl+1): if i+j+k > 0: # as long as h,k,l all positive, eliminates 0,0,0 hkllist.append([i,j,k]) hc = constants.value(u'Planck constant in eV s') * \ constants.value(u'speed of light in vacuum') * 1e-3 ## units: keV-m if self.wavelength is not None: qlist = cif.Q(hkllist) Flist = cif.StructureFactorForQ(qlist,(hc/(self.wavelength*(1e-10))*1e3)) Fall = [] qall = [] hklall = [] for i,hkl in enumerate(hkllist): if np.abs(Flist[i]) > 0.01: Fadd = np.abs(Flist[i]) qadd = np.linalg.norm(qlist[i]) if qadd not in qall and qadd < 6: Fall.extend((0,Fadd,0)) qall.extend((qadd,qadd,qadd)) if np.shape(Fall)[0] > 0: Fall = np.array(Fall) qall = np.array(qall) self.add1Ddata(qall,Fall,name=os.path.split(path)[-1],cif=True) else: print('Could not calculate real structure factors.') else: print('Wavelength/energy must be specified for structure factor calculations.') def openPONI(self,event): wildcards = 'pyFAI calibration file (*.poni)|*.poni|All files (*.*)|*.*' dlg = wx.FileDialog(self, message='Choose pyFAI calibration file', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.FD_OPEN) path, read = None, False if dlg.ShowModal() == wx.ID_OK: read = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if read: try: print('Loading calibration file: %s' % path) ai = pyFAI.load(path) except: print('Not recognized as a pyFAI calibration file.') return self.addLAMBDA(ai._wavelength,units='m') def setLAMBDA(self,event): dlg = SetLambdaDialog() path, okay = None, False if dlg.ShowModal() == wx.ID_OK: okay = True wavelength = dlg.wavelength dlg.Destroy() if okay: self.addLAMBDA(wavelength,units='A')
class ScanViewerFrame(wx.Frame): _about = """Scan Viewer, Matt Newville <newville @ cars.uchicago.edu> """ TIME_MSG = 'Point %i/%i, Time Remaining ~ %s, Status=%s' def __init__(self, parent, dbname=None, server='sqlite', host=None, port=None, user=None, password=None, create=True, _larch=None, **kws): wx.Frame.__init__(self, None, -1, style=FRAMESTYLE) title = "Epics Step Scan Viewer" self.parent = parent self.scandb = getattr(parent, 'scandb', None) if self.scandb is None and dbname is not None: self.scandb = ScanDB(dbname=dbname, server=server, host=host, user=user, password=password, port=port, create=create) self.larch = _larch if _larch is None: self.larch = LarchScanDBServer(self.scandb) self.lgroup = None self.larch.run("%s = group(filename='%s')" % (SCANGROUP, CURSCAN)) self.larch.run("_sys.localGroup = %s" % (SCANGROUP)) # self.larch.run("show(_sys)") self.lgroup = self.larch.get_symbol(SCANGROUP) self.force_newplot = False self.scan_inprogress = False self.last_column_update = 0.0 self.need_column_update = True self.positioner_pvs = {} self.x_cursor = None self.x_label = None self.SetTitle(title) self.SetSize((800, 700)) self.SetFont(Font(9)) self.createMainPanel() self.createMenus() self.last_status_msg = None self.statusbar = self.CreateStatusBar(2, 0) self.statusbar.SetStatusWidths([-3, -1]) statusbar_fields = ["Initializing....", " "] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) if self.scandb is not None: self.get_info = self.scandb.get_info self.scandb_server = self.scandb.server self.live_scanfile = None self.live_cpt = -1 self.total_npts = 1 self.scantimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onScanTimer, self.scantimer) self.scantimer.Start(300) self.Bind(wx.EVT_CLOSE, self.onClose) self.Show() self.SetStatusText('ready') self.title.SetLabel('') self.Raise() def onScanTimer(self, evt=None, **kws): if self.lgroup is None: return try: curfile = fix_filename(self.get_info('filename')) sdata = self.scandb.get_scandata() scan_stat = self.get_info('scan_status') msg = self.get_info('scan_progress') except: logging.exception("No Scan at ScanTime") try: # npts = len(sdata[-1].data) nptsall = [len(s.data) for s in sdata] npts = min(nptsall) except: npts = 0 if npts <= 0 or msg.lower().startswith('preparing'): self.need_column_update = True do_newplot = False if ((curfile != self.live_scanfile) or (npts > 0 and npts < 3 and self.need_column_update)): self.need_column_update = False self.scan_inprogress = True self.moveto_btn.Disable() do_newplot = True self.live_scanfile = curfile self.title.SetLabel(curfile) if len(sdata)>1: self.set_column_names(sdata) elif msg.lower().startswith('scan complete') and self.scan_inprogress: self.scan_inprogress = False self.moveto_btn.Enable() do_newplot = True elif msg.lower().startswith('scan abort'): self.moveto_btn.Enable() do_newplot = True if msg != self.last_status_msg: self.last_status_msg = msg self.SetStatusText(msg) if not (self.scan_inprogress or do_newplot): # print 'Scan Timer no reason to plot', do_newplot, self.scan_inprogress return for row in sdata: dat = row.data if self.scandb_server == 'sqlite': dat = json.loads(dat.replace('{', '[').replace('}', ']')) setattr(self.lgroup, fix_varname(row.name), np.array(dat)) if ((npts > 1 and npts != self.live_cpt) or (time.time() - self.last_column_update) > 30.0): if do_newplot: self.force_newplot = True self.onPlot(npts=npts) self.last_column_update = time.time() self.live_cpt = npts def set_column_names(self, sdata): """set column names from values read from scandata table""" if len(sdata) < 1: return try: self.lgroup.array_units = [fix_varname(s.units) for s in sdata] except: return self.total_npts = self.get_info('scan_total_points', as_int=True) self.live_cpt = -1 xcols, ycols, y2cols = [], [], [] self.positioner_pvs = {} for s in sdata: nam = fix_varname(s.name) ycols.append(nam) if s.notes.lower().startswith('pos'): xcols.append(nam) self.positioner_pvs[nam] = s.pvname # print("SET COLUMN NAMES", xcols, self.positioner_pvs) y2cols = ycols[:] + ['1.0', '0.0', ''] xarr_old = self.xarr.GetStringSelection() self.xarr.SetItems(xcols) ix = xcols.index(xarr_old) if xarr_old in xcols else 0 self.xarr.SetSelection(ix) for i in range(2): for j in range(3): yold = self.yarr[i][j].GetStringSelection() idef, cols = 0, y2cols if i == 0 and j == 0: idef, cols = 1, ycols self.yarr[i][j].SetItems(cols) # print(i, j, yold, yold in cols) iy = cols.index(yold) if yold in cols else idef self.yarr[i][j].SetSelection(iy) time.sleep(0.75) def createMainPanel(self): mainpanel = wx.Panel(self) mainsizer = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(mainpanel) self.yops = [[],[]] self.yarr = [[],[]] arr_kws= {'choices':[], 'size':(150, -1), 'action':self.onPlot} self.title = SimpleText(panel, 'initializing...', font=Font(13), colour='#880000') self.xarr = add_choice(panel, **arr_kws) for i in range(3): self.yarr[0].append(add_choice(panel, **arr_kws)) self.yarr[1].append(add_choice(panel, **arr_kws)) for opts, sel, wid in ((PRE_OPS, 0, 80), (ARR_OPS, 3, 40), (ARR_OPS, 3, 40)): arr_kws['choices'] = opts arr_kws['size'] = (wid, -1) self.yops[0].append(add_choice(panel, default=sel, **arr_kws)) self.yops[1].append(add_choice(panel, default=sel, **arr_kws)) # place widgets sizer = wx.GridBagSizer(5, 10) sizer.Add(self.title, (0, 1), (1, 6), LCEN, 2) sizer.Add(SimpleText(panel, ' X ='), (1, 0), (1, 1), CEN, 0) sizer.Add(self.xarr, (1, 3), (1, 1), RCEN, 0) ir = 1 for i in range(2): ir += 1 label = ' Y%i =' % (i+1) sizer.Add(SimpleText(panel, label), (ir, 0), (1, 1), CEN, 0) sizer.Add(self.yops[i][0], (ir, 1), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, '[('), (ir, 2), (1, 1), CEN, 0) sizer.Add(self.yarr[i][0], (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yops[i][1], (ir, 4), (1, 1), CEN, 0) sizer.Add(self.yarr[i][1], (ir, 5), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ')'), (ir, 6), (1, 1), LCEN, 0) sizer.Add(self.yops[i][2], (ir, 7), (1, 1), CEN, 0) sizer.Add(self.yarr[i][2], (ir, 8), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ']'), (ir, 9), (1, 1), LCEN, 0) ir += 1 sizer.Add(hline(panel), (ir, 0), (1, 12), CEN|wx.GROW|wx.ALL, 0) pack(panel, sizer) self.plotpanel = PlotPanel(mainpanel, size=(520, 550), fontsize=8) self.plotpanel.cursor_callback = self.onLeftDown self.plotpanel.messenger = self.write_message self.plotpanel.canvas.figure.set_facecolor((0.98,0.98,0.97)) self.plotpanel.unzoom = self.unzoom # self.plotpanel.popup_menu = None btnsizer = wx.StdDialogButtonSizer() btnpanel = wx.Panel(mainpanel) self.moveto_btn = add_button(btnpanel, 'Move To Position', action=self.onMoveTo) btnsizer.Add(add_button(btnpanel, 'Pause Scan', action=self.onPause)) btnsizer.Add(add_button(btnpanel, 'Resume Scan', action=self.onResume)) btnsizer.Add(add_button(btnpanel, 'Abort Scan', action=self.onAbort)) btnsizer.Add(add_button(btnpanel, 'Unzoom Plot', action=self.unzoom)) btnsizer.Add(self.moveto_btn) pack(btnpanel, btnsizer) mainsizer.Add(panel, 0, LCEN|wx.EXPAND, 2) mainsizer.Add(self.plotpanel, 1, wx.GROW|wx.ALL, 1) mainsizer.Add(btnpanel, 0, wx.GROW|wx.ALL, 1) pack(mainpanel, mainsizer) return mainpanel def onMoveTo(self, evt=None): pvname = self.positioner_pvs.get(self.x_label, None) if pvname is not None and self.x_cursor is not None: msg = " Move To Position:\n %s (%s) to %.4f " % (self.x_label, pvname, self.x_cursor) ret = popup(self, msg, "Move to Position?", style=wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION) if ret == wx.ID_YES: epics.caput(pvname, self.x_cursor) def onPause(self, evt=None): self.scandb.set_info('request_pause', 1) def onResume(self, evt=None): self.scandb.set_info('request_pause', 0) def onAbort(self, evt=None): self.scandb.set_info('request_abort', 1) def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def onLeftDown(self, x=None, y=None): self.x_cursor = x def onPlot(self, evt=None, npts=None): """draw plot of newest data""" new_plot = self.force_newplot or npts < 3 lgroup, gname = self.lgroup, SCANGROUP ix = self.xarr.GetSelection() x = self.xarr.GetStringSelection() self.x_label = x xlabel = x popts = {'labelfontsize': 8, 'xlabel': x, 'marker':'o', 'markersize':4} try: xunits = lgroup.array_units[ix] xlabel = '%s (%s)' % (xlabel, xunits) except: logging.exception("No units at onPlot") def make_array(wids, iy): gn = SCANGROUP op1 = self.yops[iy][0].GetStringSelection() op2 = self.yops[iy][1].GetStringSelection() op3 = self.yops[iy][2].GetStringSelection() yy1 = self.yarr[iy][0].GetStringSelection() yy2 = self.yarr[iy][1].GetStringSelection() yy3 = self.yarr[iy][2].GetStringSelection() if yy1 in ('0', '1', '', None) or len(yy1) < 0: return '', '' label = yy1 expr = "%s.%s" % (gn, yy1) if yy2 != '': label = "%s%s%s" % (label, op2, yy2) expr = "%s%s" % (expr, op2) if yy2 in ('1.0', '0.0'): expr = "%s%s" % (expr, yy2) else: expr = "%s%s.%s" % (expr, gn, yy2) if yy3 != '': label = "(%s)%s%s" % (label, op3, yy3) expr = "(%s)%s" % (expr, op3) if yy3 in ('1.0', '0.0'): expr = "%s%s" % (expr, yy3) else: expr = "%s%s.%s" % (expr, gn, yy3) if op1 != '': end = '' if '(' in op1: end = ')' label = "%s(%s)%s" % (op1, label, end) expr = "%s(%s)%s" % (op1, expr, end) return label, expr ylabel, yexpr = make_array(self.yops, 0) if yexpr == '': return self.larch.run("%s.arr_x = %s.%s" % (gname, gname, x)) self.larch.run("%s.arr_y1 = %s" % (gname, yexpr)) try: npts = min(len(lgroup.arr_x), len(lgroup.arr_y1)) except AttributeError: logging.exception("Problem getting arrays") y2label, y2expr = make_array(self.yops, 1) if y2expr != '': self.larch.run("%s.arr_y2 = %s" % (gname, y2expr)) n2pts = npts try: n2pts = min(len(lgroup.arr_x), len(lgroup.arr_y1), len(lgroup.arr_y2)) lgroup.arr_y2 = np.array( lgroup.arr_y2[:n2pts]) except: y2expr = '' npts = n2pts lgroup.arr_y1 = np.array( lgroup.arr_y1[:npts]) lgroup.arr_x = np.array( lgroup.arr_x[:npts]) path, fname = os.path.split(self.live_scanfile) popts.update({'title': fname, 'xlabel': xlabel, 'ylabel': ylabel, 'y2label': y2label}) if len(lgroup.arr_x) < 2 or len(lgroup.arr_y1) < 2: return if len(lgroup.arr_x) != len(lgroup.arr_y1): print 'data length mismatch ', len(lgroup.arr_x), len(lgroup.arr_y1) return ppnl = self.plotpanel if new_plot: ppnl.conf.zoom_lims = [] ppnl.plot(lgroup.arr_x, lgroup.arr_y1, label= "%s: %s" % (fname, ylabel), **popts) if y2expr != '': ppnl.oplot(lgroup.arr_x, lgroup.arr_y2, side='right', label= "%s: %s" % (fname, y2label), **popts) xmin, xmax = min(lgroup.arr_x), max(lgroup.arr_x) ppnl.axes.set_xlim((xmin, xmax), emit=True) ppnl.canvas.draw() else: ppnl.set_xlabel(xlabel) ppnl.set_ylabel(ylabel) ppnl.update_line(0, lgroup.arr_x, lgroup.arr_y1, draw=True, update_limits=True) ax = ppnl.axes ppnl.user_limits[ax] = (min(lgroup.arr_x), max(lgroup.arr_x), min(lgroup.arr_y1), max(lgroup.arr_y1)) if y2expr != '': ppnl.set_y2label(y2label) ppnl.update_line(1, lgroup.arr_x, lgroup.arr_y2, side='right', draw=True, update_limits=True) ax = ppnl.get_right_axes() ppnl.user_limits[ax] = (min(lgroup.arr_x), max(lgroup.arr_x), min(lgroup.arr_y2), max(lgroup.arr_y2)) self.force_newplot = False def createMenus(self): self.menubar = wx.MenuBar() # fmenu = wx.Menu() pmenu = wx.Menu() omenu = wx.Menu() fmenu.AppendSeparator() add_menu(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) self.menubar.Append(fmenu, "&File") fmenu.AppendSeparator() add_menu(self, fmenu, "&Copy\tCtrl+C", "Copy to Clipboard", self.onClipboard) add_menu(self, fmenu, "&Save\tCtrl+S", "Save Figure", self.onSaveFig) add_menu(self, fmenu, "&Print\tCtrl+P", "Print Figure", self.onPrint) add_menu(self, fmenu, "Page Setup", "Print Page Setup", self.onPrintSetup) add_menu(self, fmenu, "Preview", "Print Preview", self.onPrintPreview) # add_menu(self, omenu, "Enable Move To Position", "Force Enable of Move To Position", self.onForceEnableMoveTo) add_menu(self, pmenu, "Force Replot\tCtrl+F", "Replot", self.onForceReplot) add_menu(self, pmenu, "Configure\tCtrl+K", "Configure Plot", self.onConfigurePlot) add_menu(self, pmenu, "Unzoom\tCtrl+Z", "Unzoom Plot", self.unzoom) pmenu.AppendSeparator() add_menu(self, pmenu, "Toggle Legend\tCtrl+L", "Toggle Legend on Plot", self.onToggleLegend) add_menu(self, pmenu, "Toggle Grid\tCtrl+G", "Toggle Grid on Plot", self.onToggleGrid) self.menubar.Append(omenu, "Options") self.menubar.Append(pmenu, "Plot") self.SetMenuBar(self.menubar) def onForceEnableMoveTo(self, evt=None): self.moveto_btn.Enable() def onForceReplot(self, evt=None): self.force_newplot = True self.onPlot() def onClipboard(self, evt=None): self.plotpanel.canvas.Copy_to_Clipboard(evt) def onSaveFig(self, evt=None): self.plotpanel.save_figure(event=evt, transparent=True, dpi=300) def onPrint(self, evt=None): self.plotpanel.Print(evt) def onPrintSetup(self, evt=None): self.plotpanel.PrintSetup(evt) def onPrintPreview(self, evt=None): self.plotpanel.PrintPreview(evt) def onConfigurePlot(self, evt=None): self.plotpanel.configure(evt) def unzoom(self, event=None, **kwargs): ppnl = self.plotpanel ppnl.conf.zoom_lims = [] ppnl.user_limits = {} ppnl.user_limits[ppnl.axes] = (None, None, None, None) ppnl.user_limits[ppnl.get_right_axes()] = (None, None, None, None) self.force_newplot = True self.onPlot() def onToggleLegend(self, evt=None): self.plotpanel.toggle_legend(evt) def onToggleGrid(self, evt=None): self.plotpanel.toggle_grid(evt) def onAbout(self,evt): dlg = wx.MessageDialog(self, self._about,"About Epics StepScan", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self, evt=None): self.scantimer.Stop() self.Destroy()
class Fitting1DXRD(wx.Panel): ''' Frame for housing all 1D XRD fitting widgets ''' label='Fitting' def __init__(self,parent,owner=None,_larch=None): wx.Panel.__init__(self, parent) self.parent = parent self.owner = owner ## Default information self.xlabel = 'q (A^-1)' self.xunits = ['q','d'] self.Panel1DFitting() ############################################## #### PANEL DEFINITIONS def Panel1DFitting(self): ''' Frame for housing all 1D XRD viewer widgets ''' leftside = self.LeftSidePanel(self) rightside = self.RightSidePanel(self) panel1D = wx.BoxSizer(wx.HORIZONTAL) panel1D.Add(leftside,flag=wx.ALL,border=10) panel1D.Add(rightside,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) self.SetSizer(panel1D) def Toolbox(self,panel): ''' Frame for visual toolbox ''' tlbx = wx.StaticBox(self,label='PLOT TOOLBOX') vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) ########################### ## X-Scale hbox_xaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_xaxis = wx.StaticText(self, label='X-SCALE') self.ch_xaxis = wx.Choice(self,choices=self.xunits) self.ch_xaxis.Bind(wx.EVT_CHOICE, self.checkXaxis) hbox_xaxis.Add(ttl_xaxis, flag=wx.RIGHT, border=8) hbox_xaxis.Add(self.ch_xaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_xaxis, flag=wx.ALL, border=10) ########################### ## Y-Scale hbox_yaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_yaxis = wx.StaticText(self, label='Y-SCALE') yscales = ['linear','log'] self.ch_yaxis = wx.Choice(self,choices=yscales) self.ch_yaxis.Bind(wx.EVT_CHOICE, None) hbox_yaxis.Add(ttl_yaxis, flag=wx.RIGHT, border=8) hbox_yaxis.Add(self.ch_yaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_yaxis, flag=wx.ALL, border=10) return vbox def LeftSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) plttools = self.Toolbox(self) vbox.Add(plttools,flag=wx.ALL,border=10) return vbox def RightSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) self.plot1DXRD(panel) btnbox = self.QuickButtons(panel) vbox.Add(self.plot1D,proportion=1,flag=wx.ALL|wx.EXPAND,border = 10) vbox.Add(btnbox,flag=wx.ALL|wx.ALIGN_RIGHT,border = 10) return vbox def QuickButtons(self,panel): buttonbox = wx.BoxSizer(wx.HORIZONTAL) btn_img = wx.Button(panel,label='SAVE FIGURE') btn_calib = wx.Button(panel,label='PLOT SETTINGS') btn_integ = wx.Button(panel,label='RESET PLOT') btn_img.Bind(wx.EVT_BUTTON, self.onSAVEfig) btn_calib.Bind(wx.EVT_BUTTON, self.onPLOTset) btn_integ.Bind(wx.EVT_BUTTON, self.onRESETplot) buttonbox.Add(btn_img, flag=wx.ALL, border=8) buttonbox.Add(btn_calib, flag=wx.ALL, border=8) buttonbox.Add(btn_integ, flag=wx.ALL, border=8) return buttonbox ############################################## #### PLOTPANEL FUNCTIONS def plot1DXRD(self,panel): self.plot1D = PlotPanel(panel,size=(1000, 500)) self.plot1D.messenger = self.owner.write_message ## Set defaults for plotting self.plot1D.set_ylabel('Intensity (a.u.)') self.plot1D.cursor_mode = 'zoom' ## trying to get this functionality into our gui ## mkak 2016.11.10 # interactive_legend().show() def onSAVEfig(self,event): self.plot1D.save_figure() def onPLOTset(self,event): self.plot1D.configure() def onRESETplot(self,event): self.plot1D.reset_config() def checkXaxis(self, event): if self.ch_xaxis.GetSelection() == 2: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_2th(self.xy_data[plt_no*2],self.wavelength) elif self.ch_xaxis.GetSelection() == 1: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_d(self.xy_data[plt_no*2]) else: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = self.xy_data[plt_no*2] if self.ch_xaxis.GetSelection() == 2: self.xlabel = r'$2\Theta$'+r' $(^\circ)$' elif self.ch_xaxis.GetSelection() == 1: self.xlabel = 'd ($\AA$)' else: self.xlabel = 'q (1/$\AA$)' self.plot1D.set_xlabel(self.xlabel) self.updatePLOT() def updatePLOT(self): xmax,xmin,ymax,ymin = None,0,None,0 if len(self.plotted_data) > 0: for plt_no in range(len(self.plotted_data)): i = plt_no*2 j = i+1 x = self.xy_plot[i] y = self.xy_plot[j] if xmax is None or xmax < max(x): xmax = max(x) if xmin > min(x): xmin = min(x) if ymax is None or ymax < max(y): ymax = max(y) if ymin > min(y): ymin = min(y) self.plot1D.update_line(plt_no,x,y) self.unzoom_all() self.plot1D.canvas.draw() if self.ch_xaxis.GetSelection() == 1: xmax = 5 self.plot1D.set_xylims([xmin, xmax, ymin, ymax]) def reset1Dscale(self,event): plt_no = self.ch_data.GetSelection() self.xy_plot[(plt_no*2+1)] = self.xy_data[(plt_no*2+1)] self.plot1D.update_line(plt_no,self.xy_plot[(plt_no*2)], self.xy_plot[(plt_no*2+1)]) self.plot1D.canvas.draw() self.unzoom_all() self.updatePLOT() self.xy_scale[plt_no] = max(self.xy_data[(plt_no*2+1)]) self.entr_scale.SetValue(str(self.xy_scale[plt_no])) ####### BEGIN ####### ## THIS IS DIRECTLY FROM XRDDISPLAY.PY ## mkak 2016.11.11 def unzoom_all(self, event=None): xmid, xrange, xmin, xmax = self._get1Dlims() self._set_xview(xmin, xmax) self.xview_range = None def _get1Dlims(self): xmin, xmax = self.plot1D.axes.get_xlim() xrange = xmax-xmin xmid = (xmax+xmin)/2.0 if self.x_for_zoom is not None: xmid = self.x_for_zoom return (xmid, xrange, xmin, xmax) def _set_xview(self, x1, x2, keep_zoom=False, pan=False): xmin,xmax = self.abs_limits() xrange = x2-x1 x1 = max(xmin,x1) x2 = min(xmax,x2) if pan: if x2 == xmax: x1 = x2-xrange elif x1 == xmin: x2 = x1+xrange if not keep_zoom: self.x_for_zoom = (x1+x2)/2.0 self.plot1D.axes.set_xlim((x1, x2)) self.xview_range = [x1, x2] self.plot1D.canvas.draw() def abs_limits(self): if len(self.data_name) > 0: xmin, xmax = self.xy_plot[0].min(), self.xy_plot[0].max() return xmin,xmax