Changeset 5373


Ignore:
Timestamp:
Nov 17, 2022 10:59:43 AM (4 months ago)
Author:
toby
Message:

add .gpx browser

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIIctrlGUI.py

    r5371 r5373  
    109109                                   CIF powder histogram imports only
    110110:func:`PhaseSelector`              Select a phase from a list (used for phase importers)
     111:class:`gpxFileSelector`           File browser dialog for opening existing .gpx files
    111112
    112113================================  =================================================================
     
    180181import GSASIImath as G2mth
    181182import GSASIIstrMain as G2stMn
     183import GSASIIIO as G2IO
    182184import config_example
    183185if sys.version_info[0] >= 3:
     
    84928494    dlg.Show()
    84938495
     8496################################################################################
     8497# GPX browser routines
     8498def skimGPX(fl):
     8499    '''pull out fit information from a .gpx file quickly
     8500
     8501    :returns: dict with status info
     8502    '''
     8503    if fl is None: return {}
     8504    result = {}
     8505    if not os.path.exists(fl):
     8506        return {'error':'File does not exist!'}
     8507    cnt = 0
     8508    hist = 0
     8509    fp = open(fl,'rb')
     8510    result['last saved'] = time.ctime(os.stat(fl).st_mtime)
     8511    try:
     8512        while True:
     8513            cnt += 1
     8514            try:
     8515                data = G2IO.cPickleLoad(fp)
     8516            except EOFError:
     8517                #print(cnt,'entries read')       
     8518                break
     8519            if cnt > 50:  # don't spend too long on this file, if big
     8520                result['PWDR'] += 3*['   .']
     8521                break
     8522            datum = data[0]
     8523            if datum[0] == 'Notebook':
     8524                result[datum[0]] = datum[1][-1]
     8525            elif datum[0] == 'Covariance':
     8526                d = datum[1]['Rvals']
     8527                result[datum[0]] = 'Overall: Rwp={:.2f}, GOF={:.1f}'.format(
     8528                    d.get('Rwp','?'),d.get('GOF','?'))
     8529                if d.get('converged',False):
     8530                    result[datum[0]] += '  **Converged**'
     8531            elif datum[0].startswith('PWDR'):
     8532                if 'Residuals' not in datum[1][0]: continue
     8533                if 'PWDR' not in result: result['PWDR'] = []
     8534                result['PWDR'].append(
     8535                    "hist #{}: wR={:.2f} ({:})".format(
     8536                        hist,datum[1][0]['Residuals'].get('wR','?'),datum[0]))
     8537                hist += 1
     8538#            elif datum[0].startswith('HKLF'):
     8539#                pass
     8540#            elif 'Controls' in datum[0]:
     8541#                datum[0]['Seq Data']
     8542            elif datum[0] in ('Constraints','Restraints','Rigid bodies'):
     8543                pass
     8544            else:
     8545                pass
     8546                #GSASIIpath.IPyBreak_base()
     8547    except Exception as msg:
     8548        result['error'] = 'read error: '+str(msg)
     8549    finally:
     8550        fp.close()
     8551    return result
     8552
     8553class gpxFileSelector(wx.Dialog):
     8554    '''Create a file selection widget for locating .gpx files as a modal
     8555    dialog. Displays status information on selected files. After creating
     8556    this use dlg.ShowModal() to wait for selection of a file.
     8557    If dlg.ShowModal() returns wx.ID_OK, use dlg.Selection (multiple=False)
     8558    to obtain the selected file or dlg.Selections (multiple=True) to
     8559    obtain a list of multiple files.
     8560
     8561    :param wx.Frame parent: name of panel or frame that will be
     8562      the parent to the dialog. Can be None.
     8563
     8564    :param path startdir: Specifies the initial directory that is
     8565      opened when the window is initially opened. Default is '.'
     8566
     8567    :param bool multiple: if True, checkboxes are used to allow
     8568      selection of multiple files. Default is False
     8569
     8570    '''
     8571    def __init__(self,parent,startdir='.',multiple=False,*args,**kwargs):
     8572        import wx.lib.filebrowsebutton as wxfilebrowse
     8573        import wx.richtext as wxrt
     8574        self.timer = None
     8575        self.delay = 1500 # time to wait before applying filter (1.5 sec)
     8576        self.Selection = None
     8577        self.Selections = []
     8578        self.startDir = startdir
     8579        if startdir == '.':
     8580            self.startDir = os.getcwd()
     8581        self.multiple = multiple
     8582        wx.Dialog.__init__(self, parent=parent,
     8583                                 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
     8584        self.CenterOnParent()
     8585       
     8586        topSizer = wx.BoxSizer(wx.VERTICAL)
     8587        self.dirBtn = wxfilebrowse.DirBrowseButton(self,wx.ID_ANY, size=(650, -1),
     8588                            changeCallback = self.DirSelected,
     8589                            startDirectory = self.startDir
     8590                    )
     8591        topSizer.Add(self.dirBtn,0,wx.EXPAND,1)
     8592       
     8593        subSiz = wx.BoxSizer(wx.HORIZONTAL)
     8594        self.opt = {'useBak':False, 'sort':0, 'filter':'*'}
     8595        chk = G2CheckBoxFrontLbl(self,' Include\n .bakXX?',self.opt,'useBak',
     8596                                     OnChange=self.DirSelected)
     8597        subSiz.Add(chk)
     8598        subSiz.Add((10,-1),1,wx.EXPAND,1)
     8599        subSiz.Add(wx.StaticText(self,wx.ID_ANY,'   Sort by: '),0,wx.ALIGN_CENTER_VERTICAL,1)
     8600        choices = ['age','name (alpha+case)','name (alpha)']
     8601        for w in G2RadioButtons(self,self.opt,'sort',choices,
     8602                                    OnChange=self.DirSelected):
     8603            subSiz.Add(w,0,wx.ALIGN_CENTER_VERTICAL,0)
     8604        subSiz.Add((10,-1),1,wx.EXPAND,1)
     8605        subSiz.Add(wx.StaticText(self,wx.ID_ANY,'Name \nFilter: '),0,wx.ALIGN_CENTER_VERTICAL,1)
     8606        self.filterBox = ValidatedTxtCtrl(self, self.opt, 'filter',
     8607                                size=(80,-1), style=wx.TE_PROCESS_ENTER,
     8608                                OnLeave=self.DirSelected, notBlank=False)
     8609        self.filterBox.Bind(wx.EVT_TEXT,self._startUpdateTimer)
     8610        self.filterBox.Bind(wx.EVT_TEXT_ENTER,self.DirSelected)
     8611        subSiz.Add(self.filterBox)
     8612        subSiz.Add((2,-1))
     8613       
     8614        topSizer.Add(subSiz,0,wx.EXPAND,0)
     8615
     8616        mainPanel = wx.SplitterWindow(self, wx.ID_ANY, style=wx.SP_LIVE_UPDATE|wx.SP_3D)
     8617        mainPanel.SetMinimumPaneSize(100)
     8618
     8619        if self.multiple:
     8620            self.fileBox = wx.CheckListBox(mainPanel,wx.ID_ANY, size=(200, 200),
     8621                                               style=wx.LB_SINGLE)
     8622            self.fileBox.Bind(wx.EVT_CHECKLISTBOX,self.FileSelected)
     8623        else:
     8624            self.fileBox = wx.ListBox(mainPanel,wx.ID_ANY, size=(200, 200),
     8625                                          style=wx.LB_SINGLE)
     8626        self.fileBox.Bind(wx.EVT_LISTBOX,self.FileSelected)
     8627
     8628        self.rtc = wxrt.RichTextCtrl(mainPanel, style=wx.VSCROLL|wx.HSCROLL|
     8629                                       wx.NO_BORDER|wx.richtext.RE_READONLY)
     8630        mainPanel.SplitVertically(self.fileBox, self.rtc, 200)
     8631        topSizer.Add(mainPanel,1,wx.EXPAND)
     8632       
     8633        subSiz = wx.BoxSizer(wx.HORIZONTAL)
     8634        subSiz.Add((-1,-1),1,wx.EXPAND,1)
     8635        self.OKbtn = wx.Button(self, wx.ID_OK, label='Open')
     8636        self.OKbtn.Enable(False)   # A file must be selected 1st
     8637        btn = wx.Button(self, wx.ID_CANCEL)
     8638        subSiz.Add(self.OKbtn)
     8639        subSiz.Add((5,-1))
     8640        subSiz.Add(btn)
     8641        subSiz.Add((-1,-1),1,wx.EXPAND,1)
     8642        topSizer.Add(subSiz,0,wx.EXPAND)
     8643        self.SetSizer(topSizer)
     8644        topSizer.Fit(self)
     8645        self.dirBtn.SetValue(self.startDir)
     8646
     8647    def _startUpdateTimer(self,event):
     8648        if self.timer:
     8649            self.timer.Restart(self.delay)
     8650        else:
     8651            self.timer = wx.CallLater(self.delay,self.DirSelected)
     8652       
     8653    def DirSelected(self,event=None,*args,**kwargs):
     8654        '''Respond to a directory being selected. List files found in fileBox and
     8655        clear any selections. Also clear any reference to a timer.
     8656        '''
     8657        import re
     8658        try:
     8659            if self.timer: self.timer.Stop()
     8660        except:
     8661            pass
     8662        self.timer = None
     8663        self.fileBox.Clear()
     8664        self.rtc.Clear()
     8665        self.Selection = None
     8666        self.Selections = []
     8667        self.OKbtn.Enable(False)
     8668        glb = self.opt['filter'].strip()
     8669        if not glb:
     8670            glb = '*'
     8671        elif not '*' in glb:
     8672            glb = '*' + glb + '*'
     8673        fullglob = os.path.join(self.dirBtn.GetValue(),glb+'.gpx')
     8674        self.fl = glob.glob(fullglob)
     8675        if self.opt['useBak']:
     8676            self.sl = [(os.path.split(i)[1],os.stat(i).st_mtime,i) for i in self.fl]
     8677        else:
     8678            self.sl = [(os.path.split(i)[1],os.stat(i).st_mtime,i) for i in self.fl
     8679                  if not re.match(r'.*\.bak\d+\.gpx.*',i)]
     8680        if self.opt['sort'] == 0:
     8681            self.sl.sort(key=lambda x: x[1],reverse=True)
     8682        elif self.opt['sort'] == 1:
     8683            self.sl.sort(key=lambda x: x[0])
     8684        else:
     8685            self.sl.sort(key=lambda x: x[0].lower())
     8686        items = [i[0]+' ('+self._fmtTimeStampDelta(i[1])+')' for i in self.sl]
     8687        if items:
     8688            self.fileBox.InsertItems(items,0)
     8689       
     8690    def FileSelected(self,event):
     8691        '''Respond to a file being selected (or checked in multiple mode)
     8692        '''
     8693        if self.multiple:  # disable  Open when nothing is selected
     8694            self.Selections = []
     8695            OK = False
     8696            for i in self.fileBox.GetCheckedItems():
     8697                self.Selections.append(self.sl[i][2])
     8698                OK = True
     8699            self.OKbtn.Enable(OK)
     8700        else:
     8701            self.OKbtn.Enable(True)
     8702        self.Selection = self.sl[self.fileBox.GetSelection()][2]
     8703        result = skimGPX(self.Selection)
     8704        self.displayGPXrtc(result,self.Selection)
     8705
     8706    def displayGPXrtc(self,result,fwp):
     8707        '''Show info about selected file in a RichText display'''
     8708        self.rtc.Clear()
     8709        if fwp is None: return
     8710        self.rtc.Freeze()
     8711        self.rtc.BeginSuppressUndo()
     8712        self.rtc.BeginAlignment(wx.TEXT_ALIGNMENT_CENTER)
     8713        self.rtc.BeginFontSize(14)
     8714        self.rtc.BeginBold()
     8715        self.rtc.WriteText(os.path.split(fwp)[1])
     8716        self.rtc.EndBold()
     8717        self.rtc.Newline()
     8718        self.rtc.EndFontSize()
     8719        self.rtc.EndAlignment()
     8720        self.rtc.WriteText('last saved on ')
     8721        self.rtc.WriteText(result['last saved'])
     8722        self.rtc.Newline()
     8723        if 'Covariance' in result:
     8724            self.rtc.BeginLeftIndent(0,40)
     8725            self.rtc.WriteText(result['Covariance'])
     8726            self.rtc.Newline()
     8727            self.rtc.EndLeftIndent()
     8728        if 'Notebook' in result:
     8729            self.rtc.BeginLeftIndent(0,40)
     8730            self.rtc.BeginItalic()
     8731            self.rtc.WriteText('Last notebook entry: ')
     8732            self.rtc.EndItalic()
     8733            self.rtc.WriteText(result['Notebook'])
     8734            self.rtc.Newline()
     8735            self.rtc.EndLeftIndent()
     8736
     8737        if 'PWDR' in result:
     8738            self.rtc.BeginParagraphSpacing(0,0)
     8739            self.rtc.BeginLeftIndent(0)
     8740            self.rtc.BeginBold()
     8741            self.rtc.WriteText('Powder histograms:')
     8742            self.rtc.EndBold()
     8743            self.rtc.EndLeftIndent()
     8744            self.rtc.Newline()
     8745            self.rtc.BeginLeftIndent(40)
     8746            for line in result['PWDR']:
     8747                self.rtc.WriteText(line+'\n')
     8748            self.rtc.EndLeftIndent()
     8749            self.rtc.EndParagraphSpacing()
     8750           
     8751        if 'error' in result:
     8752            self.rtc.Newline()
     8753            self.rtc.BeginBold()
     8754            self.rtc.WriteText('Error encountered: ')
     8755            self.rtc.EndBold()
     8756            self.rtc.WriteText(result['error'])
     8757        self.rtc.EndSuppressUndo()
     8758        self.rtc.Thaw()
     8759
     8760    def _fmtTimeStampDelta(self,tm):
     8761        'Show file age relative to now'
     8762        delta = time.time() - tm
     8763        if delta > 60*60*24*365:
     8764            return "{:.2f} years".format(delta/(60*60*24*365))
     8765        elif delta > 60*60*24*7:
     8766            return "{:.1f} weeks".format(delta/(60*60*24*7))
     8767        elif delta > 60*60*24:
     8768            return "{:.1f} days".format(delta/(60*60*24))
     8769        elif delta > 60*60:
     8770            return "{:.1f} hours".format(delta/(60*60))
     8771        else:
     8772            return "{:.1f} minutes".format(delta/60)
     8773
     8774   
    84948775if __name__ == '__main__':
    84958776    app = wx.App()
  • trunk/GSASIIdataGUI.py

    r5362 r5373  
    678678        '''Add items to File menu
    679679        '''
    680         item = parent.Append(wx.ID_ANY,'&Open project...\tCtrl+O','Open a GSAS-II project file (*.gpx)')           
     680        item = parent.Append(wx.ID_ANY,'&Open project...\tCtrl+O','Open a GSAS-II project (.gpx) file')           
    681681        self.Bind(wx.EVT_MENU, self.OnFileOpen, id=item.GetId())
    682682        if sys.platform == "darwin":
    683             item = parent.Append(wx.ID_ANY,'&Open in new window...','Open a GSAS-II project file (*.gpx) in a separate process')
     683            item = parent.Append(wx.ID_ANY,'&Open in new window...','Open a GSAS-II project (.gpx) file in a separate process')
    684684            self.Bind(wx.EVT_MENU, self.OnNewGSASII, id=item.GetId())
    685         item = parent.Append(wx.ID_ANY,'Reopen recent...\tCtrl+E','Reopen a previously used GSAS-II project file (*.gpx)')
     685        item = parent.Append(wx.ID_ANY,'Reopen recent...\tCtrl+E','Reopen a previously used GSAS-II project (.gpx) file')
    686686        self.Bind(wx.EVT_MENU, self.OnFileReopen, id=item.GetId())
     687        item = parent.Append(wx.ID_ANY,'&Open w/project browser\tCtrl+B','Use project browser to a GSAS-II project (.gpx) file')           
     688        self.Bind(wx.EVT_MENU, self.OnFileBrowse, id=item.GetId())
    687689        item = parent.Append(wx.ID_ANY,'&Save project\tCtrl+S','Save project under current name')
    688690        self.Bind(wx.EVT_MENU, self.OnFileSave, id=item.GetId())
     
    43254327            print('file not found',f)       
    43264328       
     4329    def _SaveOld(self):
     4330        '''See if we should save current project and continue
     4331        to read another.
     4332        returns True if the project load should continue
     4333        '''
     4334        if self.dataWindow:
     4335            self.dataWindow.ClearData()
     4336            dlg = wx.MessageDialog(self,
     4337                    'Do you want to save and replace the current project?\n'
     4338                    '(Use No to read without saving or Cancel to continue '
     4339                    'with current project)',
     4340                'Save & Overwrite?',
     4341                wx.YES|wx.NO|wx.CANCEL)
     4342        try:
     4343            result = dlg.ShowModal()
     4344        finally:
     4345            dlg.Destroy()
     4346        if result == wx.ID_NO:
     4347            result = True
     4348        elif result == wx.ID_CANCEL:
     4349            return False
     4350        else:
     4351            if not self.OnFileSave(None):
     4352                return False
     4353        self.GPXtree.DeleteChildren(self.root)
     4354        self.GSASprojectfile = ''
     4355        self.HKL = []
     4356        self.Extinct = []
     4357        if self.G2plotNB.plotList:
     4358            self.G2plotNB.clear()
     4359        return True
     4360       
    43274361    def OnFileOpen(self, event, filename=None):
    43284362        '''Gets a GSAS-II .gpx project file in response to the
    43294363        File/Open Project menu button
    43304364        '''
    4331         def SaveOld():
    4332             '''See if we should save current project and continue
    4333             to read another.
    4334             returns True if the project load should continue
    4335             '''
    4336             if self.dataWindow:
    4337                 self.dataWindow.ClearData()
    4338             dlg = wx.MessageDialog(self,
    4339                     'Do you want to save and replace the current project?\n(Use No to read without saving or Cancel to continue with current project)',
    4340                     'Save & Overwrite?',
    4341                     wx.YES|wx.NO|wx.CANCEL)
    4342             try:
    4343                 result = dlg.ShowModal()
    4344             finally:
    4345                 dlg.Destroy()
    4346             if result == wx.ID_NO:
    4347                 result = True
    4348             elif result == wx.ID_CANCEL:
    4349                 return False
    4350             else:
    4351                 if not self.OnFileSave(None): return False
    4352             self.GPXtree.DeleteChildren(self.root)
    4353             self.GSASprojectfile = ''
    4354             self.HKL = []
    4355             self.Extinct = []
    4356             if self.G2plotNB.plotList:
    4357                 self.G2plotNB.clear()
    4358             return True
    43594365       
    43604366        def GetGPX():
     
    43764382        self.EnablePlot = False
    43774383        if self.GPXtree.GetChildrenCount(self.root,False):
    4378             if not SaveOld(): return
     4384            if not self._SaveOld(): return
    43794385
    43804386        if not filename:
     
    43984404            print (traceback.format_exc())
    43994405
     4406    def OnFileBrowse(self, event):
     4407        '''Gets a GSAS-II .gpx project using the GPX browser, in response
     4408        to the File/"Open Project browser" menu button
     4409        '''       
     4410        self.EnablePlot = False
     4411        if self.LastGPXdir:
     4412            pth = self.LastGPXdir
     4413        else:
     4414            pth = '.'
     4415
     4416        try:
     4417            dlg = G2G.gpxFileSelector(parent=self,startdir=pth)
     4418            if wx.ID_OK == dlg.ShowModal():
     4419                filename = dlg.Selection
     4420            else:
     4421                return
     4422        finally:
     4423            dlg.Destroy()
     4424       
     4425        if self.GPXtree.GetChildrenCount(self.root,False):
     4426            if not self._SaveOld(): return # cancel was entered; nothing changed
     4427        self.GSASprojectfile = filename
     4428        self.LastGPXdir = os.path.split(os.path.abspath(filename))[0]
     4429
     4430        self.init_vars()
     4431        try:
     4432            self.StartProject()         #open the file if possible
     4433        except:
     4434            print ('\nError opening file '+filename)
     4435            import traceback
     4436            print (traceback.format_exc())
     4437
     4438           
    44004439    def StartProject(self):
    44014440        '''Opens a GSAS-II project file & selects the 1st available data set to
Note: See TracChangeset for help on using the changeset viewer.