Esempio n. 1
0
class XYFitFrame(wx.Frame):
    _about = """Larch XYFit: XY Data Viewing & Curve Fitting

  Matt Newville <newville @ cars.uchicago.edu>
  """

    def __init__(self, parent=None, size=(875, 550), _larch=None, **kws):
        wx.Frame.__init__(self, parent, -1, size=size, style=FRAMESTYLE)

        self.last_array_sel = {}
        title = "Larch XYFit (BETA!!): XY Data Viewing & Curve Fitting"

        self.larch_buffer = parent
        if not isinstance(parent, LarchFrame):
            self.larch_buffer = LarchFrame(_larch=_larch)

        self.larch_buffer.Show()
        self.larch_buffer.Raise()
        self.larch = self.larch_buffer._larch
        self.controller = XYFitController(wxparent=self,
                                          _larch=self.larch_buffer.larchshell)

        self.subframes = {}
        self.plotframe = None
        self.SetTitle(title)
        self.SetSize(size)
        self.SetFont(Font(10))

        self.config = {'chdir_on_fileopen': True}

        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)
        read_workdir('xyfit.dat')
        self.larch_buffer.Hide()

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

        leftpanel = wx.Panel(splitter)
        ltop = wx.Panel(leftpanel)

        def Btn(msg, x, act):
            b = Button(ltop, msg, size=(x, 30), action=act)
            b.SetFont(Font(10))
            return b

        plot_one = Btn('Plot One', 120, self.onPlotOne)
        plot_sel = Btn('Plot Selected', 120, self.onPlotSel)
        sel_none = Btn('Select None', 120, self.onSelNone)
        sel_all = Btn('Select All', 120, self.onSelAll)

        self.controller.filelist = FileCheckList(leftpanel,
                                                 main=self,
                                                 select_action=self.ShowFile)
        self.controller.filelist.SetBackgroundColour(wx.Colour(255, 255, 255))

        tsizer = wx.GridBagSizer(1, 1)
        tsizer.Add(plot_one, (0, 0), (1, 1), LCEN, 2)
        tsizer.Add(plot_sel, (0, 1), (1, 1), LCEN, 2)
        tsizer.Add(sel_all, (1, 0), (1, 1), LCEN, 2)
        tsizer.Add(sel_none, (1, 1), (1, 1), LCEN, 2)

        pack(ltop, tsizer)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(ltop, 0, LCEN | wx.GROW, 1)
        sizer.Add(self.controller.filelist, 1, LCEN | wx.GROW | wx.ALL, 1)

        pack(leftpanel, sizer)

        # right hand side
        panel = wx.Panel(splitter)
        sizer = wx.BoxSizer(wx.VERTICAL)

        self.title = SimpleText(panel, 'initializing...', size=(300, -1))
        self.title.SetFont(Font(10))

        ir = 0
        sizer.Add(self.title, 0, LCEN | wx.GROW | wx.ALL, 1)

        self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE)

        self.nb.SetTabAreaColour(wx.Colour(250, 250, 250))
        self.nb.SetActiveTabColour(wx.Colour(254, 254, 195))

        self.nb.SetNonActiveTabTextColour(wx.Colour(10, 10, 128))
        self.nb.SetActiveTabTextColour(wx.Colour(128, 0, 0))

        panel_opts = dict(parent=self.nb, controller=self.controller)

        self.proc_panel = ProcessPanel(**panel_opts)
        self.fit_panel = XYFitPanel(**panel_opts)

        self.nb.AddPage(self.proc_panel, ' Data Processing ', True)
        self.nb.AddPage(self.fit_panel, ' Curve Fitting ', True)

        sizer.Add(self.nb, 1, LCEN | wx.EXPAND, 2)
        self.nb.SetSelection(0)

        pack(panel, sizer)

        splitter.SplitVertically(leftpanel, panel, 1)
        wx.CallAfter(self.init_larch)

    def onSelAll(self, event=None):
        self.controller.filelist.SetCheckedStrings(
            self.controller.file_groups.keys())

    def onSelNone(self, event=None):
        self.controller.filelist.SetCheckedStrings([])

    def init_larch(self):
        self.SetStatusText('ready')
        self.title.SetLabel('')

        self.fit_panel.larch = self.controller.larch

        fico = self.controller.get_iconfile()
        plotframe = self.controller.get_display(stacked=False)
        xpos, ypos = self.GetPosition()
        xsiz, ysiz = self.GetSize()
        plotframe.SetPosition((xpos + xsiz, ypos))
        self.Raise()

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

    def onPlotOne(self, evt=None, groupname=None):
        if groupname is None:
            groupname = self.controller.groupname

        dgroup = self.controller.get_group(groupname)
        if dgroup is not None:
            self.controller.plot_group(groupname=groupname, new=True)

    def onPlotSel(self, evt=None):
        newplot = True
        group_ids = self.controller.filelist.GetCheckedStrings()
        for checked in group_ids:
            groupname = self.controller.file_groups[str(checked)]
            dgroup = self.controller.get_group(groupname)
            if dgroup is None:
                continue
            dgroup.plot_yarrays = [(dgroup.y, PLOTOPTS_1, dgroup.filename)]
            if dgroup.datatype == 'xas':
                dgroup.plot_xlabel = '$E\,\mathrm{(eV)}$'
                dgroup.plot_ymarkers = []

            self.controller.plot_group(groupname=groupname,
                                       title='',
                                       new=newplot)
            newplot = False

    def plot_group(self, groupname=None, title=None, new=True, **kws):
        self.controller.plot_group(groupname=groupname,
                                   title=title,
                                   new=new,
                                   **kws)
        self.Raise()

    def ShowFile(self, evt=None, groupname=None, **kws):
        filename = None
        if evt is not None:
            filename = str(evt.GetString())
        if groupname is None and filename is not None:
            groupname = self.controller.file_groups[filename]

        if not hasattr(self.larch.symtable, groupname):
            print('Error reading file ', groupname)
            return

        dgroup = self.controller.get_group(groupname)
        self.controller.group = dgroup
        self.controller.groupname = groupname
        self.nb.SetSelection(0)
        self.proc_panel.fill(dgroup)
        if filename is None:
            filename = dgroup.filename
        self.title.SetLabel(filename)

    def createMenus(self):
        # ppnl = self.plotpanel
        self.menubar = wx.MenuBar()
        #
        fmenu = wx.Menu()
        MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Open Data File",
                 self.onReadDialog)

        fmenu.AppendSeparator()
        MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L',
                 'Show Larch Programming Buffer', self.onShowLarchBuffer)

        MenuItem(self, fmenu, "debug wx\tCtrl+I", "", self.showInspectionTool)
        MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose)

        self.menubar.Append(fmenu, "&File")

        omenu = wx.Menu()
        self.menubar.Append(omenu, "Options")
        MenuItem(self, omenu, "Configure Data Processing",
                 "Configure Data Processing", self.onConfigDataProcessing)

        MenuItem(self, omenu, "Configure Data Fitting",
                 "Configure Data Fitting", self.onConfigDataFitting)

        self.SetMenuBar(self.menubar)
        self.Bind(wx.EVT_CLOSE, self.onClose)

    def onShowLarchBuffer(self, evt=None):
        if self.larch_buffer is None:
            self.larch_buffer = LarchFrame(_larch=self.larch)
        self.larch_buffer.Show()
        self.larch_buffer.Raise()

    def onConfigDataProcessing(self, event=None):
        pass

    def onConfigDataFitting(self, event=None):
        pass

    def showInspectionTool(self, event=None):
        app = wx.GetApp()
        app.ShowInspectionTool()

    def onAbout(self, evt):
        dlg = wx.MessageDialog(self, self._about, "About Larch XYFit",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onClose(self, evt):
        save_workdir('xyfit.dat')
        self.proc_panel.proc_timer.Stop()

        for nam in dir(self.larch.symtable._plotter):
            obj = getattr(self.larch.symtable._plotter, nam)
            try:
                obj.Destroy()
            except:
                pass

        for nam in dir(self.larch.symtable._sys.wx):
            obj = getattr(self.larch.symtable._sys.wx, nam)
            del obj

        if self.larch_buffer is not None:
            try:
                self.larch_buffer.Destroy()
            except:
                pass
        self.Destroy()

    def show_subframe(self, name, frameclass, **opts):
        shown = False
        if name in self.subframes:
            try:
                self.subframes[name].Raise()
                shown = True
            except:
                del self.subframes[name]
        if not shown:
            self.subframes[name] = frameclass(self, **opts)

    def onSelectColumns(self, evt=None):
        dgroup = self.controller.get_group(self.controller.groupname)
        self.show_subframe('readfile',
                           ColumnDataFileFrame,
                           group=dgroup.raw,
                           last_array_sel=self.last_array_sel,
                           _larch=self.larch,
                           read_ok_cb=partial(self.onRead_OK, overwrite=True))

    def onReadDialog(self, evt=None):
        dlg = wx.FileDialog(self,
                            message="Read Data File",
                            defaultDir=os.getcwd(),
                            wildcard=FILE_WILDCARDS,
                            style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            path = path.replace('\\', '/')

            self.onRead(path)
        dlg.Destroy()

    def onRead(self, path):
        if path in self.controller.file_groups:
            if wx.ID_YES != popup(self, "Re-read file '%s'?" % path,
                                  'Re-read file?'):
                return
        filedir, filename = os.path.split(path)
        pref = fix_varname(filename.replace('.', '_'))
        if len(pref) > 15:
            pref = pref[:15]
        groupname = pref
        count, maxcount = 0, 999
        while hasattr(self.larch.symtable, groupname) and count < maxcount:
            count += 1
            groupname = '%s_%2.2i' % (pref, count)

        if self.config['chdir_on_fileopen']:
            os.chdir(filedir)

        kwargs = dict(filename=path,
                      _larch=self.larch_buffer.larchshell,
                      last_array_sel=self.last_array_sel,
                      read_ok_cb=self.onRead_OK)

        # check for athena projects
        if is_athena_project(path):
            self.show_subframe('athena_import', AthenaImporter, **kwargs)
        else:
            self.show_subframe('readfile', ColumnDataFileFrame, **kwargs)

    def onRead_OK(self, datagroup, array_sel=None, overwrite=False):
        """ called when column data has been selected and is ready to be used
        overwrite: whether to overwrite the current datagroup, as when
        editing a datagroup
        """
        gname = datagroup.groupname
        fname = datagroup.filename
        path = datagroup.path
        datatype = getattr(datagroup, 'datatype', 'raw')

        if array_sel is not None:
            self.last_array_sel = array_sel

        # file /group may already exist in list
        if fname in self.controller.file_groups and not overwrite:
            for i in range(1, 101):
                ftest = "%s (%i)" % (fname, i)
                if ftest not in self.controller.file_groups:
                    fname = ftest
                    break

        if fname not in self.controller.file_groups:
            self.controller.filelist.Append(fname)
            self.controller.file_groups[fname] = gname

        self.nb.SetSelection(0)
        self.ShowFile(groupname=gname)
Esempio n. 2
0
class XYFitFrame(wx.Frame):
    _about = """Larch XYFit: XY Data Viewing & Curve Fitting

    Matt Newville <newville @ cars.uchicago.edu>
    """
    def __init__(self, parent=None, size=(875, 550), _larch=None, **kws):
        wx.Frame.__init__(self, parent, -1, size=size, style=FRAMESTYLE)

        self.last_array_sel = {}
        self.paths2read = []

        title = "Larch XYFit: XY Data Viewing & Curve Fitting"

        self.larch_buffer = parent
        if not isinstance(parent, LarchFrame):
            self.larch_buffer = LarchFrame(_larch=_larch)


        self.larch_buffer.Show()
        self.larch_buffer.Raise()
        self.larch=self.larch_buffer.larchshell
        self.controller = XYFitController(wxparent=self, _larch=self.larch)

        self.subframes = {}
        self.plotframe = None
        self.SetTitle(title)
        self.SetSize(size)
        self.SetFont(Font(10))

        self.larch_buffer.Hide()

        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)

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

        leftpanel = wx.Panel(splitter)
        ltop = wx.Panel(leftpanel)

        def Btn(msg, x, act):
            b = Button(ltop, msg, size=(x, 30),  action=act)
            b.SetFont(Font(10))
            return b

        plot_one = Btn('Plot One',      120, self.onPlotOne)
        plot_sel = Btn('Plot Selected', 120, self.onPlotSel)
        sel_none = Btn('Select None',   120, self.onSelNone)
        sel_all  = Btn('Select All',    120, self.onSelAll)

        self.controller.filelist = FileCheckList(leftpanel, main=self,
                                                 select_action=self.ShowFile,
                                                 remove_action=self.RemoveFile)
        self.controller.filelist.SetBackgroundColour(wx.Colour(255, 255, 255))

        tsizer = wx.GridBagSizer(1, 1)
        tsizer.Add(plot_one, (0, 0), (1, 1), LCEN, 2)
        tsizer.Add(plot_sel, (0, 1), (1, 1), LCEN, 2)
        tsizer.Add(sel_all,  (1, 0), (1, 1), LCEN, 2)
        tsizer.Add(sel_none, (1, 1), (1, 1), LCEN, 2)

        pack(ltop, tsizer)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(ltop, 0, LCEN|wx.GROW, 1)
        sizer.Add(self.controller.filelist, 1, LCEN|wx.GROW|wx.ALL, 1)

        pack(leftpanel, sizer)

        # right hand side
        panel = wx.Panel(splitter)
        sizer = wx.BoxSizer(wx.VERTICAL)

        self.title = SimpleText(panel, 'initializing...', size=(300, -1))
        self.title.SetFont(Font(10))

        ir = 0
        sizer.Add(self.title, 0, LCEN|wx.GROW|wx.ALL, 1)

        self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE)

        self.nb.SetTabAreaColour(wx.Colour(250,250,250))
        self.nb.SetActiveTabColour(wx.Colour(254,254,195))

        self.nb.SetNonActiveTabTextColour(wx.Colour(10,10,128))
        self.nb.SetActiveTabTextColour(wx.Colour(128,0,0))

        panel_opts = dict(parent=self.nb, controller=self.controller)

        self.proc_panel = ProcessPanel(**panel_opts)
        self.fit_panel =  XYFitPanel(**panel_opts)

        self.nb.AddPage(self.proc_panel,  ' Data Processing ',   True)
        self.nb.AddPage(self.fit_panel,   ' Curve Fitting ',  True)

        sizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2)
        self.nb.SetSelection(0)

        pack(panel, sizer)

        splitter.SplitVertically(leftpanel, panel, 1)
        wx.CallAfter(self.init_larch)

    def onSelAll(self, event=None):
        self.controller.filelist.SetCheckedStrings(self.controller.file_groups.keys())

    def onSelNone(self, event=None):
        self.controller.filelist.SetCheckedStrings([])

    def init_larch(self):
        self.SetStatusText('initializing Larch')
        self.title.SetLabel('')

        self.fit_panel.larch = self.controller.larch

        self.controller.init_larch()

        plotframe = self.controller.get_display(stacked=False)
        xpos, ypos = self.GetPosition()
        xsiz, ysiz = self.GetSize()
        plotframe.SetPosition((xpos+xsiz, ypos))

        self.SetStatusText('ready')
        self.Raise()


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

    def onPlotOne(self, evt=None, groupname=None):
        if groupname is None:
            groupname = self.controller.groupname

        dgroup = self.controller.get_group(groupname)
        if dgroup is not None:
            self.controller.plot_group(groupname=groupname, new=True)

    def onPlotSel(self, evt=None):
        newplot = True
        group_ids = self.controller.filelist.GetCheckedStrings()
        for checked in group_ids:
            groupname = self.controller.file_groups[str(checked)]
            dgroup = self.controller.get_group(groupname)
            if dgroup is not None:
                self.controller.plot_group(groupname=groupname, title='',
                                           new=newplot, label=dgroup.filename)
                newplot=False

    def plot_group(self, groupname=None, title=None, new=True, **kws):
        self.controller.plot_group(groupname=groupname, title=title, new=new, **kws)
        self.Raise()

    def RemoveFile(self, fname=None, **kws):
        if fname is not None:
            s = str(fname)
            if s in self.controller.file_groups:
                group = self.controller.file_groups.pop(s)

    def ShowFile(self, evt=None, groupname=None, **kws):
        filename = None
        if evt is not None:
            filename = str(evt.GetString())
        if groupname is None and filename is not None:
            groupname = self.controller.file_groups[filename]

        if not hasattr(self.larch.symtable, groupname):
            return

        dgroup = self.controller.get_group(groupname)
        self.controller.group = dgroup
        self.controller.groupname = groupname
        self.nb.SetSelection(0)
        self.proc_panel.fill(dgroup)
        if filename is None:
            filename = dgroup.filename
        self.title.SetLabel(filename)

    def createMenus(self):
        # ppnl = self.plotpanel
        self.menubar = wx.MenuBar()
        #
        fmenu = wx.Menu()
        MenuItem(self, fmenu, "&Open Data File\tCtrl+O",
                 "Open Data File",  self.onReadDialog)

        fmenu.AppendSeparator()
        MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L',
                 'Show Larch Programming Buffer',
                 self.onShowLarchBuffer)

        MenuItem(self, fmenu, "debug wx\tCtrl+I", "", self.showInspectionTool)
        MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onCloseNicely)

        self.menubar.Append(fmenu, "&File")

        omenu = wx.Menu()
        self.menubar.Append(omenu, "Options")
        MenuItem(self, omenu, "Configure Data Processing",
                  "Configure Data Processing", self.onConfigDataProcessing)

        MenuItem(self, omenu, "Configure Data Fitting",
                  "Configure Data Fitting", self.onConfigDataFitting)

        self.SetMenuBar(self.menubar)
        self.Bind(wx.EVT_CLOSE,  self.onExit)

    def onShowLarchBuffer(self, evt=None):
        if self.larch_buffer is None:
            self.larch_buffer = LarchFrame(_larch=self.larch)
        self.larch_buffer.Show()
        self.larch_buffer.Raise()


    def onConfigDataProcessing(self, event=None):
        pass

    def onConfigDataFitting(self, event=None):
        pass

    def showInspectionTool(self, event=None):
        app = wx.GetApp()
        app.ShowInspectionTool()

    def onAbout(self,evt):
        dlg = wx.MessageDialog(self, self._about,
                               "About Larch XYFit",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onExit(self, evt):
        for nam in dir(self.larch.symtable._plotter):
            obj = getattr(self.larch.symtable._plotter, nam)
            time.sleep(0.05)
            try:
                obj.Destroy()
            except:
                pass

        for nam in dir(self.larch.symtable._sys.wx):
            obj = getattr(self.larch.symtable._sys.wx, nam)
            time.sleep(0.05)
            del obj

        if self.larch_buffer is not None:
            try:
                self.larch_buffer.Destroy()
            except:
                pass
        self.Destroy()

    def onCloseNicely(self, evt):
        dlg = wx.MessageDialog(None, 'Really Quit?', 'Question',
                               wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)

        if wx.ID_YES != dlg.ShowModal():
            return

        self.controller.save_config()
        self.proc_panel.proc_timer.Stop()
        time.sleep(0.05)
        self.onExit(evt)

    def show_subframe(self, name, frameclass, **opts):
        shown = False
        if name in self.subframes:
            try:
                self.subframes[name].Raise()
                shown = True
            except:
                del self.subframes[name]
        if not shown:
            self.subframes[name] = frameclass(self, **opts)

    def onSelectColumns(self, evt=None):
        dgroup = self.controller.get_group(self.controller.groupname)
        self.show_subframe('readfile', ColumnDataFileFrame,
                           group=dgroup.raw,
                           last_array_sel=self.last_array_sel,
                           _larch=self.larch,
                           read_ok_cb=partial(self.onRead_OK,
                                              overwrite=True))

    def onReadDialog(self, evt=None):
        dlg = wx.FileDialog(self, message="Read Data File",
                            defaultDir=os.getcwd(),
                            wildcard=FILE_WILDCARDS,
                            style=wx.FD_OPEN|wx.FD_MULTIPLE)
        self.paths2read = []
        if dlg.ShowModal() == wx.ID_OK:
            self.paths2read = dlg.GetPaths()
        dlg.Destroy()

        if len(self.paths2read) < 1:
            return

        path = self.paths2read.pop(0)
        path = path.replace('\\', '/')
        do_read = True
        if path in self.controller.file_groups:
            do_read = (wx.ID_YES == popup(self,
                                          "Re-read file '%s'?" % path,
                                          'Re-read file?'))
        if do_read:
            self.onRead(path)

    def onRead(self, path):
        filedir, filename = os.path.split(path)
        if self.controller.get_config('chdir_on_fileopen'):
            os.chdir(filedir)
            self.controller.set_workdir()


        # check for athena projects
        if is_athena_project(path):
            kwargs = dict(filename=path,
                          _larch = self.controller.larch,
                          read_ok_cb=self.onReadAthenaProject_OK)
            self.show_subframe('athena_import', AthenaImporter, **kwargs)
        else:

            kwargs = dict(filename=path,
                          _larch=self.larch_buffer.larchshell,
                          last_array_sel = self.last_array_sel,
                          read_ok_cb=self.onRead_OK)

            self.show_subframe('readfile', ColumnDataFileFrame, **kwargs)

    def onReadAthenaProject_OK(self, path, namelist):
        """read groups from a list of groups from an athena project file"""
        self.larch.eval("_prj = read_athena('{path:s}', do_fft=False, do_bkg=False)".format(path=path))

        s = """{group:s} = _prj.{group:s}
        {group:s}.datatype = 'xas'
        {group:s}.x = {group:s}.xdat = {group:s}.energy
        {group:s}.y = {group:s}.ydat = {group:s}.mu
        {group:s}.yerr = 1.0
        {group:s}.plot_ylabel = 'mu'
        {group:s}.plot_xlabel = 'energy'
        """
        for gname in namelist:
            self.larch.eval(s.format(group=gname))
            self.install_group(gname, gname)
        self.larch.eval("del _prj")


    def onRead_OK(self, script, path, groupname=None, array_sel=None,
                  overwrite=False):
        """ called when column data has been selected and is ready to be used
        overwrite: whether to overwrite the current datagroup, as when
        editing a datagroup
        """
        abort_read = False
        filedir, filename = os.path.split(path)
        if not overwrite and hasattr(self.larch.symtable, groupname):
            newname = file2groupname(filename, symtable=self.larch.symtable)
            msg = """Warning: groupname '%s' already used.
            Will use groupname '%s' instead """  % (groupname, newname)
            dlg = wx.MessageDialog(self, msg, 'Warning',
                                   wx.OK | wx.CANCEL )

            abort_read = (wx.ID_OK != dlg.ShowModal())
            dlg.Destroy()
            groupname = newname

        if abort_read:
            return
        self.larch.eval(script.format(group=groupname, path=path))
        if array_sel is not None:
            self.last_array_sel = array_sel

        self.install_group(groupname, filename)

        if len(self.paths2read) > 0 :
            path = self.paths2read.pop(0)
            path = path.replace('\\', '/')
            filedir, filename = os.path.split(path)
            gname = file2groupname(filename, symtable=self.larch.symtable)
            self.onRead_OK(script, path, groupname=gname)


    def install_group(self, groupname, filename):
        """add groupname / filename to list of available data groups"""

        thisgroup = getattr(self.larch.symtable, groupname)
        thisgroup.groupname = groupname
        thisgroup.filename = filename

        datatype = getattr(thisgroup, 'datatype', 'raw')
        # file /group may already exist in list
        if filename in self.controller.file_groups and not overwrite:
            for i in range(1, 101):
                ftest = "%s (%i)"  % (filename, i)
                if ftest not in self.controller.file_groups:
                    filename = ftest
                    break

        if filename not in self.controller.file_groups:
            self.controller.filelist.Append(filename)
            self.controller.file_groups[filename] = groupname
        self.nb.SetSelection(0)
        self.ShowFile(groupname=groupname)
Esempio n. 3
0
class XASFrame(wx.Frame):
    _about = """Larch XAS GUI: XAS Visualization and Analysis

    Matt Newville <newville @ cars.uchicago.edu>
    """
    def __init__(self, parent=None, _larch=None, **kws):
        wx.Frame.__init__(self, parent, -1, size=XASVIEW_SIZE, style=FRAMESTYLE)

        self.last_array_sel = {}
        self.paths2read = []

        title = "Larch XAS GUI: XAS Visualization and Analysis"

        self.larch_buffer = parent
        if not isinstance(parent, LarchFrame):
            self.larch_buffer = LarchFrame(_larch=_larch)

        self.larch_buffer.Show()
        self.larch_buffer.Raise()
        self.larch=self.larch_buffer.larchshell
        self.controller = XASController(wxparent=self, _larch=self.larch)
        self.current_filename = None
        self.subframes = {}
        self.plotframe = None
        self.SetTitle(title)
        self.SetSize(XASVIEW_SIZE)
        self.SetFont(Font(10))
        self.larch_buffer.Hide()
        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)

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

        leftpanel = wx.Panel(splitter)
        ltop = wx.Panel(leftpanel)

        def Btn(msg, x, act):
            b = Button(ltop, msg, size=(x, 30),  action=act)
            b.SetFont(Font(10))
            return b

        sel_none = Btn('Select None',   120, self.onSelNone)
        sel_all  = Btn('Select All',    120, self.onSelAll)

        self.controller.filelist = FileCheckList(leftpanel,
                                                 # main=self,
                                                 select_action=self.ShowFile,
                                                 remove_action=self.RemoveFile)
        self.controller.filelist.SetBackgroundColour(wx.Colour(255, 255, 255))

        tsizer = wx.BoxSizer(wx.HORIZONTAL)
        tsizer.Add(sel_all, 1, LCEN|wx.GROW, 1)
        tsizer.Add(sel_none, 1, LCEN|wx.GROW, 1)
        pack(ltop, tsizer)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(ltop, 0, LCEN|wx.GROW, 1)
        sizer.Add(self.controller.filelist, 1, LCEN|wx.GROW|wx.ALL, 1)

        pack(leftpanel, sizer)

        # right hand side
        panel = wx.Panel(splitter)
        sizer = wx.BoxSizer(wx.VERTICAL)

        self.title = SimpleText(panel, 'initializing...', size=(300, -1))
        self.title.SetFont(Font(10))

        ir = 0
        sizer.Add(self.title, 0, LCEN|wx.GROW|wx.ALL, 1)

        self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE)

        self.nb.SetTabAreaColour(wx.Colour(250,250,250))
        self.nb.SetActiveTabColour(wx.Colour(254,254,195))

        self.nb.SetNonActiveTabTextColour(wx.Colour(10,10,128))
        self.nb.SetActiveTabTextColour(wx.Colour(128,0,0))

        self.nb_panels = []
        for name, creator in NB_PANELS:
            _panel = creator(parent=self, controller=self.controller)
            self.nb.AddPage(_panel," %s " % name, True)
            self.nb_panels.append(_panel)

        sizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2)
        self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onNBChanged)
        self.nb.SetSelection(0)

        pack(panel, sizer)

        splitter.SplitVertically(leftpanel, panel, 1)
        wx.CallAfter(self.init_larch)

    def onNBChanged(self, event=None):
        idx = self.nb.GetSelection()
        pan = self.nb_panels[idx]

        callback = getattr(pan, 'onPanelExposed', None)
        if callable(callback):
            callback()

    def onSelAll(self, event=None):
        self.controller.filelist.SetCheckedStrings(self.controller.file_groups.keys())

    def onSelNone(self, event=None):
        self.controller.filelist.SetCheckedStrings([])

    def init_larch(self):
        self.SetStatusText('initializing Larch')
        self.title.SetLabel('')

        self.controller.init_larch()

        plotframe = self.controller.get_display(stacked=False)
        xpos, ypos = self.GetPosition()
        xsiz, ysiz = self.GetSize()
        plotframe.SetPosition((xpos+xsiz+5, ypos))

        self.SetStatusText('ready')
        self.Raise()


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

    def RemoveFile(self, fname=None, **kws):
        if fname is not None:
            s = str(fname)
            if s in self.controller.file_groups:
                group = self.controller.file_groups.pop(s)

    def ShowFile(self, evt=None, groupname=None, with_plot=True, **kws):
        filename = None
        if evt is not None: #
            filename = str(evt.GetString())
            # could have clicking on filename add to "Selected":
            #  checked = list(self.controller.filelist.GetCheckedStrings())
            #  if filename not in checked:
            #      checked.append(filename)
            #  self.controller.filelist.SetCheckedStrings(checked)
        if groupname is None and filename is not None:
            groupname = self.controller.file_groups[filename]

        if not hasattr(self.larch.symtable, groupname):
            return

        dgroup = self.controller.get_group(groupname)
        self.controller.group = dgroup
        self.controller.groupname = groupname
        current_nbpanel = self.nb_panels[self.nb.GetSelection()]

        self.nb_panels[0].fill_form(dgroup)
        if with_plot:
            self.nb_panels[0].plot(dgroup)
        if filename is None:
            filename = dgroup.filename
        self.title.SetLabel(filename)
        self.current_filename = filename

    def createMenus(self):
        # ppnl = self.plotpanel
        self.menubar = wx.MenuBar()
        #
        fmenu = wx.Menu()
        group_menu = wx.Menu()
        data_menu = wx.Menu()
        ppeak_menu = wx.Menu()
        m = {}

        MenuItem(self, fmenu, "&Open Data File\tCtrl+O",
                 "Open Data File",  self.onReadDialog)

        MenuItem(self, fmenu, "&Save Project\tCtrl+S",
                 "Save Session to Project File",  self.onSaveProject)

        MenuItem(self, fmenu, "Export Selected Groups to Athena Project",
                 "Export Selected Groups to Athena Project",
                 self.onExportAthena)

        MenuItem(self, fmenu, "Export Selected Groups to CSV",
                 "Export Selected Groups to CSV",  self.onExportCSV)

        fmenu.AppendSeparator()

        MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L',
                 'Show Larch Programming Buffer',
                 self.onShowLarchBuffer)

        #  MenuItem(self, fmenu, "&Inspect \tCtrl+I",
        #                           "e",  self.showInspectionTool)

        MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose)


        MenuItem(self, group_menu, "Copy This Group",
                 "Copy This Group", self.onCopyGroup)

        MenuItem(self, group_menu, "Rename This Group",
                 "Rename This Group", self.onRenameGroup)

        MenuItem(self, group_menu, "Remove Selected Groups",
                 "Remove Selected Group", self.onRemoveGroups)


        MenuItem(self, group_menu, "Merge Selected Groups",
                 "Merge Selected Groups", self.onMergeData)


        MenuItem(self, data_menu, "Deglitch Data",  "Deglitch Data",
                 self.onDeglitchData)

        MenuItem(self, data_menu, "Recalibrate Energy",
                 "Recalibrate Energy",
                 self.onEnergyCalibrateData)

        MenuItem(self, data_menu, "Smooth Data", "Smooth Data",
                 self.onSmoothData)

        MenuItem(self, data_menu, "Rebin Data", "Rebin Data",
                 self.onRebinData)

        MenuItem(self, data_menu, "Correct Over-absorption", "Correct Over-absorption",
                 self.onCorrectOverAbsorptionData)

        MenuItem(self, ppeak_menu, "&Read Fit Model\tCtrl+R",
                 "Read Fit Model from File", self.onLoadFitResult)

        fsave = MenuItem(self, ppeak_menu, "Save Fit Model",
                            "Save Fit Model to File", self.onSaveFitResult)

        fexport = MenuItem(self, ppeak_menu, "Export Data and Fit",
                           "Export Data and Fit",
                           self.onExportFitResult)


        self.afterfit_menus = (fsave, fexport)

        for m in self.afterfit_menus:
            m.Enable(False)

        self.menubar.Append(fmenu, "&File")
        self.menubar.Append(group_menu, "Groups")
        self.menubar.Append(data_menu, "Data")

        self.menubar.Append(ppeak_menu, "PreEdgePeaks")
        self.SetMenuBar(self.menubar)
        self.Bind(wx.EVT_CLOSE,  self.onClose)

    def onShowLarchBuffer(self, evt=None):
        if self.larch_buffer is None:
            self.larch_buffer = LarchFrame(_larch=self.larch)
        self.larch_buffer.Show()
        self.larch_buffer.Raise()


    def onExportCSV(self, evt=None):
        group_ids = self.controller.filelist.GetCheckedStrings()
        savegroups = []
        groupnames = []
        for checked in group_ids:
            groupname = self.controller.file_groups[str(checked)]
            dgroup = self.controller.get_group(groupname)
            savegroups.append(dgroup)
            groupnames.append(groupname)
        if len(savegroups) < 1:
             Popup(self, "No files selected to export to CSV",
                   "No files selected")
             return

        deffile = "%s_%i.csv" % (groupname, len(groupnames))
        wcards  = 'CSV Files (*.csv)|*.cvs|All files (*.*)|*.*'

        outfile = FileSave(self, 'Export Selected Groups to CSV File',
                           default_file=deffile, wildcard=wcards)

        if outfile is None:
            return

        groups2csv(savegroups, outfile, x='energy', y='norm', _larch=self.larch)

    def onExportAthena(self, evt=None):
        groups = []
        for checked in self.controller.filelist.GetCheckedStrings():
            groups.append(self.controller.file_groups[str(checked)])

        if len(groups) < 1:
             Popup(self, "No files selected to export to Athena",
                   "No files selected")
             return
        self.save_athena_project(groups[0], groups, prompt=True)

    def onSaveProject(self, evt=None):
        groups = [gname for gname in self.controller.file_groups]
        if len(groups) < 1:
            Popup(self, "No files selected to export to Athena",
                  "No files selected")
            return
        self.save_athena_project(groups[0], groups, prompt=True)

    def save_athena_project(self, filename, grouplist, prompt=True):
        if len(grouplist) < 1:
            return
        savegroups = [self.controller.get_group(gname) for gname in grouplist]

        deffile = "%s_%i.prj" % (filename, len(grouplist))
        wcards  = 'Athena Projects (*.prj)|*.prj|All files (*.*)|*.*'

        outfile = FileSave(self, 'Save Groups to Athena Project File',
                           default_file=deffile, wildcard=wcards)

        if outfile is None:
            return

        aprj = AthenaProject(filename=outfile, _larch=self.larch)
        for label, grp in zip(grouplist, savegroups):
            aprj.add_group(grp, label=label)
        aprj.save(use_gzip=True)

    def onConfigDataProcessing(self, event=None):
        pass

    def onCopyGroup(self, event=None):
        fname = self.current_filename
        if fname is None:
            fname = self.current_filename = self.controller.filelist.GetStringSelection()

        groupname = self.controller.file_groups[fname]
        if not hasattr(self.larch.symtable, groupname):
            return
        ogroup = self.controller.get_group(groupname)

        ngroup = Group(datatype=ogroup.datatype,
                       energy=1.0*ogroup.energy,
                       mu=1.0*ogroup.mu,
                       xdat=1.0*ogroup.energy,
                       ydat=1.0*ogroup.mu)

        for attr in dir(ogroup):
            if attr in ('i0', 'data' 'yerr'):
                val = getattr(ogroup, attr)*1.0
            if attr in ('norm', 'flat', 'deriv', 'deconv', 'post_edge', 'pre_edge'):
                pass
            else:
                try:
                    val = copy.deepcopy(getattr(ogroup, attr))
                except ValueError:
                    val = None
            setattr(ngroup, attr, val)

        new_fname = unique_name(fname,     self.controller.file_groups.keys())
        new_gname = unique_name(groupname, self.controller.file_groups.values())
        setattr(self.larch.symtable, new_gname, ngroup)
        self.install_group(new_gname, new_fname, overwrite=False)
        self.nb_panels[0].process(ngroup)
        self.ShowFile(groupname=new_gname)

    def onRenameGroup(self, event=None):
        fname = self.current_filename = self.controller.filelist.GetStringSelection()
        if fname is None:
            return
        dlg = RenameDialog(self, fname)
        res = dlg.GetResponse()
        dlg.Destroy()

        if res.ok:
            groupname = self.controller.file_groups.pop(fname)
            self.controller.file_groups[res.newname] = groupname
            self.controller.filelist.rename_item(self.current_filename, res.newname)
            dgroup = self.controller.get_group(groupname)
            dgroup.filename = self.current_filename = res.newname
            self.controller.filelist.SetStringSelection(res.newname)

    def onRemoveGroups(self, event=None):
        groups = []
        for checked in self.controller.filelist.GetCheckedStrings():
            groups.append(self.controller.file_groups[str(checked)])
        if len(groups) < 1:
            return

        dlg = RemoveDialog(self, groups)
        res = dlg.GetResponse()
        dlg.Destroy()

        if res.ok:
            filelist = self.controller.filelist
            all_fnames = filelist.GetItems()
            for fname in groups:
                gname = self.controller.file_groups.pop(fname)
                delattr(self.controller.symtable, gname)
                all_fnames.remove(fname)

            filelist.Clear()
            for name in all_fnames:
                filelist.Append(name)


    def onMergeData(self, event=None):
        groups = []
        for checked in self.controller.filelist.GetCheckedStrings():
            groups.append(self.controller.file_groups[str(checked)])
        if len(groups) < 1:
            return

        outgroup = unique_name('merge', self.controller.file_groups)
        dlg = MergeDialog(self, groups, outgroup=outgroup)
        res = dlg.GetResponse()
        dlg.Destroy()
        if res.ok:
            fname = res.group
            gname = fix_varname(res.group.lower())
            yname = 'norm' if res.ynorm else 'mu'
            self.controller.merge_groups(groups, master=res.master,
                                         yarray=yname, outgroup=gname)
            self.install_group(gname, fname, overwrite=False)
            self.controller.filelist.SetStringSelection(fname)


    def onDeglitchData(self, event=None):
        DeglitchDialog(self, self.controller).Show()

    def onSmoothData(self, event=None):
        SmoothDataDialog(self, self.controller).Show()

    def onRebinData(self, event=None):
        RebinDataDialog(self, self.controller).Show()

    def onCorrectOverAbsorptionData(self, event=None):
        OverAbsorptionDialog(self, self.controller).Show()

    def onEnergyCalibrateData(self, event=None):
        EnergyCalibrateDialog(self, self.controller).Show()

    def onConfigDataFitting(self, event=None):
        pass

    def showInspectionTool(self, event=None):
        app = wx.GetApp()
        app.ShowInspectionTool()

    def onAbout(self,evt):
        dlg = wx.MessageDialog(self, self._about,
                               "About Larch XAS GUI",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onClose(self, event):
        dlg = QuitDialog(self)
        res = dlg.GetResponse()
        dlg.Destroy()

        if not res.ok:
            return

        if res.save:
            groups = [gname for gname in self.controller.file_groups]
            if len(groups) > 0:
                self.save_athena_project(groups[0], groups, prompt=True)

        self.controller.save_config()
        self.controller.get_display().Destroy()

        if self.larch_buffer is not None:
            try:
                self.larch_buffer.Destroy()
            except:
                pass
            time.sleep(0.05)

        for nam in dir(self.larch.symtable._plotter):
            obj = getattr(self.larch.symtable._plotter, nam)
            time.sleep(0.05)
            try:
                obj.Destroy()
            except:
                pass

        for name, wid in self.subframes.items():
            if wid is not None:
                try:
                    wid.Destroy()
                except:
                    pass

        for nam in dir(self.larch.symtable._sys.wx):
            obj = getattr(self.larch.symtable._sys.wx, nam)

        self.Destroy()

    def show_subframe(self, name, frameclass, **opts):
        shown = False
        if name in self.subframes:
            try:
                self.subframes[name].Raise()
                shown = True
            except:
                del self.subframes[name]
        if not shown:
            self.subframes[name] = frameclass(self, **opts)

    def onSelectColumns(self, event=None):
        dgroup = self.controller.get_group()
        self.show_subframe('readfile', ColumnDataFileFrame,
                           group=dgroup.raw,
                           last_array_sel=self.last_array_sel,
                           _larch=self.larch,
                           read_ok_cb=partial(self.onRead_OK,
                                              overwrite=True))

    def onLoadFitResult(self, event=None):
        self.nb.SetSelection(1)
        self.nb_panels[1].onLoadFitResult(event=event)

    def onSaveFitResult(self, event=None):
        self.nb_panels[1].onSaveFitResult(event=event)

    def onExportFitResult(self, event=None):
        self.nb_panels[1].onExportFitResult(event=event)

    def onReadDialog(self, event=None):
        dlg = wx.FileDialog(self, message="Read Data File",
                            defaultDir=os.getcwd(),
                            wildcard=FILE_WILDCARDS,
                            style=wx.FD_OPEN|wx.FD_MULTIPLE)
        self.paths2read = []
        if dlg.ShowModal() == wx.ID_OK:
            self.paths2read = dlg.GetPaths()
        dlg.Destroy()

        if len(self.paths2read) < 1:
            return

        path = self.paths2read.pop(0)
        path = path.replace('\\', '/')
        do_read = True
        if path in self.controller.file_groups:
            do_read = (wx.ID_YES == Popup(self,
                                          "Re-read file '%s'?" % path,
                                          'Re-read file?'))
        if do_read:
            self.onRead(path)

    def onRead(self, path):
        filedir, filename = os.path.split(path)
        if self.controller.get_config('chdir_on_fileopen'):
            os.chdir(filedir)
            self.controller.set_workdir()

        # check for athena projects
        if is_athena_project(path):
            kwargs = dict(filename=path,
                          _larch = self.controller.larch,
                          read_ok_cb=self.onReadAthenaProject_OK)
            self.show_subframe('athena_import', AthenaImporter, **kwargs)
        else:
            kwargs = dict(filename=path,
                          _larch=self.larch_buffer.larchshell,
                          last_array_sel = self.last_array_sel,
                          read_ok_cb=self.onRead_OK)

            self.show_subframe('readfile', ColumnDataFileFrame, **kwargs)

    def onReadAthenaProject_OK(self, path, namelist):
        """read groups from a list of groups from an athena project file"""
        self.larch.eval("_prj = read_athena('{path:s}', do_fft=False, do_bkg=False)".format(path=path))
        dgroup = None
        s = """
        {group:s} = _prj.{group:s}
        {group:s}.datatype = 'xas'
        {group:s}.xdat = 1.0*{group:s}.energy
        {group:s}.ydat = 1.0*{group:s}.mu
        {group:s}.yerr = 1.0
        {group:s}.plot_ylabel = 'mu'
        {group:s}.plot_xlabel = 'energy'
        """
        for gname in namelist:
            self.larch.eval(s.format(group=gname))
            dgroup = self.install_group(gname, gname, with_plot=False)
            # self.nb_panels[0].fill_form(dgroup)
        if dgroup is not None:
            self.nb_panels[0].plot(dgroup)
        self.larch.eval("del _prj")


    def onRead_OK(self, script, path, groupname=None, array_sel=None,
                  overwrite=False):
        """ called when column data has been selected and is ready to be used
        overwrite: whether to overwrite the current datagroup, as when
        editing a datagroup
        """
        abort_read = False
        filedir, filename = os.path.split(path)
        if not overwrite and hasattr(self.larch.symtable, groupname):
            newname = file2groupname(filename, symtable=self.larch.symtable)
            msg = """Warning: groupname '%s' already used.
            Will use groupname '%s' instead """  % (groupname, newname)
            dlg = wx.MessageDialog(self, msg, 'Warning',
                                   wx.OK | wx.CANCEL )

            abort_read = (wx.ID_OK != dlg.ShowModal())
            dlg.Destroy()
            groupname = newname

        if abort_read:
            return
        self.larch.eval(script.format(group=groupname, path=path))
        if array_sel is not None:
            self.last_array_sel = array_sel
        self.install_group(groupname, filename, overwrite=overwrite)

        for path in self.paths2read:
            path = path.replace('\\', '/')
            filedir, filename = os.path.split(path)
            gname = file2groupname(filename, symtable=self.larch.symtable)
            self.larch.eval(script.format(group=gname, path=path))
            self.install_group(gname, filename, overwrite=True)

    def install_group(self, groupname, filename, overwrite=False, with_plot=True):
        """add groupname / filename to list of available data groups"""

        thisgroup = getattr(self.larch.symtable, groupname)
        thisgroup.groupname = groupname
        thisgroup.filename = filename

        datatype = getattr(thisgroup, 'datatype', 'raw')
        # file /group may already exist in list
        if filename in self.controller.file_groups and not overwrite:
            for i in range(1, 101):
                ftest = "%s (%i)"  % (filename, i)
                if ftest not in self.controller.file_groups:
                    filename = ftest
                    break

        if filename not in self.controller.file_groups:
            self.controller.filelist.Append(filename)
            self.controller.file_groups[filename] = groupname
        self.nb.SetSelection(0)
        self.ShowFile(groupname=groupname, with_plot=with_plot)
        self.controller.filelist.SetStringSelection(filename)
        return thisgroup