Exemplo n.º 1
0
class PlotterFrame(wx.Frame):
    _about = """StepScan 2D Plotter
  Matt Newville <newville @ cars.uchicago.edu>
  """
    def __init__(self, dbname=None, server='sqlite', host=None,
                 port=None, user=None, password=None, create=True, **kws):


        wx.Frame.__init__(self, None, -1, style=FRAMESTYLE)
        self.data = None
        self.filemap = {}
        title = "Step Scan Data File Viewer"
        self.scandb = None
        if dbname is not None:
            self.scandb = ScanDB(dbname=dbname, server=server, host=host,
                                 user=user, password=password, port=port,
                                 create=create)
            self.filemap[CURSCAN] = SCANGROUP
            title = '%s, with Live Scan Viewing' % title
        self.larch = None
        self.plotters = []

        self.SetTitle(title)
        self.SetSize((850, 650))
        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 dbname is not None:
            self.live_scanfile = None
            self.live_cpt = -1
            self.filelist.Append(CURSCAN)
            self.scantimer = wx.Timer(self)
            self.Bind(wx.EVT_TIMER, self.onScanTimer, self.scantimer)
            self.scantimer.Start(250)

    def onScanTimer(self, evt=None, **kws):
        if self.larch is None:
            return
        group =  getattr(self.larch.symtable, SCANGROUP)

        curfile = fix_filename(self.scandb.get_info('filename'))
        if curfile != self.live_scanfile:
            self.live_scanfile = curfile
            group.filename = self.live_scanfile
            group.array_units = []
            self.live_cpt = -1

        sdata = self.scandb.get_scandata()
        if len(sdata) <= 1:
            return
        npts = len(sdata[-1].data)

        if npts <= self.live_cpt:
            return

        self.live_cpt = npts
        if len(group.array_units) < 1:
            group.array_units = [str(row.notes) for row in sdata]

        for row in sdata:
            setattr(group, fix_filename(row.name), np.array(row.data))

        if npts > 1:
            self.onPlot()

    def createMainPanel(self):
        splitter  = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        splitter.SetMinimumPaneSize(175)

        self.filelist  = wx.ListBox(splitter)
        self.filelist.SetBackgroundColour(wx.Colour(255, 255, 255))
        self.filelist.Bind(wx.EVT_LISTBOX, self.ShowFile)

        self.detailspanel = self.createDetailsPanel(splitter)

        splitter.SplitVertically(self.filelist, self.detailspanel, 1)
        wx.CallAfter(self.init_larch)

    def createDetailsPanel(self, parent):
        mainpanel = wx.Panel(parent)
        mainsizer = wx.BoxSizer(wx.VERTICAL)
        panel = wx.Panel(mainpanel)
        sizer = wx.GridBagSizer(8, 7)

        self.title = SimpleText(panel, 'initializing...')
        ir = 0
        sizer.Add(self.title, (ir, 0), (1, 6), LCEN, 2)
        # x-axis

        self.xarr = add_choice(panel, choices=[],
                               action=self.onYchoice,  size=(120, -1))
        self.xop  = add_choice(panel, choices=('', 'log'),
                               action=self.onYchoice, size=(75, -1))

        ir += 1
        sizer.Add(SimpleText(panel, 'X = '), (ir, 0), (1, 1), CEN, 0)
        sizer.Add(self.xop,                  (ir, 1), (1, 1), CEN, 0)
        sizer.Add(SimpleText(panel, '('),    (ir, 2), (1, 1), CEN, 0)
        sizer.Add(self.xarr,                 (ir, 3), (1, 1), RCEN, 0)
        sizer.Add(SimpleText(panel, ')'),    (ir, 4), (1, 1), CEN, 0)

        self.yops = [[],[]]
        self.yarr = [[],[]]

        for opts, sel, siz in ((PRE_OPS, 0, 75), (ARR_OPS, 3, 50),
                             (ARR_OPS, 3, 50)):
            w1 = add_choice(panel, choices=opts, action=self.onYchoice,
                            size=(siz, -1))
            w1.SetSelection(sel)
            self.yops[0].append(w1)

            w2 = add_choice(panel, choices=opts, action=self.onYchoice,
                            size=(siz, -1))
            w2.SetSelection(sel)
            self.yops[1].append(w2)

        opts= {'choices':[], 'size':(120, -1), 'action':self.onYchoice}
        for i in range(3):
            self.yarr[0].append(add_choice(panel, **opts))
            self.yarr[1].append(add_choice(panel, **opts))

        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(SimpleText(panel, ' New Plot: '),  (ir,   0), (1, 3), LCEN, 0)
        # sizer.Add(SimpleText(panel, ' Over Plot: '), (ir+1, 0), (1, 3), LCEN, 0)

        for jr, ic, dc, opt, ttl in ((0, 0, 4, 'win old',    'New Plot, This Window'),
                                     (0, 4, 2, 'win new',    'New Plot, New Window'),
                                     (1, 0, 4, 'over left',  'Over Plot, Left Axis'),
                                     (1, 4, 2, 'over right', 'Over Plot, Right Axis')):
            sizer.Add(add_button(panel, ttl, size=(165, -1),
                                 action=Closure(self.onPlot, opt=opt)),
                      (ir+jr, ic), (1, dc), LCEN, 2)

        ir += 2
        self.dtcorr   = check(panel, default=True, label='correct deadtime?')
        sizer.Add(self.dtcorr,  (ir,   0), (1, 3), LCEN, 0)
        ir += 1
        sizer.Add(SimpleText(panel, ''), (ir,   0), (1, 3), LCEN, 0)

        pack(panel, sizer)


