Exemplo n.º 1
0
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()
Exemplo n.º 2
0
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')
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
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