source: trunk/G2compare.py @ 4262

Last change on this file since 4262 was 4262, checked in by toby, 4 years ago

start of project comparison tool

  • Property svn:eol-style set to native
File size: 17.5 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#GSAS-II Data/Model Comparison
4########### SVN repository information ###################
5# $Date: $
6# $Author: toby $
7# $Revision: $
8# $URL: $
9# $Id: $
10########### SVN repository information ###################
11'''
12'''
13
14#TODO: in OnDataTreeSelChanged want to plot patterns
15# Make PWDR unique (use histlist)
16# add graphics
17# implement project
18
19import sys
20import os
21import platform
22if '2' in platform.python_version_tuple()[0]:
23    import cPickle
24else:
25    try:
26        import _pickle as cPickle
27    except:
28        print('Warning: failed to import the optimized Py3 pickle (_pickle)')
29        import pickle as cPickle
30
31import wx
32import numpy as np
33import matplotlib as mpl
34try:
35    import OpenGL as ogl
36except ImportError:
37    pass
38import scipy as sp
39
40import GSASIIpath
41GSASIIpath.SetVersionNumber("$Revision: 4154 $")
42import GSASIIfiles as G2fil
43import GSASIIplot as G2plt
44import GSASIIctrlGUI as G2G
45import GSASIIobj as G2obj
46
47__version__ = '0.0.1'
48
49def cPickleLoad(fp):
50    if '2' in platform.python_version_tuple()[0]:
51        return cPickle.load(fp)
52    else:
53       return cPickle.load(fp,encoding='latin-1')
54           
55def main(application):
56    '''Start up the GSAS-II GUI'''                       
57    knownVersions = ['2.7','3.6','3.7','3.8']
58    if platform.python_version()[:3] not in knownVersions: 
59        dlg = wx.MessageDialog(None, 
60                'GSAS-II requires Python 2.7.x or 3.6+\n Yours is '+sys.version.split()[0],
61                'Python version error',  wx.OK)
62        try:
63            dlg.ShowModal()
64        finally:
65            dlg.Destroy()
66        sys.exit()
67           
68    application.main = MakeTopWindow(None)  # application.main is the main wx.Frame
69    application.SetTopWindow(application.main)
70    # save the current package versions
71    application.main.PackageVersions = G2fil.get_python_versions([wx, mpl, np, sp, ogl])
72    try:
73        application.SetAppDisplayName('GSAS-II Compare')
74    except:
75        pass
76    #application.GetTopWindow().SendSizeEvent()
77    application.GetTopWindow().Show(True)
78    return application.GetTopWindow()
79   
80class MakeTopWindow(wx.Frame):
81    '''Define the main frame and its associated menu items
82    '''
83    def __init__(self, parent):
84        size = wx.Size(700,450)
85        wx.Frame.__init__(self, name='dComp', parent=parent,
86            size=size,style=wx.DEFAULT_FRAME_STYLE, title='GSAS-II data/model comparison')
87        # plot window
88        self.plotFrame = wx.Frame(None,-1,'dComp Plots',size=size,
89            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
90        self.G2plotNB = G2plt.G2PlotNoteBook(self.plotFrame,G2frame=self)
91        self.plotFrame.Show()
92        # menus
93        Frame = self.GetTopLevelParent() # same as self
94        Menu = wx.MenuBar()
95        File = wx.Menu(title='')
96        Menu.Append(menu=File, title='&File')
97        item = File.Append(wx.ID_ANY,'&Import project...\tCtrl+O','Open a GSAS-II project file (*.gpx)')           
98        self.Bind(wx.EVT_MENU, self.onLoadGPX, id=item.GetId())
99#        item = File.Append(wx.ID_ANY,'&Import selected...','Open a GSAS-II project file (*.gpx)')
100#        self.Bind(wx.EVT_MENU, self.onLoadSel, id=item.GetId())
101
102        self.Mode = wx.Menu(title='')
103        Menu.Append(menu=self.Mode, title='&Mode')
104        self.wxID_Mode = {}
105        for m in "Histogram","Phase","Project":
106            i = self.wxID_Mode[m] = wx.NewId()
107            item = self.Mode.AppendRadioItem(i,m,'Display {}s'.format(m))
108            self.Bind(wx.EVT_MENU, self.onRefresh, id=item.GetId())
109        item = self.Mode.Append(wx.ID_ANY,'Set histogram filter','Set a filter for histograms to display')
110        self.Bind(wx.EVT_MENU, self.onHistFilter, id=item.GetId())
111       
112        Frame.SetMenuBar(Menu)
113        # status bar
114        self.Status = self.CreateStatusBar()
115        self.Status.SetFieldsCount(2)
116        # split the frame and add the tree
117        self.mainPanel = wx.SplitterWindow(self, wx.ID_ANY, style=wx.SP_LIVE_UPDATE|wx.SP_3D)
118        self.mainPanel.SetMinimumPaneSize(100)
119        self.treePanel = wx.Panel(self.mainPanel, wx.ID_ANY,
120            style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
121       
122#        self.dataWindow = G2DataWindow(self.mainPanel)
123        self.dataWindow = wx.ScrolledWindow(self.mainPanel)
124        dataSizer = wx.BoxSizer(wx.VERTICAL)
125        self.dataWindow.SetSizer(dataSizer)
126        self.mainPanel.SplitVertically(self.treePanel, self.dataWindow, 200)
127        self.Status.SetStatusWidths([200,-1])   # make these match?
128       
129        treeSizer = wx.BoxSizer(wx.VERTICAL)
130        self.treePanel.SetSizer(treeSizer)
131        self.GPXtree = G2G.G2TreeCtrl(id=wx.ID_ANY,
132            parent=self.treePanel, size=self.treePanel.GetClientSize(),style=wx.TR_DEFAULT_STYLE )
133        TreeId = self.GPXtree.Id
134
135        treeSizer.Add(self.GPXtree,1,wx.EXPAND|wx.ALL,0)
136        #self.GPXtree.Bind(wx.EVT_TREE_SEL_CHANGED,self.OnDataTreeSelChanged)
137        self.GPXtree.Bind(wx.EVT_TREE_SEL_CHANGED,self.OnDataTreeSelChanged)
138        # self.GPXtree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK,self.OnDataTreeSelChanged)
139        # self.GPXtree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
140        #     self.OnGPXtreeItemCollapsed, id=TreeId)
141        #self.GPXtree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
142        #     self.OnGPXtreeItemExpanded, id=TreeId)
143        # self.GPXtree.Bind(wx.EVT_TREE_DELETE_ITEM,
144        #     self.OnGPXtreeItemDelete, id=TreeId)
145        # self.GPXtree.Bind(wx.EVT_TREE_KEY_DOWN,
146        #     self.OnGPXtreeKeyDown, id=TreeId)
147        # self.GPXtree.Bind(wx.EVT_TREE_BEGIN_RDRAG,
148        #     self.OnGPXtreeBeginRDrag, id=TreeId)       
149        # self.GPXtree.Bind(wx.EVT_TREE_END_DRAG,
150        #     self.OnGPXtreeEndDrag, id=TreeId)       
151        self.root = self.GPXtree.root       
152        self.Bind(wx.EVT_CLOSE, lambda event: sys.exit())
153
154        self.fileList = []  # list of files read for use in Reload
155        self.histList = []  # list of histograms loaded for unique naming
156
157        self.PWDRfilter = None
158       
159    def SelectGPX(self):
160        '''Select a .GPX file to be read
161        '''
162        dlg = wx.FileDialog(self, 'Choose GSAS-II project file', 
163                wildcard='GSAS-II project file (*.gpx)|*.gpx',style=wx.FD_OPEN)
164        try:
165            if dlg.ShowModal() != wx.ID_OK: return
166            fil = os.path.splitext(dlg.GetPath())[0]+'.gpx'
167        finally:
168            dlg.Destroy()
169        if os.path.exists(fil):
170            self.fileList.append([fil,'GPX'])
171            return fil
172        else:
173            print('File {} not found, skipping'.format(fil))
174            return
175       
176    def getMode(self):
177        '''returns the display mode (one of "Histogram","Phase","Project").
178        Could return '?' in case of an error.
179        '''
180        for m in self.wxID_Mode:
181            if self.Mode.FindItemById(self.wxID_Mode[m]).IsChecked():
182                break
183        else:
184            m = '?'
185        return m
186   
187    def onRefresh(self,event):
188        '''reread all files, in response to a change in mode, etc.
189        '''
190        self.GPXtree.DeleteChildren(self.root)  # delete tree contents
191        self.histList = []  # clear list of loaded histograms
192        for fil,mode in self.fileList:
193            self.loadFile(fil)
194       
195    def loadFile(self,fil):
196        '''read or reread a file
197        '''
198        if self.getMode() == "Histogram":
199            self.LoadPwdr(fil)
200        elif self.getMode() == "Phase":
201            self.LoadPhase(fil)
202        elif self.getMode() == "Project":
203            self.LoadProject(fil)
204        else:
205            print("mode not implemented")
206            #raise Exception("mode not implemented")
207       
208    def onLoadGPX(self,event):
209        '''Initial load of GPX file in response to a menu command
210        '''
211        fil = self.SelectGPX()
212        if not fil: return
213        if not os.path.exists(fil): return
214        self.fileList.append([fil,'GPX'])
215        self.loadFile(fil)
216
217    def LoadPwdr(self,fil):
218        '''Load PWDR entries from a .GPX file to the tree.
219        see :func:`GSASIIIO.ProjFileOpen`
220        '''
221        G2frame = self
222        filep = open(fil,'rb')
223        shortname = os.path.splitext(os.path.split(fil)[1])[0]
224
225        wx.BeginBusyCursor()
226        histLoadList = []
227        try:
228            while True:
229                try:
230                    data = cPickleLoad(filep)
231                except EOFError:
232                    break
233                if not data[0][0].startswith('PWDR'): continue
234                if self.PWDRfilter is not None: # implement filter
235                    if self.PWDRfilter not in data[0][0]: continue
236                data[0][0] += ' ('
237                data[0][0] += shortname
238                data[0][0] += ')'
239                histLoadList.append(data)
240                       
241        except Exception as errmsg:
242            if GSASIIpath.GetConfigValue('debug'):
243                print('\nError reading GPX file:',errmsg)
244                import traceback
245                print (traceback.format_exc())
246            msg = wx.MessageDialog(G2frame,message="Error reading file "+
247                str(fil)+". This is not a current GSAS-II .gpx file",
248                caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
249            msg.ShowModal()
250        finally:
251            filep.close()
252            wx.EndBusyCursor()
253
254        datum = None
255        for i,data in enumerate(histLoadList):
256            datum = data[0]
257            datum[0] = G2obj.MakeUniqueLabel(datum[0],self.histList)
258            Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=datum[0])
259            self.histList.append(datum[0])
260            # if 'ranId' not in datum[1][0]: # patch: add random Id if not present
261            #     datum[1][0]['ranId'] = ran.randint(0,sys.maxsize)
262            G2frame.GPXtree.SetItemPyData(Id,datum[1][:3])  #temp. trim off junk (patch?)
263            for datus in data[1:]:
264                sub = G2frame.GPXtree.AppendItem(Id,datus[0])
265    #patch
266                if datus[0] == 'Instrument Parameters' and len(datus[1]) == 1:
267                    if datum[0].startswith('PWDR'):
268                        datus[1] = [dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2]))),{}]
269                    else:
270                        datus[1] = [dict(zip(datus[1][2],zip(datus[1][0],datus[1][1]))),{}]
271                    for item in datus[1][0]:               #zip makes tuples - now make lists!
272                        datus[1][0][item] = list(datus[1][0][item])
273    #end patch
274                G2frame.GPXtree.SetItemPyData(sub,datus[1])
275        if datum: # was anything loaded?
276            print('project load successful for {}'.format(datum[0]))
277    #        G2frame.Status.SetStatusText('Mouse RB drag/drop to reorder',0)
278    #    G2frame.SetTitleByGPX()
279        self.GPXtree.Expand(self.root)
280       
281    def onHistFilter(self,event):
282        'Load a filter string via a dialog in response to a menu event'
283        lbl = ''
284        if self.PWDRfilter is not None:
285            lbl = self.PWDRfilter
286        dlg = G2G.SingleStringDialog(self,'Set string',
287                                'Set a string that must be in histogram name',
288                                 lbl,size=(400,-1))
289        if dlg.Show():
290            if dlg.GetValue().strip() == '':
291                self.PWDRfilter = None
292            else:
293                self.PWDRfilter = dlg.GetValue()
294            dlg.Destroy()
295            self.onRefresh(event)
296        else:
297            dlg.Destroy()
298
299    def LoadPhase(self,fil):
300        '''Load Phase entries from a .GPX file to the tree.
301        see :func:`GSASIIIO.ProjFileOpen`
302        '''
303        G2frame = self
304        filep = open(fil,'rb')
305        shortname = os.path.splitext(os.path.split(fil)[1])[0]
306
307        wx.BeginBusyCursor()
308        Phases = None
309        try:
310            while True:
311                try:
312                    data = cPickleLoad(filep)
313                except EOFError:
314                    break
315                if not data[0][0].startswith('Phase'): continue
316                Phases = data
317                #if self.PWDRfilter is not None: # implement filter
318                #    if self.PWDRfilter not in data[0][0]: continue
319                data[0][0] += ' ('
320                if Phases:
321                    data[0][0] += shortname
322                    data[0][0] += ')'
323                else: 
324                    data[0][0] += shortname
325                    data[0][0] += 'has no phases)'
326                Phases = data
327                break
328               
329        except Exception as errmsg:
330            if GSASIIpath.GetConfigValue('debug'):
331                print('\nError reading GPX file:',errmsg)
332                import traceback
333                print (traceback.format_exc())
334            msg = wx.MessageDialog(G2frame,message="Error reading file "+
335                str(fil)+". This is not a current GSAS-II .gpx file",
336                caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
337            msg.ShowModal()
338        finally:
339            filep.close()
340            wx.EndBusyCursor()
341
342        datum = None
343        if Phases:
344            datum = data[0]
345            #datum[0] = G2obj.MakeUniqueLabel(datum[0],self.histList)
346            Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=datum[0])
347            G2frame.GPXtree.SetItemPyData(Id,datum[1])
348            for datus in data[1:]:
349                #datus[0] += ' ('
350                #datus[0] += shortname
351                #datus[0] += ')'
352                sub = G2frame.GPXtree.AppendItem(Id,datus[0])
353                G2frame.GPXtree.SetItemPyData(sub,datus[1])
354        if datum: # was anything loaded?
355            self.GPXtree.Expand(Id)
356            print('project load successful for {}'.format(datum[0]))
357    #        G2frame.Status.SetStatusText('Mouse RB drag/drop to reorder',0)
358    #    G2frame.SetTitleByGPX()
359        self.GPXtree.Expand(self.root)
360
361    def LoadProject(self,fil):
362        '''Load the Covariance entry from a .GPX file to the tree.
363        see :func:`GSASIIIO.ProjFileOpen`
364        '''
365        G2frame = self
366        filep = open(fil,'rb')
367        shortname = os.path.splitext(os.path.split(fil)[1])[0]
368
369        wx.BeginBusyCursor()
370        Phases = None
371        try:
372            while True:
373                try:
374                    data = cPickleLoad(filep)
375                except EOFError:
376                    break
377                if not data[0][0].startswith('Covariance'): continue
378                Covar = data[0]
379                GSASIIpath.IPyBreak_base()
380                #if self.PWDRfilter is not None: # implement filter
381                #    if self.PWDRfilter not in data[0][0]: continue
382                Covar[0] = shortname + ' Covariance'
383                Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=Covar[0])
384                G2frame.GPXtree.SetItemPyData(Id,Covar[1])
385                break
386            else:
387                print("{} does not have refinement results".format(shortname))
388        except Exception as errmsg:
389            if GSASIIpath.GetConfigValue('debug'):
390                print('\nError reading GPX file:',errmsg)
391                import traceback
392                print (traceback.format_exc())
393            msg = wx.MessageDialog(G2frame,message="Error reading file "+
394                str(fil)+". This is not a current GSAS-II .gpx file",
395                caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
396            msg.ShowModal()
397        finally:
398            filep.close()
399            wx.EndBusyCursor()
400        self.GPXtree.Expand(self.root)
401       
402    def OnDataTreeSelChanged(self,event):
403        item = event.GetItem()
404        print('selected',item)
405       
406        #print(self.GPXtree._getTreeItemsList(item))
407        # pltNum = self.G2plotNB.nb.GetSelection()
408        # print(pltNum)
409        # if pltNum >= 0:                         #to avoid the startup with no plot!
410        #     self.G2plotNB.nb.GetPage(pltNum)
411        #     NewPlot = False
412        # else:
413        #     NewPlot = True
414        #if self.getMode() == "Histogram":
415        #self.PatternId = self.PickId  = item
416        #G2plt.PlotPatterns(self,plotType='PWDR',newPlot=NewPlot)
417           
418    # def OnGPXtreeItemExpanded(self,event):
419    #     item = event.GetItem()
420    #     print('expanded',item)
421    #     print(self.GPXtree._getTreeItemsList(item))
422    #     if item == self.root:
423    #         event.StopPropagation()
424    #     else:
425    #         event.Skip(False)
426
427if __name__ == '__main__':
428    #if sys.platform == "darwin":
429    #    application = G2App(0) # create the GUI framework
430    #else:
431    application = wx.App(0) # create the GUI framework
432    try:
433        GSASIIpath.SetBinaryPath(True)
434    except:
435        print('Unable to run with current setup, do you want to update to the')
436        try:
437            if '2' in platform.python_version_tuple()[0]:           
438                ans = raw_input("latest GSAS-II version? Update ([Yes]/no): ")
439            else:
440                ans = input("latest GSAS-II version? Update ([Yes]/no): ")               
441        except:
442            ans = 'no'
443        if ans.strip().lower() == "no":
444            import sys
445            print('Exiting')
446            sys.exit()
447        print('Updating...')
448        GSASIIpath.svnUpdateProcess()
449    GSASIIpath.InvokeDebugOpts()
450    Frame = main(application) # start the GUI
451    argLoadlist = sys.argv[1:]
452    if len(argLoadlist) == 0:
453        argLoadlist = ['/Users/toby/Scratch/copy.gpx',
454                       '/Users/toby/Scratch/CW_YAG.gpx']
455    for arg in argLoadlist:
456        fil = os.path.splitext(arg)[0] + '.gpx'
457        if os.path.exists(fil):
458            Frame.fileList.append([fil,'GPX'])
459            Frame.loadFile(fil)
460        else:
461            print('File {} not found. Skipping'.format(fil))
462    application.MainLoop()
Note: See TracBrowser for help on using the repository browser.