Changeset 4785
- Timestamp:
- Jan 27, 2021 3:27:25 PM (3 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/G2compare.py
r4364 r4785 18 18 #TODO: 19 19 # Prince-test next 20 # Make P WDR unique? (use histlist)20 # Make Phase unique? (need a phaselist) 21 21 # more graphics 22 22 # display more in datawindow … … 25 25 import os 26 26 import platform 27 import glob 27 28 if '2' in platform.python_version_tuple()[0]: 28 29 import cPickle … … 47 48 import GSASIIfiles as G2fil 48 49 import GSASIIplot as G2plt 50 import GSASIIdataGUI as G2gd 49 51 import GSASIIctrlGUI as G2G 50 52 import GSASIIobj as G2obj … … 105 107 def main(application): 106 108 '''Start up the GSAS-II GUI''' 107 knownVersions = [' 2.7','3.6','3.7','3.8']109 knownVersions = ['3.6','3.7','3.8','3.9'] 108 110 if platform.python_version()[:3] not in knownVersions: 109 111 dlg = wx.MessageDialog(None, 110 'GSAS-II requires Python 2.7.x or3.6+\n Yours is '+sys.version.split()[0],112 'GSAS-II requires Python 3.6+\n Yours is '+sys.version.split()[0], 111 113 'Python version error', wx.OK) 112 114 try: … … 158 160 File = wx.Menu(title='') 159 161 self.MenuBar.Append(menu=File, title='&File') 160 item = File.Append(wx.ID_ANY,'&Import project...\tCtrl+O','Open a GSAS-II project file (*.gpx)')162 item = File.Append(wx.ID_ANY,'&Import single project...\tCtrl+O','Open a GSAS-II project file (*.gpx)') 161 163 self.Bind(wx.EVT_MENU, self.onLoadGPX, id=item.GetId()) 164 item = File.Append(wx.ID_ANY,'&Import multiple projects...\tCtrl+M','Open a GSAS-II project file (*.gpx)') 165 self.Bind(wx.EVT_MENU, self.onLoadMultGPX, id=item.GetId()) 166 item = File.Append(wx.ID_ANY,'&Wildcard import of projects...\tCtrl+W','Open a GSAS-II project file (*.gpx)') 167 self.Bind(wx.EVT_MENU, self.onLoadWildGPX, id=item.GetId()) 162 168 # item = File.Append(wx.ID_ANY,'&Import selected...','Open a GSAS-II project file (*.gpx)') 163 169 # self.Bind(wx.EVT_MENU, self.onLoadSel, id=item.GetId()) … … 166 172 self.MenuBar.Append(menu=self.Mode, title='&Mode') 167 173 self.wxID_Mode = {} 168 for m in "Histogram","Phase","Project": 169 i = self.wxID_Mode[m] = wx.NewId() 170 item = self.Mode.AppendRadioItem(i,m,'Display {}s'.format(m)) 174 for i,m in enumerate(("Histogram","Phase","Project")): 175 self.wxID_Mode[m] = i+1 176 item = self.Mode.AppendRadioItem(i+1,m+'\tCtrl+{}'.format(i+1), 177 'Display {}s'.format(m)) 171 178 self.Bind(wx.EVT_MENU, self.onRefresh, id=item.GetId()) 172 179 item = self.Mode.Append(wx.ID_ANY,'Set histogram filter','Set a filter for histograms to display') … … 198 205 self.GPXtree = G2G.G2TreeCtrl(id=wx.ID_ANY, 199 206 parent=self.treePanel, size=self.treePanel.GetClientSize(),style=wx.TR_DEFAULT_STYLE ) 200 TreeId = self.GPXtree.Id207 #TreeId = self.GPXtree.Id 201 208 202 209 treeSizer.Add(self.GPXtree,1,wx.EXPAND|wx.ALL,0) … … 221 228 self.fileList = [] # list of files read for use in Reload 222 229 self.histList = [] # list of histograms loaded for unique naming 230 self.projList = [] 223 231 224 232 self.PWDRfilter = None … … 229 237 if type(pos) is str: pos = eval(pos) 230 238 win.SetPosition(pos) 231 if G etDisplay(pos) is None: win.Center()239 if G2gd.GetDisplay(pos) is None: win.Center() 232 240 except: 233 241 if GSASIIpath.GetConfigValue(var): … … 247 255 dlg.Destroy() 248 256 if os.path.exists(fil): 249 self.fileList.append([fil,'GPX'])257 #self.fileList.append([fil,'GPX']) 250 258 return fil 251 259 else: 252 260 print('File {} not found, skipping'.format(fil)) 253 261 return 262 263 def SelectMultGPX(self): 264 '''Select multiple .GPX files to be read 265 ''' 266 dlg = wx.FileDialog(self, 'Choose GSAS-II project file', 267 wildcard='GSAS-II project file (*.gpx)|*.gpx', 268 style=wx.FD_OPEN|wx.FD_MULTIPLE) 269 try: 270 if dlg.ShowModal() != wx.ID_OK: return 271 files = dlg.GetPaths() 272 finally: 273 dlg.Destroy() 274 fileList = [] 275 for f in files: 276 fil = os.path.splitext(f)[0]+'.gpx' 277 if os.path.exists(fil): 278 if fil not in fileList: 279 fileList.append(fil) 280 else: 281 print('File {} not found, skipping'.format(fil)) 282 return fileList 254 283 255 284 def getMode(self): … … 269 298 self.GPXtree.DeleteChildren(self.root) # delete tree contents 270 299 self.histList = [] # clear list of loaded histograms 300 self.projList = [] 271 301 for fil,mode in self.fileList: 272 302 self.loadFile(fil) 303 self.doneLoad() 273 304 self.SetModeMenu() 274 305 … … 300 331 print("mode not implemented") 301 332 #raise Exception("mode not implemented") 302 333 334 def doneLoad(self): 335 self.GPXtree.Expand(self.root) 336 if self.getMode() == "Project": 337 overId = self.GPXtree.InsertItem(pos=0,parent=self.root,text='Project Overview') 338 self.GPXtree.SelectItem(overId) 339 303 340 def onLoadGPX(self,event): 304 341 '''Initial load of GPX file in response to a menu command … … 309 346 self.fileList.append([fil,'GPX']) 310 347 self.loadFile(fil) 348 self.doneLoad() 349 350 def onLoadMultGPX(self,event): 351 '''Initial load of multiple GPX files in response to a menu command 352 ''' 353 for fil in self.SelectMultGPX(): 354 if not os.path.exists(fil): continue 355 self.fileList.append([fil,'GPX']) 356 self.loadFile(fil) 357 self.doneLoad() 358 359 def onLoadWildGPX(self,event,wildcard=None): 360 '''Initial load of GPX file in response to a menu command 361 ''' 362 home = os.path.abspath(os.getcwd()) 363 hlp = '''Enter a wildcard version of a file name. 364 The directory is assumed to be "{}" unless specified otherwise. 365 Extensions will be set to .gpx and .bak files will be ignored unless 366 the wildcard string includes "bak". For example, "*abc*" will match any 367 .gpx file in that directory containing "abc". String "/tmp/A*" will match 368 files in "/tmp" beginning with "A". Supplying two strings, "A*" and "B*bak*" 369 will match files names beginning with "A" or "B", but ".bak" files will 370 be included for the files beginning with "B" only. 371 '''.format(home) 372 if wildcard is None: 373 dlg = G2G.MultiStringDialog(self, 'Enter wildcard file names', 374 ['wild-card 1'] , values=['*'], 375 lbl='Provide string(s) with "*" to find matching files', 376 addRows=True, hlp=hlp) 377 res = dlg.Show() 378 wl = dlg.GetValues() 379 dlg.Destroy() 380 if not res: return 381 else: 382 wl = [wildcard] 383 for w in wl: 384 if not os.path.split(w)[0]: 385 w = os.path.join(home,w) 386 w = os.path.splitext(w)[0] + '.gpx' 387 for fil in glob.glob(w): 388 if not os.path.exists(fil): continue 389 if '.bak' in fil and 'bak' not in w: continue 390 if fil in [i for i,j in self.fileList]: continue 391 self.fileList.append([fil,'GPX']) 392 self.loadFile(fil) 393 self.doneLoad() 311 394 312 395 def LoadPwdr(self,fil): … … 369 452 G2frame.GPXtree.SetItemPyData(sub,datus[1]) 370 453 if datum: # was anything loaded? 371 print(' projectload successful for {}'.format(datum[0]))454 print('data load successful for {}'.format(datum[0])) 372 455 # G2frame.Status.SetStatusText('Mouse RB drag/drop to reorder',0) 373 456 # G2frame.SetTitleByGPX() … … 449 532 if datum: # was anything loaded? 450 533 self.GPXtree.Expand(Id) 451 print(' projectload successful for {}'.format(datum[0]))534 print('Phase load successful for {}'.format(datum[0])) 452 535 # G2frame.Status.SetStatusText('Mouse RB drag/drop to reorder',0) 453 536 # G2frame.SetTitleByGPX() … … 458 541 see :func:`GSASIIIO.ProjFileOpen` 459 542 ''' 543 import datetime 460 544 G2frame = self 461 545 filep = open(fil,'rb') 546 saved = datetime.datetime.fromtimestamp(os.path.getmtime(fil)).strftime("%Y-%h-%d %H:%M") 462 547 shortname = os.path.splitext(os.path.split(fil)[1])[0] 463 548 projInfo = [shortname,saved] 464 549 wx.BeginBusyCursor() 465 Phases = None 550 #Phases = None 551 #G2frame.GPXtree.SetItemPyData(Id,Covar[1]) 466 552 try: 467 553 while True: … … 470 556 except EOFError: 471 557 break 558 #if data[0][0] == 'Controls' and 'LastSavedUsing' in data[0][1]: 472 559 if not data[0][0].startswith('Covariance'): continue 473 560 Covar = data[0] 561 f = '{:d}' 562 if 'varyList' in data[0][1]: 563 projInfo += [f.format(len(data[0][1]['varyList']))] 564 else: 565 projInfo += ['?'] 566 for v in 'Nobs','GOF': 567 if 'Rvals' in data[0][1] and v in data[0][1]['Rvals']: 568 projInfo += [f.format(data[0][1]['Rvals'][v])] 569 else: 570 projInfo += ['?'] 571 f = '{:6.2f}' 474 572 #GSASIIpath.IPyBreak_base() 475 573 #if self.PWDRfilter is not None: # implement filter 476 574 # if self.PWDRfilter not in data[0][0]: continue 477 Covar[0] = shortname + ' Covariance'575 Covar[0] = shortname # + ' Covariance' 478 576 Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=Covar[0]) 479 577 G2frame.GPXtree.SetItemPyData(Id,Covar[1]) 578 self.projList.append(projInfo) 480 579 break 481 580 else: … … 493 592 filep.close() 494 593 wx.EndBusyCursor() 495 self.GPXtree.Expand(self.root)496 594 497 595 def OnDataTreeSelChanged(self,event): … … 510 608 item = event.GetItem() 511 609 #print('selected',item) 512 if self.getMode() == "Project": 610 lbl = G2frame.GPXtree.GetItemText(item) 611 if self.getMode() == "Project" and lbl == 'Project Overview': 612 ClearData(G2frame.dataWindow) 613 #import imp 614 #imp.reload(G2G) 615 pnl = G2G.SortableLstCtrl(G2frame.dataWindow) 616 h = ["File", "last saved", "vars", "Nobs", "GOF"] 617 j = [ 0, 0, 1, 1, 1] 618 pnl.PopulateHeader(h,j) 619 for i,line in enumerate(self.projList): 620 pnl.PopulateLine(i,line) 621 G2frame.dataWindow.GetSizer().Add(pnl,1,wx.EXPAND) 622 pnl.SetColWidth(0,maxwidth=170) 623 for i in range(1,len(h)): 624 pnl.SetColWidth(i,minwidth=50) 625 G2frame.dataWindow.SendSizeEvent() 626 elif self.getMode() == "Project": 513 627 ClearData(G2frame.dataWindow) 514 628 data = G2frame.GPXtree.GetItemPyData(item) … … 528 642 if 'lamMax' in Rvals: 529 643 text += '\n\tlog10 MaxLambda = {:.1f}'.format(np.log10(Rvals['lamMax'])) 644 text += '\n\tReduced Ï**2 = {:.2f}'.format(Rvals['GOF']**2) 530 645 G2frame.dataWindow.GetSizer().Add( 531 646 wx.StaticText(G2frame.dataWindow,wx.ID_ANY,text) … … 722 837 G2G.G2MessageBox(self,'Unable to use test: "X" values differ','Comparison not valid') 723 838 return 724 X = data0[3] - data1[3]725 # Z = np.sqrt(data0[3]) * (data0[1] - (data0[3] + data1[3])/2)726 X = (data0[3] - data1[3]) / np.sqrt(data0[1])727 Z = (data0[1] - (data0[3] + data1[3])/2) / np.sqrt(data0[1])728 lam = np.sum(X*Z) / np.sum(X)729 sig = np.sqrt(730 (np.sum(Z*Z) - lam*lam*np.sum(X*X)) /731 ((len(data0[0]) - 1) * np.sum(X*X))732 )839 # X = data0[3] - data1[3] 840 # #Z = np.sqrt(data0[3]) * (data0[1] - (data0[3] + data1[3])/2) 841 # X = (data0[3] - data1[3]) / np.sqrt(data0[1]) 842 # Z = (data0[1] - (data0[3] + data1[3])/2) / np.sqrt(data0[1]) 843 # lam = np.sum(X*Z) / np.sum(X) 844 # sig = np.sqrt( 845 # (np.sum(Z*Z) - lam*lam*np.sum(X*X)) / 846 # ((len(data0[0]) - 1) * np.sum(X*X)) 847 # ) 733 848 734 849 # 0 the x-postions (two-theta in degrees), … … 752 867 print('Unable to run with current setup, do you want to update to the') 753 868 try: 754 if '2' in platform.python_version_tuple()[0]:755 ans = raw_input("latest GSAS-II version? Update ([Yes]/no): ")756 else:869 # if '2' in platform.python_version_tuple()[0]: 870 # ans = raw_input("latest GSAS-II version? Update ([Yes]/no): ") 871 # else: 757 872 ans = input("latest GSAS-II version? Update ([Yes]/no): ") 758 873 except: 759 874 ans = 'no' 760 875 if ans.strip().lower() == "no": 761 import sys762 876 print('Exiting') 763 877 sys.exit() … … 774 888 else: 775 889 print('File {} not found. Skipping'.format(fil)) 776 777 # debug code to select in initial mode778 # self=Frame779 # self.Mode.FindItemById(self.wxID_Mode['Project']).Check(True)780 # self.onRefresh(None)890 Frame.doneLoad() 891 # debug code to select Project in initial mode 892 #Frame.onLoadWildGPX(None,wildcard='*') 893 #Frame.Mode.FindItemById(Frame.wxID_Mode['Project']).Check(True) 894 #Frame.onRefresh(None) 781 895 782 896 application.MainLoop() -
trunk/GSASIIctrlGUI.py
r4783 r4785 57 57 :class:`OrderBox` Creates a wx.Panel with scrollbars where items can be 58 58 ordered into columns. 59 :class:`SortableLstCtrl` Creates a wx.Panel for a table of data that 60 can be sorted by clicking on a column label. 59 61 :class:`ScrolledMultiEditor` wx.Dialog for editing many dict- or list-contained items. 60 62 with validation. Results are placed in dict or list. … … 2784 2786 hlp = HelpButton(self, self.hlp, wrap=450) 2785 2787 btnsizer.Add((-1,-1),1, wx.EXPAND, 1) 2786 btnsizer.Add(hlp,0,wx.ALIGN_RIGHT|wx.ALL) 2788 #btnsizer.Add(hlp,0,wx.ALIGN_RIGHT|wx.ALL) 2789 btnsizer.Add(hlp,0) 2787 2790 mainSizer.Add(btnsizer,0,wx.EXPAND) 2788 2791 if self.lbl: 2789 mainSizer.Add(wx.StaticText(self,wx.ID_ANY,self.lbl) ,0,WACV,0)2792 mainSizer.Add(wx.StaticText(self,wx.ID_ANY,self.lbl)) 2790 2793 mainSizer.Add((-1,15)) 2791 2794 promptSizer = wx.FlexGridSizer(0,2,5,5) … … 2793 2796 self.Indx = {} 2794 2797 for prompt,value in zip(self.prompts,self.values): 2795 promptSizer.Add(wx.StaticText(self,-1,prompt) ,0,WACV,0)2798 promptSizer.Add(wx.StaticText(self,-1,prompt)) 2796 2799 valItem = wx.TextCtrl(self,-1,value=value,style=wx.TE_PROCESS_ENTER,size=(self.size,-1)) 2797 2800 self.Indx[valItem.GetId()] = prompt … … 2810 2813 btn = wx.Button(self, wx.ID_ANY,'+',style=wx.BU_EXACTFIT) 2811 2814 btn.Bind(wx.EVT_BUTTON,self.onExpand) 2812 btnsizer.Add(btn ,0,wx.ALIGN_RIGHT)2815 btnsizer.Add(btn) 2813 2816 mainSizer.Add(btnsizer,0,wx.EXPAND) 2814 2817 self.SetSizer(mainSizer) … … 5992 5995 'Get the version number in the dialog' 5993 5996 return self.spin.GetValue() 5997 5998 ################################################################################ 5999 ################################################################################ 6000 import wx.lib.mixins.listctrl as listmix 6001 class SortableLstCtrl(wx.Panel): 6002 '''Creates a read-only table with sortable columns. Sorting is done by 6003 clicking on a column label. A triangle facing up or down is added to 6004 indicate the column is sorted. 6005 6006 To use, the header is labeled using 6007 :meth:`PopulateHeader`, then :meth:`PopulateLine` is called for every 6008 row in table and finally :meth:`SetColWidth` is called to set the column 6009 widths. 6010 6011 :param wx.Frame parent: parent object for control 6012 ''' 6013 def __init__(self, parent): 6014 wx.Panel.__init__(self, parent, wx.ID_ANY)#, style=wx.WANTS_CHARS) 6015 sizer = wx.BoxSizer(wx.VERTICAL) 6016 self.list = G2LstCtrl(self, wx.ID_ANY, style=wx.LC_REPORT| wx.BORDER_SUNKEN) 6017 sizer.Add(self.list, 1, wx.EXPAND) 6018 self.SetSizer(sizer) 6019 self.SetAutoLayout(True) 6020 #self.SortListItems(0, True) 6021 6022 def PopulateHeader(self, header, justify): 6023 '''Defines the column labels 6024 6025 :param list header: a list of strings with header labels 6026 :param list justify: a list of int values where 0 causes left justification, 6027 1 causes right justification, and -1 causes centering 6028 ''' 6029 info = wx.ListItem() 6030 info.Mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT 6031 info.Image = -1 6032 for i,(h,j) in enumerate(zip(header, justify)): 6033 info.Text = h 6034 if j > 0: 6035 info.Align = wx.LIST_FORMAT_RIGHT 6036 elif j < 0: 6037 info.Align = wx.LIST_FORMAT_CENTER 6038 else: 6039 info.Align = 0 6040 self.list.InsertColumn(i, info) 6041 listmix.ColumnSorterMixin.__init__(self.list, len(header)) 6042 self.list.itemDataMap = {} 6043 6044 def PopulateLine(self, key, data): 6045 '''Enters each row into the table 6046 6047 :param int key: a unique int value for each line, probably should 6048 be sequential 6049 :param list data: a list of strings for each column in that row 6050 ''' 6051 index = self.list.InsertItem(self.list.GetItemCount(), data[0]) 6052 for i,d in enumerate(data[1:]): 6053 self.list.SetItem(index, i+1, d) 6054 self.list.SetItemData(index, key) 6055 self.list.itemDataMap[key] = data 6056 6057 def SetColWidth(self,col,width=None,auto=True,minwidth=0,maxwidth=None): 6058 '''Sets the column width. 6059 6060 :param int width: the column width in pixels 6061 :param bool auto: if True (default) and width is None (default) the 6062 width is set by the maximum width entry in the column 6063 :param int minwidth: used when auto is True, sets a minimum 6064 column width 6065 :param int maxwidth: used when auto is True, sets a maximum 6066 column width. Do not use with minwidth 6067 ''' 6068 if width: 6069 self.list.SetColumnWidth(col, width) 6070 elif auto: 6071 self.list.SetColumnWidth(col, wx.LIST_AUTOSIZE) 6072 if minwidth and self.list.GetColumnWidth(col) < minwidth: 6073 self.list.SetColumnWidth(col, minwidth) 6074 elif maxwidth and self.list.GetColumnWidth(col) > maxwidth: 6075 self.list.SetColumnWidth(col, maxwidth) 6076 else: 6077 print('Error in SetColWidth: use either auto or width') 6078 6079 class G2LstCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ColumnSorterMixin): 6080 '''Creates a custom ListCtrl with support for images in column labels 6081 ''' 6082 def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition, 6083 size=wx.DefaultSize, style=0): 6084 wx.ListCtrl.__init__(self, parent, ID, pos, size, style) 6085 listmix.ListCtrlAutoWidthMixin.__init__(self) 6086 from wx.lib.embeddedimage import PyEmbeddedImage 6087 # from demo/images.py 6088 SmallUpArrow = PyEmbeddedImage( 6089 b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADxJ" 6090 b"REFUOI1jZGRiZqAEMFGke2gY8P/f3/9kGwDTjM8QnAaga8JlCG3CAJdt2MQxDCAUaOjyjKMp" 6091 b"cRAYAABS2CPsss3BWQAAAABJRU5ErkJggg==") 6092 SmallDnArrow = PyEmbeddedImage( 6093 b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEhJ" 6094 b"REFUOI1jZGRiZqAEMFGke9QABgYGBgYWdIH///7+J6SJkYmZEacLkCUJacZqAD5DsInTLhDR" 6095 b"bcPlKrwugGnCFy6Mo3mBAQChDgRlP4RC7wAAAABJRU5ErkJggg==") 6096 self.il = wx.ImageList(16, 16) 6097 self.UpArrow = self.il.Add(SmallUpArrow.GetBitmap()) 6098 self.DownArrow = self.il.Add(SmallDnArrow.GetBitmap()) 6099 self.parent=parent 6100 self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) 6101 6102 def GetListCtrl(self): # needed for sorting 6103 return self 6104 def GetSortImages(self): 6105 #return (self.parent.DownArrow, self.parent.UpArrow) 6106 return (self.DownArrow, self.UpArrow) 5994 6107 5995 6108 ################################################################################
Note: See TracChangeset
for help on using the changeset viewer.