#         self.nb = flat_nb.FlatNotebook(mainpanel, -1, agwStyle=FNB_STYLE)
#
#         self.nb.SetTabAreaColour(wx.Colour(248,248,240))
#         self.nb.SetActiveTabColour(wx.Colour(254,254,195))
#
#         self.nb.SetNonActiveTabTextColour(wx.Colour(40,40,180))
#         self.nb.SetActiveTabTextColour(wx.Colour(80,0,0))
#
#         self.xas_panel = self.CreateXASPanel(self.nb) # mainpanel)
#         self.fit_panel = self.CreateFitPanel(self.nb) # mainpanel)
#
#         self.nb.AddPage(self.fit_panel, ' General Analysis ', True)
#         self.nb.AddPage(self.xas_panel, ' XAS Processing ',   True)

        mainsizer.Add(panel,   0, LCEN|wx.EXPAND, 2)
        self.plotpanel = PlotPanel(mainpanel, size=(500, 670))
        self.plotpanel.messenger = self.write_message

        bgcol = panel.GetBackgroundColour()
        bgcol = (bgcol[0]/255., bgcol[1]/255., bgcol[2]/255.)
        self.plotpanel.canvas.figure.set_facecolor(bgcol)

        mainsizer.Add(self.plotpanel, 1, wx.GROW|wx.ALL, 1)

        # mainsizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2)
        pack(mainpanel, mainsizer)

        return mainpanel

    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._x1_
        y = lgroup._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)
        # plotframe = self.get_plotwindow()
        # plotframe.oplot(x, pgroup.fit, label='fit (%s)' % model)
        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
        """
        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._x1_),  max(lgroup._x1_)
            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.SetStatusText('ready')
        self.datagroups = self.larch.symtable
        self.title.SetLabel('')

    def write_message(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(s, panel)

    def get_plotwindow(self, new=False, **kws):
        pframe = None
        if not new:
            while pframe is None:
                try:
                    pframe = self.plotters.pop()
                    pframe.Show()
                    pframe.Raise()
                except IndexError:
                    pframe = None
                    break
                except PyDeadObjectError:
                    pframe = None

        if pframe is None:
            pframe = PlotFrame()
            pframe.Show()
            pframe.Raise()

        self.plotters.append(pframe)

        return pframe

    def onYchoice(self, evt=None, side='left'):
        self.onPlot()

    def onPlot(self, evt=None, opt='new old', npts=None):
        # 'win new', 'New Window'),
        # 'win old',  'Old Window'),
        # 'over left', 'Left Axis'),
        # 'over right', 'Right Axis')):
        # 'update left',  from scan

        optwords = opt.split()
        # plotframe = self.get_plotwindow(new=('new' in optwords[1]))
        # plotcmd = plotframe.plot
        plotcmd = self.plotpanel.plot

        optwords = opt.split()
        side = 'left'
        update = False
        if optwords[0] == 'over':
            side = optwords[1]
            plotcmd = self.plotpanel.oplot
        elif optwords[0] == 'update'  and npts > 4:
            plotcmd = self.plotpanel.update_line
            update = True

        popts = {'side': side}

        ix = self.xarr.GetSelection()
        x  = self.xarr.GetStringSelection()

        try:
            gname = self.groupname
            lgroup = getattr(self.larch.symtable, gname)
        except:
            gname = SCANGROUP
            lgroup = getattr(self.larch.symtable, gname)

        xfmt = "%s._x1_ = %s(%s)"
        yfmt = "%s._y1_ = %s((%s %s %s) %s (%s))"
        xop = self.xop.GetStringSelection()

        xlabel = x
        try:
            xunits = lgroup.array_units[ix]
        except:
            xunits = ''
        if xop != '':
            xlabel = "%s(%s)" % (xop, xlabel)
        if xunits != '':
            xlabel = '%s (%s)' % (xlabel, xunits)
        popts['xlabel'] = xlabel

        opl1 = self.yops[0][0].GetStringSelection()
        opl2 = self.yops[0][1].GetStringSelection()
        opl3 = self.yops[0][2].GetStringSelection()

        yl1 = self.yarr[0][0].GetStringSelection()
        yl2 = self.yarr[0][1].GetStringSelection()
        yl3 = self.yarr[0][2].GetStringSelection()

        opr1 = self.yops[1][0].GetStringSelection()
        opr2 = self.yops[1][1].GetStringSelection()
        opr3 = self.yops[1][2].GetStringSelection()

        yr1 = self.yarr[1][0].GetStringSelection()
        yr2 = self.yarr[1][1].GetStringSelection()
        yr3 = self.yarr[1][2].GetStringSelection()

        ylabel = yl1

        if yl2 == '':
            yl2, opl2 = '1', '*'
        else:
            ylabel = "%s%s%s" % (ylabel, opl2, yl2)
        if yl3 == '':
            yl3, opl3 = '1', '*'
        else:
            ylabel = "(%s)%s%s" % (ylabel, opl3, yl3)

        if opl1 != '':
            ylabel = "%s(%s)" % (opl1, ylabel)

        if yl1 not in ('0', '1'): yl1 = "%s.%s" % (gname, yl1)
        if yl2 not in ('0', '1'): yl2 = "%s.%s" % (gname, yl2)
        if yl3 not in ('0', '1'): yl3 = "%s.%s" % (gname, yl3)
        if x  not in ('0', '1'):  x = "%s.%s" % (gname,  x)


        self.larch(xfmt % (gname, xop, x))
        self.larch(yfmt % (gname, opl1, yl1, opl2, yl2, opl3, yl3))

        try:
            npts = min(len(lgroup._x1_), len(lgroup._y1_))
        except AttributeError:
            return

        lgroup._x1_ = np.array( lgroup._x1_[:npts])
        lgroup._y1_ = np.array( lgroup._y1_[:npts])


        path, fname = os.path.split(lgroup.filename)
        popts['label'] = "%s: %s" % (fname, ylabel)
        if side == 'right':
            popts['y2label'] = ylabel
        else:
            popts['ylabel'] = ylabel

        if plotcmd == self.plotpanel.plot:
            popts['title'] = fname

        # XAFS Processing!
        #if (self.nb.GetCurrentPage() == self.xas_panel):
        #    popts = self.xas_process(gname, popts)

        if update:
            self.plotpanel.set_xlabel(popts['xlabel'])
            self.plotpanel.set_ylabel(popts['ylabel'])

            plotcmd(0, lgroup._x1_, lgroup._y1_, draw=True,
                        update_limits=True) # ((npts < 5) or (npts % 5 == 0)))

            self.plotpanel.set_xylims((
                min(lgroup._x1_), max(lgroup._x1_),
                min(lgroup._y1_), max(lgroup._y1_)))

        else:
            plotcmd(lgroup._x1_, lgroup._y1_, **popts)
            self.plotpanel.canvas.draw()

    def ShowFile(self, evt=None, filename=None, **kws):
        if filename is None and evt is not None:
            filename = evt.GetString()
        key = filename
        if filename in self.filemap:
            key = self.filemap[filename]

        if key == SCANGROUP:
            array_labels = [fix_filename(s.name) for s in self.scandb.get_scandata()]
            title = filename
        elif hasattr(self.datagroups, key):
            data = getattr(self.datagroups, key)
            title = data.filename
            array_labels = data.array_labels[:]

        self.groupname = key
        xcols  = array_labels[:]
        ycols  = array_labels[:]
        y2cols = array_labels[:] + ['1.0', '0.0', '']
        ncols  = len(xcols)
        self.title.SetLabel(title)
        self.xarr.SetItems(xcols)
        self.xarr.SetSelection(0)
        self.xop.SetSelection(0)
        for i in range(2):
            for j in range(3):
                self.yarr[i][j].SetItems(y2cols)
                self.yarr[i][j].SetSelection(len(y2cols))
            if i == 0:
                self.yarr[i][0].SetItems(ycols)
                self.yarr[i][0].SetSelection(1)

        inb = 0
        for colname in xcols:
            if 'energ' in colname.lower():
                inb = 1
        #self.nb.SetSelection(inb)

    def createMenus(self):
        # ppnl = self.plotpanel
        self.menubar = wx.MenuBar()
        #
        fmenu = wx.Menu()
        pmenu = wx.Menu()
        add_menu(self, fmenu, "&Open Scan File\tCtrl+O",
                 "Read Scan File",  self.onReadScan)

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

    def onReadScan(self, evt=None):
        dlg = wx.FileDialog(self, message="Load Epics Scan Data File",
                            defaultDir=os.getcwd(),
                            wildcard=FILE_WILDCARDS, style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            path = path.replace('\\', '/')
            if path in self.filemap:
                if wx.ID_YES != popup(self, "Re-read file '%s'?" % path,
                                      'Re-read file?'):
                    return

            gname = randname(n=5)
            if hasattr(self.datagroups, gname):
                time.sleep(0.005)
                gname = randname(n=6)
            parent, fname = os.path.split(path)
            self.larch("%s = read_xdi('%s')" % (gname, path))
            self.larch("%s.path  = '%s'"     % (gname, path))
            self.filelist.Append(fname)
            self.filemap[fname] = gname
            print( 'Larch:: ', gname, path, fname)
            self.ShowFile(filename=fname)

        dlg.Destroy()
Exemplo n.º 2
0
class StripChartFrame(wx.Frame):
    def __init__(self, parent, ID, **kws):
        kws["style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL

        wx.Frame.__init__(self, parent, ID, '', wx.DefaultPosition,
                          wx.Size(-1, -1), **kws)
        self.SetTitle("wxmplot StripChart Demo")

        self.tmin = 15.0

        self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        menu = wx.Menu()
        ID_EXIT = wx.NewId()
        ID_TIMER = wx.NewId()

        menu_exit = menu.Append(ID_EXIT, "E&xit", "Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(menu, "&File")
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.OnExit, menu_exit)
        self.Bind(wx.EVT_CLOSE, self.OnExit)

        sbar = self.CreateStatusBar(2, wx.CAPTION)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(11)
        sbar.SetFont(sfont)
        self.SetStatusWidths([-3, -1])
        self.SetStatusText('', 0)

        mainsizer = wx.BoxSizer(wx.VERTICAL)

        btnpanel = wx.Panel(self, -1)
        btnsizer = wx.BoxSizer(wx.HORIZONTAL)

        b_on = wx.Button(btnpanel, -1, 'Start', size=(-1, -1))
        b_off = wx.Button(btnpanel, -1, 'Stop', size=(-1, -1))

        b_on.Bind(wx.EVT_BUTTON, self.onStartTimer)
        b_off.Bind(wx.EVT_BUTTON, self.onStopTimer)

        tlabel = wx.StaticText(btnpanel, -1, '  Time range:')
        self.time_range = FloatCtrl(btnpanel,
                                    size=(100, -1),
                                    value=abs(self.tmin),
                                    precision=1)

        btnsizer.Add(b_on, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0)
        btnsizer.Add(b_off, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0)
        btnsizer.Add(
            tlabel, 1,
            wx.GROW | wx.ALL | wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0)
        btnsizer.Add(self.time_range, 0,
                     wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0)

        btnpanel.SetSizer(btnsizer)
        btnsizer.Fit(btnpanel)

        self.plotpanel = PlotPanel(self, messenger=self.write_message)
        self.plotpanel.BuildPanel()
        self.plotpanel.set_xlabel('Time from Present (s)')
        mainsizer.Add(btnpanel, 0,
                      wx.GROW | wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0)
        mainsizer.Add(
            self.plotpanel, 1,
            wx.GROW | wx.ALL | wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)
        self.count = 0
        self.Refresh()
        wx.CallAfter(self.onStartTimer)

    def write_message(self, msg, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(msg, panel)

    def onStartTimer(self, event=None):
        self.count = 0
        t0, y0 = next_data()
        self.ylist = [y0]
        self.tlist = [t0]
        self.tmin_last = -10000
        self.time0 = time.time()
        self.timer.Start(50)

    def onStopTimer(self, event=None):
        self.timer.Stop()

    def onTimer(self, event):
        self.count += 1
        etime = time.time() - self.time0
        self.tmin = float(self.time_range.GetValue())
        t1, y1 = next_data()
        self.tlist.append(t1)
        self.ylist.append(y1)
        tdat = np.array(self.tlist) - t1
        mask = np.where(tdat > -abs(self.tmin))
        ydat = np.array(self.ylist)

        n = len(self.ylist)
        if n <= 2:
            self.plotpanel.plot(tdat, ydat)
        else:
            self.plotpanel.update_line(0, tdat, ydat, draw=True)
            self.write_message(" %i points in %8.4f s" % (n, etime))

        lims = self.plotpanel.get_viewlimits()
        try:
            ymin, ymax = ydat[mask].min(), ydat[mask].max()
        except:
            ymin, ymax = ydat.min(), ydat.max()
        tmin = max(int(min(tdat)) - 1.0, -self.tmin)
        if (ymin < lims[2] or ymax > lims[3] or tmin != self.tmin_last
                or time.time() - self.last_update > 2):
            self.tmin_last = tmin
            self.last_update = time.time()
            self.plotpanel.set_xylims((tmin, 0, ymin, ymax))

    def OnAbout(self, event):
        dlg = wx.MessageDialog(self, "wxmplot example: stripchart app",
                               "About WXMPlot test",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, event):
        self.Destroy()
Exemplo n.º 3
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.º 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
Exemplo n.º 5
0
class StripChartFrame(wx.Frame):
    def __init__(self, parent, ID, **kws):
        kws["style"] = wx.DEFAULT_FRAME_STYLE|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL

        wx.Frame.__init__(self, parent, ID, '',
                         wx.DefaultPosition, wx.Size(-1,-1), **kws)
        self.SetTitle("wxmplot StripChart Demo")

        self.tmin = 15.0

        self.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.BOLD,False))
        menu = wx.Menu()
        ID_EXIT  = wx.NewId()
        ID_TIMER = wx.NewId()

        menu_exit = menu.Append(ID_EXIT, "E&xit",
                                "Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(menu, "&File");
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU,  self.OnExit, menu_exit)
        self.Bind(wx.EVT_CLOSE, self.OnExit)

        sbar = self.CreateStatusBar(2,wx.CAPTION)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(11)
        sbar.SetFont(sfont)
        self.SetStatusWidths([-3,-1])
        self.SetStatusText('',0)

        mainsizer = wx.BoxSizer(wx.VERTICAL)

        btnpanel = wx.Panel(self, -1)
        btnsizer = wx.BoxSizer(wx.HORIZONTAL)

        b_on  = wx.Button(btnpanel, -1, 'Start',   size=(-1,-1))
        b_off = wx.Button(btnpanel, -1, 'Stop',    size=(-1,-1))

        b_on.Bind(wx.EVT_BUTTON, self.onStartTimer)
        b_off.Bind(wx.EVT_BUTTON, self.onStopTimer)

        tlabel = wx.StaticText(btnpanel, -1, '  Time range:')
        self.time_range = FloatCtrl(btnpanel,  size=(100, -1),
                                    value=abs(self.tmin), precision=1)

        btnsizer.Add(b_on,   0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)
        btnsizer.Add(b_off,  0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)
        btnsizer.Add(tlabel, 1, wx.GROW|wx.ALL|wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)
        btnsizer.Add(self.time_range, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)

        btnpanel.SetSizer(btnsizer)
        btnsizer.Fit(btnpanel)

        self.plotpanel = PlotPanel(self, messenger=self.write_message)
        self.plotpanel.BuildPanel()
        self.plotpanel.set_xlabel('Time from Present (s)')
        mainsizer.Add(btnpanel,       0,
                      wx.GROW|wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)
        mainsizer.Add(self.plotpanel, 1,
                      wx.GROW|wx.ALL|wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)
        self.count    = 0
        self.Refresh()
        wx.CallAfter(self.onStartTimer)

    def write_message(self, msg, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(msg, panel)

    def onStartTimer(self,event=None):
        self.count    = 0
        t0,y0 = next_data()
        self.ylist = [y0]
        self.tlist = [t0]
        self.tmin_last = -10000
        self.time0    = time.time()
        self.timer.Start(50)

    def onStopTimer(self,event=None):
        self.timer.Stop()

    def onTimer(self, event):
        self.count += 1
        etime = time.time() - self.time0
        self.tmin = float(self.time_range.GetValue())
        t1, y1 = next_data()
        self.tlist.append(t1)
        self.ylist.append(y1)
        tdat = np.array(self.tlist) - t1
        mask = np.where(tdat > -abs(self.tmin))
        ydat = np.array(self.ylist)

        n = len(self.ylist)
        if n <= 2:
            self.plotpanel.plot(tdat, ydat)
        else:
            self.plotpanel.update_line(0, tdat, ydat, draw=True)
            self.write_message(" %i points in %8.4f s" % (n,etime))

        lims = self.plotpanel.get_viewlimits()
        try:
            ymin, ymax = ydat[mask].min(), ydat[mask].max()
        except:
            ymin, ymax = ydat.min(), ydat.max()
        tmin = max(int(min(tdat)) - 1.0, -self.tmin)
        if (ymin < lims[2] or ymax >  lims[3] or
            tmin != self.tmin_last or time.time()-self.last_update > 2):
            self.tmin_last = tmin
            self.last_update = time.time()
            self.plotpanel.set_xylims((tmin, 0, ymin, ymax))

    def OnAbout(self, event):
        dlg = wx.MessageDialog(self, "wxmplot example: stripchart app",
                              "About WXMPlot test", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, event):
        self.Destroy()
Exemplo n.º 6
0
class PlotterFrame(wx.Frame):
    _about = """StepScan 2D Plotter
  Matt Newville <newville @ cars.uchicago.edu>
  """

    def __init__(self,
                 dbname=None,
                 server='sqlite',
                 host=None,
                 port=None,
                 user=None,
                 password=None,
                 create=True,
                 **kws):

        wx.Frame.__init__(self, None, -1, style=FRAMESTYLE)
        self.data = None
        self.filemap = {}
        title = "Step Scan Data File Viewer"
        self.scandb = None
        if dbname is not None:
            self.scandb = ScanDB(dbname=dbname,
                                 server=server,
                                 host=host,
                                 user=user,
                                 password=password,
                                 port=port,
                                 create=create)
            self.filemap[CURSCAN] = SCANGROUP
            title = '%s, with Live Scan Viewing' % title
        self.larch = None
        self.plotters = []

        self.SetTitle(title)
        self.SetSize((850, 650))
        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 dbname is not None:
            self.live_scanfile = None
            self.live_cpt = -1
            self.filelist.Append(CURSCAN)
            self.scantimer = wx.Timer(self)
            self.Bind(wx.EVT_TIMER, self.onScanTimer, self.scantimer)
            self.scantimer.Start(250)

    def onScanTimer(self, evt=None, **kws):
        if self.larch is None:
            return
        group = getattr(self.larch.symtable, SCANGROUP)

        curfile = fix_filename(self.scandb.get_info('filename'))
        if curfile != self.live_scanfile:
            self.live_scanfile = curfile
            group.filename = self.live_scanfile
            group.array_units = []
            self.live_cpt = -1

        sdata = self.scandb.get_scandata()
        if len(sdata) <= 1:
            return
        npts = len(sdata[-1].data)

        if npts <= self.live_cpt:
            return

        self.live_cpt = npts
        if len(group.array_units) < 1:
            group.array_units = [str(row.notes) for row in sdata]

        for row in sdata:
            setattr(group, fix_filename(row.name), np.array(row.data))

        if npts > 1:
            self.onPlot()

    def createMainPanel(self):
        splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        splitter.SetMinimumPaneSize(175)

        self.filelist = wx.ListBox(splitter)
        self.filelist.SetBackgroundColour(wx.Colour(255, 255, 255))
        self.filelist.Bind(wx.EVT_LISTBOX, self.ShowFile)

        self.detailspanel = self.createDetailsPanel(splitter)

        splitter.SplitVertically(self.filelist, self.detailspanel, 1)
        wx.CallAfter(self.init_larch)

    def createDetailsPanel(self, parent):
        mainpanel = wx.Panel(parent)
        mainsizer = wx.BoxSizer(wx.VERTICAL)
        panel = wx.Panel(mainpanel)
        sizer = wx.GridBagSizer(8, 7)

        self.title = SimpleText(panel, 'initializing...')
        ir = 0
        sizer.Add(self.title, (ir, 0), (1, 6), LCEN, 2)
        # x-axis

        self.xarr = add_choice(panel,
                               choices=[],
                               action=self.onYchoice,
                               size=(120, -1))
        self.xop = add_choice(panel,
                              choices=('', 'log'),
                              action=self.onYchoice,
                              size=(75, -1))

        ir += 1
        sizer.Add(SimpleText(panel, 'X = '), (ir, 0), (1, 1), CEN, 0)
        sizer.Add(self.xop, (ir, 1), (1, 1), CEN, 0)
        sizer.Add(SimpleText(panel, '('), (ir, 2), (1, 1), CEN, 0)
        sizer.Add(self.xarr, (ir, 3), (1, 1), RCEN, 0)
        sizer.Add(SimpleText(panel, ')'), (ir, 4), (1, 1), CEN, 0)

        self.yops = [[], []]
        self.yarr = [[], []]

        for opts, sel, siz in ((PRE_OPS, 0, 75), (ARR_OPS, 3, 50), (ARR_OPS, 3,
                                                                    50)):
            w1 = add_choice(panel,
                            choices=opts,
                            action=self.onYchoice,
                            size=(siz, -1))
            w1.SetSelection(sel)
            self.yops[0].append(w1)

            w2 = add_choice(panel,
                            choices=opts,
                            action=self.onYchoice,
                            size=(siz, -1))
            w2.SetSelection(sel)
            self.yops[1].append(w2)

        opts = {'choices': [], 'size': (120, -1), 'action': self.onYchoice}
        for i in range(3):
            self.yarr[0].append(add_choice(panel, **opts))
            self.yarr[1].append(add_choice(panel, **opts))

        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(SimpleText(panel, ' New Plot: '),  (ir,   0), (1, 3), LCEN, 0)
        # sizer.Add(SimpleText(panel, ' Over Plot: '), (ir+1, 0), (1, 3), LCEN, 0)

        for jr, ic, dc, opt, ttl in ((0, 0, 4, 'win old',
                                      'New Plot, This Window'),
                                     (0, 4, 2, 'win new',
                                      'New Plot, New Window'),
                                     (1, 0, 4, 'over left',
                                      'Over Plot, Left Axis'),
                                     (1, 4, 2, 'over right',
                                      'Over Plot, Right Axis')):
            sizer.Add(
                add_button(panel,
                           ttl,
                           size=(165, -1),
                           action=Closure(self.onPlot, opt=opt)),
                (ir + jr, ic), (1, dc), LCEN, 2)

        ir += 2
        self.dtcorr = check(panel, default=True, label='correct deadtime?')
        sizer.Add(self.dtcorr, (ir, 0), (1, 3), LCEN, 0)
        ir += 1
        sizer.Add(SimpleText(panel, ''), (ir, 0), (1, 3), LCEN, 0)

        pack(panel, sizer)

        #         self.nb = flat_nb.FlatNotebook(mainpanel, -1, agwStyle=FNB_STYLE)
        #
        #         self.nb.SetTabAreaColour(wx.Colour(248,248,240))
        #         self.nb.SetActiveTabColour(wx.Colour(254,254,195))
        #
        #         self.nb.SetNonActiveTabTextColour(wx.Colour(40,40,180))
        #         self.nb.SetActiveTabTextColour(wx.Colour(80,0,0))
        #
        #         self.xas_panel = self.CreateXASPanel(self.nb) # mainpanel)
        #         self.fit_panel = self.CreateFitPanel(self.nb) # mainpanel)
        #
        #         self.nb.AddPage(self.fit_panel, ' General Analysis ', True)
        #         self.nb.AddPage(self.xas_panel, ' XAS Processing ',   True)

        mainsizer.Add(panel, 0, LCEN | wx.EXPAND, 2)
        self.plotpanel = PlotPanel(mainpanel, size=(500, 670))
        self.plotpanel.messenger = self.write_message

        bgcol = panel.GetBackgroundColour()
        bgcol = (bgcol[0] / 255., bgcol[1] / 255., bgcol[2] / 255.)
        self.plotpanel.canvas.figure.set_facecolor(bgcol)

        mainsizer.Add(self.plotpanel, 1, wx.GROW | wx.ALL, 1)

        # mainsizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2)
        pack(mainpanel, mainsizer)

        return mainpanel

    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._x1_
        y = lgroup._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)
        # plotframe = self.get_plotwindow()
        # plotframe.oplot(x, pgroup.fit, label='fit (%s)' % model)
        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
        """
        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._x1_), max(lgroup._x1_)
            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.SetStatusText('ready')
        self.datagroups = self.larch.symtable
        self.title.SetLabel('')

    def write_message(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(s, panel)

    def get_plotwindow(self, new=False, **kws):
        pframe = None
        if not new:
            while pframe is None:
                try:
                    pframe = self.plotters.pop()
                    pframe.Show()
                    pframe.Raise()
                except IndexError:
                    pframe = None
                    break
                except PyDeadObjectError:
                    pframe = None

        if pframe is None:
            pframe = PlotFrame()
            pframe.Show()
            pframe.Raise()

        self.plotters.append(pframe)

        return pframe

    def onYchoice(self, evt=None, side='left'):
        self.onPlot()

    def onPlot(self, evt=None, opt='new old', npts=None):
        # 'win new', 'New Window'),
        # 'win old',  'Old Window'),
        # 'over left', 'Left Axis'),
        # 'over right', 'Right Axis')):
        # 'update left',  from scan

        optwords = opt.split()
        # plotframe = self.get_plotwindow(new=('new' in optwords[1]))
        # plotcmd = plotframe.plot
        plotcmd = self.plotpanel.plot

        optwords = opt.split()
        side = 'left'
        update = False
        if optwords[0] == 'over':
            side = optwords[1]
            plotcmd = self.plotpanel.oplot
        elif optwords[0] == 'update' and npts > 4:
            plotcmd = self.plotpanel.update_line
            update = True

        popts = {'side': side}

        ix = self.xarr.GetSelection()
        x = self.xarr.GetStringSelection()

        try:
            gname = self.groupname
            lgroup = getattr(self.larch.symtable, gname)
        except:
            gname = SCANGROUP
            lgroup = getattr(self.larch.symtable, gname)

        xfmt = "%s._x1_ = %s(%s)"
        yfmt = "%s._y1_ = %s((%s %s %s) %s (%s))"
        xop = self.xop.GetStringSelection()

        xlabel = x
        try:
            xunits = lgroup.array_units[ix]
        except:
            xunits = ''
        if xop != '':
            xlabel = "%s(%s)" % (xop, xlabel)
        if xunits != '':
            xlabel = '%s (%s)' % (xlabel, xunits)
        popts['xlabel'] = xlabel

        opl1 = self.yops[0][0].GetStringSelection()
        opl2 = self.yops[0][1].GetStringSelection()
        opl3 = self.yops[0][2].GetStringSelection()

        yl1 = self.yarr[0][0].GetStringSelection()
        yl2 = self.yarr[0][1].GetStringSelection()
        yl3 = self.yarr[0][2].GetStringSelection()

        opr1 = self.yops[1][0].GetStringSelection()
        opr2 = self.yops[1][1].GetStringSelection()
        opr3 = self.yops[1][2].GetStringSelection()

        yr1 = self.yarr[1][0].GetStringSelection()
        yr2 = self.yarr[1][1].GetStringSelection()
        yr3 = self.yarr[1][2].GetStringSelection()

        ylabel = yl1

        if yl2 == '':
            yl2, opl2 = '1', '*'
        else:
            ylabel = "%s%s%s" % (ylabel, opl2, yl2)
        if yl3 == '':
            yl3, opl3 = '1', '*'
        else:
            ylabel = "(%s)%s%s" % (ylabel, opl3, yl3)

        if opl1 != '':
            ylabel = "%s(%s)" % (opl1, ylabel)

        if yl1 not in ('0', '1'): yl1 = "%s.%s" % (gname, yl1)
        if yl2 not in ('0', '1'): yl2 = "%s.%s" % (gname, yl2)
        if yl3 not in ('0', '1'): yl3 = "%s.%s" % (gname, yl3)
        if x not in ('0', '1'): x = "%s.%s" % (gname, x)

        self.larch(xfmt % (gname, xop, x))
        self.larch(yfmt % (gname, opl1, yl1, opl2, yl2, opl3, yl3))

        try:
            npts = min(len(lgroup._x1_), len(lgroup._y1_))
        except AttributeError:
            return

        lgroup._x1_ = np.array(lgroup._x1_[:npts])
        lgroup._y1_ = np.array(lgroup._y1_[:npts])

        path, fname = os.path.split(lgroup.filename)
        popts['label'] = "%s: %s" % (fname, ylabel)
        if side == 'right':
            popts['y2label'] = ylabel
        else:
            popts['ylabel'] = ylabel

        if plotcmd == self.plotpanel.plot:
            popts['title'] = fname

        # XAFS Processing!
        #if (self.nb.GetCurrentPage() == self.xas_panel):
        #    popts = self.xas_process(gname, popts)

        if update:
            self.plotpanel.set_xlabel(popts['xlabel'])
            self.plotpanel.set_ylabel(popts['ylabel'])

            plotcmd(0, lgroup._x1_, lgroup._y1_, draw=True,
                    update_limits=True)  # ((npts < 5) or (npts % 5 == 0)))

            self.plotpanel.set_xylims((min(lgroup._x1_), max(lgroup._x1_),
                                       min(lgroup._y1_), max(lgroup._y1_)))

        else:
            plotcmd(lgroup._x1_, lgroup._y1_, **popts)
            self.plotpanel.canvas.draw()

    def ShowFile(self, evt=None, filename=None, **kws):
        if filename is None and evt is not None:
            filename = evt.GetString()
        key = filename
        if filename in self.filemap:
            key = self.filemap[filename]

        if key == SCANGROUP:
            array_labels = [
                fix_filename(s.name) for s in self.scandb.get_scandata()
            ]
            title = filename
        elif hasattr(self.datagroups, key):
            data = getattr(self.datagroups, key)
            title = data.filename
            array_labels = data.array_labels[:]

        self.groupname = key
        xcols = array_labels[:]
        ycols = array_labels[:]
        y2cols = array_labels[:] + ['1.0', '0.0', '']
        ncols = len(xcols)
        self.title.SetLabel(title)
        self.xarr.SetItems(xcols)
        self.xarr.SetSelection(0)
        self.xop.SetSelection(0)
        for i in range(2):
            for j in range(3):
                self.yarr[i][j].SetItems(y2cols)
                self.yarr[i][j].SetSelection(len(y2cols))
            if i == 0:
                self.yarr[i][0].SetItems(ycols)
                self.yarr[i][0].SetSelection(1)

        inb = 0
        for colname in xcols:
            if 'energ' in colname.lower():
                inb = 1
        #self.nb.SetSelection(inb)

    def createMenus(self):
        # ppnl = self.plotpanel
        self.menubar = wx.MenuBar()
        #
        fmenu = wx.Menu()
        pmenu = wx.Menu()
        add_menu(self, fmenu, "&Open Scan File\tCtrl+O", "Read Scan File",
                 self.onReadScan)

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

    def onReadScan(self, evt=None):
        dlg = wx.FileDialog(self,
                            message="Load Epics Scan Data File",
                            defaultDir=os.getcwd(),
                            wildcard=FILE_WILDCARDS,
                            style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            path = path.replace('\\', '/')
            if path in self.filemap:
                if wx.ID_YES != popup(self, "Re-read file '%s'?" % path,
                                      'Re-read file?'):
                    return

            gname = randname(n=5)
            if hasattr(self.datagroups, gname):
                time.sleep(0.005)
                gname = randname(n=6)
            parent, fname = os.path.split(path)
            self.larch("%s = read_xdi('%s')" % (gname, path))
            self.larch("%s.path  = '%s'" % (gname, path))
            self.filelist.Append(fname)
            self.filemap[fname] = gname
            print('Larch:: ', gname, path, fname)
            self.ShowFile(filename=fname)

        dlg.Destroy()