source: trunk/GSASII.py @ 38

Last change on this file since 38 was 38, checked in by vondreel, 13 years ago

convert to python 2.6 from Enthought
small fixes to plotting ellipses

File size: 78.7 KB
Line 
1#GSASII
2
3import os.path as ospath
4import sys
5import math
6import cPickle
7import time
8import numpy as np
9import wx
10import matplotlib as mpl
11# use the newer wxmpl when needed
12(main,sub) = mpl.__version__.split('.')[0:2]
13if int(main) > 0 or int(sub) > 91: 
14    import wxmpl131 as wxmpl
15else:
16    import wxmpl as wxmpl
17import pylab
18
19# load the GSAS routines
20import GSASIIIO as G2IO
21import GSASIIcomp as G2cmp
22import GSASIIgrid as G2gd
23
24# print versions
25print "Available python module versions for pyGSASII:"
26print "python:     ",sys.version[:5]
27print "wxpython:   ",wx.__version__
28print "matplotlib: ",mpl.__version__
29print "numpy:      ",np.__version__
30print "wxmpl:      ",wxmpl.__version__
31
32__version__ = '0.1.2'
33
34# useful degree trig functions
35sind = lambda x: math.sin(x*math.pi/180.)
36cosd = lambda x: math.cos(x*math.pi/180.)
37tand = lambda x: math.tan(x*math.pi/180.)
38asind = lambda x: 180.*math.asin(x)/math.pi
39acosd = lambda x: 180.*math.acos(x)/math.pi
40atan2d = lambda x,y: 180.*math.atan2(y,x)/math.pi
41
42def create(parent):
43    return GSASII(parent)
44
45[wxID_GSASII, wxID_GSASIIPATTERNTREE, wxID_GSASIIDATA, wxID_GSASIIPICKGRID,
46] = [wx.NewId() for _init_ctrls in range(4)]
47
48[wxID_GSASIIFILECLOSE, wxID_GSASIIFILEEXIT, wxID_GSASIIFILEOPEN, 
49 wxID_GSASIIFILESAVE, wxID_GSASIIFILESAVEAS, wxID_GSASIIUNDO, 
50] = [wx.NewId() for _init_coll_File_Items in range(6)]
51
52[wxID_GSASIIPWDRREAD,wxID_GSASIISNGLREAD,wxID_GSASIIADDPHASE,wxID_GSASIIDELETEPHASE,
53 wxID_GSASIIDATADELETE,wxID_GSASIIREADPEAKS,wxID_GSASIIPWDSUM,wxID_GSASIIIMGREAD,
54 wxID_GSASIIIMSUM,
55] = [wx.NewId() for _init_coll_Data_Items in range(9)]
56
57[wxID_GSASIIIMPORT, wxID_GSASIIIMPORTPATTERN, wxID_GSASIIIMPORTHKL, wxID_GSASIIIMPORTPHASE,
58wxID_GSASIIIMPORTCIF, wxID_GSASIIIMPORTPDB, 
59] = [wx.NewId() for _init_coll_Import_Items in range(6)]
60
61[wxID_GSAIIEXPORT, wxID_GSASIIEXPORTPATTERN, wxID_GSASIIEXPORTHKL, wxID_GSASIIEXPORTPHASE,
62wxID_GSASIIEXPORTCIF, wxID_GSASIIEXPORTPEAKLIST
63] = [wx.NewId() for _init_coll_Export_Items in range(6)]
64
65[wxID_GSASIIHELPABOUT, wxID_GSASIIHELPHELP, 
66] = [wx.NewId() for _init_coll_Help_Items in range(2)]
67
68class GSASII(wx.Frame):
69   
70    def _init_coll_GSASIIMenu_Menus(self, parent):
71        parent.Append(menu=self.File, title='File')
72        parent.Append(menu=self.Data, title='Data')
73        parent.Append(menu=self.Calculate, title='Calculate')
74        parent.Append(menu=self.Import, title='Import')
75        parent.Append(menu=self.Export, title='Export')
76        parent.Append(menu=self.Help, title='Help')
77
78    def _init_coll_File_Items(self, parent):
79        parent.Append(help='', id=wxID_GSASIIFILEOPEN, kind=wx.ITEM_NORMAL,
80            text='Open project')
81        parent.Append(help='', id=wxID_GSASIIFILESAVE, kind=wx.ITEM_NORMAL,
82            text='Save project')
83        parent.Append(help='', id=wxID_GSASIIFILESAVEAS, kind=wx.ITEM_NORMAL,
84            text='SaveAs')
85        parent.Append(help='', id=wxID_GSASIIFILECLOSE, kind=wx.ITEM_NORMAL,
86            text='Close project')
87        parent.Append(help='', id=wxID_GSASIIFILEEXIT, kind=wx.ITEM_NORMAL,
88            text='Exit')
89        self.Bind(wx.EVT_MENU, self.OnFileOpenMenu, id=wxID_GSASIIFILEOPEN)
90        self.Bind(wx.EVT_MENU, self.OnFileSaveMenu, id=wxID_GSASIIFILESAVE)
91        self.Bind(wx.EVT_MENU, self.OnFileSaveasMenu, id=wxID_GSASIIFILESAVEAS)
92        self.Bind(wx.EVT_MENU, self.OnFileCloseMenu, id=wxID_GSASIIFILECLOSE)
93        self.Bind(wx.EVT_MENU, self.OnFileExitMenu, id=wxID_GSASIIFILEEXIT)
94       
95    def _init_coll_Data_Items(self,parent):
96        parent.Append(help='', id=wxID_GSASIIPWDRREAD, kind=wx.ITEM_NORMAL,
97            text='Read powder data')
98        parent.Append(help='',id=wxID_GSASIIIMGREAD, kind=wx.ITEM_NORMAL,
99            text='Read image data')
100        parent.Append(help='',id=wxID_GSASIIREADPEAKS, kind=wx.ITEM_NORMAL,
101            text='Read Powder Pattern Peaks')
102        parent.Append(help='', id=wxID_GSASIISNGLREAD, kind=wx.ITEM_NORMAL,
103            text='Read single crystal data')
104        parent.Append(help='', id=wxID_GSASIIPWDSUM, kind=wx.ITEM_NORMAL,
105            text='Sum powder data')
106        parent.Append(help='',id=wxID_GSASIIIMSUM, kind=wx.ITEM_NORMAL,
107            text='Sum image data')
108        parent.Append(help='', id=wxID_GSASIIADDPHASE, kind=wx.ITEM_NORMAL,
109            text='Add phase')
110        parent.Append(help='', id=wxID_GSASIIDELETEPHASE, kind=wx.ITEM_NORMAL,
111            text='Delete phase')
112        parent.Append(help='', id=wxID_GSASIIDATADELETE, kind=wx.ITEM_NORMAL,
113            text='Delete data')
114        self.Bind(wx.EVT_MENU, self.OnPwdrReadMenu, id=wxID_GSASIIPWDRREAD)
115        self.Bind(wx.EVT_MENU, self.OnPwdrSumMenu, id=wxID_GSASIIPWDSUM)
116        self.Bind(wx.EVT_MENU, self.OnReadPowderPeaks, id=wxID_GSASIIREADPEAKS)
117        self.Bind(wx.EVT_MENU, self.OnImageRead, id=wxID_GSASIIIMGREAD)
118        self.Bind(wx.EVT_MENU, self.OnImageSum, id=wxID_GSASIIIMSUM)
119        self.Bind(wx.EVT_MENU, self.OnSnglReadMenu, id=wxID_GSASIISNGLREAD)
120        self.Bind(wx.EVT_MENU, self.OnAddPhase, id=wxID_GSASIIADDPHASE)
121        self.Bind(wx.EVT_MENU, self.OnDeletePhase, id=wxID_GSASIIDELETEPHASE)
122        self.Bind(wx.EVT_MENU, self.OnDataDeleteMenu, id=wxID_GSASIIDATADELETE)
123               
124    def _init_coll_Calculate_Items(self,parent):
125        self.UnDo = parent.Append(help='', id=wxID_GSASIIUNDO, kind=wx.ITEM_NORMAL,
126            text='UnDo')
127        self.UnDo.Enable(False)
128        self.Bind(wx.EVT_MENU, self.OnUnDo, id=wxID_GSASIIUNDO)
129       
130    def _init_coll_Import_Items(self,parent):
131        self.ImportPhase = parent.Append(help='Import phase data from GSAS EXP file',
132            id=wxID_GSASIIIMPORTPHASE, kind=wx.ITEM_NORMAL,text='Import GSAS EXP Phase')
133        self.ImportPDB = parent.Append(help='Import phase data from PDB file',
134            id=wxID_GSASIIIMPORTPDB, kind=wx.ITEM_NORMAL,text='Import PDB Phase')
135        self.ImportPattern = parent.Append(help='',id=wxID_GSASIIIMPORTPATTERN, kind=wx.ITEM_NORMAL,
136            text='Import Powder Pattern')
137        self.ImportHKL = parent.Append(help='',id=wxID_GSASIIIMPORTHKL, kind=wx.ITEM_NORMAL,
138            text='Import HKLs')
139        self.ImportCIF = parent.Append(help='',id=wxID_GSASIIIMPORTCIF, kind=wx.ITEM_NORMAL,
140            text='Import CIF')
141        self.Bind(wx.EVT_MENU, self.OnImportPhase, id=wxID_GSASIIIMPORTPHASE)
142        self.Bind(wx.EVT_MENU, self.OnImportPDB, id=wxID_GSASIIIMPORTPDB)
143        self.Bind(wx.EVT_MENU, self.OnImportPattern, id=wxID_GSASIIIMPORTPATTERN)
144        self.Bind(wx.EVT_MENU, self.OnImportHKL, id=wxID_GSASIIIMPORTHKL)
145        self.Bind(wx.EVT_MENU, self.OnImportCIF, id=wxID_GSASIIIMPORTCIF)
146
147    def _init_coll_Export_Items(self,parent):
148        self.ExportPattern = parent.Append(help='',id=wxID_GSASIIEXPORTPATTERN, kind=wx.ITEM_NORMAL,
149            text='Export Powder Pattern')
150        self.ExportPeakList = parent.Append(help='',id=wxID_GSASIIEXPORTPEAKLIST, kind=wx.ITEM_NORMAL,
151            text='Export All Peak Lists')
152        self.ExportHKL = parent.Append(help='',id=wxID_GSASIIEXPORTHKL, kind=wx.ITEM_NORMAL,
153            text='Export HKLs')
154        self.ExportPhase = parent.Append(help='',id=wxID_GSASIIEXPORTPHASE, kind=wx.ITEM_NORMAL,
155            text='Export Phase')
156        self.ExportCIF = parent.Append(help='',id=wxID_GSASIIEXPORTCIF, kind=wx.ITEM_NORMAL,
157            text='Export CIF')
158        self.ExportPattern.Enable(False)
159        self.ExportPeakList.Enable(True)
160        self.ExportHKL.Enable(False)
161        self.ExportPhase.Enable(False)
162        self.ExportCIF.Enable(False)
163        self.Bind(wx.EVT_MENU, self.OnExportPattern, id=wxID_GSASIIEXPORTPATTERN)
164        self.Bind(wx.EVT_MENU, self.OnExportPeakList, id=wxID_GSASIIEXPORTPEAKLIST)
165        self.Bind(wx.EVT_MENU, self.OnExportHKL, id=wxID_GSASIIEXPORTHKL)
166        self.Bind(wx.EVT_MENU, self.OnExportPhase, id=wxID_GSASIIEXPORTPHASE)
167        self.Bind(wx.EVT_MENU, self.OnExportCIF, id=wxID_GSASIIEXPORTCIF)
168               
169    def _init_coll_Help_Items(self, parent):
170        parent.Append(help='', id=wxID_GSASIIHELPHELP, kind=wx.ITEM_NORMAL,
171            text='Help')
172        parent.Append(help='', id=wxID_GSASIIHELPABOUT, kind=wx.ITEM_NORMAL,
173            text='About')
174        self.Bind(wx.EVT_MENU, self.OnHelpHelpMenu, id=wxID_GSASIIHELPHELP)
175        self.Bind(wx.EVT_MENU, self.OnHelpAboutMenu, id=wxID_GSASIIHELPABOUT)
176
177    def _init_utils(self):
178        self.GSASIIMenu = wx.MenuBar()
179        self.File = wx.Menu(title='')
180        self.Data = wx.Menu(title='')       
181        self.Calculate = wx.Menu(title='')       
182        self.Import = wx.Menu(title='')       
183        self.Export = wx.Menu(title='')       
184        self.Help = wx.Menu(title='')
185
186        self._init_coll_GSASIIMenu_Menus(self.GSASIIMenu)
187        self._init_coll_File_Items(self.File)
188        self._init_coll_Data_Items(self.Data)
189        self._init_coll_Calculate_Items(self.Calculate)
190        self._init_coll_Import_Items(self.Import)
191        self._init_coll_Export_Items(self.Export)
192        self._init_coll_Help_Items(self.Help)
193       
194    def _init_ctrls(self, parent):
195        wx.Frame.__init__(self, id=wxID_GSASII, name='GSASII', parent=parent,
196            size=wx.Size(300, 250),style=wx.DEFAULT_FRAME_STYLE, title='GSAS-II')
197        screenSize = wx.DisplaySize()
198        Size = self.GetSize()
199        xPos = screenSize[0]-Size[0]
200        self.SetPosition(wx.Point(xPos,0))
201        self._init_utils()
202        self.SetMenuBar(self.GSASIIMenu)
203        self.Bind(wx.EVT_SIZE, self.OnSize)
204        self.mainPanel = wx.Panel(self,-1)
205       
206        self.PatternTree = wx.TreeCtrl(id=wxID_GSASIIPATTERNTREE,
207            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
208        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,
209            self.OnPatternTreeSelChanged, id=wxID_GSASIIPATTERNTREE)
210        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
211            self.OnPatternTreeItemCollapsed, id=wxID_GSASIIPATTERNTREE)
212        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
213            self.OnPatternTreeItemExpanded, id=wxID_GSASIIPATTERNTREE)
214        self.root = self.PatternTree.AddRoot("Loaded Data")
215       
216        self.dataDisplay = None
217       
218    def __init__(self, parent):
219        self._init_ctrls(parent)
220        self.Bind(wx.EVT_CLOSE, self.ExitMain)
221        self.dirname = ''
222        self.GSASprojectfile = ''
223        self.Offset = 0.0
224        self.Weight = False
225        self.IparmName = ''
226        self.NewPlot = True
227        self.IfPlot = False
228        self.PatternId = 0
229        self.PickId = 0
230        self.PeakTable = []
231        self.LimitsTable = []
232        self.HKL = []
233        self.Lines = []
234        self.itemPicked = None
235        self.dataFrame = None
236        self.Contour = False
237        self.plotView = 0
238        self.Image = 0
239        self.Img = 0
240        self.imageDefault = {}
241        self.PDevent = []
242        self.IMevent = []
243        self.SCevent = []
244        self.Sngl = 0
245        self.ifGetRing = False
246
247    def OnSize(self,event):
248        w,h = self.GetClientSizeTuple()
249        self.mainPanel.SetSize(wx.Size(w,h))
250        self.PatternTree.SetSize(wx.Size(w,h))
251                       
252    def OnPatternTreeSelChanged(self, event):
253        if self.PickId:
254            if self.PatternTree.GetItemText(self.PickId) in ['Peak List','Limits','Peak Index List','Unit Cell List','Background']:
255                self.plotView = self.getPlotLimits()
256        item = event.GetItem()
257        G2gd.MovePatternTreeToGrid(self,item)
258       
259    def OnPatternTreeItemCollapsed(self, event):
260        event.Skip()
261
262    def OnPatternTreeItemExpanded(self, event):
263        self.PatternTree.ScrollTo(self.PatternTree.GetLastChild(event.GetItem()))
264       
265    def OnPatternTreeDeleteItem(self, event):
266        event.Skip()
267
268    def OnPatternTreeItemActivated(self, event):
269        event.Skip()
270       
271    def OnPwdrReadMenu(self, event):
272        self.CheckNotebook()
273        dlg = wx.FileDialog(self, 'Choose files', '.', '', 
274            'GSAS fxye files (*.fxye)|*.fxye|GSAS fxy files (*.fxy)|*.fxy|All files (*.*)|*.*', 
275            wx.OPEN | wx.MULTIPLE)
276        if self.dirname: dlg.SetDirectory(self.dirname)
277        try:
278            if dlg.ShowModal() == wx.ID_OK:
279                filenames = dlg.GetPaths()
280                filenames.sort()
281                self.dirname = dlg.GetDirectory()
282                for filename in filenames:
283                    Data,Iparm,Comments = G2IO.SelectPowderData(self, filename)              #Data: list of tuples (filename,Pos,Bank)
284                    if not Data:                                                    #if Data rejected by user - go to next one
285                        continue
286                    DataType = Iparm['INS   HTYPE ']                                #expect only 4 char string
287                    DataType = DataType.strip()[0:3]                                #just 1st 3 chars
288                    wx.BeginBusyCursor()
289                    try:
290                        for Item in Data:
291                            vals = Item[2].split()          #split up the BANK record
292                            Id = self.PatternTree.AppendItem(parent=self.root,text='PWDR '+ospath.basename(Item[0])+': '+vals[0]+vals[1])
293                            data = G2IO.GetPowderData(filename,Item[1],Item[2],DataType)
294                            self.PatternTree.SetItemPyData(Id,[Item,data])
295                            '''
296                            Each tree item data is a list with:
297                            Item: the (filename,Pos,Bank) tuple
298                            data: (x,y,w,yc,yb,yd) list from GetPowderData
299                            '''
300                           
301                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                           
302                            Tmin = min(data[0])
303                            Tmax = max(data[0])
304                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[(Tmin,Tmax),[Tmin,Tmax]])
305                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0]])
306       
307                            data = [DataType,]
308                            if 'C' in DataType:
309                                s = Iparm['INS  1 ICONS']
310                                v = (G2IO.sfloat(s[:10]),G2IO.sfloat(s[10:20]),G2IO.sfloat(s[20:30]),G2IO.sfloat(s[55:65]),G2IO.sfloat(s[40:50])) #get lam1, lam2, zero, pola & ratio
311                                if not v[1]:
312                                    names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L'] 
313                                    v = (v[0],v[2],v[4])
314                                    codes = [0,0,0,0]
315                                else:
316                                    names = ['Type','Lam1','Lam2','Zero','I(L2)/I(L1)','Polariz.','U','V','W','X','Y','SH/L']
317                                    codes = [0,0,0,0,0,0]
318                                data.extend(v)
319                                v1 = Iparm['INS  1PRCF1 '].split()                                                 
320                                v = Iparm['INS  1PRCF11'].split()
321                                data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
322                                v = Iparm['INS  1PRCF12'].split()
323                                if v1[0] == 3:
324                                    data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3])])  #get LX, LY & S+H/L
325                                else:
326                                    data.extend([0.0,0.0,0.002])                                      #OK defaults if fxn #3 not 1st in iprm file
327                                codes.extend([0,0,0,0,0,0])
328                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),[tuple(data),data,codes,names])
329                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),[])
330                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[])
331                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
332                            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
333                    finally:
334                        wx.EndBusyCursor()
335                self.PatternTree.Expand(Id)
336                self.PatternTree.SelectItem(Id)
337                self.NewPlot = True
338                self.PlotPatterns()
339   
340        finally:
341            dlg.Destroy()
342       
343    def OnReadPowderPeaks(self,event):
344        Cuka = 1.54052
345        self.CheckNotebook()
346        dlg = wx.FileDialog(self, 'Choose file with peak list', '.', '', 
347            'peak files (*.txt)|*.txt|All files (*.*)|*.*',wx.OPEN)
348        if self.dirname:
349            dlg.SetDirectory(self.dirname)
350        try:
351            if dlg.ShowModal() == wx.ID_OK:
352                self.HKL = []
353                self.powderfile = dlg.GetPath()
354                self.dirname = dlg.GetDirectory()
355                comments,peaks = G2IO.GetPowderPeaks(self.powderfile)
356                Id = self.PatternTree.AppendItem(parent=self.root,text='PKS '+ospath.basename(self.powderfile))
357                data = ['PKS',Cuka,0.0]
358                names = ['Type','Lam','Zero'] 
359                codes = [0,0]
360                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),[tuple(data),data,codes,names])
361                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),comments)
362                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),peaks)
363                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
364                self.NewPlot = True
365                self.PatternTree.Expand(Id)
366        finally:
367            dlg.Destroy()
368           
369    def OnImageRead(self,event):
370        import copy
371        self.CheckNotebook()
372        dlg = wx.FileDialog(self, 'Choose image file', '.', '',\
373        'MAR345 (*.mar3450;*.mar2300)|*.mar3450;*.mar2300|ADSC Image (*.img)\
374        |*.img|Perkin-Elmer TIF (*.tif)|*.tif|GE Image sum (*.sum)\
375        |*.sum|GE Image avg (*.avg)|*.avg|All files (*.*)|*.*',wx.OPEN)
376        if self.dirname:
377            dlg.SetDirectory(self.dirname)
378        try:
379            if dlg.ShowModal() == wx.ID_OK:
380                self.imagefile = dlg.GetPath()
381                self.dirname = dlg.GetDirectory()
382                ext = ospath.splitext(self.imagefile)[1]
383                Comments = []
384                if ext == '.tif':
385                    Comments,Data,Size,Image = G2IO.GetTifData(self.imagefile)
386                elif ext == '.img':
387                    Comments,Data,Size,Image = G2IO.GetImgData(self.imagefile)
388                    Image[0][0] = 0
389                elif ext == '.mar3450' or ext == '.mar2300':
390                    Comments,Data,Size,Image = G2IO.GetMAR345Data(self.imagefile)
391                elif ext in ['.sum','.avg']:
392                    Comments,Data,Size,Image = G2IO.GetGEsumData(self.imagefile)
393                if Comments:
394                    Id = self.PatternTree.AppendItem(parent=self.root,text='IMG '+ospath.basename(self.imagefile))
395                    self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
396                    Imax = np.amax(Image)
397                    Imin = np.amin(Image)
398                    if self.imageDefault:
399                        Data = copy.copy(self.imageDefault)
400                        Data['refine'] = [False,False,False,False,False]
401                        Data['showLines'] = True
402                    else:
403                        Data['color'] = 'binary'
404                        Data['tilt'] = 0.0
405                        Data['rotation'] = 0.0
406                        Data['showLines'] = False
407                        Data['ring'] = []
408                        Data['rings'] = []
409                        Data['cutoff'] = 10
410                        Data['pixLimit'] = 20
411                        Data['ellipses'] = []
412                        Data['masks'] = []
413                        Data['calibrant'] = ''
414                        Data['IOradii'] = [10.,100.]
415                        Data['LRazimuth'] = [-45,45]
416                        Data['outChannels'] = 2500
417                        Data['fullIntegrate'] = False
418                        Data['setRings'] = False
419                    Data['setDefault'] = False
420                    Data['range'] = [(Imin,Imax),[Imin,Imax]]
421                    self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)
422                    self.PatternTree.SetItemPyData(Id,[Size,Image])
423                    self.PickId = Id
424                    self.Image = Id
425                    self.PlotImage()
426                    self.PatternTree.SelectItem(Id)
427                    self.PatternTree.Expand(Id)
428        finally:
429            dlg.Destroy()
430       
431    def OnSnglReadMenu(self,event):
432        self.CheckNotebook()
433        dlg = wx.FileDialog(self, 'Choose file', '.', '', 
434            'hkl files (*.hkl)|*.hkl|All files (*.*)|*.*', 
435            wx.OPEN)
436        if self.dirname: dlg.SetDirectory(self.dirname)
437        try:
438            if dlg.ShowModal() == wx.ID_OK:
439                filename = dlg.GetPath()
440                self.dirname = dlg.GetDirectory()
441                wx.BeginBusyCursor()
442                try:
443                    Data = {}
444                    names = ['Type','Lam']
445                    HKLref,HKLmin,HKLmax,FoMax,ifFc = G2IO.GetHKLData(filename)
446                    Id = self.PatternTree.AppendItem(parent=self.root,text='SXTL '+ospath.basename(filename))
447                    self.PatternTree.SetItemPyData(Id,HKLref)
448                    Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
449                    data = ['SXC',1.5428,]
450                    self.PatternTree.SetItemPyData(Sub,[tuple(data),data,names])
451                    Data['Type'] = 'Fosq'
452                    Data['ifFc'] = ifFc
453                    Data['HKLmax'] = HKLmax
454                    Data['HKLmin'] = HKLmin
455                    Data['FoMax'] = FoMax
456                    Data['Zone'] = '001'
457                    Data['Layer'] = 0
458                    Data['Scale'] = 1.0
459                    Data['log-lin'] = 'lin'                   
460                    self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='HKL Plot Controls'),Data)
461                    self.PatternTree.SelectItem(Id)
462                    self.PatternTree.Expand(Id)
463                    self.Sngl = Id
464                finally:
465                    wx.EndBusyCursor()   
466        finally:
467            dlg.Destroy()
468           
469    def CheckNotebook(self):
470        if not G2gd.GetPatternTreeItemId(self,self.root,'Notebook'):
471            sub = self.PatternTree.AppendItem(parent=self.root,text='Notebook')
472            self.PatternTree.SetItemPyData(sub,[''])
473            sub = self.PatternTree.AppendItem(parent=self.root,text='Controls')
474            self.PatternTree.SetItemPyData(sub,[0])
475       
476       
477    class SumDialog(wx.Dialog):
478        def __init__(self,parent,title,text,type,data):
479            wx.Dialog.__init__(self,parent,-1,title, 
480                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
481            self.data = data
482            panel = wx.Panel(self)
483            mainSizer = wx.BoxSizer(wx.VERTICAL)
484            topLabl = wx.StaticText(panel,-1,text)
485            mainSizer.Add((10,10),1)
486            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
487            mainSizer.Add((10,10),1)
488            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
489            for id,item in enumerate(self.data[:-1]):
490                name = wx.TextCtrl(panel,-1,item[1],size=wx.Size(200,20))
491                name.SetEditable(False)
492                scale = wx.TextCtrl(panel,id,str(item[0]),style=wx.TE_PROCESS_ENTER)
493                scale.Bind(wx.EVT_TEXT,self.OnScaleChange)                   
494                dataGridSizer.Add(scale,0,wx.LEFT,10)
495                dataGridSizer.Add(name,0,wx.RIGHT,10)
496            dataGridSizer.Add(wx.StaticText(panel,-1,'Sum result name: '+type),0, \
497                wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
498            self.name = wx.TextCtrl(panel,-1,self.data[-1],size=wx.Size(200,20),style=wx.TE_PROCESS_ENTER)
499            self.name.Bind(wx.EVT_TEXT,self.OnNameChange)
500            dataGridSizer.Add(self.name,0,wx.RIGHT|wx.TOP,10)
501            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
502            OkBtn = wx.Button(panel,-1,"Ok")
503            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
504            cancelBtn = wx.Button(panel,-1,"Cancel")
505            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
506            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
507            btnSizer.Add((20,20),1)
508            btnSizer.Add(OkBtn)
509            btnSizer.Add((20,20),1)
510            btnSizer.Add(cancelBtn)
511            btnSizer.Add((20,20),1)
512           
513            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
514            panel.SetSizer(mainSizer)
515            panel.Fit()
516            self.Fit()
517           
518        def OnNameChange(self,event):
519            self.data[-1] = self.name.GetValue() 
520           
521        def OnScaleChange(self,event):
522            id = event.GetId()
523            value = self.FindWindowById(id).GetValue()
524            try:
525                self.data[id][0] = float(value)
526            except ValueError:
527                if value and '-' not in value[0]:
528                    print 'bad input - numbers only'
529                    self.FindWindowById(id).SetValue('0.0')
530           
531        def OnOk(self,event):
532            parent = self.GetParent()
533            parent.Raise()
534            self.SetReturnCode(wx.ID_OK)
535            self.MakeModal(False)             
536            self.Destroy()
537           
538        def OnCancel(self,event):
539            parent = self.GetParent()
540            parent.Raise()
541            self.SetReturnCode(wx.ID_CANCEL)
542            self.MakeModal(False)             
543            self.Destroy()
544           
545        def GetData(self):
546                return self.data
547           
548    def OnPwdrSumMenu(self,event):
549        TextList = []
550        DataList = []
551        SumList = []
552        Names = []
553        Inst = []
554        SumItemList = []
555        Comments = ['Sum equals: \n']
556        if self.PatternTree.GetCount():
557            item, cookie = self.PatternTree.GetFirstChild(self.root)
558            while item:
559                name = self.PatternTree.GetItemText(item)
560                Names.append(name)
561                if 'PWDR' in name:
562                    TextList.append([0.0,name])
563                    DataList.append(self.PatternTree.GetItemPyData(item)[1])    # (x,y,w,yc,yb,yd)
564                    if not Inst:
565                        Inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item, 'Instrument Parameters'))
566                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
567            if len(TextList) < 2:
568                self.ErrorDialog('Not enough data to sum','There must be more than one "PWDR" pattern')
569                return
570            TextList.append('default sum name')               
571            dlg = self.SumDialog(self,'Sum data','Enter scale for each pattern in summation','PWDR',TextList)
572            try:
573                if dlg.ShowModal() == wx.ID_OK:
574                    lenX = 0
575                    Xminmax = [0,0]
576                    Xsum = []
577                    Ysum = []
578                    Wsum = []
579                    result = dlg.GetData()
580                    for i,item in enumerate(result[:-1]):
581                        scale,name = item
582                        data = DataList[i]
583                        if scale:
584                            Comments.append("%10.3f %s" % (scale,' * '+name))
585                            x,y,w,yc,yb,yd = data
586                            if lenX:
587                                if lenX != len(x):
588                                    self.ErrorDialog('Data length error','Data to be summed must have same number of points'+ \
589                                        '\nExpected:'+str(lenX)+ \
590                                        '\nFound:   '+str(len(x))+'\nfor '+name)
591                                    return
592                            else:
593                                lenX = len(x)
594                            if Xminmax[1]:
595                                if Xminmax != [x[0],x[-1]]:
596                                    self.ErrorDialog('Data range error','Data to be summed must span same range'+ \
597                                        '\nExpected:'+str(Xminmax[0])+' '+str(Xminmax[1])+ \
598                                        '\nFound:   '+str(x[0])+' '+str(x[-1])+'\nfor '+name)
599                                    return
600                                else:
601                                    for j,yi in enumerate(y):
602                                         Ysum[j] += scale*yi
603                            else:
604                                Xminmax = [x[0],x[-1]]
605                                YCsum = [0.0 for i in range(lenX)]
606                                YBsum = [0.0 for i in range(lenX)]
607                                YDsum = [0.0 for i in range(lenX)]
608                                for j,yi in enumerate(y):
609                                    Xsum.append(x[j])
610                                    Ysum.append(scale*yi)
611                                    Wsum.append(w[j])
612                    outname = 'PWDR '+result[-1]
613                    Id = 0
614                    if outname in Names:
615                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
616                        try:
617                            if dlg2.ShowModal() == wx.ID_OK:
618                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
619                        finally:
620                            dlg2.Destroy()
621                    else:
622                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
623                    if Id:
624                        self.PatternTree.SetItemPyData(Id,[[''],[Xsum,Ysum,Wsum,YCsum,YBsum,YDsum]])
625                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
626                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
627                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0]])
628                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
629                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),[])
630                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[])
631                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
632                        self.PatternTree.SelectItem(Id)
633                   
634                    self.PlotPatterns()
635                    self.NewPlot = True
636            finally:
637                dlg.Destroy()
638
639    def OnImageSum(self,event):
640        TextList = []
641        DataList = []
642        SumList = []
643        Names = []
644        Inst = []
645        SumItemList = []
646        Comments = ['Sum equals: \n']
647        if self.PatternTree.GetCount():
648            item, cookie = self.PatternTree.GetFirstChild(self.root)
649            while item:
650                name = self.PatternTree.GetItemText(item)
651                Names.append(name)
652                if 'IMG' in name:
653                    TextList.append([0.0,name])
654                    DataList.append(self.PatternTree.GetItemPyData(item))        #Size,Image
655                    Data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item,'Image Controls'))
656                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
657            if len(TextList) < 2:
658                self.ErrorDialog('Not enough data to sum','There must be more than one "IMG" pattern')
659                return
660            TextList.append('default sum name')               
661            dlg = self.SumDialog(self,'Sum data','Enter scale for each image in summation','IMG',TextList)
662            try:
663                if dlg.ShowModal() == wx.ID_OK:
664                    imSize = 0
665                    newImage = []
666                    result = dlg.GetData()
667                    for i,item in enumerate(result[:-1]):
668                        scale,name = item
669                        data = DataList[i]
670                        if scale:
671                            Comments.append("%10.3f %s" % (scale,' * '+name))
672                            size,image = data
673                            if imSize:
674                                if imSize != size:
675                                    self.ErrorDialog('Image size error','Images to be summed must be same size'+ \
676                                        '\nExpected:'+str(imSize)+ \
677                                        '\nFound:   '+str(size)+'\nfor '+name)
678                                    return
679                                newImage += scale*image
680                            else:
681                                imSize = size
682                                newImage = scale*image
683                    outname = 'IMG '+result[-1]
684                    Id = 0
685                    if outname in Names:
686                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
687                        try:
688                            if dlg2.ShowModal() == wx.ID_OK:
689                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
690                        finally:
691                            dlg2.Destroy()
692                    else:
693                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
694                    if Id:
695                        self.PatternTree.SetItemPyData(Id,[imSize,newImage])
696                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
697                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)                                           
698                        self.PatternTree.SelectItem(Id)
699                    self.PickId = Id
700                    self.Image = Id
701                    self.PlotImage()
702                    self.NewPlot = True
703            finally:
704                dlg.Destroy()
705                     
706    def OnAddPhase(self,event):
707        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
708            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
709        else:
710            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
711        PhaseName = ''
712        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
713            style=wx.OK)
714        if dlg.ShowModal() == wx.ID_OK:
715            PhaseName = dlg.GetValue()
716        dlg.Destroy()
717        sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
718        SGData = {'SpGrp':'P 1'}
719        self.PatternTree.SetItemPyData(sub, \
720            {'General':[PhaseName,'nuclear',SGData,[False,10.,10.,10.,90.,90.,90,1000.],
721            [False,1.0],[],{},[],[],[]],'Atoms':[]})
722       
723    def OnDeletePhase(self,event):
724        if self.dataFrame:
725            self.dataFrame.Clear() 
726        TextList = []
727        DelList = []
728        DelItemList = []
729        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
730            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
731        else:
732            return
733        if sub:
734            item, cookie = self.PatternTree.GetFirstChild(sub)
735            while item:
736                TextList.append(self.PatternTree.GetItemText(item))
737                item, cookie = self.PatternTree.GetNextChild(sub, cookie)               
738            dlg = wx.MultiChoiceDialog(self, 'Which phase to delete?', 'Delete phase', TextList, wx.CHOICEDLG_STYLE)
739            try:
740                if dlg.ShowModal() == wx.ID_OK:
741                    result = dlg.GetSelections()
742                    for i in result: DelList.append([i,TextList[i]])
743                    item, cookie = self.PatternTree.GetFirstChild(sub)
744                    i = 0
745                    while item:
746                        if [i,self.PatternTree.GetItemText(item)] in DelList: DelItemList.append(item)
747                        item, cookie = self.PatternTree.GetNextChild(sub, cookie)
748                        i += 1
749                    for item in DelItemList:
750                        self.PatternTree.Delete(item)
751            finally:
752                dlg.Destroy()       
753       
754    def OnDataDeleteMenu(self, event):
755        TextList = []
756        DelList = []
757        DelItemList = []
758        if self.PatternTree.GetCount():
759            item, cookie = self.PatternTree.GetFirstChild(self.root)
760            while item:
761                name = self.PatternTree.GetItemText(item)
762                if 'PWDR' in name or 'SXTL' in name or 'IMG' in name:
763                    TextList.append(name)
764                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
765            dlg = wx.MultiChoiceDialog(self, 'Which data to delete?', 'Delete data', TextList, wx.CHOICEDLG_STYLE)
766            try:
767                if dlg.ShowModal() == wx.ID_OK:
768                    result = dlg.GetSelections()
769                    for i in result: DelList.append(TextList[i])
770                    item, cookie = self.PatternTree.GetFirstChild(self.root)
771                    while item:
772                        if self.PatternTree.GetItemText(item) in DelList: DelItemList.append(item)
773                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
774                    for item in DelItemList:
775                        self.PatternTree.Delete(item)
776                    self.PlotPatterns()
777                    self.NewPlot = True
778            finally:
779                dlg.Destroy()
780
781    def OnFileOpenMenu(self, event):
782        result = ''
783        if self.PatternTree.GetChildrenCount(self.root,False):
784            if self.dataFrame:
785                self.dataFrame.Clear() 
786            dlg = wx.MessageDialog(self, 'Overwrite?','Project exists!',  wx.OK | wx.CANCEL)
787            try:
788                result = dlg.ShowModal()
789                if result == wx.ID_OK:
790                    self.PatternTree.DeleteChildren(self.root)
791            finally:
792                dlg.Destroy()
793        if result != wx.ID_CANCEL:   
794            if self.dataDisplay: self.dataDisplay.Destroy()
795            dlg = wx.FileDialog(self, 'Choose GSAS-II project file', '.', '', 
796                'GSAS-II project file (*.gpx)|*.gpx',wx.OPEN)
797            if self.dirname: dlg.SetDirectory(self.dirname)
798            try:
799                if dlg.ShowModal() == wx.ID_OK:
800                    self.GSASprojectfile = dlg.GetPath()
801                    self.dirname = dlg.GetDirectory()
802                    G2IO.ProjFileOpen(self)
803                    self.HKL = []
804                    self.NewPlot = True
805#                    self.PlotPatterns()
806            finally:
807                dlg.Destroy()
808
809    def OnFileCloseMenu(self, event):
810        if self.dataFrame:
811            self.dataFrame.Clear()
812            self.dataFrame.SetLabel('GSAS-II data display') 
813        dlg = wx.MessageDialog(self, 'Save current project?', ' ', wx.YES | wx.NO | wx.CANCEL)
814        try:
815            result = dlg.ShowModal()
816            if result == wx.ID_OK:
817                self.OnFileSaveMenu(event)
818            if result != wx.ID_CANCEL:
819                self.GSASprojectfile = ''
820                self.PatternTree.DeleteChildren(self.root)
821                if self.HKL: self.HKL = []
822                self.NewPlot = True
823                self.PlotPatterns()
824        finally:
825            dlg.Destroy()
826
827    def OnFileSaveMenu(self, event):
828        if self.GSASprojectfile: 
829            G2IO.ProjFileSave(self)
830        else:
831            self.OnFileSaveasMenu(event)
832
833    def OnFileSaveasMenu(self, event):
834        dlg = wx.FileDialog(self, 'Choose GSAS-II project file name', '.', '', 
835            'GSAS-II project file (*.gpx)|*.gpx',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
836        if self.dirname:
837            dlg.SetDirectory(self.dirname)
838        try:
839            if dlg.ShowModal() == wx.ID_OK:
840                self.GSASprojectfile = dlg.GetPath()
841                G2IO.ProjFileSave(self)
842                self.dirname = dlg.GetDirectory()
843        finally:
844            dlg.Destroy()
845
846    def ExitMain(self, event):
847        sys.exit()
848       
849    def OnFileExitMenu(self, event):
850        if self.dataFrame:
851            self.dataFrame.Clear() 
852            self.dataFrame.Destroy()
853        pylab.close('all')
854        self.Close()
855       
856    def OnImportPattern(self,event):
857            dlg = wx.FileDialog(self, 'Choose nonGSAS powder file', '.', '', 
858                '(*.*)|*.*',wx.OPEN)
859            if self.dirname:
860                dlg.SetDirectory(self.dirname)
861            try:
862                if dlg.ShowModal() == wx.ID_OK:
863                    self.powderfile = dlg.GetPath()
864                    self.dirname = dlg.GetDirectory()
865            finally:
866                dlg.Destroy()
867               
868    def OnImportHKL(self,event):
869            dlg = wx.FileDialog(self, 'Choose structure factor file', '.', '', 
870                '(*.*)|*.*',wx.OPEN)
871            if self.dirname:
872                dlg.SetDirectory(self.dirname)
873            try:
874                if dlg.ShowModal() == wx.ID_OK:
875                    self.HKLfile = dlg.GetPath()
876                    self.dirname = dlg.GetDirectory()
877            finally:
878                dlg.Destroy()
879       
880    def OnImportPhase(self,event):
881            dlg = wx.FileDialog(self, 'Choose GSAS EXP file', '.', '', 
882                'EXP file (*.EXP)|*.EXP',wx.OPEN)
883            if self.dirname:
884                dlg.SetDirectory(self.dirname)
885            try:
886                Phase = {}
887                if dlg.ShowModal() == wx.ID_OK:
888                    EXPfile = dlg.GetPath()
889                    self.dirname = dlg.GetDirectory()
890                    Phase = G2IO.ReadEXPPhase(EXPfile)
891            finally:
892                dlg.Destroy()
893            if Phase:
894                PhaseName = Phase['General'][0]
895                if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
896                    sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
897                else:
898                    sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
899                sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
900                self.PatternTree.SetItemPyData(sub,Phase)
901               
902    def OnImportPDB(self,event):
903            dlg = wx.FileDialog(self, 'Choose PDB file', '.', '', 
904                'PDB file (*.pdb,*.ent)|*.pdb;*.ent|All files (*.*)|*.*',wx.OPEN)
905            if self.dirname:
906                dlg.SetDirectory(self.dirname)
907            try:
908                if dlg.ShowModal() == wx.ID_OK:
909                    PDBfile = dlg.GetPath()
910                    self.dirname = dlg.GetDirectory()
911                    Phase = G2IO.ReadPDBPhase(PDBfile)
912            finally:
913                dlg.Destroy()
914            if Phase:
915                PhaseName = Phase['General'][0]
916                if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
917                    sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
918                else:
919                    sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
920                sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
921                self.PatternTree.SetItemPyData(sub,Phase)       
922       
923    def OnImportCIF(self,event):
924            dlg = wx.FileDialog(self, 'Choose CIF file', '.', '', 
925                'CIF file (*.cif)|*.cif',wx.OPEN)
926            if self.dirname:
927                dlg.SetDirectory(self.dirname)
928            try:
929                if dlg.ShowModal() == wx.ID_OK:
930                    self.CIFfile = dlg.GetPath()
931                    self.dirname = dlg.GetDirectory()
932            finally:
933                dlg.Destroy()
934       
935    def OnExportPattern(self,event):
936        dlg = wx.FileDialog(self, 'Choose output powder file name', '.', '', 
937            'xye file (*.xye)|*.xye',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
938        if self.dirname:
939            dlg.SetDirectory(self.dirname)
940        try:
941            if dlg.ShowModal() == wx.ID_OK:
942                self.powderfile = dlg.GetPath()
943                G2IO.PowderxyeSave(self)
944                self.dirname = dlg.GetDirectory()
945        finally:
946            dlg.Destroy()
947       
948    def OnExportPeakList(self,event):
949        dlg = wx.FileDialog(self, 'Choose output peak list file name', '.', '', 
950            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
951        if self.dirname:
952            dlg.SetDirectory(self.dirname)
953        try:
954            if dlg.ShowModal() == wx.ID_OK:
955                self.peaklistfile = dlg.GetPath()
956                file = open(self.peaklistfile,'wa')               
957                item, cookie = self.PatternTree.GetFirstChild(self.root)
958                while item:
959                    name = self.PatternTree.GetItemText(item)
960                    if 'PWDR' in name:
961                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
962                        while item2:
963                            name2 = self.PatternTree.GetItemText(item2)
964                            if name2 == 'Peak List':
965                                peaks = self.PatternTree.GetItemPyData(item2)
966                                file.write("%s \n" % (name+' Peak List'))               
967                                for peak in peaks:
968                                    file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
969                                        (peak[0],peak[2],peak[4],peak[6]))
970                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
971                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
972                file.close()
973                self.dirname = dlg.GetDirectory()
974        finally:
975            dlg.Destroy()
976       
977    def OnExportHKL(self,event):
978        event.Skip()
979       
980    def OnExportPhase(self,event):
981        event.Skip()
982       
983    def OnExportCIF(self,event):
984        event.Skip()
985       
986    def OnUnDo(self,event):
987        self.DoUnDo()
988        self.UnDo.Enable(False)
989       
990    def DoUnDo(self):
991        print 'Undo last refinement'
992        file = open('GSASII.save','rb')
993        PatternId = self.PatternId
994        for item in ['Background','Instrument Parameters','Peak List']:
995            self.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, item),cPickle.load(file))
996            if self.dataDisplay.GetName() == item:
997                if item == 'Background':
998                    G2gd.UpdateBackgroundGrid(self,self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, item)))
999                elif item == 'Instrument Parameters':
1000                    G2gd.UpdateInstrumentGrid(self,self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, item)))
1001                elif item == 'Peak List':
1002                    G2gd.UpdatePeakGrid(self,self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, item)))
1003            print item,' recovered'
1004        file.close()
1005       
1006    def SaveState(self):
1007        file = open('GSASII.save','wb')
1008        PatternId = self.PatternId
1009        for item in ['Background','Instrument Parameters','Peak List']:
1010            cPickle.dump(self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId,item)),file,1)
1011        file.close()
1012        self.UnDo.Enable(True)
1013       
1014    def getPlotLimits(self):
1015        ax = self.pdplot.gca()
1016        return [ax.get_xlim(),ax.get_ylim()]
1017
1018         
1019    def ClearEventList(self,eventList):
1020        if eventList:
1021            for i in range(len(eventList)):
1022                self.pdplot.canvas.mpl_disconnect(eventList[i])
1023        return []
1024
1025    def PlotPeakWidths(self):
1026        newPlot = False 
1027        PatternId = self.PatternId
1028        limitID = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
1029        if limitID:
1030            limits = self.PatternTree.GetItemPyData(limitID)
1031        else:
1032            return
1033        instParms = self.PatternTree.GetItemPyData( \
1034            G2gd.GetPatternTreeItemId(self,PatternId, 'Instrument Parameters'))
1035        if instParms[0][0] == 'PXC':
1036            lam = instParms[1][1]
1037            if len(instParms[1]) == 12:
1038                GU,GV,GW,LX,LY = instParms[0][6:11]
1039            else:
1040                GU,GV,GW,LX,LY = instParms[0][4:9]
1041        peakID = G2gd.GetPatternTreeItemId(self,PatternId, 'Peak List')
1042        if peakID:
1043            peaks = self.PatternTree.GetItemPyData(peakID)
1044        else:
1045            peaks = []
1046        try:
1047            self.pdplot.clear()
1048            self.IMevent = self.ClearEventList(self.IMevent)
1049            self.PDevent = self.ClearEventList(self.PDevent)
1050            self.SCevent = self.ClearEventList(self.SCevent)
1051            self.pdplot.canvas.set_window_title('Peak Widths')
1052        except:
1053            self.pdplot.clear()
1054            self.pdplot = pylab.figure(facecolor='white')
1055            self.pdplot.canvas.set_window_title('Peak Widths')
1056            self.NewPlot = True
1057            newPlot = True
1058        self.pdplot.canvas.SetToolTipString('')
1059        colors=['b','g','r','c','m','k']
1060        Xmin,Xmax = limits[1]
1061        Xmin = min(0.5,max(Xmin,1))
1062        Xmin /= 2
1063        Xmax /= 2
1064        nPts = 100
1065        delt = (Xmax-Xmin)/nPts
1066        thetas = []
1067        for i in range(nPts):
1068            thetas.append(Xmin+i*delt)
1069        X = []
1070        Y = []
1071        Z = []
1072        W = []
1073        sig = lambda Th,U,V,W: 1.17741*math.sqrt(U*tand(Th)**2+V*tand(Th)+W)*math.pi/18000.
1074        gam = lambda Th,X,Y: (X/cosd(Th)+Y*tand(Th))*math.pi/18000.
1075        gamFW = lambda s,g: math.exp(math.log(g**5+2.69269*g**4*s+2.42843*g**3*s**2+4.47163*g**2*s**3+0.07842*g*s**4+s**5)/5.)
1076        for theta in thetas:
1077            X.append(4.0*math.pi*sind(theta)/lam)              #q
1078            s = sig(theta,GU,GV,GW)
1079            g = gam(theta,LX,LY)
1080            G = gamFW(g,s)
1081            Y.append(s/tand(theta))
1082            Z.append(g/tand(theta))
1083            W.append(G/tand(theta))
1084        ax = self.pdplot.add_subplot(111)
1085        ax.clear()
1086        ax.set_title('Instrument and sample peak widths')
1087        ax.set_ylabel(r'$\Delta q/q, \Delta d/d$',fontsize=14)
1088        ax.set_xlabel(r'$q, \AA^{-1}$',fontsize=14)
1089        ax.plot(X,Y,color='r',label='Gaussian')
1090        ax.plot(X,Z,color='g',label='Lorentzian')
1091        ax.plot(X,W,color='b',label='G+L')
1092        X = []
1093        Y = []
1094        Z = []
1095        W = []
1096        for peak in peaks:
1097            X.append(4.0*math.pi*sind(peak[0]/2.0)/lam)
1098            s = 1.17741*math.sqrt(peak[4])*math.pi/18000.
1099            g = peak[6]*math.pi/18000.
1100            G = gamFW(g,s)
1101            Y.append(s/tand(peak[0]/2.))
1102            Z.append(g/tand(peak[0]/2.))
1103            W.append(G/tand(peak[0]/2.))
1104        ax.plot(X,Y,'+',color='r',label='G peak')
1105        ax.plot(X,Z,'+',color='g',label='L peak')
1106        ax.plot(X,W,'+',color='b',label='G+L peak')
1107        ax.legend(loc='best')
1108        self.NewPlot = True
1109           
1110        if newPlot:
1111            pylab.show()
1112        else:                       #1st plot
1113            pylab.draw()
1114           
1115    def PlotImage(self):
1116        from matplotlib.patches import Ellipse
1117
1118        def OnImMotion(event):
1119            self.pdplot.canvas.SetToolTipString('')
1120            size = len(self.ImageZ)
1121            if (xlim[0] < event.xdata < xlim[1]) & (ylim[0] > event.ydata > ylim[1]):
1122                item = self.itemPicked
1123                if item and self.PatternTree.GetItemText(self.PickId) == 'Image Controls':
1124                    if 'Text' in str(item):
1125                        self.pdplot.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
1126                    else:
1127                        xcent,ycent = Data['center']
1128                        xpos = event.xdata-xcent
1129                        ypos = event.ydata-ycent
1130                        if 'line2' in  str(item) or 'line3' in str(item) and not Data['fullIntegrate']:
1131                            ang = int(atan2d(-ypos,xpos))
1132                            self.pdplot.canvas.SetToolTipString('%6d deg'%(ang))
1133                        elif 'line0' in  str(item) or 'line1' in str(item):
1134                            radius = math.sqrt(xpos**2+ypos**2)
1135                            self.pdplot.canvas.SetToolTipString('%8.3fmm'%(radius))                           
1136                else:
1137                    xpix = event.xdata*scalex
1138                    ypix = event.ydata*scaley
1139                    if (0 <= xpix <= size) and (0 <= ypix <= size):
1140                        self.pdplot.canvas.SetToolTipString('%6d'%(self.ImageZ[ypix][xpix]))
1141
1142        def OnImPlotKeyPress(event):
1143            if self.PatternTree.GetItemText(self.PickId) == 'Image Controls':
1144                Data = self.PatternTree.GetItemPyData(self.PickId)
1145                pixelSize = Data['pixelSize']
1146                size = len(self.ImageZ)
1147                Xpos = event.xdata
1148                if not Xpos:            #got point out of frame
1149                    return
1150                Ypos = event.ydata
1151                if event.key == 'm':
1152                    print 'mask = ',Xpos,Ypos
1153                self.PlotImage()
1154               
1155        def OnImPick(event):
1156            if self.PatternTree.GetItemText(self.PickId) != 'Image Controls':
1157                return
1158            if self.itemPicked is not None: return
1159            pick = event.artist
1160            self.itemPicked = pick
1161           
1162        def OnImRelease(event):
1163            if self.PatternTree.GetItemText(self.PickId) != 'Image Controls':
1164                return
1165            Data = self.PatternTree.GetItemPyData(self.PickId)
1166            pixelSize = Data['pixelSize']
1167            scalex = 1000./pixelSize[0]
1168            scaley = 1000./pixelSize[1]
1169            if self.itemPicked is None:
1170                size = len(self.ImageZ)
1171                Xpos = event.xdata
1172                if not (Xpos and self.ifGetRing):                   #got point out of frame
1173                    return
1174                Ypos = event.ydata
1175                if Ypos and not self.pdplot.canvas.toolbar._active:         #make sure zoom/pan not selected
1176                    if event.button == 1:
1177                        Xpix = Xpos*scalex
1178                        Ypix = Ypos*scaley
1179                        xpos,ypos,I,J = G2cmp.ImageLocalMax(self.ImageZ,20,Xpix,Ypix)
1180                        if I and J:
1181                            xpos /= scalex
1182                            ypos /= scaley
1183                            Data['ring'].append([xpos,ypos])
1184                    self.PlotImage()
1185                return
1186            else:
1187                xpos = event.xdata
1188                if xpos:                                        #avoid out of frame mouse position
1189                    ypos = event.ydata
1190                    if self.ifGetRing:
1191                        xypos = [xpos,ypos]
1192                        rings = Data['ring']
1193                        for ring in rings:
1194                            if np.allclose(ring,xypos,.01,0):
1195                                rings.remove(ring)                                                                       
1196                    else:
1197                        xcent,ycent = Data['center']
1198                        xpos -= xcent
1199                        ypos -= ycent
1200                        radius = math.sqrt(xpos**2+ypos**2)
1201                        xpos /= radius
1202                        ypos /= radius
1203                        ang = int(atan2d(-ypos,xpos))
1204                        if 'Line2D' in str(self.itemPicked):
1205                            if 'line2' in str(self.itemPicked) and not Data['fullIntegrate']:
1206                                Data['LRazimuth'][0] = ang
1207                            elif 'line3' in str(self.itemPicked) and not Data['fullIntegrate']:
1208                                Data['LRazimuth'][1] = ang
1209                            elif 'line0' in str(self.itemPicked):
1210                                Data['IOradii'][0] = radius
1211                            elif 'line1' in str(self.itemPicked):
1212                                Data['IOradii'][1] = radius
1213                            if Data['LRazimuth'][1] < Data['LRazimuth'][0]:
1214                                Data['LRazimuth'][1] += 360
1215                            if  Data['IOradii'][0] > Data['IOradii'][1]:
1216                                Data['IOradii'] = G2cmp.SwapXY(Data['IOradii'][0],Data['IOradii'][1])
1217                            self.IOradText.SetValue("%8.3f,%8.3f" % (Data['IOradii'][0],Data['IOradii'][1]))
1218                            self.LRazim.SetValue("%6d,%6d" % (Data['LRazimuth'][0],Data['LRazimuth'][1]))
1219                        else:
1220                            print event.xdata,event.ydata,event.button
1221                    self.PlotImage()
1222                self.itemPicked = None
1223           
1224        newPlot = False
1225        self.NewPlot = True
1226        self.itemPicked = None 
1227        try:
1228            self.pdplot.clear()
1229            self.pdplot.canvas.toolbar.set_history_buttons()
1230            self.pdplot.canvas.set_window_title('2D Powder Image')
1231            self.PDevent = self.ClearEventList(self.PDevent)
1232            self.SCevent = self.ClearEventList(self.SCevent)
1233        except:
1234            self.pdplot = pylab.figure(facecolor='white')
1235            self.pdplot.clear()
1236            self.pdplot.canvas.set_window_title('2D Powder Image')
1237            self.NewPlot = True                     #to make sure subsequent 1-D plot will be OK
1238            newPlot = True
1239        if not self.IMevent:
1240            self.IMevent.append(self.pdplot.canvas.mpl_connect('key_press_event', OnImPlotKeyPress))
1241            self.IMevent.append(self.pdplot.canvas.mpl_connect('motion_notify_event', OnImMotion))
1242            self.IMevent.append(self.pdplot.canvas.mpl_connect('pick_event', OnImPick))
1243            self.IMevent.append(self.pdplot.canvas.mpl_connect('button_release_event', OnImRelease))           
1244        PickId = self.PickId
1245        ax = self.pdplot.add_subplot(111)
1246        self.PlotAX = ax
1247        ax.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1248        size,self.ImageZ = self.PatternTree.GetItemPyData(self.Image)
1249        Data = self.PatternTree.GetItemPyData( \
1250            G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1251        imScale = 1
1252        if len(self.ImageZ) > 1024:
1253            imScale = len(self.ImageZ)/1024
1254        pixelSize = Data['pixelSize']
1255        scalex = 1000./pixelSize[0]
1256        scaley = 1000./pixelSize[1]
1257        xmax = len(self.ImageZ)
1258        Xmax = len(self.ImageZ)*pixelSize[0]/1000.
1259        xlim = (-0.5,Xmax-.5)
1260        ylim = (Xmax-.5,-0.5,)
1261        if self.Img:
1262            xlim = self.Img.axes.get_xlim()
1263            ylim = self.Img.axes.get_ylim()
1264        Imin,Imax = Data['range'][1]
1265        acolor = mpl.cm.get_cmap(Data['color'])
1266        xcent,ycent = Data['center']
1267        ax.set_xlabel('Image x-axis, mm',fontsize=12)
1268        ax.set_ylabel('Image y-axis, mm',fontsize=12)
1269        A = G2cmp.ImageCompress(self.ImageZ,imScale)
1270        self.Img = ax.imshow(self.ImageZ[::imScale,::imScale], \
1271            aspect='equal',cmap=acolor, \
1272            interpolation='nearest',vmin=Imin,vmax=Imax, \
1273            extent=[0,Xmax,Xmax,0])
1274        ax.text(xcent,ycent,'+',ha='center',va='center',picker=3)
1275        if Data['showLines']:
1276            LRAzim = Data['LRazimuth']
1277            IOradii = Data['IOradii']
1278            arcxI = arcyI = np.array(range(LRAzim[0],LRAzim[1]+1))
1279            arcxI = np.sin(arcxI*math.pi/180.)*Data['IOradii'][0]+xcent
1280            arcyI = -np.cos(arcyI*math.pi/180.)*Data['IOradii'][0]+ycent
1281            ax.plot(arcxI,arcyI,picker=3)
1282            arcxO = arcyO = np.array(range(LRAzim[0],LRAzim[1]+1))
1283            arcxO = np.sin(arcxO*math.pi/180.)*Data['IOradii'][1]+xcent
1284            arcyO = -np.cos(arcyO*math.pi/180.)*Data['IOradii'][1]+ycent
1285            ax.plot(arcxO,arcyO,picker=3)
1286            if not Data['fullIntegrate']:
1287                xbeg = arcxI[0]
1288                ybeg = arcyI[0]
1289                ax.plot([xbeg,sind(LRAzim[0])*IOradii[1]+xcent],
1290                    [ybeg,-cosd(LRAzim[0])*IOradii[1]+ycent],picker=3)
1291                xbeg = arcxI[-1]
1292                ybeg = arcyI[-1]
1293                ax.plot([xbeg,sind(LRAzim[1])*IOradii[1]+xcent],
1294                    [ybeg,-cosd(LRAzim[1])*IOradii[1]+ycent],picker=3)
1295        for xring,yring in Data['ring']:
1296            ax.text(xring,yring,'+',color='b',ha='center',va='center',picker=3)
1297        if Data['setRings']:
1298            for ring in Data['rings']:
1299                for xring,yring in ring:
1300                    ax.text(xring,yring,'+',ha='center',va='center')           
1301        for ellipse in Data['ellipses']:
1302            cent,phi,[width,height] = ellipse
1303            ax.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec='r',fc='none'))
1304            ax.text(cent[0],cent[1],'+',color='b',ha='center',va='center')
1305        self.Img.axes.set_xlim(xlim)
1306        self.Img.axes.set_ylim(ylim)
1307        self.pdplot.colorbar(self.Img)
1308        if newPlot:
1309            pylab.show()
1310        else:                       #1st plot
1311            pylab.draw()       
1312               
1313    def PlotPatterns(self):
1314       
1315        def OnPick(event):
1316            if self.itemPicked is not None: return
1317            PatternId = self.PatternId
1318            PickId = self.PickId
1319            pick = event.artist
1320            mouse = event.mouseevent
1321            xpos = pick.get_xdata()
1322            ypos = pick.get_ydata()
1323            ind = event.ind
1324            xy = zip(xpos[ind],ypos[ind])
1325            if self.PatternTree.GetItemText(PickId) == 'Peak List':
1326                if ind.all() != [0]:                                    #picked a data point
1327                    inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Instrument Parameters'))
1328                    if len(inst[1]) == 10:
1329                        ins = inst[1][4:10]
1330                    else:
1331                        ins = inst[1][6:12]   
1332                    sig = ins[0]*tand(xy[0][0]/2.0)**2+ins[1]*tand(xy[0][0]/2.0)+ins[2]
1333                    gam = ins[3]/cosd(xy[0][0]/2.0)+ins[4]*tand(xy[0][0]/2.0)           
1334                    data = self.PatternTree.GetItemPyData(self.PickId)
1335                    XY = [xy[0][0],0, xy[0][1],1, sig,0, gam,0, ins[5],0]       #default refine intensity 1st   
1336                    data.append(XY)
1337                    G2gd.UpdatePeakGrid(self,data)
1338                else:                                                   #picked a peak list line
1339                    self.itemPicked = pick
1340            elif self.PatternTree.GetItemText(PickId) == 'Limits':
1341                if ind.all() != [0]:                                    #picked a data point
1342                    LimitId = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
1343                    data = self.PatternTree.GetItemPyData(LimitId)
1344                    if mouse.button==1:
1345                        data[1][0] = min(xy[0][0],data[1][1])
1346                    if mouse.button==3:
1347                        data[1][1] = max(xy[0][0],data[1][0])
1348                    self.PatternTree.SetItemPyData(LimitId,data)
1349                    G2gd.UpdateLimitsGrid(self,data)
1350                else:                                                   #picked a limit line
1351                    self.itemPicked = pick               
1352            self.PlotPatterns()
1353           
1354        def OnPlotKeyPress(event):
1355            if event.key == 'w':
1356                if self.Weight:
1357                    self.Weight = False
1358                else:
1359                    self.Weight = True
1360                self.PlotPatterns()
1361                print 'plot weighting:',self.Weight
1362            if self.PatternTree.GetChildrenCount(self.root,False) > 1:
1363                if event.key == 'u' and self.Offset < 100.:
1364                    self.Offset += 1.
1365                    self.PlotPatterns()
1366                elif event.key == 'd' and self.Offset > 0.:
1367                    self.Offset -= 1.
1368                    self.PlotPatterns()
1369                elif event.key == 'c':
1370                    print 'contouring'
1371                    if self.Contour:
1372                        self.Contour = False
1373                    else:
1374                        self.Contour = True
1375                    self.PlotPatterns()
1376    #            elif self.Contour and event.key == 'l':
1377    #                event.StopPropagation()
1378            else:
1379                event.Skip()
1380                           
1381        def OnMotion(event):
1382            if self.itemPicked:
1383                xpos = event.xdata
1384                if xpos:                                        #avoid out of frame mouse position
1385                    self.pdplot.canvas.SetToolTipString('%9.3f'%(xpos))
1386                       
1387        def OnRelease(event):
1388            if self.itemPicked is None: return
1389            xpos = event.xdata
1390            if xpos:                                        #avoid out of frame mouse position
1391                lines = []
1392                for line in self.Lines: lines.append(line.get_xdata()[0])
1393                lineNo = lines.index(self.itemPicked.get_xdata()[0])
1394                if  lineNo in [0,1]:
1395                    LimitId = G2gd.GetPatternTreeItemId(self,self.PatternId, 'Limits')
1396                    data = self.PatternTree.GetItemPyData(LimitId)
1397                    data[1][lineNo] = xpos
1398                    self.PatternTree.SetItemPyData(LimitId,data)
1399                    if self.PatternTree.GetItemText(self.PickId) == 'Limits':
1400                        G2gd.UpdateLimitsGrid(self,data)
1401                else:
1402                    PeakId = G2gd.GetPatternTreeItemId(self,self.PatternId, 'Peak List')
1403                    data = self.PatternTree.GetItemPyData(PeakId)
1404                    data[lineNo-2][0] = xpos
1405                    self.PatternTree.SetItemPyData(PeakId,data)
1406                    G2gd.UpdatePeakGrid(self,data)
1407            self.PlotPatterns()
1408            self.itemPicked = None   
1409           
1410        try:
1411            if self.NewPlot:
1412                self.pdplot.clear()
1413            self.pdplot.canvas.toolbar.set_history_buttons()
1414            self.pdplot.canvas.set_window_title('Powder Patterns')
1415            self.IMevent = self.ClearEventList(self.IMevent)
1416            self.SCevent = self.ClearEventList(self.SCevent)
1417        except:
1418            self.pdplot = pylab.figure(facecolor='white')
1419            self.pdplot.clear()
1420            self.pdplot.canvas.set_window_title('Powder Patterns')
1421            self.NewPlot = True
1422        if not self.PDevent:
1423            self.PDevent.append(self.pdplot.canvas.mpl_connect('key_press_event', OnPlotKeyPress))
1424            self.PDevent.append(self.pdplot.canvas.mpl_connect('pick_event', OnPick))
1425            self.PDevent.append(self.pdplot.canvas.mpl_connect('button_release_event', OnRelease))
1426            self.PDevent.append(self.pdplot.canvas.mpl_connect('motion_notify_event', OnMotion))
1427        PickId = self.PickId
1428        PatternId = self.PatternId
1429        colors=['b','g','r','c','m','k']
1430        Ymax = 1.0
1431        PlotList = []
1432        Lines = []
1433        item, cookie = self.PatternTree.GetFirstChild(self.root)
1434        while item:
1435            if 'PWDR' in self.PatternTree.GetItemText(item):
1436                Pattern = self.PatternTree.GetItemPyData(item)
1437                Pattern.append(self.PatternTree.GetItemText(item))
1438                PlotList.append(Pattern)
1439            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
1440        for Pattern in PlotList:
1441            xye = Pattern[1]
1442            Ymax = max(Ymax,max(xye[1]))
1443        offset = self.Offset*Ymax/100.0
1444        ax = self.pdplot.add_subplot(111)
1445        ax.cla()
1446        if not self.NewPlot:
1447            xlim = ax.get_xlim()
1448            ylim = ax.get_ylim()
1449        ax.clear()
1450        ax.set_title('Powder Patterns')
1451        ax.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
1452        ax.set_ylabel('Intensity',fontsize=12)
1453        if self.Contour:
1454            ContourZ = []
1455            ContourY = []
1456            Nseq = 0
1457        for Pattern in PlotList:
1458            ifpicked = False
1459            LimitId = 0
1460            if PickId:
1461                ifpicked = Pattern[2] == self.PatternTree.GetItemText(PatternId)
1462                LimitId = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
1463            xye = Pattern[1]
1464            N = PlotList.index(Pattern)
1465            X = np.array(xye[0])
1466            Y = np.array(xye[1])
1467            Y += offset*N
1468            if LimitId:
1469                limits = self.PatternTree.GetItemPyData(LimitId)
1470                Lines.append(ax.axvline(limits[1][0],color='g',dashes=(5,5),picker=3))   
1471                Lines.append(ax.axvline(limits[1][1],color='r',dashes=(5,5),picker=3))                   
1472            if self.Contour:
1473                ContourY.append(N)
1474                ContourZ.append(Y)
1475                ContourX = X
1476                Nseq += 1
1477                ax.set_ylabel('Data sequence',fontsize=12)
1478            else:
1479                if ifpicked:
1480                    Z = np.array(xye[3])+offset*N
1481                    W = np.array(xye[4])+offset*N
1482                    D = np.array(xye[5])+offset*N
1483                    if self.Weight:
1484                        W2 = np.sqrt(np.array(xye[2]))
1485                        D *= W2
1486                    ax.plot(X,Y,colors[N%6]+'+',picker=3)
1487                    ax.plot(X,Z,colors[(N+1)%6],picker=False)
1488                    ax.plot(X,W,colors[(N+2)%6],picker=False)
1489                    ax.plot(X,D,colors[(N+3)%6],picker=False)
1490                    ax.axhline(0.,color=wx.BLACK)
1491                    self.pdplot.canvas.SetToolTipString('')
1492                    if self.PatternTree.GetItemText(PickId) == 'Peak List':
1493                        tip = 'On data point: Pick peak - L or R MB.On line: MB down to move'
1494                        self.pdplot.canvas.SetToolTipString(tip)
1495                        data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Peak List'))
1496                        for item in data:
1497                            Lines.append(ax.axvline(item[0],color=colors[N%6],picker=2))
1498                    if self.PatternTree.GetItemText(PickId) == 'Limits':
1499                        tip = 'On data point: Lower limit - L MB; Upper limit - R MB. On limit: MB down to move'
1500                        self.pdplot.canvas.SetToolTipString(tip)
1501                        data = self.LimitsTable.GetData()
1502                else:
1503                    ax.plot(xye[0],Y,colors[N%6],picker=False)
1504        if PickId and self.PatternTree.GetItemText(PickId) in ['Index Peak List','Unit Cells List']:
1505            peaks = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Index Peak List'))
1506            for peak in peaks:
1507                ax.axvline(peak[0],color='b')
1508            for hkl in self.HKL:
1509                ax.axvline(hkl[5],color='r',dashes=(5,5))
1510            if self.NewPlot and peaks:
1511                xmin = peaks[0][0]
1512                xmax = peaks[-1][0]
1513                delt = xmax-xmin
1514                xlim = [max(0,xmin-delt/20.),min(180.,xmax+delt/20.)]
1515                ax.set_xlim(xlim)               
1516        if self.Contour:
1517            ax.contourf(ContourX,ContourY,ContourZ)
1518        self.Lines = Lines
1519        if self.NewPlot:
1520            if self.plotView:
1521                ax.set_xlim(self.plotView[0])
1522                ax.set_ylim(self.plotView[1])
1523        else:
1524            ax.set_xlim(xlim)
1525            ax.set_ylim(ylim)
1526            if self.Contour:
1527                ax.set_ylim(0,Nseq-1)
1528        if self.NewPlot:
1529            pylab.show()
1530            self.NewPlot = False
1531        else:                       #1st plot
1532            pylab.draw()
1533       
1534    def PlotSngl(self):
1535        from matplotlib.patches import Circle
1536
1537        def OnSCMotion(event):
1538            xpos = event.xdata
1539            if xpos:
1540                xpos = round(xpos)                                        #avoid out of frame mouse position
1541                ypos = round(event.ydata)
1542                zpos = Data['Layer']
1543                if '100' in Data['Zone']:
1544                    self.pdplot.canvas.SetToolTipString('(%3d,%3d,%3d)'%(zpos,xpos,ypos))
1545                elif '010' in Data['Zone']:
1546                    self.pdplot.canvas.SetToolTipString('(%3d,%3d,%3d)'%(xpos,zpos,ypos))
1547                elif '001' in Data['Zone']:
1548                    self.pdplot.canvas.SetToolTipString('(%3d,%3d,%3d)'%(xpos,ypos,zpos))
1549                   
1550        def OnSCPick(event):
1551            zpos = Data['Layer']
1552            pos = event.artist.center
1553            if '100' in Data['Zone']:
1554                self.pdplot.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(zpos,pos[0],pos[1]))
1555            elif '010' in Data['Zone']:
1556                self.pdplot.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],zpos,pos[1]))
1557            elif '001' in Data['Zone']:
1558                self.pdplot.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],pos[1],zpos))                 
1559           
1560        def OnSCKeyPress(event):
1561            print event.key
1562                   
1563        try:
1564            if self.NewPlot:
1565                self.pdplot.clear()
1566            self.pdplot.canvas.toolbar.set_history_buttons()
1567            self.pdplot.canvas.set_window_title('Structure Factors')
1568            self.IMevent = self.ClearEventList(self.IMevent)
1569            self.PDevent = self.ClearEventList(self.PDevent)
1570        except:
1571            self.pdplot = pylab.figure(facecolor='white')
1572            self.pdplot.clear()
1573            self.pdplot.canvas.set_window_title('Structure Factors')
1574            self.NewPlot = True
1575        if not self.SCevent:
1576            self.SCevent.append(self.pdplot.canvas.mpl_connect('key_press_event', OnSCKeyPress))
1577            self.SCevent.append(self.pdplot.canvas.mpl_connect('pick_event', OnSCPick))
1578            self.SCevent.append(self.pdplot.canvas.mpl_connect('motion_notify_event', OnSCMotion))
1579        PickId = self.PickId
1580        ax = self.pdplot.add_subplot(111)
1581        ax.set_aspect(aspect='equal')
1582        HKLref = self.PatternTree.GetItemPyData(self.Sngl)
1583        Data = self.PatternTree.GetItemPyData( \
1584            G2gd.GetPatternTreeItemId(self,self.Sngl, 'HKL Plot Controls'))
1585
1586        Type = Data['Type']           
1587        scale = Data['Scale']
1588        HKLmax = Data['HKLmax']
1589        HKLmin = Data['HKLmin']
1590        FosqMax = Data['FoMax']
1591        FoMax = math.sqrt(FosqMax)
1592        ifFc = Data['ifFc']
1593        xlabel = ['k, h=','h, k=','h, l=']
1594        ylabel = ['l','l','k']
1595        zones = ['100','010','001']
1596        pzone = [[1,2],[0,2],[0,1]]
1597        izone = zones.index(Data['Zone'])
1598        ax.set_title(self.PatternTree.GetItemText(self.Sngl)[5:])
1599        for h,k,l,Fosq,sig,Fcsq,x,x,x in HKLref:
1600            H = [h,k,l]
1601            if H[izone] == Data['Layer']:
1602                B = 0
1603                if Type == 'Fosq':
1604                    A = scale*Fosq/FosqMax
1605                    B = scale*Fcsq/FosqMax
1606                    C = abs(A-B)
1607                elif Type == 'Fo':
1608                    A = scale*math.sqrt(max(0,Fosq))/FoMax
1609                    B = scale*math.sqrt(max(0,Fcsq))/FoMax
1610                    C = abs(A-B)
1611                elif Type == '|DFsq|/sig':
1612                    A = abs(Fosq-Fcsq)/(scale*sig)
1613                elif Type == '|DFsq|>sig':
1614                    A = abs(Fosq-Fcsq)/(scale*sig)
1615                    if A < 1.0: A = 0                   
1616                elif Type == '|DFsq|>3sig':
1617                    A = abs(Fosq-Fcsq)/(scale*sig)
1618                    if A < 3.0: A = 0                   
1619                xy = (H[pzone[izone][0]],H[pzone[izone][1]])
1620                if A > 0.0:
1621                    ax.add_artist(Circle(xy,radius=A,ec='g',fc='w',picker=3))
1622                if B:
1623                    ax.add_artist(Circle(xy,radius=B,ec='b',fc='w'))
1624                    radius = C
1625                    if radius > 0:
1626                        if A > B:
1627                            ax.add_artist(Circle(xy,radius=radius,ec='r',fc='r'))
1628                        else:                   
1629                            ax.add_artist(Circle(xy,radius=radius,ec='g',fc='g'))
1630                   
1631        ax.set_xlabel(xlabel[izone]+str(Data['Layer']),fontsize=12)
1632        ax.set_ylabel(ylabel[izone],fontsize=12)
1633        ax.set_xlim((HKLmin[pzone[izone][0]],HKLmax[pzone[izone][0]]))
1634        ax.set_ylim((HKLmin[pzone[izone][1]],HKLmax[pzone[izone][1]]))
1635
1636        if self.NewPlot:
1637            pylab.show()
1638            self.NewPlot = False
1639        else:                       #1st plot
1640            pylab.draw()
1641       
1642    def ErrorDialog(self,title,message):
1643        dlg = wx.MessageDialog(self, message, title,  wx.OK)
1644        try:
1645            result = dlg.ShowModal()
1646        finally:
1647            dlg.Destroy()
1648
1649    def OnHelpHelpMenu(self, event):
1650        event.Skip()
1651       
1652    def OnHelpAboutMenu(self, event):
1653        info = wx.AboutDialogInfo()
1654        info.Name = 'GSAS-II'
1655        info.Version = '0.0.1'
1656        info.Copyright = '''
1657Robert B. Von Dreele
1658Argonne National Laboratory(C)
1659This product includes software developed
1660by the UChicago Argonne, LLC, as
1661Operator of Argonne National Laboratory.         '''
1662        info.Description = '''
1663General Structure Analysis System - II
1664        '''
1665        wx.AboutBox(info)
1666       
1667class GSASIImain(wx.App):
1668    def OnInit(self):
1669        self.main = GSASII(None)
1670        self.main.Show()
1671        self.SetTopWindow(self.main)
1672        return True
1673
1674def main():
1675    application = GSASIImain(0)
1676    application.MainLoop()
1677
1678if __name__ == '__main__':
1679    main()
Note: See TracBrowser for help on using the repository browser.