source: trunk/GSASIIphsGUI.py @ 762

Last change on this file since 762 was 762, checked in by toby, 10 years ago

update py files to use native line ends, add update from svn to help menu when svn or svn.exe is in path or ./svn/bin

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 209.3 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - phase data display routines
3########### SVN repository information ###################
4# $Date: 2012-09-23 21:57:51 +0000 (Sun, 23 Sep 2012) $
5# $Author: toby $
6# $Revision: 762 $
7# $URL: trunk/GSASIIphsGUI.py $
8# $Id: GSASIIphsGUI.py 762 2012-09-23 21:57:51Z toby $
9########### SVN repository information ###################
10import wx
11import wx.grid as wg
12import matplotlib as mpl
13import math
14import copy
15import time
16import sys
17import random as ran
18import cPickle
19import GSASIIpath
20GSASIIpath.SetVersionNumber("$Revision: 762 $")
21import GSASIIlattice as G2lat
22import GSASIIspc as G2spc
23import GSASIIElem as G2elem
24import GSASIIElemGUI as G2elemGUI
25import GSASIIplot as G2plt
26import GSASIIgrid as G2gd
27import GSASIIIO as G2IO
28import GSASIIstruct as G2str
29import GSASIImath as G2mth
30import GSASIIpwd as G2pwd
31import numpy as np
32import numpy.linalg as nl
33import numpy.ma as ma
34
35VERY_LIGHT_GREY = wx.Colour(235,235,235)
36WHITE = wx.Colour(255,255,255)
37BLACK = wx.Colour(0,0,0)
38mapDefault = {'MapType':'','RefList':'','Resolution':0.5,
39                'rho':[],'rhoMax':0.,'mapSize':10.0,'cutOff':50.,'Flip':False}
40# trig functions in degrees
41sind = lambda x: np.sin(x*np.pi/180.)
42tand = lambda x: np.tan(x*np.pi/180.)
43cosd = lambda x: np.cos(x*np.pi/180.)
44asind = lambda x: 180.*np.arcsin(x)/np.pi
45acosd = lambda x: 180.*np.arccos(x)/np.pi
46
47class SymOpDialog(wx.Dialog):
48    def __init__(self,parent,SGData,New=True,ForceUnit=False):
49        wx.Dialog.__init__(self,parent,-1,'Select symmetry operator',
50            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
51        panel = wx.Panel(self)
52        self.SGData = SGData
53        self.New = New
54        self.Force = ForceUnit
55        self.OpSelected = [0,0,0,[0,0,0],False,False]
56        mainSizer = wx.BoxSizer(wx.VERTICAL)
57        if ForceUnit:
58            choice = ['No','Yes']
59            self.force = wx.RadioBox(panel,-1,'Force to unit cell?',choices=choice)
60            self.force.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
61            mainSizer.Add(self.force,0,wx.ALIGN_CENTER_VERTICAL)
62        mainSizer.Add((5,5),0)
63        if SGData['SGInv']:
64            choice = ['No','Yes']
65            self.inv = wx.RadioBox(panel,-1,'Choose inversion?',choices=choice)
66            self.inv.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
67            mainSizer.Add(self.inv,0,wx.ALIGN_CENTER_VERTICAL)
68        mainSizer.Add((5,5),0)
69        if SGData['SGLatt'] != 'P':
70            LattOp = G2spc.Latt2text(SGData['SGLatt']).split(';')
71            self.latt = wx.RadioBox(panel,-1,'Choose cell centering?',choices=LattOp)
72            self.latt.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
73            mainSizer.Add(self.latt,0,wx.ALIGN_CENTER_VERTICAL)
74        mainSizer.Add((5,5),0)
75        if SGData['SGLaue'] in ['-1','2/m','mmm','4/m','4/mmm']:
76            Ncol = 2
77        else:
78            Ncol = 3
79        OpList = []
80        for M,T in SGData['SGOps']:
81            OpList.append(G2spc.MT2text(M,T))
82        self.oprs = wx.RadioBox(panel,-1,'Choose space group operator?',choices=OpList,
83            majorDimension=Ncol)
84        self.oprs.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
85        mainSizer.Add(self.oprs,0,wx.ALIGN_CENTER_VERTICAL)
86        mainSizer.Add((5,5),0)
87        mainSizer.Add(wx.StaticText(panel,-1,"   Choose unit cell?"),0,wx.ALIGN_CENTER_VERTICAL)
88        mainSizer.Add((5,5),0)
89        cellSizer = wx.BoxSizer(wx.HORIZONTAL)
90        cellSizer.Add((5,0),0)
91        cellName = ['X','Y','Z']
92        self.cell = []
93        for i in range(3):
94            self.cell.append(wx.SpinCtrl(panel,-1,cellName[i],size=wx.Size(50,20)))
95            self.cell[-1].SetRange(-3,3)
96            self.cell[-1].SetValue(0)
97            self.cell[-1].Bind(wx.EVT_SPINCTRL, self.OnOpSelect)
98            cellSizer.Add(self.cell[-1],0,wx.ALIGN_CENTER_VERTICAL)
99        mainSizer.Add(cellSizer,0,)
100        if self.New:
101            choice = ['No','Yes']
102            self.new = wx.RadioBox(panel,-1,'Generate new positions?',choices=choice)
103            self.new.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
104            mainSizer.Add(self.new,0,wx.ALIGN_CENTER_VERTICAL)
105        mainSizer.Add((5,5),0)
106
107        OkBtn = wx.Button(panel,-1,"Ok")
108        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
109        cancelBtn = wx.Button(panel,-1,"Cancel")
110        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
111        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
112        btnSizer.Add((20,20),1)
113        btnSizer.Add(OkBtn)
114        btnSizer.Add((20,20),1)
115        btnSizer.Add(cancelBtn)
116        btnSizer.Add((20,20),1)
117
118        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
119        panel.SetSizer(mainSizer)
120        panel.Fit()
121        self.Fit()
122
123    def OnOpSelect(self,event):
124        if self.SGData['SGInv']:
125            self.OpSelected[0] = self.inv.GetSelection()
126        if self.SGData['SGLatt'] != 'P':
127            self.OpSelected[1] = self.latt.GetSelection()
128        self.OpSelected[2] = self.oprs.GetSelection()
129        for i in range(3):
130            self.OpSelected[3][i] = float(self.cell[i].GetValue())
131        if self.New:
132            self.OpSelected[4] = self.new.GetSelection()
133        if self.Force:
134            self.OpSelected[5] = self.force.GetSelection()
135
136    def GetSelection(self):
137        return self.OpSelected
138
139    def OnOk(self,event):
140        parent = self.GetParent()
141        parent.Raise()
142        self.EndModal(wx.ID_OK)
143
144    def OnCancel(self,event):
145        parent = self.GetParent()
146        parent.Raise()
147        self.EndModal(wx.ID_CANCEL)
148
149class DisAglDialog(wx.Dialog):
150   
151    def __default__(self,data,default):
152        if data:
153            self.data = data
154        else:
155            self.data = {}
156            self.data['Name'] = default['Name']
157            self.data['Factors'] = [0.85,0.85]
158            self.data['AtomTypes'] = default['AtomTypes']
159            self.data['BondRadii'] = default['BondRadii']
160            self.data['AngleRadii'] = default['AngleRadii']
161       
162    def __init__(self,parent,data,default):
163        wx.Dialog.__init__(self,parent,-1,'Distance Angle Controls', 
164            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
165        self.default = default
166        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
167        self.__default__(data,self.default)
168        self.Draw(self.data)
169               
170    def Draw(self,data):
171        self.panel.Destroy()
172        self.panel = wx.Panel(self)
173        mainSizer = wx.BoxSizer(wx.VERTICAL)
174        mainSizer.Add(wx.StaticText(self.panel,-1,'Controls for phase '+data['Name']),
175            0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
176        mainSizer.Add((10,10),1)
177       
178        radiiSizer = wx.FlexGridSizer(2,3,5,5)
179        radiiSizer.Add(wx.StaticText(self.panel,-1,' Type'),0,wx.ALIGN_CENTER_VERTICAL)
180        radiiSizer.Add(wx.StaticText(self.panel,-1,'Bond radii'),0,wx.ALIGN_CENTER_VERTICAL)
181        radiiSizer.Add(wx.StaticText(self.panel,-1,'Angle radii'),0,wx.ALIGN_CENTER_VERTICAL)
182        self.objList = {}
183        for id,item in enumerate(self.data['AtomTypes']):
184            radiiSizer.Add(wx.StaticText(self.panel,-1,' '+item),0,wx.ALIGN_CENTER_VERTICAL)
185            bRadii = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['BondRadii'][id]),style=wx.TE_PROCESS_ENTER)
186            self.objList[bRadii.GetId()] = ['BondRadii',id]
187            bRadii.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
188            bRadii.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
189            radiiSizer.Add(bRadii,0,wx.ALIGN_CENTER_VERTICAL)
190            aRadii = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['AngleRadii'][id]),style=wx.TE_PROCESS_ENTER)
191            self.objList[aRadii.GetId()] = ['AngleRadii',id]
192            aRadii.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
193            aRadii.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
194            radiiSizer.Add(aRadii,0,wx.ALIGN_CENTER_VERTICAL)
195        mainSizer.Add(radiiSizer,0,wx.EXPAND)
196        factorSizer = wx.FlexGridSizer(2,2,5,5)
197        Names = ['Bond','Angle']
198        for i,name in enumerate(Names):
199            factorSizer.Add(wx.StaticText(self.panel,-1,name+' search factor'),0,wx.ALIGN_CENTER_VERTICAL)
200            bondFact = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['Factors'][i]),style=wx.TE_PROCESS_ENTER)
201            self.objList[bondFact.GetId()] = ['Factors',i]
202            bondFact.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
203            bondFact.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
204            factorSizer.Add(bondFact)
205        mainSizer.Add(factorSizer,0,wx.EXPAND)
206       
207        OkBtn = wx.Button(self.panel,-1,"Ok")
208        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
209        ResetBtn = wx.Button(self.panel,-1,'Reset')
210        ResetBtn.Bind(wx.EVT_BUTTON, self.OnReset)
211        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
212        btnSizer.Add((20,20),1)
213        btnSizer.Add(OkBtn)
214        btnSizer.Add(ResetBtn)
215        btnSizer.Add((20,20),1)
216        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
217        self.panel.SetSizer(mainSizer)
218        self.panel.Fit()
219        self.Fit()
220   
221    def OnRadiiVal(self,event):
222        Obj = event.GetEventObject()
223        item = self.objList[Obj.GetId()]
224        try:
225            self.data[item[0]][item[1]] = float(Obj.GetValue())
226        except ValueError:
227            pass
228        Obj.SetValue("%.3f"%(self.data[item[0]][item[1]]))          #reset in case of error
229       
230    def GetData(self):
231        return self.data
232       
233    def OnOk(self,event):
234        parent = self.GetParent()
235        parent.Raise()
236        self.EndModal(wx.ID_OK)             
237       
238    def OnReset(self,event):
239        data = {}
240        self.__default__(data,self.default)
241        self.Draw(self.data)
242       
243class SingleFloatDialog(wx.Dialog):
244   
245    def __init__(self,parent,title,prompt,value,limits=[0.,1.]):
246        wx.Dialog.__init__(self,parent,-1,title, 
247            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
248        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
249        self.limits = limits
250        self.value = value
251        self.prompt = prompt
252        self.Draw()
253       
254    def Draw(self):
255       
256        def OnValItem(event):
257            try:
258                val = float(valItem.GetValue())
259                if val < self.limits[0] or val > self.limits[1]:
260                    raise ValueError
261            except ValueError:
262                val = self.value
263            self.value = val
264            valItem.SetValue('%.5g'%(self.value))
265           
266        self.panel.Destroy()
267        self.panel = wx.Panel(self)
268        mainSizer = wx.BoxSizer(wx.VERTICAL)
269        mainSizer.Add(wx.StaticText(self.panel,-1,self.prompt),0,wx.ALIGN_CENTER)
270        valItem = wx.TextCtrl(self.panel,-1,value='%.5g'%(self.value),style=wx.TE_PROCESS_ENTER)
271        mainSizer.Add(valItem,0,wx.ALIGN_CENTER)
272        valItem.Bind(wx.EVT_TEXT_ENTER,OnValItem)
273        valItem.Bind(wx.EVT_KILL_FOCUS,OnValItem)
274        OkBtn = wx.Button(self.panel,-1,"Ok")
275        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
276        CancelBtn = wx.Button(self.panel,-1,'Cancel')
277        CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
278        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
279        btnSizer.Add((20,20),1)
280        btnSizer.Add(OkBtn)
281        btnSizer.Add(CancelBtn)
282        btnSizer.Add((20,20),1)
283        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
284        self.panel.SetSizer(mainSizer)
285        self.panel.Fit()
286        self.Fit()
287
288    def GetValue(self):
289        return self.value
290       
291    def OnOk(self,event):
292        parent = self.GetParent()
293        parent.Raise()
294        self.EndModal(wx.ID_OK)             
295       
296    def OnCancel(self,event):
297        parent = self.GetParent()
298        parent.Raise()
299        self.EndModal(wx.ID_CANCEL)
300       
301class GridFractionEditor(wg.PyGridCellEditor):
302    def __init__(self,grid):
303        wg.PyGridCellEditor.__init__(self)
304
305    def Create(self, parent, id, evtHandler):
306        self._tc = wx.TextCtrl(parent, id, "")
307        self._tc.SetInsertionPoint(0)
308        self.SetControl(self._tc)
309
310        if evtHandler:
311            self._tc.PushEventHandler(evtHandler)
312
313        self._tc.Bind(wx.EVT_CHAR, self.OnChar)
314
315    def SetSize(self, rect):
316        self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2,
317                               wx.SIZE_ALLOW_MINUS_ONE)
318
319    def BeginEdit(self, row, col, grid):
320        self.startValue = grid.GetTable().GetValue(row, col)
321        self._tc.SetValue(str(self.startValue))
322        self._tc.SetInsertionPointEnd()
323        self._tc.SetFocus()
324        self._tc.SetSelection(0, self._tc.GetLastPosition())
325
326    def EndEdit(self, row, col, grid):
327        changed = False
328
329        val = self._tc.GetValue()
330       
331        if val != self.startValue:
332            changed = True
333            if '/' in val and '.' not in val:
334                val += '.'
335            try:
336                val = float(eval(val))
337            except (SyntaxError,NameError):
338                val = self.startValue
339            grid.GetTable().SetValue(row, col, val) # update the table
340
341        self.startValue = ''
342        self._tc.SetValue('')
343        return changed
344
345    def Reset(self):
346        self._tc.SetValue(self.startValue)
347        self._tc.SetInsertionPointEnd()
348
349    def Clone(self):
350        return GridFractionEditor(grid)
351
352    def StartingKey(self, evt):
353        self.OnChar(evt)
354        if evt.GetSkipped():
355            self._tc.EmulateKeyPress(evt)
356
357    def OnChar(self, evt):
358        key = evt.GetKeyCode()
359        if key > 255:
360            evt.Skip()
361            return
362        char = chr(key)
363        if char in '.+-/0123456789':
364            self._tc.WriteText(char)
365        else:
366            evt.Skip()
367
368def FindAtomIndexByIDs(atomData,IDs,Draw=True):
369    indx = []
370    for i,atom in enumerate(atomData):
371        if Draw and atom[-3] in IDs:
372            indx.append(i)
373        elif atom[-1] in IDs:
374            indx.append(i)
375    return indx
376       
377def UpdatePhaseData(G2frame,Item,data,oldPage):
378
379    Atoms = []
380    if G2frame.dataDisplay:
381        G2frame.dataDisplay.Destroy()
382    PhaseName = G2frame.PatternTree.GetItemText(Item)
383    G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
384    G2frame.dataFrame.SetLabel('Phase Data for '+PhaseName)
385    G2frame.dataFrame.CreateStatusBar()
386    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
387
388    def SetupGeneral():
389        generalData = data['General']
390        atomData = data['Atoms']
391        generalData['AtomTypes'] = []
392        generalData['Isotopes'] = {}
393# various patches
394        if 'Isotope' not in generalData:
395            generalData['Isotope'] = {}
396        if 'Data plot type' not in generalData:
397            generalData['Data plot type'] = 'Mustrain'
398        if 'POhkl' not in generalData:
399            generalData['POhkl'] = [0,0,1]
400        if 'Map' not in generalData:
401            generalData['Map'] = mapDefault
402        if 'Flip' not in generalData:
403            generalData['Flip'] = {'RefList':'','Resolution':0.5,'Norm element':'None',
404                'k-factor':0.1}
405        if 'doPawley' not in generalData:
406            generalData['doPawley'] = False
407        if 'Pawley dmin' not in generalData:
408            generalData['Pawley dmin'] = 1.0
409        if 'Pawley neg wt' not in generalData:
410            generalData['Pawley neg wt'] = 0.0
411           
412#        if 'SH Texture' not in generalData:
413#            generalData['SH Texture'] = data['SH Texture']
414        generalData['NoAtoms'] = {}
415        generalData['BondRadii'] = []
416        generalData['AngleRadii'] = []
417        generalData['vdWRadii'] = []
418        generalData['AtomMass'] = []
419        generalData['Color'] = []
420        generalData['Mydir'] = G2frame.dirname
421        cx,ct,cs,cia = [3,1,7,9]
422        if generalData['Type'] =='macromolecular':
423            cx,ct,cs,cia = [6,4,10,12]
424        generalData['AtomPtrs'] = [cx,ct,cs,cia]
425        for atom in atomData:
426            atom[ct] = atom[ct].lower().capitalize()              #force to standard form
427            if generalData['AtomTypes'].count(atom[ct]):
428                generalData['NoAtoms'][atom[ct]] += atom[cs-1]*float(atom[cs+1])
429            elif atom[ct] != 'UNK':
430                Info = G2elem.GetAtomInfo(atom[ct])
431                generalData['AtomTypes'].append(atom[ct])
432                generalData['Z'] = Info['Z']
433                generalData['Isotopes'][atom[ct]] = Info['Isotopes']
434                generalData['BondRadii'].append(Info['Drad'])
435                generalData['AngleRadii'].append(Info['Arad'])
436                generalData['vdWRadii'].append(Info['Vdrad'])
437                if atom[ct] in generalData['Isotope']:
438                    generalData['AtomMass'].append(Info['Isotopes'][generalData['Isotope'][atom[ct]]][0])
439                else:
440                    generalData['Isotope'][atom[ct]] = 'Nat. Abund.'
441                    generalData['AtomMass'].append(Info['Mass'])
442                generalData['NoAtoms'][atom[ct]] = atom[cs-1]*float(atom[cs+1])
443                generalData['Color'].append(Info['Color'])
444        F000X = 0.
445        F000N = 0.
446        for i,elem in enumerate(generalData['AtomTypes']):
447            F000X += generalData['NoAtoms'][elem]*generalData['Z']
448            isotope = generalData['Isotope'][elem]
449            F000N += generalData['NoAtoms'][elem]*generalData['Isotopes'][elem][isotope][1]
450        generalData['F000X'] = F000X
451        generalData['F000N'] = F000N
452       
453
454################################################################################
455##### General phase routines
456################################################################################
457
458    def UpdateGeneral():
459       
460        ''' default dictionary structure for phase data: (taken from GSASII.py)
461        'General':{
462            'Name':PhaseName
463            'Type':'nuclear'
464            'SGData':SGData
465            'Cell':[False,10.,10.,10.,90.,90.,90,1000.]
466            'AtomPtrs':[]
467            'Histogram list':['',]
468            'Pawley dmin':1.0,
469            'Pawley neg wt':0.0}
470        'Atoms':[]
471        'Drawing':{}
472        '''
473       
474        phaseTypes = ['nuclear','modulated','magnetic','macromolecular']
475        SetupGeneral()
476        generalData = data['General']
477        Map = generalData['Map']
478        Flip = generalData['Flip'] 
479        PWDR = any(['PWDR' in item for item in data['Histograms'].keys()])
480       
481        def NameSizer():
482                   
483            def OnPhaseName(event):
484                oldName = generalData['Name']
485                generalData['Name'] = NameTxt.GetValue()
486                G2frame.G2plotNB.Rename(oldName,generalData['Name'])
487                G2frame.dataFrame.SetLabel('Phase Data for '+generalData['Name'])
488                G2frame.PatternTree.SetItemText(Item,generalData['Name'])
489                #Hmm, need to change phase name key in Reflection Lists for each histogram
490                           
491            def OnPhaseType(event):
492                if not generalData['AtomTypes']:             #can change only if no atoms!
493                    generalData['Type'] = TypeTxt.GetValue()
494                    dataDisplay.DestroyChildren()           #needed to clear away bad cellSizer, etc.
495                    wx.CallAfter(UpdateGeneral)
496                else:
497                    TypeTxt.SetValue(generalData['Type'])               
498               
499            def OnSpaceGroup(event):
500                SpcGp = SGTxt.GetValue()
501                SGErr,SGData = G2spc.SpcGroup(SpcGp)
502                # try a lookup on the user-supplied name
503                if SGErr:
504                    SpGrpNorm = G2spc.StandardizeSpcName(SpcGp)
505                    if SpGrpNorm:
506                        E,SGData = G2spc.SpcGroup(SpGrpNorm)
507                        if not E: SGErr = False
508                if SGErr:
509                    text = [G2spc.SGErrors(SGErr)+'\nSpace Group set to previous']
510                    SGTxt.SetValue(generalData['SGData']['SpGrp'])
511                    msg = 'Space Group Error'
512                    Style = wx.ICON_EXCLAMATION
513                else:
514                    text = G2spc.SGPrint(SGData)
515                    generalData['SGData'] = SGData
516                    msg = 'Space Group Information'
517                    Style = wx.ICON_INFORMATION
518                Text = ''
519                for line in text:
520                    Text += line+'\n'
521                wx.MessageBox(Text,caption=msg,style=Style)
522                dataDisplay.DestroyChildren()           #needed to clear away bad cellSizer, etc.
523                wx.CallAfter(UpdateGeneral)
524               
525            nameSizer = wx.BoxSizer(wx.HORIZONTAL)
526            nameSizer.Add(wx.StaticText(dataDisplay,-1,' Phase name: '),0,wx.ALIGN_CENTER_VERTICAL)
527            NameTxt = wx.TextCtrl(dataDisplay,-1,value=generalData['Name'],style=wx.TE_PROCESS_ENTER)
528            NameTxt.Bind(wx.EVT_TEXT_ENTER,OnPhaseName)
529            NameTxt.Bind(wx.EVT_KILL_FOCUS,OnPhaseName)
530            nameSizer.Add(NameTxt,0,wx.ALIGN_CENTER_VERTICAL)
531            nameSizer.Add(wx.StaticText(dataDisplay,-1,'  Phase type: '),0,wx.ALIGN_CENTER_VERTICAL)
532            if len(data['Atoms']):
533                choices = phaseTypes[:-1]
534            else:
535                choices = phaseTypes           
536            TypeTxt = wx.ComboBox(dataDisplay,-1,value=generalData['Type'],choices=choices,
537                style=wx.CB_READONLY|wx.CB_DROPDOWN)
538            TypeTxt.Bind(wx.EVT_COMBOBOX, OnPhaseType)
539            nameSizer.Add(TypeTxt,0,wx.ALIGN_CENTER_VERTICAL)
540            nameSizer.Add(wx.StaticText(dataDisplay,-1,'  Space group: '),0,wx.ALIGN_CENTER_VERTICAL)
541            SGTxt = wx.TextCtrl(dataDisplay,-1,value=generalData['SGData']['SpGrp'],style=wx.TE_PROCESS_ENTER)
542            SGTxt.Bind(wx.EVT_TEXT_ENTER,OnSpaceGroup)
543            nameSizer.Add(SGTxt,0,wx.ALIGN_CENTER_VERTICAL)
544            return nameSizer
545           
546        def CellSizer():
547           
548            cellGUIlist = [[['m3','m3m'],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
549            [['3R','3mR'],6,zip([" a = "," alpha = "," Vol = "],["%.5f","%.3f","%.3f"],[True,True,False],[0,2,0])],
550            [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],6,zip([" a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
551            [['mmm'],8,zip([" a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
552                [True,True,True,False],[0,1,2,0])],
553            [['2/m'+'a'],10,zip([" a = "," b = "," c = "," alpha = "," Vol = "],
554                ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
555            [['2/m'+'b'],10,zip([" a = "," b = "," c = "," beta = "," Vol = "],
556                ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
557            [['2/m'+'c'],10,zip([" a = "," b = "," c = "," gamma = "," Vol = "],
558                ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
559            [['-1'],8,zip([" a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
560                ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
561                [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
562               
563            def OnCellRef(event):
564                generalData['Cell'][0] = cellRef.GetValue()
565               
566            def OnCellChange(event):
567                SGData = generalData['SGData']
568                laue = SGData['SGLaue']
569                if laue == '2/m':
570                    laue += SGData['SGUniq']
571                cell = generalData['Cell']
572                Obj = event.GetEventObject()
573                ObjId = cellList.index(Obj.GetId())
574                try:
575                    value = max(1.0,float(Obj.GetValue()))
576                except ValueError:
577                    if ObjId < 3:               #bad cell edge - reset
578                        value = controls[6+ObjId]
579                    else:                       #bad angle
580                        value = 90.
581                if laue in ['m3','m3m']:
582                    cell[1] = cell[2] = cell[3] = value
583                    cell[4] = cell[5] = cell[6] = 90.0
584                    Obj.SetValue("%.5f"%(cell[1]))
585                elif laue in ['3R','3mR']:
586                    if ObjId == 0:
587                        cell[1] = cell[2] = cell[3] = value
588                        Obj.SetValue("%.5f"%(cell[1]))
589                    else:
590                        cell[4] = cell[5] = cell[6] = value
591                        Obj.SetValue("%.5f"%(cell[4]))
592                elif laue in ['3','3m1','31m','6/m','6/mmm','4/m','4/mmm']:                   
593                    cell[4] = cell[5] = 90.
594                    cell[6] = 120.
595                    if laue in ['4/m','4/mmm']:
596                        cell[6] = 90.
597                    if ObjId == 0:
598                        cell[1] = cell[2] = value
599                        Obj.SetValue("%.5f"%(cell[1]))
600                    else:
601                        cell[3] = value
602                        Obj.SetValue("%.5f"%(cell[3]))
603                elif laue in ['mmm']:
604                    cell[ObjId+1] = value
605                    cell[4] = cell[5] = cell[6] = 90.
606                    Obj.SetValue("%.5f"%(cell[ObjId+1]))
607                elif laue in ['2/m'+'a']:
608                    cell[5] = cell[6] = 90.
609                    if ObjId != 3:
610                        cell[ObjId+1] = value
611                        Obj.SetValue("%.5f"%(cell[ObjId+1]))
612                    else:
613                        cell[4] = value
614                        Obj.SetValue("%.3f"%(cell[4]))
615                elif laue in ['2/m'+'b']:
616                    cell[4] = cell[6] = 90.
617                    if ObjId != 3:
618                        cell[ObjId+1] = value
619                        Obj.SetValue("%.5f"%(cell[ObjId+1]))
620                    else:
621                        cell[5] = value
622                        Obj.SetValue("%.3f"%(cell[5]))
623                elif laue in ['2/m'+'c']:
624                    cell[5] = cell[6] = 90.
625                    if ObjId != 3:
626                        cell[ObjId+1] = value
627                        Obj.SetValue("%.5f"%(cell[ObjId+1]))
628                    else:
629                        cell[6] = value
630                        Obj.SetValue("%.3f"%(cell[6]))
631                else:
632                    cell[ObjId+1] = value
633                    if ObjId < 3:
634                        Obj.SetValue("%.5f"%(cell[1+ObjId]))
635                    else:
636                        Obj.SetValue("%.3f"%(cell[1+ObjId]))                       
637                cell[7] = G2lat.calc_V(G2lat.cell2A(cell[1:7]))
638                volVal.SetValue("%.3f"%(cell[7]))
639                density,mattCoeff = G2mth.getDensity(generalData)
640                if denSizer:
641                    denSizer[1].SetValue('%.3f'%(density))
642                    if denSizer[2]:
643                        denSizer[2].SetValue('%.3f'%(mattCoeff))
644                generalData['Cell'] = cell
645           
646            cell = generalData['Cell']
647            laue = generalData['SGData']['SGLaue']
648            if laue == '2/m':
649                laue += generalData['SGData']['SGUniq']
650            for cellGUI in cellGUIlist:
651                if laue in cellGUI[0]:
652                    useGUI = cellGUI
653            cellSizer = wx.FlexGridSizer(2,useGUI[1]+1,5,5)
654            if PWDR:
655                cellRef = wx.CheckBox(dataDisplay,-1,label='Refine unit cell:')
656                cellSizer.Add(cellRef,0,wx.ALIGN_CENTER_VERTICAL)
657                cellRef.Bind(wx.EVT_CHECKBOX, OnCellRef)
658                cellRef.SetValue(cell[0])
659            cellList = []
660            for txt,fmt,ifEdit,Id in useGUI[2]:
661                cellSizer.Add(wx.StaticText(dataDisplay,label=txt),0,wx.ALIGN_CENTER_VERTICAL)
662                if ifEdit:          #a,b,c,etc.
663                    cellVal = wx.TextCtrl(dataDisplay,value=(fmt%(cell[Id+1])),
664                        style=wx.TE_PROCESS_ENTER)
665                    cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
666                    cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
667                    cellSizer.Add(cellVal,0,wx.ALIGN_CENTER_VERTICAL)
668                    cellList.append(cellVal.GetId())
669                else:               #volume
670                    volVal = wx.TextCtrl(dataDisplay,value=(fmt%(cell[7])),style=wx.TE_READONLY)
671                    volVal.SetBackgroundColour(VERY_LIGHT_GREY)
672                    cellSizer.Add(volVal,0,wx.ALIGN_CENTER_VERTICAL)
673            return cellSizer
674           
675        def ElemSizer():
676           
677            def OnIsotope(event):
678                Obj = event.GetEventObject()
679                item = Indx[Obj.GetId()]
680                isotope = Obj.GetValue()
681                generalData['Isotope'][item] = isotope
682                indx = generalData['AtomTypes'].index(item)
683                data['General']['AtomMass'][indx] = generalData['Isotopes'][item][isotope][0]
684                density,mattCoeff = G2mth.getDensity(generalData)
685                denSizer[1].SetValue('%.3f'%(density))
686                if denSizer[2]:
687                    denSizer[2].SetValue('%.3f'%(mattCoeff))
688               
689            elemSizer = wx.FlexGridSizer(8,len(generalData['AtomTypes'])+1,1,1)
690            elemSizer.Add(wx.StaticText(dataDisplay,label=' Elements'),0,wx.ALIGN_CENTER_VERTICAL)
691            for elem in generalData['AtomTypes']:
692                typTxt = wx.TextCtrl(dataDisplay,value=elem,style=wx.TE_READONLY)
693                typTxt.SetBackgroundColour(VERY_LIGHT_GREY)
694                elemSizer.Add(typTxt,0,wx.ALIGN_CENTER_VERTICAL)
695            elemSizer.Add(wx.StaticText(dataDisplay,label=' Isotope'),0,wx.ALIGN_CENTER_VERTICAL)
696            for elem in generalData['AtomTypes']:
697                choices = generalData['Isotopes'][elem].keys()
698                isoSel = wx.ComboBox(dataDisplay,-1,value=generalData['Isotope'][elem],choices=choices,
699                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
700                isoSel.Bind(wx.EVT_COMBOBOX,OnIsotope)
701                Indx[isoSel.GetId()] = elem
702                elemSizer.Add(isoSel,1,wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
703            elemSizer.Add(wx.StaticText(dataDisplay,label=' No. per cell'),0,wx.ALIGN_CENTER_VERTICAL)
704            for elem in generalData['AtomTypes']:
705                numbTxt = wx.TextCtrl(dataDisplay,value='%.1f'%(generalData['NoAtoms'][elem]),
706                    style=wx.TE_READONLY)
707                numbTxt.SetBackgroundColour(VERY_LIGHT_GREY)
708                elemSizer.Add(numbTxt,0,wx.ALIGN_CENTER_VERTICAL)
709            elemSizer.Add(wx.StaticText(dataDisplay,label=' Atom weight'),0,wx.ALIGN_CENTER_VERTICAL)
710            for wt in generalData['AtomMass']:
711                wtTxt = wx.TextCtrl(dataDisplay,value='%.3f'%(wt),style=wx.TE_READONLY)
712                wtTxt.SetBackgroundColour(VERY_LIGHT_GREY)
713                elemSizer.Add(wtTxt,0,wx.ALIGN_CENTER_VERTICAL)
714            elemSizer.Add(wx.StaticText(dataDisplay,label=' Bond radii'),0,wx.ALIGN_CENTER_VERTICAL)
715            for rad in generalData['BondRadii']:
716                bondRadii = wx.TextCtrl(dataDisplay,value='%.2f'%(rad),style=wx.TE_READONLY)
717                bondRadii.SetBackgroundColour(VERY_LIGHT_GREY)
718                elemSizer.Add(bondRadii,0,wx.ALIGN_CENTER_VERTICAL)
719            elemSizer.Add(wx.StaticText(dataDisplay,label=' Angle radii'),0,wx.ALIGN_CENTER_VERTICAL)
720            for rad in generalData['AngleRadii']:
721                elemTxt = wx.TextCtrl(dataDisplay,value='%.2f'%(rad),style=wx.TE_READONLY)
722                elemTxt.SetBackgroundColour(VERY_LIGHT_GREY)
723                elemSizer.Add(elemTxt,0,wx.ALIGN_CENTER_VERTICAL)
724            elemSizer.Add(wx.StaticText(dataDisplay,label=' van der Waals radii'),0,wx.ALIGN_CENTER_VERTICAL)
725            for rad in generalData['vdWRadii']:
726                elemTxt = wx.TextCtrl(dataDisplay,value='%.2f'%(rad),style=wx.TE_READONLY)
727                elemTxt.SetBackgroundColour(VERY_LIGHT_GREY)
728                elemSizer.Add(elemTxt,0,wx.ALIGN_CENTER_VERTICAL)
729            elemSizer.Add(wx.StaticText(dataDisplay,label=' Default color'),0,wx.ALIGN_CENTER_VERTICAL)
730            for R,G,B in generalData['Color']:
731                colorTxt = wx.TextCtrl(dataDisplay,value='',style=wx.TE_READONLY)
732                colorTxt.SetBackgroundColour(wx.Colour(R,G,B))
733                elemSizer.Add(colorTxt,0,wx.ALIGN_CENTER_VERTICAL)
734            return elemSizer
735       
736        def DenSizer():
737           
738            mass = G2mth.getMass(generalData)
739            density,mattCoeff = G2mth.getDensity(generalData)
740            denSizer = wx.BoxSizer(wx.HORIZONTAL)
741            denSizer.Add(wx.StaticText(dataDisplay,-1,' Density: '),0,wx.ALIGN_CENTER_VERTICAL)
742            denTxt = wx.TextCtrl(dataDisplay,-1,'%.3f'%(density),style=wx.TE_READONLY)
743            denTxt.SetBackgroundColour(VERY_LIGHT_GREY)
744            denSizer.Add(denTxt,0,wx.ALIGN_CENTER_VERTICAL)
745            mattTxt = None       
746            if generalData['Type'] == 'macromolecular' and mass > 0.0:
747                denSizer.Add(wx.StaticText(dataDisplay,-1,' Matthews coeff.: '),
748                    0,wx.ALIGN_CENTER_VERTICAL)
749                mattTxt = wx.TextCtrl(dataDisplay,-1,'%.3f'%(mattCoeff),style=wx.TE_READONLY)
750                mattTxt.SetBackgroundColour(VERY_LIGHT_GREY)
751                denSizer.Add(mattTxt,0,wx.ALIGN_CENTER_VERTICAL)
752            return denSizer,denTxt,mattTxt
753           
754        def PawleySizer():
755           
756            def OnPawleyRef(event):
757                generalData['doPawley'] = pawlRef.GetValue()
758           
759            def OnPawleyVal(event):
760                try:
761                    dmin = float(pawlVal.GetValue())
762                    if 0.25 <= dmin <= 20.:
763                        generalData['Pawley dmin'] = dmin
764                except ValueError:
765                    pass
766                pawlVal.SetValue("%.3f"%(generalData['Pawley dmin']))          #reset in case of error               
767           
768            def OnPawleyNegWt(event):
769                try:
770                    wt = float(pawlNegWt.GetValue())
771                    if 0. <= wt <= 1.:
772                        generalData['Pawley neg wt'] = wt
773                except ValueError:
774                    pass
775                pawlNegWt.SetValue("%.3g"%(generalData['Pawley neg wt']))          #reset in case of error               
776
777            pawleySizer = wx.BoxSizer(wx.HORIZONTAL)
778            pawleySizer.Add(wx.StaticText(dataDisplay,label=' Pawley controls: '),0,wx.ALIGN_CENTER_VERTICAL)
779            pawlRef = wx.CheckBox(dataDisplay,-1,label=' Do Pawley refinement?')
780            pawlRef.SetValue(generalData['doPawley'])
781            pawlRef.Bind(wx.EVT_CHECKBOX,OnPawleyRef)
782            pawleySizer.Add(pawlRef,0,wx.ALIGN_CENTER_VERTICAL)
783            pawleySizer.Add(wx.StaticText(dataDisplay,label=' Pawley dmin: '),0,wx.ALIGN_CENTER_VERTICAL)
784            pawlVal = wx.TextCtrl(dataDisplay,value='%.3f'%(generalData['Pawley dmin']),style=wx.TE_PROCESS_ENTER)
785            pawlVal.Bind(wx.EVT_TEXT_ENTER,OnPawleyVal)       
786            pawlVal.Bind(wx.EVT_KILL_FOCUS,OnPawleyVal)
787            pawleySizer.Add(pawlVal,0,wx.ALIGN_CENTER_VERTICAL)
788            pawleySizer.Add(wx.StaticText(dataDisplay,label=' Pawley neg. wt.: '),0,wx.ALIGN_CENTER_VERTICAL)
789            pawlNegWt = wx.TextCtrl(dataDisplay,value='%.3g'%(generalData['Pawley neg wt']),style=wx.TE_PROCESS_ENTER)
790            pawlNegWt.Bind(wx.EVT_TEXT_ENTER,OnPawleyNegWt)       
791            pawlNegWt.Bind(wx.EVT_KILL_FOCUS,OnPawleyNegWt)
792            pawleySizer.Add(pawlNegWt,0,wx.ALIGN_CENTER_VERTICAL)
793            return pawleySizer
794           
795        def MapSizer():
796           
797            def OnMapType(event):
798                Map['MapType'] = mapType.GetValue()
799               
800            def OnRefList(event):
801                Map['RefList'] = refList.GetValue()
802               
803            def OnResVal(event):
804                try:
805                    res = float(mapRes.GetValue())
806                    if 0.25 <= res <= 20.:
807                        Map['Resolution'] = res
808                except ValueError:
809                    pass
810                mapRes.SetValue("%.2f"%(Map['Resolution']))          #reset in case of error
811           
812            def OnCutOff(event):
813                try:
814                    res = float(cutOff.GetValue())
815                    if 10.0 <= res <= 100.:
816                        Map['cutOff'] = res
817                except ValueError:
818                    pass
819                cutOff.SetValue("%.1f"%(Map['cutOff']))          #reset in case of error
820           
821            #patch
822            if 'cutOff' not in Map:
823                Map['cutOff'] = 100.0
824            mapTypes = ['Fobs','Fcalc','delt-F','2*Fo-Fc','Patterson']
825            refList = data['Histograms'].keys()
826            if not generalData['AtomTypes']:
827                 mapTypes = ['Patterson',]
828                 Map['MapType'] = 'Patterson'
829            mapSizer = wx.BoxSizer(wx.VERTICAL)
830            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
831            lineSizer.Add(wx.StaticText(dataDisplay,label=' Fourier map controls: Map type: '),0,wx.ALIGN_CENTER_VERTICAL)
832            mapType = wx.ComboBox(dataDisplay,-1,value=Map['MapType'],choices=mapTypes,
833                style=wx.CB_READONLY|wx.CB_DROPDOWN)
834            mapType.Bind(wx.EVT_COMBOBOX,OnMapType)
835            lineSizer.Add(mapType,0,wx.ALIGN_CENTER_VERTICAL)
836            lineSizer.Add(wx.StaticText(dataDisplay,label=' Reflection set from: '),0,wx.ALIGN_CENTER_VERTICAL)
837            refList = wx.ComboBox(dataDisplay,-1,value=Map['RefList'],choices=refList,
838                style=wx.CB_READONLY|wx.CB_DROPDOWN)
839            refList.Bind(wx.EVT_COMBOBOX,OnRefList)
840            lineSizer.Add(refList,0,wx.ALIGN_CENTER_VERTICAL)
841            mapSizer.Add(lineSizer,0,wx.ALIGN_CENTER_VERTICAL)
842            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
843            line2Sizer.Add(wx.StaticText(dataDisplay,label=' Resolution: '),0,wx.ALIGN_CENTER_VERTICAL)
844            mapRes =  wx.TextCtrl(dataDisplay,value='%.2f'%(Map['Resolution']),style=wx.TE_PROCESS_ENTER)
845            mapRes.Bind(wx.EVT_TEXT_ENTER,OnResVal)       
846            mapRes.Bind(wx.EVT_KILL_FOCUS,OnResVal)
847            line2Sizer.Add(mapRes,0,wx.ALIGN_CENTER_VERTICAL)
848            line2Sizer.Add(wx.StaticText(dataDisplay,label=' Peak cutoff %: '),0,wx.ALIGN_CENTER_VERTICAL)
849            cutOff =  wx.TextCtrl(dataDisplay,value='%.1f'%(Map['cutOff']),style=wx.TE_PROCESS_ENTER)
850            cutOff.Bind(wx.EVT_TEXT_ENTER,OnCutOff)       
851            cutOff.Bind(wx.EVT_KILL_FOCUS,OnCutOff)
852            line2Sizer.Add(cutOff,0,wx.ALIGN_CENTER_VERTICAL)
853            mapSizer.Add(line2Sizer,0,wx.ALIGN_CENTER_VERTICAL)
854            return mapSizer
855               
856        def FlipSizer():
857           
858            def OnRefList(event):
859                Flip['RefList'] = refList.GetValue()
860               
861            def OnNormElem(event):
862                PE = G2elemGUI.PickElement(G2frame,ifNone=True)
863                if PE.ShowModal() == wx.ID_OK:
864                    Flip['Norm element'] = PE.Elem.strip()
865                    normElem.SetLabel(Flip['Norm element'])
866                PE.Destroy()               
867               
868            def OnResVal(event):
869                try:
870                    res = float(flipRes.GetValue())
871                    if 0.25 <= res <= 20.:
872                        Flip['Resolution'] = res
873                except ValueError:
874                    pass
875                flipRes.SetValue("%.2f"%(Flip['Resolution']))          #reset in case of error
876           
877            def OnkFactor(event):
878                try:
879                    res = float(kFactor.GetValue())
880                    if 0.1 <= res <= 1.2:
881                        Flip['k-factor'] = res
882                except ValueError:
883                    pass
884                kFactor.SetValue("%.3f"%(Flip['k-factor']))          #reset in case of error
885           
886            refList = data['Histograms'].keys()
887            flipSizer = wx.BoxSizer(wx.VERTICAL)
888            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
889            lineSizer.Add(wx.StaticText(dataDisplay,label=' Charge flip controls: Reflection set from: '),0,wx.ALIGN_CENTER_VERTICAL)
890            refList = wx.ComboBox(dataDisplay,-1,value=Flip['RefList'],choices=refList,
891                style=wx.CB_READONLY|wx.CB_DROPDOWN)
892            refList.Bind(wx.EVT_COMBOBOX,OnRefList)
893            lineSizer.Add(refList,0,wx.ALIGN_CENTER_VERTICAL)
894            flipSizer.Add(lineSizer,0,wx.ALIGN_CENTER_VERTICAL)
895            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
896            line2Sizer.Add(wx.StaticText(dataDisplay,label=' Normalizing element: '),0,wx.ALIGN_CENTER_VERTICAL)
897            normElem = wx.Button(dataDisplay,label=Flip['Norm element'],style=wx.TE_READONLY)
898            normElem.Bind(wx.EVT_BUTTON,OnNormElem)
899            line2Sizer.Add(normElem,0,wx.ALIGN_CENTER_VERTICAL)
900            line2Sizer.Add(wx.StaticText(dataDisplay,label=' Resolution: '),0,wx.ALIGN_CENTER_VERTICAL)
901            flipRes =  wx.TextCtrl(dataDisplay,value='%.2f'%(Flip['Resolution']),style=wx.TE_PROCESS_ENTER)
902            flipRes.Bind(wx.EVT_TEXT_ENTER,OnResVal)       
903            flipRes.Bind(wx.EVT_KILL_FOCUS,OnResVal)
904            line2Sizer.Add(flipRes,0,wx.ALIGN_CENTER_VERTICAL)
905            line2Sizer.Add(wx.StaticText(dataDisplay,label=' k-Factor (0.1-1.2): '),0,wx.ALIGN_CENTER_VERTICAL)
906            kFactor =  wx.TextCtrl(dataDisplay,value='%.3f'%(Flip['k-factor']),style=wx.TE_PROCESS_ENTER)
907            kFactor.Bind(wx.EVT_TEXT_ENTER,OnkFactor)       
908            kFactor.Bind(wx.EVT_KILL_FOCUS,OnkFactor)
909            line2Sizer.Add(kFactor,0,wx.ALIGN_CENTER_VERTICAL)
910            flipSizer.Add(line2Sizer,0,wx.ALIGN_CENTER_VERTICAL)
911            return flipSizer
912               
913        General.DestroyChildren()
914        dataDisplay = wx.Panel(General)
915        mainSizer = wx.BoxSizer(wx.VERTICAL)
916        mainSizer.Add((5,5),0)
917        mainSizer.Add(NameSizer(),0)
918        mainSizer.Add((5,5),0)       
919        mainSizer.Add(CellSizer(),0)
920        mainSizer.Add((5,5),0)
921       
922        Indx = {}
923        denSizer = None
924        if len(generalData['AtomTypes']):
925            denSizer = DenSizer()
926            mainSizer.Add(denSizer[0])
927            mainSizer.Add((5,5),0)           
928            mainSizer.Add(ElemSizer())
929           
930        mainSizer.Add((5,5),0)
931        mainSizer.Add(PawleySizer())
932
933        mainSizer.Add((5,5),0)
934        mainSizer.Add(MapSizer())
935
936        mainSizer.Add((5,5),0)
937        mainSizer.Add(FlipSizer())
938
939        dataDisplay.SetSizer(mainSizer)
940        Size = mainSizer.Fit(G2frame.dataFrame)
941        Size[1] += 35                           #compensate for status bar
942        dataDisplay.SetSize(Size)
943        G2frame.dataFrame.SetStatusText('')
944        G2frame.dataFrame.setSizePosLeft(Size)
945
946################################################################################
947#####  Atom routines
948################################################################################
949
950    def FillAtomsGrid():
951
952        G2frame.dataFrame.setSizePosLeft([700,300])
953        generalData = data['General']
954        atomData = data['Atoms']
955        DData = data['Drawing']
956        Items = [G2gd.wxID_ATOMSEDITINSERT, G2gd.wxID_ATOMSEDITDELETE, G2gd.wxID_ATOMSREFINE, 
957            G2gd.wxID_ATOMSMODIFY, G2gd.wxID_ATOMSTRANSFORM, G2gd.wxID_ATOMVIEWINSERT]
958        if atomData:
959            for item in Items:   
960                G2frame.dataFrame.AtomsMenu.Enable(item,True)
961        else:
962            for item in Items:
963                G2frame.dataFrame.AtomsMenu.Enable(item,False)
964        Items = [G2gd.wxID_ATOMVIEWINSERT, G2gd.wxID_ATOMSVIEWADD]
965        if data['Drawing']['showABC']:
966            for item in Items:
967                G2frame.dataFrame.AtomsMenu.Enable(item,True)
968        else:
969            for item in Items:
970                G2frame.dataFrame.AtomsMenu.Enable(item,False)
971
972        AAchoice = ": ,ALA,ARG,ASN,ASP,CYS,GLN,GLU,GLY,HIS,ILE,LEU,LYS,MET,PHE,PRO,SER,THR,TRP,TYR,VAL,MSE,HOH,UNK"
973        Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+": ,X,XU,U,F,FX,FXU,FU",]+ \
974            3*[wg.GRID_VALUE_FLOAT+':10,5',]+[wg.GRID_VALUE_FLOAT+':10,4', #x,y,z,frac
975            wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+":I,A",]
976        Types += 7*[wg.GRID_VALUE_FLOAT+':10,5',]
977        colLabels = ['Name','Type','refine','x','y','z','frac','site sym','mult','I/A','Uiso','U11','U22','U33','U12','U13','U23']
978        if generalData['Type'] == 'magnetic':
979            colLabels += ['Mx','My','Mz']
980            Types[2] = wg.GRID_VALUE_CHOICE+": ,X,XU,U,M,MX,MXU,MU,F,FX,FXU,FU,FM,FMX,FMU,"
981            Types += 3*[wg.GRID_VALUE_FLOAT+':10,4',]
982        elif generalData['Type'] == 'macromolecular':
983            colLabels = ['res no','residue','chain'] + colLabels
984            Types = [wg.GRID_VALUE_STRING,
985                wg.GRID_VALUE_CHOICE+AAchoice,
986                wg.GRID_VALUE_STRING] + Types
987        elif generalData['Type'] == 'modulated':
988            Types += []
989            colLabels += []
990
991        def RefreshAtomGrid(event):
992
993            r,c =  event.GetRow(),event.GetCol()
994            if r < 0 and c < 0:
995                for row in range(Atoms.GetNumberRows()):
996                    Atoms.SelectRow(row,True)                   
997            if r < 0:                          #double click on col label! Change all atoms!
998                sel = -1
999                noSkip = True
1000                if Atoms.GetColLabelValue(c) == 'refine':
1001                    Type = generalData['Type']
1002                    if Type in ['nuclear','macromolecular']:
1003                        choice = ['F - site fraction','X - coordinates','U - thermal parameters']
1004                    elif Type in ['magnetic',]:
1005                        choice = ['F - site fraction','X - coordinates','U - thermal parameters','M - magnetic moment']
1006                    dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',choice)
1007                    if dlg.ShowModal() == wx.ID_OK:
1008                        sel = dlg.GetSelections()
1009                        parms = ''
1010                        for x in sel:
1011                            parms += choice[x][0]
1012                    dlg.Destroy()
1013                elif Atoms.GetColLabelValue(c) == 'I/A':
1014                    choice = ['Isotropic','Anisotropic']
1015                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Thermal Motion',choice)
1016                    if dlg.ShowModal() == wx.ID_OK:
1017                        sel = dlg.GetSelection()
1018                        parms = choice[sel][0]
1019                    dlg.Destroy()
1020                elif Atoms.GetColLabelValue(c) == 'Type':
1021                    choice = generalData['AtomTypes']
1022                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom types',choice)
1023                    if dlg.ShowModal() == wx.ID_OK:
1024                        sel = dlg.GetSelection()
1025                        parms = choice[sel]
1026                        noSkip = False
1027                        Atoms.ClearSelection()
1028                        for row in range(Atoms.GetNumberRows()):
1029                            if parms == atomData[row][c]:
1030                                Atoms.SelectRow(row,True)
1031                    dlg.Destroy()
1032                    SetupGeneral()
1033                elif Atoms.GetColLabelValue(c) == 'residue':
1034                    choice = []
1035                    for r in range(Atoms.GetNumberRows()):
1036                        if str(atomData[r][c]) not in choice:
1037                            choice.append(str(atomData[r][c]))
1038                    choice.sort()
1039                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Residue',choice)
1040                    if dlg.ShowModal() == wx.ID_OK:
1041                        sel = dlg.GetSelection()
1042                        parms = choice[sel]
1043                        noSkip = False
1044                        Atoms.ClearSelection()
1045                        for row in range(Atoms.GetNumberRows()):
1046                            if parms == atomData[row][c]:
1047                                Atoms.SelectRow(row,True)
1048                    dlg.Destroy()
1049                elif Atoms.GetColLabelValue(c) == 'res no':
1050                    choice = []
1051                    for r in range(Atoms.GetNumberRows()):
1052                        if str(atomData[r][c]) not in choice:
1053                            choice.append(str(atomData[r][c]))
1054                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Residue no.',choice)
1055                    if dlg.ShowModal() == wx.ID_OK:
1056                        sel = dlg.GetSelection()
1057                        parms = choice[sel]
1058                        noSkip = False
1059                        Atoms.ClearSelection()
1060                        for row in range(Atoms.GetNumberRows()):
1061                            if int(parms) == atomData[row][c]:
1062                                Atoms.SelectRow(row,True)
1063                    dlg.Destroy()
1064                elif Atoms.GetColLabelValue(c) == 'chain':
1065                    choice = []
1066                    for r in range(Atoms.GetNumberRows()):
1067                        if atomData[r][c] not in choice:
1068                            choice.append(atomData[r][c])
1069                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Chain',choice)
1070                    if dlg.ShowModal() == wx.ID_OK:
1071                        sel = dlg.GetSelection()
1072                        parms = choice[sel]
1073                        noSkip = False
1074                        Atoms.ClearSelection()
1075                        for row in range(Atoms.GetNumberRows()):
1076                            if parms == atomData[row][c]:
1077                                Atoms.SelectRow(row,True)
1078                    dlg.Destroy()
1079                elif Atoms.GetColLabelValue(c) == 'Uiso':       #this needs to ask for value
1080                    pass                                        #& then change all 'I' atoms
1081                if sel >= 0 and noSkip:
1082                    ui = colLabels.index('U11')
1083                    us = colLabels.index('Uiso')
1084                    ss = colLabels.index('site sym')
1085                    for r in range(Atoms.GetNumberRows()):
1086                        ID = atomData[r][-1]
1087                        if parms != atomData[r][c] and Atoms.GetColLabelValue(c) == 'I/A':
1088                            if parms == 'A':                #'I' --> 'A'
1089                                Uiso = float(Atoms.GetCellValue(r,us))
1090                                sytsym = atomData[r][ss]
1091                                CSI = G2spc.GetCSuinel(sytsym)
1092                                atomData[r][ui:ui+6] = Uiso*np.array(CSI[3])
1093                                atomData[r][us] = 0.0
1094                                Atoms.SetCellStyle(r,us,VERY_LIGHT_GREY,True)
1095                                for i in range(6):
1096                                    ci = ui+i
1097                                    Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
1098                                    if CSI[2][i]:
1099                                        Atoms.SetCellStyle(r,ci,WHITE,False)
1100                            else:                           #'A' --> 'I'
1101                                Uij = atomData[r][ui:ui+6]
1102                                Uiso = (Uij[0]+Uij[1]+Uij[2])/3.0
1103                                atomData[r][us] = Uiso
1104                                Atoms.SetCellStyle(r,us,WHITE,False)
1105                                for i in range(6):
1106                                    ci = ui+i
1107                                    atomData[r][ci] = 0.0
1108                                    Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
1109                        atomData[r][c] = parms
1110                        if 'Atoms' in data['Drawing']:
1111                            DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
1112                    FillAtomsGrid()
1113                   
1114        def ChangeAtomCell(event):
1115           
1116            def chkUij(Uij,CSI): #needs to do something!!!
1117                return Uij
1118
1119            r,c =  event.GetRow(),event.GetCol()
1120            if r >= 0 and c >= 0:
1121                ID = atomData[r][-1]
1122                if Atoms.GetColLabelValue(c) in ['x','y','z']:
1123                    ci = colLabels.index('x')
1124                    XYZ = atomData[r][ci:ci+3]
1125                    if None in XYZ:
1126                        XYZ = [0,0,0]
1127                    SScol = colLabels.index('site sym')
1128                    Mulcol = colLabels.index('mult')
1129                    E,SGData = G2spc.SpcGroup(generalData['SGData']['SpGrp'])
1130                    Sytsym,Mult = G2spc.SytSym(XYZ,SGData)
1131                    atomData[r][SScol] = Sytsym
1132                    atomData[r][Mulcol] = Mult
1133                    if atomData[r][colLabels.index('I/A')] == 'A':
1134                        ui = colLabels.index('U11')
1135                        CSI = G2spc.GetCSuinel(Sytsym)
1136                        atomData[r][ui:ui+6] = chkUij(atomData[r][ui:ui+6],Sytsym)
1137                        for i in range(6):
1138                            ci = i+ui
1139                            Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
1140                            if CSI[2][i]:
1141                                Atoms.SetCellStyle(r,ci,WHITE,False)
1142                    SetupGeneral()
1143                elif Atoms.GetColLabelValue(c) == 'I/A':            #note use of text color to make it vanish!
1144                    if atomData[r][c] == 'I':
1145                        Uij = atomData[r][c+2:c+8]
1146                        atomData[r][c+1] = (Uij[0]+Uij[1]+Uij[2])/3.0
1147                        Atoms.SetCellStyle(r,c+1,WHITE,False)
1148                        Atoms.SetCellTextColour(r,c+1,BLACK)
1149                        for i in range(6):
1150                            ci = i+colLabels.index('U11')
1151                            Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
1152                            Atoms.SetCellTextColour(r,ci,VERY_LIGHT_GREY)
1153                            atomData[r][ci] = 0.0
1154                    else:
1155                        value = atomData[r][c+1]
1156                        CSI = G2spc.GetCSuinel(atomData[r][colLabels.index('site sym')])
1157                        atomData[r][c+1] =  0.0
1158                        Atoms.SetCellStyle(r,c+1,VERY_LIGHT_GREY,True)
1159                        Atoms.SetCellTextColour(r,c+1,VERY_LIGHT_GREY)
1160                        for i in range(6):
1161                            ci = i+colLabels.index('U11')
1162                            atomData[r][ci] = value*CSI[3][i]
1163                            Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
1164                            Atoms.SetCellTextColour(r,ci,BLACK)
1165                            if CSI[2][i]:
1166                                Atoms.SetCellStyle(r,ci,WHITE,False)
1167                elif Atoms.GetColLabelValue(c) in ['U11','U22','U33','U12','U13','U23']:
1168                    value = atomData[r][c]
1169                    CSI = G2spc.GetCSuinel(atomData[r][colLabels.index('site sym')])
1170                    iUij = CSI[0][c-colLabels.index('U11')]
1171                    for i in range(6):
1172                        if iUij == CSI[0][i]:
1173                            atomData[r][i+colLabels.index('U11')] = value*CSI[1][i]
1174                if 'Atoms' in data['Drawing']:
1175                    DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
1176                    FindBondsDraw()
1177
1178        def AtomTypeSelect(event):
1179            r,c =  event.GetRow(),event.GetCol()
1180            if Atoms.GetColLabelValue(c) == 'Type':
1181                PE = G2elemGUI.PickElement(G2frame)
1182                if PE.ShowModal() == wx.ID_OK:
1183                    if PE.Elem != 'None':                       
1184                        atomData[r][c] = PE.Elem.strip()
1185                        name = atomData[r][c]
1186                        if len(name) in [2,4]:
1187                            atomData[r][c-1] = name[:2]+'(%d)'%(r+1)
1188                        else:
1189                            atomData[r][c-1] = name[:1]+'(%d)'%(r+1)
1190                PE.Destroy()
1191                SetupGeneral()
1192                FillAtomsGrid()
1193                value = Atoms.GetCellValue(r,c)
1194                atomData[r][c] = value
1195                ID = atomData[r][-1]
1196                if 'Atoms' in data['Drawing']:
1197                    DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
1198                SetupGeneral()
1199            else:
1200                event.Skip()
1201
1202        def RowSelect(event):
1203            r,c =  event.GetRow(),event.GetCol()
1204            if r < 0 and c < 0:
1205                if Atoms.IsSelection():
1206                    Atoms.ClearSelection()
1207            elif c < 0:                   #only row clicks
1208                if event.ControlDown():                   
1209                    if r in Atoms.GetSelectedRows():
1210                        Atoms.DeselectRow(r)
1211                    else:
1212                        Atoms.SelectRow(r,True)
1213                elif event.ShiftDown():
1214                    for row in range(r+1):
1215                        Atoms.SelectRow(row,True)
1216                else:
1217                    Atoms.ClearSelection()
1218                    Atoms.SelectRow(r,True)
1219               
1220        def ChangeSelection(event):
1221            r,c =  event.GetRow(),event.GetCol()
1222            if r < 0 and c < 0:
1223                Atoms.ClearSelection()
1224            if c < 0:
1225                if r in Atoms.GetSelectedRows():
1226                    Atoms.DeselectRow(r)
1227                else:
1228                    Atoms.SelectRow(r,True)
1229            if r < 0:
1230                if c in Atoms.GetSelectedCols():
1231                    Atoms.DeselectCol(c)
1232                else:
1233                    Atoms.SelectCol(c,True)
1234       
1235        SGData = data['General']['SGData']
1236        G2frame.dataFrame.SetStatusText('')
1237        if SGData['SGPolax']:
1238            G2frame.dataFrame.SetStatusText('Warning: The location of the origin is arbitrary in '+SGData['SGPolax'])
1239        table = []
1240        rowLabels = []
1241        for i,atom in enumerate(atomData):
1242            table.append(atom)
1243            rowLabels.append(str(i))
1244        atomTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1245        Atoms.SetTable(atomTable, True)
1246        Atoms.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeAtomCell)
1247        Atoms.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, AtomTypeSelect)
1248        Atoms.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, RefreshAtomGrid)
1249        Atoms.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
1250        Atoms.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, ChangeSelection)
1251        Atoms.SetMargins(0,0)
1252        Atoms.AutoSizeColumns(False)
1253        colType = colLabels.index('Type')
1254        colSS = colLabels.index('site sym')
1255        colX = colLabels.index('x')
1256        colIA = colLabels.index('I/A')
1257        colU11 = colLabels.index('U11')
1258        colUiso = colLabels.index('Uiso')
1259        attr = wx.grid.GridCellAttr()
1260        attr.SetEditor(GridFractionEditor(Atoms))
1261        for c in range(colX,colX+3):
1262            Atoms.SetColAttr(c, attr)
1263        for i in range(colU11-1,colU11+6):
1264            Atoms.SetColSize(i,50)           
1265        for row in range(Atoms.GetNumberRows()):
1266            Atoms.SetReadOnly(row,colType,True)
1267            Atoms.SetReadOnly(row,colSS,True)                         #site sym
1268            Atoms.SetReadOnly(row,colSS+1,True)                       #Mult
1269            if Atoms.GetCellValue(row,colIA) == 'A':
1270                CSI = G2spc.GetCSuinel(atomData[row][colLabels.index('site sym')])
1271                Atoms.SetCellStyle(row,colUiso,VERY_LIGHT_GREY,True)
1272                Atoms.SetCellTextColour(row,colUiso,VERY_LIGHT_GREY)
1273                for i in range(6):
1274                    ci = colU11+i
1275                    Atoms.SetCellTextColour(row,ci,BLACK)
1276                    Atoms.SetCellStyle(row,ci,VERY_LIGHT_GREY,True)
1277                    if CSI[2][i]:
1278                        Atoms.SetCellStyle(row,ci,WHITE,False)
1279            else:
1280                Atoms.SetCellStyle(row,colUiso,WHITE,False)
1281                Atoms.SetCellTextColour(row,colUiso,BLACK)
1282                for i in range(6):
1283                    ci = colU11+i
1284                    Atoms.SetCellStyle(row,ci,VERY_LIGHT_GREY,True)
1285                    Atoms.SetCellTextColour(row,ci,VERY_LIGHT_GREY)
1286
1287    def OnAtomAdd(event):
1288        AtomAdd(0,0,0)
1289        FillAtomsGrid()
1290        event.StopPropagation()
1291       
1292    def OnAtomViewAdd(event):
1293        try:
1294            drawData = data['Drawing']
1295            x,y,z = drawData['viewPoint'][0]
1296            AtomAdd(x,y,z)
1297        except:
1298            AtomAdd(0,0,0)
1299        FillAtomsGrid()
1300        event.StopPropagation()
1301               
1302    def AtomAdd(x,y,z,El='H'):
1303        atomData = data['Atoms']
1304        generalData = data['General']
1305        Ncol = Atoms.GetNumberCols()
1306        atId = ran.randint(0,sys.maxint)
1307        E,SGData = G2spc.SpcGroup(generalData['SGData']['SpGrp'])
1308        Sytsym,Mult = G2spc.SytSym([x,y,z],SGData)
1309        if generalData['Type'] == 'macromolecular':
1310            atomData.append([0,'UNK','','UNK',El,'',x,y,z,1,Sytsym,Mult,'I',0.10,0,0,0,0,0,0,atId])
1311        elif generalData['Type'] == 'nuclear':
1312            atomData.append(['UNK',El,'',x,y,z,1,Sytsym,Mult,'I',0.01,0,0,0,0,0,0,atId])
1313        elif generalData['Type'] == 'magnetic':
1314            atomData.append(['UNK',El,'',x,y,z,1,Sytsym,Mult,0,'I',0.01,0,0,0,0,0,0,0,0,0,atId])
1315        SetupGeneral()
1316        if 'Atoms' in data['Drawing']:           
1317            DrawAtomAdd(data['Drawing'],atomData[-1])
1318            G2plt.PlotStructure(G2frame,data)
1319
1320    def OnAtomInsert(event):
1321        AtomInsert(0,0,0)
1322        FillAtomsGrid()
1323        event.StopPropagation()
1324       
1325    def OnAtomViewInsert(event):
1326        if 'Drawing' in data:
1327            drawData = data['Drawing']
1328            x,y,z = drawData['viewPoint'][0]
1329            AtomAdd(x,y,z)
1330            FillAtomsGrid()
1331        event.StopPropagation()
1332           
1333    def AtomInsert(x,y,z):
1334        indx = Atoms.GetSelectedRows()
1335        if indx:
1336            indx = indx[0]
1337            atomData = data['Atoms']
1338            generalData = data['General']
1339            Ncol = Atoms.GetNumberCols()
1340            E,SGData = G2spc.SpcGroup(generalData['SGData']['SpGrp'])
1341            Sytsym,Mult = G2spc.SytSym([0,0,0],SGData)
1342            atId = ran.randint(0,sys.maxint)
1343            if generalData['Type'] == 'macromolecular':
1344                atomData.insert(indx,[0,'UNK','','UNK','UNK','',x,y,z,1,Sytsym,Mult,'I',0.10,0,0,0,0,0,0,atId])
1345            elif generalData['Type'] == 'nuclear':
1346                atomData.insert(indx,['UNK','UNK','',x,y,z,1,Sytsym,Mult,'I',0.01,0,0,0,0,0,0,atId])
1347            elif generalData['Type'] == 'magnetic':
1348                atomData.insert(indx,['UNK','UNK','',x,y,z,1,Sytsym,Mult,0,'I',0.01,0,0,0,0,0,0,0,0,0,atId])
1349            SetupGeneral()
1350
1351    def AtomDelete(event):
1352        indx = Atoms.GetSelectedRows()
1353        IDs = []
1354        if indx:
1355            atomData = data['Atoms']
1356            indx.reverse()
1357            for ind in indx:
1358                atom = atomData[ind]
1359                IDs.append(atom[-1])
1360                del atomData[ind]
1361            if 'Atoms' in data['Drawing']:
1362                DrawAtomsDeleteByIDs(IDs)
1363                wx.CallAfter(FillAtomsGrid)
1364                G2plt.PlotStructure(G2frame,data)
1365            SetupGeneral()
1366        event.StopPropagation()
1367
1368    def AtomRefine(event):
1369        colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1370        c = colLabels.index('refine')
1371        indx = Atoms.GetSelectedRows()
1372        if indx:
1373            atomData = data['Atoms']
1374            generalData = data['General']
1375            Type = generalData['Type']
1376            if Type in ['nuclear','macromolecular']:
1377                choice = ['F - site fraction','X - coordinates','U - thermal parameters']
1378            elif Type == 'magnetic':
1379                choice = ['F - site fraction','X - coordinates','U - thermal parameters','M - magnetic moment']
1380            dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',choice)
1381            if dlg.ShowModal() == wx.ID_OK:
1382                sel = dlg.GetSelections()
1383                parms = ''
1384                for x in sel:
1385                    parms += choice[x][0]
1386                for r in indx:
1387                    atomData[r][c] = parms
1388                Atoms.ForceRefresh()
1389            dlg.Destroy()
1390
1391    def AtomModify(event):                  #intent to implement global modifications (+,-,*,/, etc.)?
1392        indx = Atoms.GetSelectedRows()
1393        if indx:
1394            atomData = data['Atoms']
1395            generalData = data['General']
1396            colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1397            choices = ['Type','Name','x','y','z','frac','I/A','Uiso']
1398            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom parameter',choices)
1399            if dlg.ShowModal() == wx.ID_OK:
1400                sel = dlg.GetSelection()
1401                parm = choices[sel]
1402                cid = colLabels.index(parm)
1403            dlg.Destroy()
1404            if parm in ['Type']:
1405                dlg = G2elemGUI.PickElement(G2frame)
1406                if dlg.ShowModal() == wx.ID_OK:
1407                    if dlg.Elem not in ['None']:
1408                        El = dlg.Elem.strip()
1409                        for r in indx:                       
1410                            atomData[r][cid] = El
1411                            if len(El) in [2,4]:
1412                                atomData[r][cid-1] = El[:2]+'(%d)'%(r+1)
1413                            else:
1414                                atomData[r][cid-1] = El[:1]+'(%d)'%(r+1)
1415                        SetupGeneral()
1416                        if 'Atoms' in data['Drawing']:
1417                            for r in indx:
1418                                ID = atomData[r][-1]
1419                                DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
1420                    FillAtomsGrid()
1421                dlg.Destroy()
1422            elif parm in ['Name',]:
1423                dlg = wx.MessageDialog(G2frame,'Do you really want to rename the selected atoms?','Rename', 
1424                    wx.YES_NO | wx.ICON_QUESTION)
1425                try:
1426                    result = dlg.ShowModal()
1427                    if result == wx.ID_YES:
1428                        for r in indx:
1429                            El = atomData[r][cid+1]
1430                            if len(El) in [2,4]:
1431                                atomData[r][cid] = El[:2]+'(%d)'%(r+1)
1432                            else:
1433                                atomData[r][cid] = El[:1]+'(%d)'%(r+1)
1434                    FillAtomsGrid()
1435                finally:
1436                    dlg.Destroy()
1437                   
1438            elif parm in ['I/A']:
1439                choices = ['Isotropic','Anisotropic']
1440                dlg = wx.SingleChoiceDialog(G2frame,'Select','Thermal parameter model',choices)
1441                if dlg.ShowModal() == wx.ID_OK:
1442                    sel = dlg.GetSelection()
1443                    parm = choices[sel][0]
1444                    for r in indx:                       
1445                        atomData[r][cid] = parm
1446                    FillAtomsGrid()
1447                dlg.Destroy()
1448            elif parm in ['frac','Uiso']:
1449                limits = [0.,1.]
1450                val = 1.0
1451                if  parm in ['Uiso']:
1452                    limits = [0.,0.25]
1453                    val = 0.01
1454                dlg = SingleFloatDialog(G2frame,'New value','Enter new value for '+parm,val,limits)
1455                if dlg.ShowModal() == wx.ID_OK:
1456                    parm = dlg.GetValue()
1457                    for r in indx:                       
1458                        atomData[r][cid] = parm
1459                    SetupGeneral()
1460                    FillAtomsGrid()
1461                dlg.Destroy()
1462            elif parm in ['x','y','z']:
1463                limits = [-1.,1.]
1464                val = 0.
1465                dlg = SingleFloatDialog(G2frame,'Atom shift','Enter shift for '+parm,val,limits)
1466                if dlg.ShowModal() == wx.ID_OK:
1467                    parm = dlg.GetValue()
1468                    for r in indx:                       
1469                        atomData[r][cid] += parm
1470                    SetupGeneral()
1471                    FillAtomsGrid()
1472                dlg.Destroy()
1473
1474    def AtomTransform(event):
1475        indx = Atoms.GetSelectedRows()
1476        if indx:
1477            generalData = data['General']
1478            colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1479            cx = colLabels.index('x')
1480            cuia = colLabels.index('I/A')
1481            cuij = colLabels.index('U11')
1482            css = colLabels.index('site sym')
1483            atomData = data['Atoms']
1484            generalData = data['General']
1485            SGData = generalData['SGData']
1486            dlg = SymOpDialog(G2frame,SGData,True,True)
1487            try:
1488                if dlg.ShowModal() == wx.ID_OK:
1489                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
1490                    Cell = np.array(Cell)
1491                    cent = SGData['SGCen'][Cent]
1492                    M,T = SGData['SGOps'][Opr]
1493                    for ind in indx:
1494                        XYZ = np.array(atomData[ind][cx:cx+3])
1495                        XYZ = np.inner(M,XYZ)+T
1496                        if Inv:
1497                            XYZ = -XYZ
1498                        XYZ = XYZ+cent+Cell
1499                        if Force:
1500                            XYZ = G2spc.MoveToUnitCell(XYZ)
1501                        if New:
1502                            atom = copy.copy(atomData[ind])
1503                        else:
1504                            atom = atomData[ind]
1505                        atom[cx:cx+3] = XYZ
1506                        atom[css:css+2] = G2spc.SytSym(XYZ,SGData)
1507                        if atom[cuia] == 'A':
1508                            Uij = atom[cuij:cuij+6]
1509                            U = G2spc.Uij2U(Uij)
1510                            U = np.inner(np.inner(M,U),M)
1511                            Uij = G2spc.U2Uij(U)
1512                            atom[cuij:cuij+6] = Uij
1513                        if New:
1514                            atomData.append(atom)
1515            finally:
1516                dlg.Destroy()
1517            Atoms.ClearSelection()
1518            if New:
1519                FillAtomsGrid()
1520            else:
1521                Atoms.ForceRefresh()
1522
1523    def OnDistAngle(event):
1524        indx = Atoms.GetSelectedRows()
1525        Oxyz = []
1526        xyz = []
1527        DisAglData = {}
1528        DisAglCtls = {}
1529        if indx:
1530            generalData = data['General']
1531            DisAglData['OrigIndx'] = indx
1532            if 'DisAglCtls' in generalData:
1533                DisAglCtls = generalData['DisAglCtls']
1534            dlg = DisAglDialog(G2frame,DisAglCtls,generalData)
1535            if dlg.ShowModal() == wx.ID_OK:
1536                DisAglCtls = dlg.GetData()
1537            dlg.Destroy()
1538            generalData['DisAglCtls'] = DisAglCtls
1539            atomData = data['Atoms']
1540            colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1541            cx = colLabels.index('x')
1542            cn = colLabels.index('Name')
1543            for i,atom in enumerate(atomData):
1544                xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
1545                if i in indx:
1546                    Oxyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
1547            DisAglData['OrigAtoms'] = Oxyz
1548            DisAglData['TargAtoms'] = xyz
1549            generalData = data['General']
1550            DisAglData['SGData'] = generalData['SGData']
1551            DisAglData['Cell'] = generalData['Cell'][1:] #+ volume
1552            if 'pId' in data:
1553                DisAglData['pId'] = data['pId']
1554                DisAglData['covData'] = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Covariance'))
1555            G2str.DistAngle(DisAglCtls,DisAglData)
1556                       
1557################################################################################
1558#Structure drawing GUI stuff               
1559################################################################################
1560
1561    def SetupDrawingData():
1562        generalData = data['General']
1563        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
1564        atomData = data['Atoms']
1565        AA3letter = ['ALA','ARG','ASN','ASP','CYS','GLN','GLU','GLY','HIS','ILE',
1566            'LEU','LYS','MET','PHE','PRO','SER','THR','TRP','TYR','VAL','MSE','HOH','WAT','UNK']
1567        AA1letter = ['A','R','N','D','C','Q','E','G','H','I',
1568            'L','K','M','F','P','S','T','W','Y','V','M',' ',' ',' ']
1569        defaultDrawing = {'Atoms':[],'viewPoint':[[0.5,0.5,0.5],[]],'showHydrogen':True,
1570            'backColor':[0,0,0],'depthFog':False,'Zclip':50.0,'cameraPos':50.,'Zstep':0.5,
1571            'radiusFactor':0.85,'contourLevel':1.,'bondRadius':0.1,'ballScale':0.33,
1572            'vdwScale':0.67,'ellipseProb':50,'sizeH':0.50,'unitCellBox':False,
1573            'showABC':True,'selectedAtoms':[],'Atoms':[],'oldxy':[],
1574            'bondList':{},'viewDir':[1,0,0]}
1575        V0 = np.array([0,0,1])
1576        V = np.inner(Amat,V0)
1577        V /= np.sqrt(np.sum(V**2))
1578        A = np.arccos(np.sum(V*V0))
1579        defaultDrawing['Quaternion'] = G2mth.AV2Q(A,[0,1,0])
1580        try:
1581            drawingData = data['Drawing']
1582        except KeyError:
1583            data['Drawing'] = {}
1584            drawingData = data['Drawing']
1585        if not drawingData:                 #fill with defaults if empty
1586            drawingData.update(defaultDrawing)
1587        if 'Zstep' not in drawingData:
1588            drawingData['Zstep'] = 0.5
1589        if 'contourLevel' not in drawingData:
1590            drawingData['contourLevel'] = 1.
1591        if 'viewDir' not in drawingData:
1592            drawingData['viewDir'] = [0,0,1]
1593        if 'Quaternion' not in drawingData:
1594            drawingData['Quaternion'] = G2mth.AV2Q(2*np.pi,np.inner(Amat,[0,0,1]))
1595        cx,ct,cs,ci = [0,0,0,0]
1596        if generalData['Type'] == 'nuclear':
1597            cx,ct,cs,ci = [2,1,6,17]         #x, type, style & index
1598        elif generalData['Type'] == 'macromolecular':
1599            cx,ct,cs,ci = [5,4,9,20]         #x, type, style & index
1600        elif generalData['Type'] == 'magnetic':
1601            cx,ct,cs,ci = [2,1,6,20]         #x, type, style & index
1602#        elif generalData['Type'] == 'modulated':
1603#           ?????   for future
1604        drawingData['atomPtrs'] = [cx,ct,cs,ci]
1605        if not drawingData.get('Atoms'):
1606            for atom in atomData:
1607                DrawAtomAdd(drawingData,atom)
1608            data['Drawing'] = drawingData
1609           
1610    def MakeDrawAtom(atom,oldatom=None):
1611        AA3letter = ['ALA','ARG','ASN','ASP','CYS','GLN','GLU','GLY','HIS','ILE',
1612            'LEU','LYS','MET','PHE','PRO','SER','THR','TRP','TYR','VAL','MSE','HOH','WAT','UNK']
1613        AA1letter = ['A','R','N','D','C','Q','E','G','H','I',
1614            'L','K','M','F','P','S','T','W','Y','V','M',' ',' ',' ']
1615        generalData = data['General']
1616        SGData = generalData['SGData']
1617        if generalData['Type'] == 'nuclear':
1618            if oldatom:
1619                opr = oldatom[5]
1620                if atom[9] == 'A':                   
1621                    X,U = G2spc.ApplyStringOps(opr,SGData,atom[3:6],atom[11:17])
1622                    atomInfo = [atom[:2]+list(X)+oldatom[5:9]+atom[9:11]+list(U)+oldatom[17:]][0]
1623                else:
1624                    X = G2spc.ApplyStringOps(opr,SGData,atom[3:6])
1625                    atomInfo = [atom[:2]+list(X)+oldatom[5:9]+atom[9:]+[oldatom[-1]]][0]
1626            else:
1627                atomInfo = [atom[:2]+atom[3:6]+['1',]+['vdW balls',]+
1628                    ['',]+[[255,255,255],]+atom[9:]+[[],[]]][0]
1629            ct,cs = [1,8]         #type & color
1630        elif generalData['Type'] == 'macromolecular':
1631            try:
1632                oneLetter = AA3letter.index(atom[1])
1633            except ValueError:
1634                oneLetter = -1
1635            atomInfo = [[atom[1].strip()+atom[0],]+
1636                [AA1letter[oneLetter]+atom[0],]+atom[2:5]+
1637                atom[6:9]+['1',]+['sticks',]+['',]+[[255,255,255],]+atom[12:]+[[],[]]][0]
1638            ct,cs = [4,11]         #type & color
1639        elif generalData['Type'] == 'magnetic':
1640            if oldatom:
1641                atomInfo = [atom[:2]+oldatom[3:]][0]
1642            else:
1643                atomInfo = [atom[:2]+atom[3:6]+['vdW balls',]+['',]+atom[9:]+[[],[]]][0]
1644            ct,cs = [1,8]         #type & color
1645#        elif generalData['Type'] == 'modulated':
1646#           ?????   for future
1647        atNum = generalData['AtomTypes'].index(atom[ct])
1648        atomInfo[cs] = list(generalData['Color'][atNum])
1649        return atomInfo
1650           
1651    def DrawAtomAdd(drawingData,atom):
1652        drawingData['Atoms'].append(MakeDrawAtom(atom))
1653       
1654    def DrawAtomsReplaceByID(drawingData,atom,ID):
1655        IDs = [ID,]
1656        atomData = drawingData['Atoms']
1657        indx = FindAtomIndexByIDs(atomData,IDs)
1658        for ind in indx:
1659            atomData[ind] = MakeDrawAtom(atom,atomData[ind])
1660           
1661    def OnRestraint(event):       
1662        indx = drawAtoms.GetSelectedRows()
1663        restData = G2frame.PatternTree.GetItemPyData(   
1664            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Restraints'))
1665        drawingData = data['Drawing']
1666        generalData = data['General']
1667        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
1668        cx,ct,cs,ci = drawingData['atomPtrs']
1669        atomData = drawingData['Atoms']
1670        atNames = []
1671        atXYZ = []
1672        atSymOp = []
1673        atIndx = []
1674        for item in indx:
1675            atNames.append(atomData[item][ct-1])
1676            atXYZ.append(np.array(atomData[item][cx:cx+3]))
1677            atSymOp.append(atomData[item][cs-1])
1678            atIndx.append(atomData[item][ci])
1679        if event.GetId() == G2gd.wxID_DRAWRESTRBOND and len(indx) == 2:
1680            try:
1681                bondData = restData[PhaseName]['Bond']
1682            except KeyError:
1683                bondData = {'wtFactor':1.0,'Bonds':[]}
1684                restData[PhaseName] = {}
1685                restData[PhaseName]['Bond'] = bondData
1686            dist = G2mth.getRestDist(atXYZ,Amat)
1687            bondData['Bonds'].append([atNames,atSymOp,atIndx,dist,1.54,0.01])
1688        elif event.GetId() == G2gd.wxID_DRAWRESTRANGLE and len(indx) == 3:
1689            try:
1690                angleData = restData[PhaseName]['Angle']
1691            except KeyError:
1692                angleData = {'wtFactor':1.0,'Angles':[]}
1693                restData[PhaseName] = {}
1694                restData[PhaseName]['Angle'] = angleData
1695            angle = G2mth.getRestAngle(atXYZ,Amat)
1696            angleData['Angles'].append([atNames,atSymOp,atIndx,angle,109.5,1.0])           
1697        elif event.GetId() == G2gd.wxID_DRAWRESTRPLANE and len(indx) > 3:
1698            try:
1699                planeData = restData[PhaseName]['Plane']
1700            except KeyError:
1701                planeData = {'wtFactor':1.0,'Planes':[]}
1702                restData[PhaseName] = {}
1703                restData[PhaseName]['Plane'] = planeData
1704            plane = G2mth.getRestPlane(atXYZ,Amat)
1705            planeData['Planes'].append([atNames,atSymOp,atIndx,plane,0.0,0.01])           
1706        elif event.GetId() == G2gd.wxID_DRAWRESTRCHIRAL and len(indx) == 4:
1707            try:
1708                chiralData = restData[PhaseName]['Chiral']
1709            except KeyError:
1710                chiralData = {'wtFactor':1.0,'Volumes':[]}
1711                restData[PhaseName] = {}
1712                restData[PhaseName]['Chiral'] = chiralData
1713            volume = G2mth.getRestChiral(atXYZ,Amat)
1714            chiralData['Volumes'].append([atNames,atSymOp,atIndx,volume,2.5,0.1])           
1715        else:
1716            print '**** ERROR wrong number of atoms selected for this restraint'
1717            return
1718        G2frame.PatternTree.SetItemPyData(   
1719            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Restraints'),restData)
1720
1721################################################################################
1722##### Atom draw routines
1723################################################################################
1724           
1725    def UpdateDrawAtoms():
1726        G2frame.dataFrame.SetStatusText('')
1727        generalData = data['General']
1728        SetupDrawingData()
1729        drawingData = data['Drawing']
1730        cx,ct,cs,ci = drawingData['atomPtrs']
1731        atomData = drawingData['Atoms']
1732        Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]+ \
1733            [wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,polyhedra",
1734            wg.GRID_VALUE_CHOICE+": ,type,name,number",wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]
1735        styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
1736        labelChoice = [' ','type','name','number']
1737        colLabels = ['Name','Type','x','y','z','Sym Op','Style','Label','Color','I/A']
1738        if generalData['Type'] == 'macromolecular':
1739            colLabels = ['Residue','1-letter','Chain'] + colLabels
1740            Types = 3*[wg.GRID_VALUE_STRING,]+Types
1741            Types[8] = wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,backbone,ribbons,schematic"
1742            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','backbone','ribbons','schematic']
1743            labelChoice = [' ','type','name','number','residue','1-letter','chain']
1744            Types[9] = wg.GRID_VALUE_CHOICE+": ,type,name,number,residue,1-letter,chain"
1745#        elif generalData['Type'] == 'modulated':
1746#            Types += []
1747#            colLabels += []
1748
1749        def RefreshAtomGrid(event):
1750
1751            def SetChoice(name,c,n=0):
1752                choice = []
1753                for r in range(len(atomData)):
1754                    if n:
1755                        srchStr = str(atomData[r][c][:n])
1756                    else:
1757                        srchStr = str(atomData[r][c])
1758                    if srchStr not in choice:
1759                        if n:
1760                            choice.append(str(atomData[r][c][:n]))
1761                        else:
1762                            choice.append(str(atomData[r][c]))
1763                choice.sort()
1764
1765                dlg = wx.MultiChoiceDialog(G2frame,'Select',name,choice)
1766                if dlg.ShowModal() == wx.ID_OK:
1767                    sel = dlg.GetSelections()
1768                    parms = []
1769                    for x in sel:
1770                        parms.append(choice[x])
1771                    noSkip = False
1772                    drawAtoms.ClearSelection()
1773                    drawingData['selectedAtoms'] = []
1774                    for row in range(len(atomData)):
1775                        test = atomData[row][c]
1776                        if n:
1777                            test = test[:n]
1778                        if  test in parms:
1779                            drawAtoms.SelectRow(row,True)
1780                            drawingData['selectedAtoms'].append(row)
1781                    G2plt.PlotStructure(G2frame,data)                   
1782                dlg.Destroy()
1783               
1784            r,c =  event.GetRow(),event.GetCol()
1785            if r < 0 and c < 0:
1786                for row in range(drawAtoms.GetNumberRows()):
1787                    drawingData['selectedAtoms'].append(row)
1788                    drawAtoms.SelectRow(row,True)                   
1789            elif r < 0:                          #dclick on col label
1790                sel = -1
1791                Parms = False
1792                noSkip = True
1793                if drawAtoms.GetColLabelValue(c) == 'Style':
1794                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
1795                    if dlg.ShowModal() == wx.ID_OK:
1796                        sel = dlg.GetSelection()
1797                        parms = styleChoice[sel]
1798                        for r in range(len(atomData)):
1799                            atomData[r][c] = parms
1800                            drawAtoms.SetCellValue(r,c,parms)
1801                        FindBondsDraw()
1802                        G2plt.PlotStructure(G2frame,data)
1803                    dlg.Destroy()
1804                elif drawAtoms.GetColLabelValue(c) == 'Label':
1805                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom labelling style',labelChoice)
1806                    if dlg.ShowModal() == wx.ID_OK:
1807                        sel = dlg.GetSelection()
1808                        parms = labelChoice[sel]
1809                        for r in range(len(atomData)):
1810                            atomData[r][c] = parms
1811                            drawAtoms.SetCellValue(r,c,parms)
1812                    dlg.Destroy()                   
1813                elif drawAtoms.GetColLabelValue(c) == 'Color':
1814                    dlg = wx.ColourDialog(G2frame)
1815                    if dlg.ShowModal() == wx.ID_OK:
1816                        color = dlg.GetColourData().GetColour()
1817                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1818                        attr.SetReadOnly(True)
1819                        attr.SetBackgroundColour(color)
1820                        for r in range(len(atomData)):
1821                            atomData[r][c] = color
1822                            drawingData['Atoms'][r][c] = color
1823                            drawAtoms.SetAttr(r,c,attr)
1824                        UpdateDrawAtoms()
1825                    dlg.Destroy()
1826                elif drawAtoms.GetColLabelValue(c) == 'Residue':
1827                    SetChoice('Residue',c,3)
1828                elif drawAtoms.GetColLabelValue(c) == '1-letter':
1829                    SetChoice('1-letter',c,1)
1830                elif drawAtoms.GetColLabelValue(c) == 'Chain':
1831                    SetChoice('Chain',c)
1832                elif drawAtoms.GetColLabelValue(c) == 'Name':
1833                    SetChoice('Name',c)
1834                elif drawAtoms.GetColLabelValue(c) == 'Sym Op':
1835                    SetChoice('Name',c)
1836                elif drawAtoms.GetColLabelValue(c) == 'Type':
1837                    SetChoice('Type',c)
1838                elif drawAtoms.GetColLabelValue(c) in ['x','y','z','I/A']:
1839                    drawAtoms.ClearSelection()
1840            else:
1841                if drawAtoms.GetColLabelValue(c) in ['Style','Label']:
1842                    atomData[r][c] = drawAtoms.GetCellValue(r,c)
1843                    FindBondsDraw()
1844                elif drawAtoms.GetColLabelValue(c) == 'Color':
1845                    dlg = wx.ColourDialog(G2frame)
1846                    if dlg.ShowModal() == wx.ID_OK:
1847                        color = dlg.GetColourData().GetColour()
1848                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1849                        attr.SetReadOnly(True)
1850                        attr.SetBackgroundColour(color)
1851                        atomData[r][c] = color
1852                        drawingData['Atoms'][r][c] = color
1853                        drawAtoms.SetAttr(i,cs+2,attr)
1854                    dlg.Destroy()
1855                    UpdateDrawAtoms()
1856            G2plt.PlotStructure(G2frame,data)
1857                   
1858        def RowSelect(event):
1859            r,c =  event.GetRow(),event.GetCol()
1860            if r < 0 and c < 0:
1861                if drawAtoms.IsSelection():
1862                    drawAtoms.ClearSelection()
1863            elif c < 0:                   #only row clicks
1864                if event.ControlDown():                   
1865                    if r in drawAtoms.GetSelectedRows():
1866                        drawAtoms.DeselectRow(r)
1867                    else:
1868                        drawAtoms.SelectRow(r,True)
1869                elif event.ShiftDown():
1870                    for row in range(r+1):
1871                        drawAtoms.SelectRow(row,True)
1872                else:
1873                    drawAtoms.ClearSelection()
1874                    drawAtoms.SelectRow(r,True)               
1875            drawingData['selectedAtoms'] = []
1876            drawingData['selectedAtoms'] = drawAtoms.GetSelectedRows()
1877            G2plt.PlotStructure(G2frame,data)                   
1878               
1879        table = []
1880        rowLabels = []
1881        for i,atom in enumerate(drawingData['Atoms']):
1882            table.append(atom[:colLabels.index('I/A')+1])
1883            rowLabels.append(str(i))
1884
1885        atomTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1886        drawAtoms.SetTable(atomTable, True)
1887        drawAtoms.SetMargins(0,0)
1888        drawAtoms.AutoSizeColumns(True)
1889        drawAtoms.SetColSize(colLabels.index('Style'),80)
1890        drawAtoms.SetColSize(colLabels.index('Color'),50)
1891        drawAtoms.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshAtomGrid)
1892        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, RefreshAtomGrid)
1893        drawAtoms.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, RefreshAtomGrid)
1894        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
1895        for i,atom in enumerate(drawingData['Atoms']):
1896            attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1897            attr.SetReadOnly(True)
1898            attr.SetBackgroundColour(atom[cs+2])
1899            drawAtoms.SetAttr(i,cs+2,attr)
1900            drawAtoms.SetCellValue(i,cs+2,'')
1901        indx = drawingData['selectedAtoms']
1902        if indx:
1903            for r in range(len(atomData)):
1904                if r in indx:
1905                    drawAtoms.SelectRow(r)
1906        for c in range(len(colLabels)):
1907           attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1908           attr.SetReadOnly(True)
1909           attr.SetBackgroundColour(VERY_LIGHT_GREY)
1910           if colLabels[c] not in ['Style','Label','Color']:
1911                drawAtoms.SetColAttr(c,attr)
1912        G2frame.dataFrame.setSizePosLeft([600,300])
1913       
1914        FindBondsDraw()
1915        drawAtoms.ClearSelection()
1916        G2plt.PlotStructure(G2frame,data)
1917
1918    def DrawAtomStyle(event):
1919        indx = drawAtoms.GetSelectedRows()
1920        if indx:
1921            generalData = data['General']
1922            atomData = data['Drawing']['Atoms']
1923            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1924            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
1925            if generalData['Type'] == 'macromolecular':
1926                styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids',
1927                'backbone','ribbons','schematic']
1928            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
1929            if dlg.ShowModal() == wx.ID_OK:
1930                sel = dlg.GetSelection()
1931                parms = styleChoice[sel]
1932                for r in indx:
1933                    atomData[r][cs] = parms
1934                    drawAtoms.SetCellValue(r,cs,parms)
1935            dlg.Destroy()
1936            FindBondsDraw()
1937            drawAtoms.ClearSelection()
1938            G2plt.PlotStructure(G2frame,data)
1939
1940    def DrawAtomLabel(event):
1941        indx = drawAtoms.GetSelectedRows()
1942        if indx:
1943            generalData = data['General']
1944            atomData = data['Drawing']['Atoms']
1945            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1946            styleChoice = [' ','type','name','number']
1947            if generalData['Type'] == 'macromolecular':
1948                styleChoice = [' ','type','name','number','residue','1-letter','chain']
1949            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom label style',styleChoice)
1950            if dlg.ShowModal() == wx.ID_OK:
1951                sel = dlg.GetSelection()
1952                parms = styleChoice[sel]
1953                for r in indx:
1954                    atomData[r][cs+1] = parms
1955                    drawAtoms.SetCellValue(r,cs+1,parms)
1956            dlg.Destroy()
1957            drawAtoms.ClearSelection()
1958            G2plt.PlotStructure(G2frame,data)
1959           
1960    def DrawAtomColor(event):
1961
1962        indx = drawAtoms.GetSelectedRows()
1963        if indx:
1964            if len(indx) > 1:
1965                G2frame.dataFrame.SetStatusText('Select Custom Color, change color, Add to Custom Colors, then OK')
1966            else:
1967                G2frame.dataFrame.SetStatusText('Change color, Add to Custom Colors, then OK')
1968            generalData = data['General']
1969            atomData = data['Drawing']['Atoms']
1970            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1971            atmColors = []
1972            atmTypes = []
1973            for r in indx:
1974                if atomData[r][cs+2] not in atmColors:
1975                    atmColors.append(atomData[r][cs+2])
1976                    atmTypes.append(atomData[r][ct])
1977                    if len(atmColors) > 16:
1978                        break
1979            colors = wx.ColourData()
1980            colors.SetChooseFull(True)
1981            dlg = wx.ColourDialog(G2frame)
1982            if dlg.ShowModal() == wx.ID_OK:
1983                for i in range(len(atmColors)):                   
1984                    atmColors[i] = dlg.GetColourData().GetColour()
1985                colorDict = dict(zip(atmTypes,atmColors))
1986                for r in indx:
1987                    color = colorDict[atomData[r][ct]]
1988                    atomData[r][cs+2] = color
1989                    attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1990                    attr.SetBackgroundColour(color)
1991                    drawAtoms.SetAttr(r,cs+2,attr)
1992                    data['Drawing']['Atoms'][r][cs+2] = color
1993            drawAtoms.ClearSelection()
1994            dlg.Destroy()
1995            G2frame.dataFrame.SetStatusText('')
1996            G2plt.PlotStructure(G2frame,data)
1997           
1998    def ResetAtomColors(event):
1999        generalData = data['General']
2000        atomData = data['Drawing']['Atoms']
2001        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2002        for atom in atomData:           
2003            atNum = generalData['AtomTypes'].index(atom[ct])
2004            atom[cs+2] = list(generalData['Color'][atNum])
2005        UpdateDrawAtoms()
2006        drawAtoms.ClearSelection()
2007        G2plt.PlotStructure(G2frame,data)       
2008       
2009    def SetViewPoint(event):
2010        indx = drawAtoms.GetSelectedRows()
2011        if indx:
2012            atomData = data['Drawing']['Atoms']
2013            cx = data['Drawing']['atomPtrs'][0]
2014            data['Drawing']['viewPoint'] = [atomData[indx[0]][cx:cx+3],[indx[0],0]]
2015            drawAtoms.ClearSelection()                                  #do I really want to do this?
2016            G2plt.PlotStructure(G2frame,data)
2017           
2018    def noDuplicate(xyz,atomData):                  #be careful where this is used - it's slow
2019        cx = data['Drawing']['atomPtrs'][0]
2020        if True in [np.allclose(np.array(xyz),np.array(atom[cx:cx+3]),atol=0.0002) for atom in atomData]:
2021            return False
2022        else:
2023            return True
2024               
2025    def AddSymEquiv(event):
2026        indx = drawAtoms.GetSelectedRows()
2027        indx.sort()
2028        if indx:
2029            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2030            cx = colLabels.index('x')
2031            cuia = colLabels.index('I/A')
2032            cuij = cuia+2
2033            atomData = data['Drawing']['Atoms']
2034            generalData = data['General']
2035            SGData = generalData['SGData']
2036            dlg = SymOpDialog(G2frame,SGData,False,True)
2037            try:
2038                if dlg.ShowModal() == wx.ID_OK:
2039                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
2040                    Cell = np.array(Cell)
2041                    cent = SGData['SGCen'][Cent]
2042                    M,T = SGData['SGOps'][Opr]
2043                    for ind in indx:
2044                        XYZ = np.array(atomData[ind][cx:cx+3])
2045                        XYZ = np.inner(M,XYZ)+T
2046                        if Inv:
2047                            XYZ = -XYZ
2048                        XYZ = XYZ+cent+Cell
2049                        if Force:
2050                            XYZ = G2spc.MoveToUnitCell(XYZ)
2051                        if noDuplicate(XYZ,atomData):
2052                            atom = copy.copy(atomData[ind])
2053                            atom[cx:cx+3] = XYZ
2054                            atomOp = atom[cx+3]
2055                            newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2056                                str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))                           
2057                            atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2058                            if atom[cuia] == 'A':
2059                                Uij = atom[cuij:cuij+6]
2060                                U = G2spc.Uij2U(Uij)
2061                                U = np.inner(np.inner(M,U),M)
2062                                Uij = G2spc.U2Uij(U)
2063                                atom[cuij:cuij+6] = Uij
2064                            atomData.append(atom)
2065            finally:
2066                dlg.Destroy()
2067            UpdateDrawAtoms()
2068            drawAtoms.ClearSelection()
2069            G2plt.PlotStructure(G2frame,data)
2070           
2071    def TransformSymEquiv(event):
2072        indx = drawAtoms.GetSelectedRows()
2073        indx.sort()
2074        if indx:
2075            atomData = data['Drawing']['Atoms']
2076            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2077            cx = colLabels.index('x')
2078            cuia = colLabels.index('I/A')
2079            cuij = cuia+2
2080            atomData = data['Drawing']['Atoms']
2081            generalData = data['General']
2082            SGData = generalData['SGData']
2083            dlg = SymOpDialog(G2frame,SGData,False,True)
2084            try:
2085                if dlg.ShowModal() == wx.ID_OK:
2086                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
2087                    Cell = np.array(Cell)
2088                    cent = SGData['SGCen'][Cent]
2089                    M,T = SGData['SGOps'][Opr]
2090                    for ind in indx:
2091                        XYZ = np.array(atomData[ind][cx:cx+3])
2092                        XYZ = np.inner(M,XYZ)+T
2093                        if Inv:
2094                            XYZ = -XYZ
2095                        XYZ = XYZ+cent+Cell
2096                        if Force:
2097                            XYZ = G2spc.MoveToUnitCell(XYZ)
2098                        atom = atomData[ind]
2099                        atom[cx:cx+3] = XYZ
2100                        atomOp = atom[cx+3]
2101                        newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2102                            str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))
2103                        atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2104                        if atom[cuia] == 'A':
2105                            Uij = atom[cuij:cuij+6]
2106                            U = G2spc.Uij2U(Uij)
2107                            U = np.inner(np.inner(M,U),M)
2108                            Uij = G2spc.U2Uij(U)
2109                            atom[cuij:cuij+6] = Uij
2110                    data['Drawing']['Atoms'] = atomData
2111            finally:
2112                dlg.Destroy()
2113            UpdateDrawAtoms()
2114            drawAtoms.ClearSelection()
2115            G2plt.PlotStructure(G2frame,data)
2116           
2117    def FillCoordSphere(event):
2118        generalData = data['General']
2119        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2120        radii = generalData['BondRadii']
2121        atomTypes = generalData['AtomTypes']
2122        try:
2123            indH = atomTypes.index('H')
2124            radii[indH] = 0.5
2125        except:
2126            pass           
2127        indx = drawAtoms.GetSelectedRows()
2128        if indx:
2129            indx.sort()
2130            atomData = data['Drawing']['Atoms']
2131            numAtoms = len(atomData)
2132            cx,ct,cs,ci = data['Drawing']['atomPtrs']
2133            generalData = data['General']
2134            SGData = generalData['SGData']
2135            cellArray = G2lat.CellBlock(1)
2136            wx.BeginBusyCursor()
2137            try:
2138                for ind in indx:
2139                    atomA = atomData[ind]
2140                    xyzA = np.array(atomA[cx:cx+3])
2141                    indA = atomTypes.index(atomA[ct])
2142                    for atomB in atomData[:numAtoms]:
2143                        indB = atomTypes.index(atomB[ct])
2144                        sumR = radii[indA]+radii[indB]
2145                        xyzB = np.array(atomB[cx:cx+3])
2146                        for xyz in cellArray+xyzB:
2147                            dist = np.sqrt(np.sum(np.inner(Amat,xyz-xyzA)**2))
2148                            if 0 < dist <= data['Drawing']['radiusFactor']*sumR:
2149                                if noDuplicate(xyz,atomData):
2150                                    oprB = atomB[cx+3]
2151                                    C = xyz-xyzB
2152                                    newOp = '1+'+str(int(round(C[0])))+','+str(int(round(C[1])))+','+str(int(round(C[2])))
2153                                    newAtom = atomB[:]
2154                                    newAtom[cx:cx+3] = xyz
2155                                    newAtom[cx+3] = G2spc.StringOpsProd(oprB,newOp,SGData)
2156                                    atomData.append(newAtom)
2157            finally:
2158                wx.EndBusyCursor()
2159            data['Drawing']['Atoms'] = atomData
2160            UpdateDrawAtoms()
2161            drawAtoms.ClearSelection()
2162            G2plt.PlotStructure(G2frame,data)
2163           
2164    def FillUnitCell(event):
2165        indx = drawAtoms.GetSelectedRows()
2166        indx.sort()
2167        if indx:
2168            atomData = data['Drawing']['Atoms']
2169            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2170            cx = colLabels.index('x')
2171            cuia = colLabels.index('I/A')
2172            cuij = cuia+2
2173            generalData = data['General']
2174            SGData = generalData['SGData']
2175            wx.BeginBusyCursor()
2176            try:
2177                for ind in indx:
2178                    atom = atomData[ind]
2179                    XYZ = np.array(atom[cx:cx+3])
2180                    if atom[cuia] == 'A':
2181                        Uij = atom[cuij:cuij+6]
2182                        result = G2spc.GenAtom(XYZ,SGData,False,Uij,False)
2183                        for item in result:
2184                            atom = copy.copy(atomData[ind])
2185                            atom[cx:cx+3] = item[0]
2186                            atom[cx+3] = str(item[2])+'+' \
2187                                +str(item[3][0])+','+str(item[3][1])+','+str(item[3][2])
2188                            atom[cuij:cuij+6] = item[1]
2189                            Opp = G2spc.Opposite(item[0])
2190                            for xyz in Opp:
2191                                if noDuplicate(xyz,atomData):
2192                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2193                                    cell = '1'+'+'+ \
2194                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2195                                    atom[cx:cx+3] = xyz
2196                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2197                                    atomData.append(atom[:])
2198                    else:
2199                        result = G2spc.GenAtom(XYZ,SGData,False,Move=False)
2200                        for item in result:
2201                            atom = copy.copy(atomData[ind])
2202                            atom[cx:cx+3] = item[0]
2203                            atom[cx+3] = str(item[1])+'+' \
2204                                +str(item[2][0])+','+str(item[2][1])+','+str(item[2][2])
2205                            Opp = G2spc.Opposite(item[0])
2206                            for xyz in Opp:
2207                                if noDuplicate(xyz,atomData):
2208                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2209                                    cell = '1'+'+'+ \
2210                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2211                                    atom[cx:cx+3] = xyz
2212                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2213                                    atomData.append(atom[:])               
2214                    data['Drawing']['Atoms'] = atomData
2215            finally:
2216                wx.EndBusyCursor()
2217            UpdateDrawAtoms()
2218            drawAtoms.ClearSelection()
2219            G2plt.PlotStructure(G2frame,data)
2220           
2221    def FindBondsToo():                         #works but slow for large structures - keep as reference
2222        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2223        atomData = data['Drawing']['Atoms']
2224        generalData = data['General']
2225        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2226        radii = generalData['BondRadii']
2227        atomTypes = generalData['AtomTypes']
2228        try:
2229            indH = atomTypes.index('H')
2230            radii[indH] = 0.5
2231        except:
2232            pass           
2233        for atom in atomData:
2234            atom[-1] = []
2235        Atoms = []
2236        for i,atom in enumerate(atomData):
2237            Atoms.append([i,np.array(atom[cx:cx+3]),atom[cs],radii[atomTypes.index(atom[ct])]])
2238        for atomA in Atoms:
2239            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2240                for atomB in Atoms:                   
2241                    Dx = atomB[1]-atomA[1]
2242                    DX = np.inner(Amat,Dx)
2243                    dist = np.sqrt(np.sum(DX**2))
2244                    sumR = atomA[3]+atomB[3]
2245                    if 0.5 < dist <= 0.85*sumR:
2246                        i = atomA[0]
2247                        if atomA[2] == 'polyhedra':
2248                            atomData[i][-1].append(DX)
2249                        elif atomB[1] != 'polyhedra':
2250                            j = atomB[0]
2251                            atomData[i][-1].append(Dx*atomA[3]/sumR)
2252                            atomData[j][-1].append(-Dx*atomB[3]/sumR)
2253                   
2254    def FindBondsDraw():                    #uses numpy & masks - very fast even for proteins!
2255        import numpy.ma as ma
2256        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2257        hydro = data['Drawing']['showHydrogen']
2258        atomData = data['Drawing']['Atoms']
2259        generalData = data['General']
2260        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2261        radii = generalData['BondRadii']
2262        atomTypes = generalData['AtomTypes']
2263        try:
2264            indH = atomTypes.index('H')
2265            radii[indH] = 0.5
2266        except:
2267            pass           
2268        for atom in atomData:
2269            atom[-2] = []               #clear out old bonds/polyhedra
2270            atom[-1] = []
2271        Indx = range(len(atomData))
2272        Atoms = []
2273        Styles = []
2274        Radii = []
2275        for atom in atomData:
2276            Atoms.append(np.array(atom[cx:cx+3]))
2277            Styles.append(atom[cs])
2278            try:
2279                if not hydro and atom[ct] == 'H':
2280                    Radii.append(0.0)
2281                else:
2282                    Radii.append(radii[atomTypes.index(atom[ct])])
2283            except ValueError:          #changed atom type!
2284                Radii.append(0.20)
2285        Atoms = np.array(Atoms)
2286        Radii = np.array(Radii)
2287        IASR = zip(Indx,Atoms,Styles,Radii)
2288        for atomA in IASR:
2289            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2290                Dx = Atoms-atomA[1]
2291                dist = ma.masked_less(np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0)),0.5) #gets rid of G2frame & disorder "bonds" < 0.5A
2292                sumR = atomA[3]+Radii
2293                IndB = ma.nonzero(ma.masked_greater(dist-data['Drawing']['radiusFactor']*sumR,0.))                 #get indices of bonded atoms
2294                i = atomA[0]
2295                for j in IndB[0]:
2296                    if Styles[i] == 'polyhedra':
2297                        atomData[i][-2].append(np.inner(Amat,Dx[j]))
2298                    elif Styles[j] != 'polyhedra' and j > i:
2299                        atomData[i][-2].append(Dx[j]*Radii[i]/sumR[j])
2300                        atomData[j][-2].append(-Dx[j]*Radii[j]/sumR[j])
2301                if Styles[i] == 'polyhedra':
2302                    Bonds = atomData[i][-2]
2303                    Faces = []
2304                    if len(Bonds) > 2:
2305                        FaceGen = G2lat.uniqueCombinations(Bonds,3)     #N.B. this is a generator
2306                        for face in FaceGen:
2307                            vol = nl.det(face)
2308                            if abs(vol) > 1. or len(Bonds) == 3:
2309                                if vol < 0.:
2310                                    face = [face[0],face[2],face[1]]
2311                                face = np.array(face)
2312                                if not np.array([np.array(nl.det(face-bond))+0.0001 < 0 for bond in Bonds]).any():
2313                                    norm = np.cross(face[1]-face[0],face[2]-face[0])
2314                                    norm /= np.sqrt(np.sum(norm**2))
2315                                    Faces.append([face,norm])
2316                        atomData[i][-1] = Faces
2317                       
2318    def DrawAtomsDelete(event):   
2319        indx = drawAtoms.GetSelectedRows()
2320        indx.sort()
2321        if indx:
2322            atomData = data['Drawing']['Atoms']
2323            indx.reverse()
2324            for ind in indx:
2325                del atomData[ind]
2326            UpdateDrawAtoms()
2327            drawAtoms.ClearSelection()
2328            G2plt.PlotStructure(G2frame,data)
2329        event.StopPropagation()
2330       
2331    def OnReloadDrawAtoms(event):
2332        data['Drawing']['Atoms'] = []
2333        UpdateDrawAtoms()
2334        drawAtoms.ClearSelection()
2335        G2plt.PlotStructure(G2frame,data)
2336        event.StopPropagation()
2337       
2338    def FindAtomIndexByIDs(atomData,IDs,Draw=True):
2339        indx = []
2340        for i,atom in enumerate(atomData):
2341            if Draw and atom[-3] in IDs:
2342                indx.append(i)
2343            elif atom[-1] in IDs:
2344                indx.append(i)
2345        return indx
2346       
2347    def DrawAtomsDeleteByIDs(IDs):
2348        atomData = data['Drawing']['Atoms']
2349        indx = FindAtomIndexByIDs(atomData,IDs)
2350        indx.reverse()
2351        for ind in indx:
2352            del atomData[ind]
2353           
2354    def ChangeDrawAtomsByIDs(colName,IDs,value):
2355        atomData = data['Drawing']['Atoms']
2356        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2357        if colName == 'Name':
2358            col = ct-1
2359        elif colName == 'Type':
2360            col = ct
2361        elif colName == 'I/A':
2362            col = cs
2363        indx = FindAtomIndexByIDs(atomData,IDs)
2364        for ind in indx:
2365            atomData[ind][col] = value
2366               
2367    def OnDrawPlane(event):
2368        indx = drawAtoms.GetSelectedRows()
2369        if len(indx) < 4:
2370            print '**** ERROR - need 4+ atoms for plane calculation'
2371            return
2372        PlaneData = {}
2373        drawingData = data['Drawing']
2374        atomData = drawingData['Atoms']
2375        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2376        cx = colLabels.index('x')
2377        cn = colLabels.index('Name')
2378        xyz = []
2379        for i,atom in enumerate(atomData):
2380            if i in indx:
2381                xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
2382        generalData = data['General']
2383        PlaneData['Name'] = generalData['Name']
2384        PlaneData['Atoms'] = xyz
2385        PlaneData['Cell'] = generalData['Cell'][1:] #+ volume
2386        G2str.BestPlane(PlaneData)
2387       
2388    def OnDrawDistVP(event):
2389        # distance to view point
2390        indx = drawAtoms.GetSelectedRows()
2391        if not indx:
2392            print '***** ERROR - no atoms selected'
2393            return
2394        generalData = data['General']
2395        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
2396        drawingData = data['Drawing']
2397        viewPt = np.array(drawingData['viewPoint'][0])
2398        print ' Distance from view point at %.3f %.3f %.3f to:'%(viewPt[0],viewPt[1],viewPt[2])
2399        atomDData = drawingData['Atoms']
2400        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2401        cx = colLabels.index('x')
2402        cn = colLabels.index('Name')
2403        for i in indx:
2404            atom = atomDData[i]
2405            Dx = np.array(atom[cx:cx+3])-viewPt
2406            dist = np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0))
2407            print 'Atom: %8s (%12s) distance = %.3f'%(atom[cn],atom[cx+3],dist)
2408   
2409    def OnDrawDAT(event):
2410        #distance, angle, torsion
2411        indx = drawAtoms.GetSelectedRows()
2412        if len(indx) not in [2,3,4]:
2413            print '**** ERROR - wrong number of atoms for distance, angle or torsion calculation'
2414            return
2415        DATData = {}
2416        ocx,oct,ocs,cia = data['General']['AtomPtrs']
2417        drawingData = data['Drawing']
2418        atomData = data['Atoms']
2419        atomDData = drawingData['Atoms']
2420        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2421        cx = colLabels.index('x')
2422        cn = colLabels.index('Name')
2423        cid = colLabels.index('I/A')+8
2424        xyz = []
2425        Oxyz = []
2426        DATData['Natoms'] = len(indx)
2427        for i in indx:
2428            atom = atomDData[i]
2429            xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+4]) #also gets Sym Op
2430            id = FindAtomIndexByIDs(atomData,[atom[cid],],False)[0]
2431            Oxyz.append([id,]+atomData[id][cx+1:cx+4])
2432        DATData['Datoms'] = xyz
2433        DATData['Oatoms'] = Oxyz
2434        generalData = data['General']
2435        DATData['Name'] = generalData['Name']
2436        DATData['SGData'] = generalData['SGData']
2437        DATData['Cell'] = generalData['Cell'][1:] #+ volume
2438        if 'pId' in data:
2439            DATData['pId'] = data['pId']
2440            DATData['covData'] = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Covariance'))
2441        G2str.DisAglTor(DATData)
2442               
2443################################################################################
2444#### Draw Options page
2445################################################################################
2446
2447    def UpdateDrawOptions():
2448        import copy
2449        import wx.lib.colourselect as wcs
2450        generalData = data['General']
2451        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2452        SetupDrawingData()
2453        drawingData = data['Drawing']
2454        if generalData['Type'] == 'nuclear':
2455            pickChoice = ['Atoms','Bonds','Torsions','Planes']
2456        elif generalData['Type'] == 'macromolecular':
2457            pickChoice = ['Atoms','Residues','Chains','Bonds','Torsions','Planes','phi/psi']
2458
2459        def SlopSizer():
2460           
2461            def OnCameraPos(event):
2462                drawingData['cameraPos'] = cameraPos.GetValue()
2463                cameraPosTxt.SetLabel(' Camera Distance: '+'%.2f'%(drawingData['cameraPos']))
2464                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2465                G2plt.PlotStructure(G2frame,data)
2466
2467            def OnZclip(event):
2468                drawingData['Zclip'] = Zclip.GetValue()
2469                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2470                G2plt.PlotStructure(G2frame,data)
2471               
2472            def OnZstep(event):
2473                try:
2474                    step = float(Zstep.GetValue())
2475                    if not (0.01 <= step <= 1.0):
2476                        raise ValueError
2477                except ValueError:
2478                    step = drawingData['Zstep']
2479                drawingData['Zstep'] = step
2480                Zstep.SetValue('%.2fA'%(drawingData['Zstep']))
2481               
2482            def OnMoveZ(event):
2483                move = MoveZ.GetValue()*drawingData['Zstep']
2484                MoveZ.SetValue(0)
2485                VP = np.inner(Amat,np.array(drawingData['viewPoint'][0]))
2486                VD = np.inner(Amat,np.array(drawingData['viewDir']))
2487                VD /= np.sqrt(np.sum(VD**2))
2488                VP += move*VD
2489                VP = np.inner(Bmat,VP)
2490                drawingData['viewPoint'][0] = VP
2491                panel = dataDisplay.GetChildren()
2492                names = [child.GetName() for child in panel]
2493                panel[names.index('viewPoint')].SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))               
2494                G2plt.PlotStructure(G2frame,data)
2495               
2496            def OnVdWScale(event):
2497                drawingData['vdwScale'] = vdwScale.GetValue()/100.
2498                vdwScaleTxt.SetLabel(' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2499                G2plt.PlotStructure(G2frame,data)
2500   
2501            def OnEllipseProb(event):
2502                drawingData['ellipseProb'] = ellipseProb.GetValue()
2503                ellipseProbTxt.SetLabel(' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2504                G2plt.PlotStructure(G2frame,data)
2505   
2506            def OnBallScale(event):
2507                drawingData['ballScale'] = ballScale.GetValue()/100.
2508                ballScaleTxt.SetLabel(' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2509                G2plt.PlotStructure(G2frame,data)
2510
2511            def OnBondRadius(event):
2512                drawingData['bondRadius'] = bondRadius.GetValue()/100.
2513                bondRadiusTxt.SetLabel(' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2514                G2plt.PlotStructure(G2frame,data)
2515               
2516            def OnContourLevel(event):
2517                drawingData['contourLevel'] = contourLevel.GetValue()/100.
2518                contourLevelTxt.SetLabel(' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2519                G2plt.PlotStructure(G2frame,data)
2520
2521            def OnMapSize(event):
2522                drawingData['mapSize'] = mapSize.GetValue()/10.
2523                mapSizeTxt.SetLabel(' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2524                G2plt.PlotStructure(G2frame,data)
2525
2526           
2527            slopSizer = wx.BoxSizer(wx.HORIZONTAL)
2528            slideSizer = wx.FlexGridSizer(7,2)
2529            slideSizer.AddGrowableCol(1,1)
2530   
2531            cameraPosTxt = wx.StaticText(dataDisplay,-1,
2532                ' Camera Distance: '+'%.2f'%(drawingData['cameraPos']),name='cameraPos')
2533            slideSizer.Add(cameraPosTxt,0,wx.ALIGN_CENTER_VERTICAL)
2534            cameraPos = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=drawingData['cameraPos'],name='cameraSlider')
2535            cameraPos.SetRange(10,500)
2536            cameraPos.Bind(wx.EVT_SLIDER, OnCameraPos)
2537            slideSizer.Add(cameraPos,1,wx.EXPAND|wx.RIGHT)
2538           
2539            ZclipTxt = wx.StaticText(dataDisplay,-1,' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2540            slideSizer.Add(ZclipTxt,0,wx.ALIGN_CENTER_VERTICAL)
2541            Zclip = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=drawingData['Zclip'])
2542            Zclip.SetRange(1,99)
2543            Zclip.Bind(wx.EVT_SLIDER, OnZclip)
2544            slideSizer.Add(Zclip,1,wx.EXPAND|wx.RIGHT)
2545           
2546            ZstepSizer = wx.BoxSizer(wx.HORIZONTAL)
2547            ZstepSizer.Add(wx.StaticText(dataDisplay,-1,' Z step:'),0,wx.ALIGN_CENTER_VERTICAL)
2548            Zstep = wx.TextCtrl(dataDisplay,value='%.2f'%(drawingData['Zstep']),
2549                style=wx.TE_PROCESS_ENTER)
2550            Zstep.Bind(wx.EVT_TEXT_ENTER,OnZstep)
2551            Zstep.Bind(wx.EVT_KILL_FOCUS,OnZstep)
2552            ZstepSizer.Add(Zstep,0,wx.ALIGN_CENTER_VERTICAL)
2553            slideSizer.Add(ZstepSizer)
2554            MoveSizer = wx.BoxSizer(wx.HORIZONTAL)
2555            MoveSizer.Add(wx.StaticText(dataDisplay,-1,'   Press to step:'),0,wx.ALIGN_CENTER_VERTICAL)
2556            MoveZ = wx.SpinButton(dataDisplay,style=wx.SP_HORIZONTAL,size=wx.Size(100,20))
2557            MoveZ.SetValue(0)
2558            MoveZ.SetRange(-1,1)
2559            MoveZ.Bind(wx.EVT_SPIN, OnMoveZ)
2560            MoveSizer.Add(MoveZ)
2561            slideSizer.Add(MoveSizer,1,wx.EXPAND|wx.RIGHT)
2562           
2563            vdwScaleTxt = wx.StaticText(dataDisplay,-1,' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2564            slideSizer.Add(vdwScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2565            vdwScale = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['vdwScale']))
2566            vdwScale.Bind(wx.EVT_SLIDER, OnVdWScale)
2567            slideSizer.Add(vdwScale,1,wx.EXPAND|wx.RIGHT)
2568   
2569            ellipseProbTxt = wx.StaticText(dataDisplay,-1,' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2570            slideSizer.Add(ellipseProbTxt,0,wx.ALIGN_CENTER_VERTICAL)
2571            ellipseProb = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=drawingData['ellipseProb'])
2572            ellipseProb.SetRange(1,99)
2573            ellipseProb.Bind(wx.EVT_SLIDER, OnEllipseProb)
2574            slideSizer.Add(ellipseProb,1,wx.EXPAND|wx.RIGHT)
2575   
2576            ballScaleTxt = wx.StaticText(dataDisplay,-1,' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2577            slideSizer.Add(ballScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2578            ballScale = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['ballScale']))
2579            ballScale.Bind(wx.EVT_SLIDER, OnBallScale)
2580            slideSizer.Add(ballScale,1,wx.EXPAND|wx.RIGHT)
2581   
2582            bondRadiusTxt = wx.StaticText(dataDisplay,-1,' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2583            slideSizer.Add(bondRadiusTxt,0,wx.ALIGN_CENTER_VERTICAL)
2584            bondRadius = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['bondRadius']))
2585            bondRadius.SetRange(1,25)
2586            bondRadius.Bind(wx.EVT_SLIDER, OnBondRadius)
2587            slideSizer.Add(bondRadius,1,wx.EXPAND|wx.RIGHT)
2588           
2589            if generalData['Map']['rhoMax']:
2590                contourLevelTxt = wx.StaticText(dataDisplay,-1,' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2591                slideSizer.Add(contourLevelTxt,0,wx.ALIGN_CENTER_VERTICAL)
2592                contourLevel = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['contourLevel']))
2593                contourLevel.SetRange(1,100)
2594                contourLevel.Bind(wx.EVT_SLIDER, OnContourLevel)
2595                slideSizer.Add(contourLevel,1,wx.EXPAND|wx.RIGHT)
2596                mapSizeTxt = wx.StaticText(dataDisplay,-1,' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2597                slideSizer.Add(mapSizeTxt,0,wx.ALIGN_CENTER_VERTICAL)
2598                mapSize = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(10*drawingData['mapSize']))
2599                mapSize.SetRange(1,100)
2600                mapSize.Bind(wx.EVT_SLIDER, OnMapSize)
2601                slideSizer.Add(mapSize,1,wx.EXPAND|wx.RIGHT)
2602           
2603            slopSizer.Add(slideSizer,1,wx.EXPAND|wx.RIGHT)
2604            slopSizer.Add((10,5),0)
2605            slopSizer.SetMinSize(wx.Size(350,10))
2606            return slopSizer
2607           
2608        def ShowSizer():
2609           
2610            def OnBackColor(event):
2611                drawingData['backColor'] = event.GetValue()
2612                G2plt.PlotStructure(G2frame,data)
2613   
2614            def OnShowABC(event):
2615                drawingData['showABC'] = showABC.GetValue()
2616                G2plt.PlotStructure(G2frame,data)
2617   
2618            def OnShowUnitCell(event):
2619                drawingData['unitCellBox'] = unitCellBox.GetValue()
2620                G2plt.PlotStructure(G2frame,data)
2621   
2622            def OnShowHyd(event):
2623                drawingData['showHydrogen'] = showHydrogen.GetValue()
2624                FindBondsDraw()
2625                G2plt.PlotStructure(G2frame,data)
2626               
2627            def OnViewPoint(event):
2628                Obj = event.GetEventObject()
2629                viewPt = Obj.GetValue().split()
2630                try:
2631                    VP = [float(viewPt[i]) for i in range(3)]
2632                except (ValueError,IndexError):
2633                    VP = drawingData['viewPoint'][0]
2634                Obj.SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))
2635                drawingData['viewPoint'][0] = VP
2636                G2plt.PlotStructure(G2frame,data)
2637               
2638            def OnViewDir(event):
2639                Obj = event.GetEventObject()
2640                viewDir = Obj.GetValue().split()
2641                try:
2642                    Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2643                    VD = np.array([float(viewDir[i]) for i in range(3)])
2644                    VC = np.inner(Amat,VD)
2645                    VC /= np.sqrt(np.sum(VC**2))
2646                    V = np.array(drawingData['viewDir'])
2647                    VB = np.inner(Amat,V)
2648                    VB /= np.sqrt(np.sum(VB**2))
2649                    VX = np.cross(VC,VB)
2650                    A = acosd(max((2.-np.sum((VB-VC)**2))/2.,-1.))
2651                    QV = G2mth.AVdeg2Q(A,VX)
2652                    Q = drawingData['Quaternion']
2653                    drawingData['Quaternion'] = G2mth.prodQQ(Q,QV)
2654                except (ValueError,IndexError):
2655                    VD = drawingData['viewDir']
2656                Obj.SetValue('%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]))
2657                drawingData['viewDir'] = VD
2658                G2plt.PlotStructure(G2frame,data)
2659                               
2660            showSizer = wx.BoxSizer(wx.VERTICAL)           
2661            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2662            lineSizer.Add(wx.StaticText(dataDisplay,-1,' Background color:'),0,wx.ALIGN_CENTER_VERTICAL)
2663            backColor = wcs.ColourSelect(dataDisplay, -1,colour=drawingData['backColor'],size=wx.Size(25,25))
2664            backColor.Bind(wcs.EVT_COLOURSELECT, OnBackColor)
2665            lineSizer.Add(backColor,0,wx.ALIGN_CENTER_VERTICAL)
2666            lineSizer.Add(wx.StaticText(dataDisplay,-1,' View Dir.:'),0,wx.ALIGN_CENTER_VERTICAL)
2667            VD = drawingData['viewDir']
2668            viewDir = wx.TextCtrl(dataDisplay,value='%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]),
2669                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewDir')
2670            viewDir.Bind(wx.EVT_TEXT_ENTER,OnViewDir)
2671            viewDir.Bind(wx.EVT_KILL_FOCUS,OnViewDir)
2672            lineSizer.Add(viewDir,0,wx.ALIGN_CENTER_VERTICAL)
2673            showSizer.Add(lineSizer)
2674            showSizer.Add((0,5),0)
2675           
2676            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2677            showABC = wx.CheckBox(dataDisplay,-1,label=' Show view point?')
2678            showABC.Bind(wx.EVT_CHECKBOX, OnShowABC)
2679            showABC.SetValue(drawingData['showABC'])
2680            lineSizer.Add(showABC,0,wx.ALIGN_CENTER_VERTICAL)
2681            lineSizer.Add(wx.StaticText(dataDisplay,-1,' View Point:'),0,wx.ALIGN_CENTER_VERTICAL)
2682            VP = drawingData['viewPoint'][0]
2683            viewPoint = wx.TextCtrl(dataDisplay,value='%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]),
2684                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewPoint')
2685            viewPoint.Bind(wx.EVT_TEXT_ENTER,OnViewPoint)
2686            viewPoint.Bind(wx.EVT_KILL_FOCUS,OnViewPoint)
2687            lineSizer.Add(viewPoint,0,wx.ALIGN_CENTER_VERTICAL)
2688            showSizer.Add(lineSizer)
2689            showSizer.Add((0,5),0)
2690           
2691            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
2692   
2693            unitCellBox = wx.CheckBox(dataDisplay,-1,label=' Show unit cell?')
2694            unitCellBox.Bind(wx.EVT_CHECKBOX, OnShowUnitCell)
2695            unitCellBox.SetValue(drawingData['unitCellBox'])
2696            line2Sizer.Add(unitCellBox,0,wx.ALIGN_CENTER_VERTICAL)
2697   
2698            showHydrogen = wx.CheckBox(dataDisplay,-1,label=' Show hydrogens?')
2699            showHydrogen.Bind(wx.EVT_CHECKBOX, OnShowHyd)
2700            showHydrogen.SetValue(drawingData['showHydrogen'])
2701            line2Sizer.Add(showHydrogen,0,wx.ALIGN_CENTER_VERTICAL)
2702            showSizer.Add(line2Sizer)
2703            return showSizer
2704           
2705        def RadSizer():
2706           
2707            def OnSizeHatoms(event):
2708                try:
2709                    value = max(0.1,min(1.2,float(sizeH.GetValue())))
2710                except ValueError:
2711                    value = 0.5
2712                drawingData['sizeH'] = value
2713                sizeH.SetValue("%.2f"%(value))
2714                G2plt.PlotStructure(G2frame,data)
2715               
2716            def OnRadFactor(event):
2717                try:
2718                    value = max(0.1,min(1.2,float(radFactor.GetValue())))
2719                except ValueError:
2720                    value = 0.85
2721                drawingData['radiusFactor'] = value
2722                radFactor.SetValue("%.2f"%(value))
2723                FindBondsDraw()
2724                G2plt.PlotStructure(G2frame,data)
2725           
2726            radSizer = wx.BoxSizer(wx.HORIZONTAL)
2727            radSizer.Add(wx.StaticText(dataDisplay,-1,' Hydrogen radius, A:  '),0,wx.ALIGN_CENTER_VERTICAL)
2728            sizeH = wx.TextCtrl(dataDisplay,-1,value='%.2f'%(drawingData['sizeH']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2729            sizeH.Bind(wx.EVT_TEXT_ENTER,OnSizeHatoms)
2730            sizeH.Bind(wx.EVT_KILL_FOCUS,OnSizeHatoms)
2731            radSizer.Add(sizeH,0,wx.ALIGN_CENTER_VERTICAL)
2732   
2733            radSizer.Add(wx.StaticText(dataDisplay,-1,' Bond search factor:  '),0,wx.ALIGN_CENTER_VERTICAL)
2734            radFactor = wx.TextCtrl(dataDisplay,value='%.2f'%(drawingData['radiusFactor']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2735            radFactor.Bind(wx.EVT_TEXT_ENTER,OnRadFactor)
2736            radFactor.Bind(wx.EVT_KILL_FOCUS,OnRadFactor)
2737            radSizer.Add(radFactor,0,wx.ALIGN_CENTER_VERTICAL)
2738            return radSizer
2739
2740        G2frame.dataFrame.SetStatusText('')
2741        drawOptions.DestroyChildren()
2742        dataDisplay = wx.Panel(drawOptions)
2743        mainSizer = wx.BoxSizer(wx.VERTICAL)
2744        mainSizer.Add((5,5),0)
2745        mainSizer.Add(wx.StaticText(dataDisplay,-1,' Drawing controls:'),0,wx.ALIGN_CENTER_VERTICAL)
2746        mainSizer.Add((5,5),0)       
2747        mainSizer.Add(SlopSizer(),0)
2748        mainSizer.Add((5,5),0)
2749        mainSizer.Add(ShowSizer(),0,)
2750        mainSizer.Add((5,5),0)
2751        mainSizer.Add(RadSizer(),0,)
2752
2753        dataDisplay.SetSizer(mainSizer)
2754        Size = mainSizer.Fit(G2frame.dataFrame)
2755        Size[1] += 35                           #compensate for status bar
2756        dataDisplay.SetSize(Size)
2757        G2frame.dataFrame.setSizePosLeft(Size)
2758
2759################################################################################
2760####  Texture routines
2761################################################################################
2762       
2763    def UpdateTexture():
2764        G2frame.dataFrame.SetStatusText('')
2765        generalData = data['General']       
2766        SGData = generalData['SGData']
2767        try:
2768            textureData = generalData['SH Texture']
2769        except KeyError:            #fix old files!
2770            textureData = generalData['SH Texture'] = {'Order':0,'Model':'cylindrical',
2771                'Sample omega':[False,0.0],'Sample chi':[False,0.0],'Sample phi':[False,0.0],
2772                'SH Coeff':[False,{}],'SHShow':False,'PFhkl':[0,0,1],
2773                'PFxyz':[0,0,1.],'PlotType':'Pole figure'}
2774        if 'SHShow' not in textureData:     #another fix
2775            textureData.update({'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2776        try:                        #another fix!
2777            x = textureData['PlotType']
2778        except KeyError:
2779            textureData.update({'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2780        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
2781        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
2782        if generalData['doPawley'] and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequental results'):
2783            G2frame.dataFrame.RefineTexture.Enable(True)
2784        shAngles = ['omega','chi','phi']
2785       
2786        def SetSHCoef():
2787            cofNames = G2lat.GenSHCoeff(SGData['SGLaue'],SamSym[textureData['Model']],textureData['Order'])
2788            newSHCoef = dict(zip(cofNames,np.zeros(len(cofNames))))
2789            SHCoeff = textureData['SH Coeff'][1]
2790            for cofName in SHCoeff:
2791                if cofName in  cofNames:
2792                    newSHCoef[cofName] = SHCoeff[cofName]
2793            return newSHCoef
2794       
2795        def OnShOrder(event):
2796            Obj = event.GetEventObject()
2797            textureData['Order'] = int(Obj.GetValue())
2798            textureData['SH Coeff'][1] = SetSHCoef()
2799            wx.CallAfter(UpdateTexture)
2800            G2plt.PlotTexture(G2frame,data)
2801                       
2802        def OnShModel(event):
2803            Obj = event.GetEventObject()
2804            textureData['Model'] = Obj.GetValue()
2805            textureData['SH Coeff'][1] = SetSHCoef()
2806            wx.CallAfter(UpdateTexture)
2807            G2plt.PlotTexture(G2frame,data)
2808           
2809        def OnSHRefine(event):
2810            Obj = event.GetEventObject()
2811            textureData['SH Coeff'][0] = Obj.GetValue()
2812           
2813        def OnSHShow(event):
2814            Obj = event.GetEventObject()
2815            textureData['SHShow'] = Obj.GetValue()
2816            wx.CallAfter(UpdateTexture)
2817           
2818        def OnProjSel(event):
2819            Obj = event.GetEventObject()
2820            G2frame.Projection = Obj.GetValue()
2821            G2plt.PlotTexture(G2frame,data)
2822           
2823        def OnColorSel(event):
2824            Obj = event.GetEventObject()
2825            G2frame.ContourColor = Obj.GetValue()
2826            G2plt.PlotTexture(G2frame,data)
2827           
2828        def OnAngRef(event):
2829            Obj = event.GetEventObject()
2830            textureData[angIndx[Obj.GetId()]][0] = Obj.GetValue()
2831           
2832        def OnAngValue(event):
2833            Obj = event.GetEventObject()
2834            try:
2835                value =  float(Obj.GetValue())
2836            except ValueError:
2837                value = textureData[valIndx[Obj.GetId()]][1]
2838            Obj.SetValue('%8.2f'%(value))
2839            textureData[valIndx[Obj.GetId()]][1] = value
2840           
2841        def OnODFValue(event): 
2842            Obj = event.GetEventObject()
2843            try:
2844                value =  float(Obj.GetValue())
2845            except ValueError:
2846                value = textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]]
2847            Obj.SetValue('%8.3f'%(value))
2848            textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]] = value
2849            G2plt.PlotTexture(G2frame,data)
2850           
2851        def OnPfType(event):
2852            Obj = event.GetEventObject()
2853            textureData['PlotType'] = Obj.GetValue()
2854            wx.CallAfter(UpdateTexture)
2855            G2plt.PlotTexture(G2frame,data)
2856           
2857        def OnPFValue(event):
2858            Obj = event.GetEventObject()
2859            Saxis = Obj.GetValue().split()
2860            if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:               
2861                try:
2862                    hkl = [int(Saxis[i]) for i in range(3)]
2863                except (ValueError,IndexError):
2864                    hkl = textureData['PFhkl']
2865                if not np.any(np.array(hkl)):       #can't be all zeros!
2866                    hkl = textureData['PFhkl']
2867                Obj.SetValue('%d %d %d'%(hkl[0],hkl[1],hkl[2]))
2868                textureData['PFhkl'] = hkl
2869            else:
2870                try:
2871                    xyz = [float(Saxis[i]) for i in range(3)]
2872                except (ValueError,IndexError):
2873                    xyz = textureData['PFxyz']
2874                if not np.any(np.array(xyz)):       #can't be all zeros!
2875                    xyz = textureData['PFxyz']
2876                Obj.SetValue('%3.1f %3.1f %3.1f'%(xyz[0],xyz[1],xyz[2]))
2877                textureData['PFxyz'] = xyz
2878            G2plt.PlotTexture(G2frame,data)
2879
2880        if Texture.GetSizer():
2881            Texture.GetSizer().Clear(True)
2882        mainSizer = wx.BoxSizer(wx.VERTICAL)
2883        titleSizer = wx.BoxSizer(wx.HORIZONTAL)
2884        titleSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonics texture data for '+PhaseName+':'),0,wx.ALIGN_CENTER_VERTICAL)
2885        titleSizer.Add(wx.StaticText(Texture,-1,
2886            ' Texture Index J = %7.3f'%(G2lat.textureIndex(textureData['SH Coeff'][1]))),
2887            0,wx.ALIGN_CENTER_VERTICAL)
2888        mainSizer.Add(titleSizer,0)
2889        mainSizer.Add((0,5),0)
2890        shSizer = wx.FlexGridSizer(1,6,5,5)
2891        shSizer.Add(wx.StaticText(Texture,-1,'Texture model: '),0,wx.ALIGN_CENTER_VERTICAL)
2892        shModel = wx.ComboBox(Texture,-1,value=textureData['Model'],choices=shModels,
2893            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2894        shModel.Bind(wx.EVT_COMBOBOX,OnShModel)
2895        shSizer.Add(shModel,0,wx.ALIGN_CENTER_VERTICAL)
2896        shSizer.Add(wx.StaticText(Texture,-1,'  Harmonic order: '),0,wx.ALIGN_CENTER_VERTICAL)
2897        shOrder = wx.ComboBox(Texture,-1,value=str(textureData['Order']),choices=[str(2*i) for i in range(18)],
2898            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2899        shOrder.Bind(wx.EVT_COMBOBOX,OnShOrder)
2900        shSizer.Add(shOrder,0,wx.ALIGN_CENTER_VERTICAL)
2901        shRef = wx.CheckBox(Texture,-1,label=' Refine texture?')
2902        shRef.SetValue(textureData['SH Coeff'][0])
2903        shRef.Bind(wx.EVT_CHECKBOX, OnSHRefine)
2904        shSizer.Add(shRef,0,wx.ALIGN_CENTER_VERTICAL)
2905        shShow = wx.CheckBox(Texture,-1,label=' Show coeff.?')
2906        shShow.SetValue(textureData['SHShow'])
2907        shShow.Bind(wx.EVT_CHECKBOX, OnSHShow)
2908        shSizer.Add(shShow,0,wx.ALIGN_CENTER_VERTICAL)
2909        mainSizer.Add(shSizer,0,0)
2910        mainSizer.Add((0,5),0)
2911        PTSizer = wx.FlexGridSizer(2,4,5,5)
2912        PTSizer.Add(wx.StaticText(Texture,-1,' Texture plot type: '),0,wx.ALIGN_CENTER_VERTICAL)
2913        choices = ['Axial pole distribution','Pole figure','Inverse pole figure']           
2914        pfType = wx.ComboBox(Texture,-1,value=str(textureData['PlotType']),choices=choices,
2915            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2916        pfType.Bind(wx.EVT_COMBOBOX,OnPfType)
2917        PTSizer.Add(pfType,0,wx.ALIGN_CENTER_VERTICAL)
2918        if 'Axial' not in textureData['PlotType']:
2919            PTSizer.Add(wx.StaticText(Texture,-1,' Projection type: '),0,wx.ALIGN_CENTER_VERTICAL)
2920            projSel = wx.ComboBox(Texture,-1,value=G2frame.Projection,choices=['equal area','stereographic','3D display'],
2921                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2922            projSel.Bind(wx.EVT_COMBOBOX,OnProjSel)
2923            PTSizer.Add(projSel,0,wx.ALIGN_CENTER_VERTICAL)
2924        if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:
2925            PTSizer.Add(wx.StaticText(Texture,-1,' Pole figure HKL: '),0,wx.ALIGN_CENTER_VERTICAL)
2926            PH = textureData['PFhkl']
2927            pfVal = wx.TextCtrl(Texture,-1,'%d %d %d'%(PH[0],PH[1],PH[2]),style=wx.TE_PROCESS_ENTER)
2928        else:
2929            PTSizer.Add(wx.StaticText(Texture,-1,' Inverse pole figure XYZ: '),0,wx.ALIGN_CENTER_VERTICAL)
2930            PX = textureData['PFxyz']
2931            pfVal = wx.TextCtrl(Texture,-1,'%3.1f %3.1f %3.1f'%(PX[0],PX[1],PX[2]),style=wx.TE_PROCESS_ENTER)
2932        pfVal.Bind(wx.EVT_TEXT_ENTER,OnPFValue)
2933        pfVal.Bind(wx.EVT_KILL_FOCUS,OnPFValue)
2934        PTSizer.Add(pfVal,0,wx.ALIGN_CENTER_VERTICAL)
2935        if 'Axial' not in textureData['PlotType']:
2936            PTSizer.Add(wx.StaticText(Texture,-1,' Color scheme'),0,wx.ALIGN_CENTER_VERTICAL)
2937            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
2938            choice.sort()
2939            colorSel = wx.ComboBox(Texture,-1,value=G2frame.ContourColor,choices=choice,
2940                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2941            colorSel.Bind(wx.EVT_COMBOBOX,OnColorSel)
2942            PTSizer.Add(colorSel,0,wx.ALIGN_CENTER_VERTICAL)       
2943        mainSizer.Add(PTSizer,0,wx.ALIGN_CENTER_VERTICAL)
2944        mainSizer.Add((0,5),0)
2945        if textureData['SHShow']:
2946            mainSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonic coefficients: '),0,wx.ALIGN_CENTER_VERTICAL)
2947            mainSizer.Add((0,5),0)
2948            ODFSizer = wx.FlexGridSizer(2,8,2,2)
2949            ODFIndx = {}
2950            ODFkeys = textureData['SH Coeff'][1].keys()
2951            ODFkeys.sort()
2952            for item in ODFkeys:
2953                ODFSizer.Add(wx.StaticText(Texture,-1,item),0,wx.ALIGN_CENTER_VERTICAL)
2954                ODFval = wx.TextCtrl(Texture,wx.ID_ANY,'%8.3f'%(textureData['SH Coeff'][1][item]),style=wx.TE_PROCESS_ENTER)
2955                ODFIndx[ODFval.GetId()] = item
2956                ODFval.Bind(wx.EVT_TEXT_ENTER,OnODFValue)
2957                ODFval.Bind(wx.EVT_KILL_FOCUS,OnODFValue)
2958                ODFSizer.Add(ODFval,0,wx.ALIGN_CENTER_VERTICAL)
2959            mainSizer.Add(ODFSizer,0,wx.ALIGN_CENTER_VERTICAL)
2960            mainSizer.Add((0,5),0)
2961        mainSizer.Add((0,5),0)
2962        mainSizer.Add(wx.StaticText(Texture,-1,'Sample orientation angles: '),0,wx.ALIGN_CENTER_VERTICAL)
2963        mainSizer.Add((0,5),0)
2964        angSizer = wx.BoxSizer(wx.HORIZONTAL)
2965        angIndx = {}
2966        valIndx = {}
2967        for item in ['Sample omega','Sample chi','Sample phi']:
2968            angRef = wx.CheckBox(Texture,-1,label=item+': ')
2969            angRef.SetValue(textureData[item][0])
2970            angIndx[angRef.GetId()] = item
2971            angRef.Bind(wx.EVT_CHECKBOX, OnAngRef)
2972            angSizer.Add(angRef,0,wx.ALIGN_CENTER_VERTICAL)
2973            angVal = wx.TextCtrl(Texture,wx.ID_ANY,'%8.2f'%(textureData[item][1]),style=wx.TE_PROCESS_ENTER)
2974            valIndx[angVal.GetId()] = item
2975            angVal.Bind(wx.EVT_TEXT_ENTER,OnAngValue)
2976            angVal.Bind(wx.EVT_KILL_FOCUS,OnAngValue)
2977            angSizer.Add(angVal,0,wx.ALIGN_CENTER_VERTICAL)
2978            angSizer.Add((5,0),0)
2979        mainSizer.Add(angSizer,0,wx.ALIGN_CENTER_VERTICAL)
2980        Texture.SetSizer(mainSizer,True)
2981        mainSizer.Fit(G2frame.dataFrame)
2982        Size = mainSizer.GetMinSize()
2983        Size[0] += 40
2984        Size[1] = max(Size[1],250) + 35
2985        Texture.SetSize(Size)
2986        Texture.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
2987        Size[1] = min(Size[1],450)
2988        G2frame.dataFrame.setSizePosLeft(Size)
2989
2990################################################################################
2991##### DData routines
2992################################################################################
2993       
2994    def UpdateDData():
2995        G2frame.dataFrame.SetStatusText('')
2996        UseList = data['Histograms']
2997        if UseList:
2998            G2frame.dataFrame.DataMenu.Enable(G2gd.wxID_DATADELETE,True)
2999            G2frame.Refine.Enable(True)
3000        else:
3001            G2frame.dataFrame.DataMenu.Enable(G2gd.wxID_DATADELETE,False)
3002            G2frame.Refine.Enable(False)           
3003        generalData = data['General']       
3004        SGData = generalData['SGData']
3005        keyList = UseList.keys()
3006        keyList.sort()
3007        PWDR = any(['PWDR' in item for item in keyList])
3008        Indx = {}
3009       
3010        def PlotSizer():
3011
3012            def OnPlotSel(event):
3013                Obj = event.GetEventObject()
3014                generalData['Data plot type'] = Obj.GetStringSelection()
3015                wx.CallAfter(UpdateDData)
3016                G2plt.PlotSizeStrainPO(G2frame,data)
3017               
3018            def OnPOhkl(event):
3019                Obj = event.GetEventObject()
3020                Saxis = Obj.GetValue().split()
3021                try:
3022                    hkl = [int(Saxis[i]) for i in range(3)]
3023                except (ValueError,IndexError):
3024                    hkl = generalData['POhkl']
3025                if not np.any(np.array(hkl)):
3026                    hkl = generalData['POhkl']
3027                generalData['POhkl'] = hkl
3028                h,k,l = hkl
3029                Obj.SetValue('%3d %3d %3d'%(h,k,l)) 
3030                G2plt.PlotSizeStrainPO(G2frame,data)
3031           
3032            plotSizer = wx.BoxSizer(wx.VERTICAL)
3033            choice = ['None','Mustrain','Size','Preferred orientation']
3034            plotSel = wx.RadioBox(DData,-1,'Select plot type:',choices=choice,
3035                majorDimension=2,style=wx.RA_SPECIFY_COLS)
3036            plotSel.SetStringSelection(generalData['Data plot type'])
3037            plotSel.Bind(wx.EVT_RADIOBOX,OnPlotSel)   
3038            plotSizer.Add(plotSel)
3039            if generalData['Data plot type'] == 'Preferred orientation':
3040                POhklSizer = wx.BoxSizer(wx.HORIZONTAL)
3041                POhklSizer.Add(wx.StaticText(DData,-1,' Plot preferred orientation for H K L: '),0,wx.ALIGN_CENTER_VERTICAL)
3042                h,k,l = generalData['POhkl']
3043                poAxis = wx.TextCtrl(DData,-1,'%3d %3d %3d'%(h,k,l),style=wx.TE_PROCESS_ENTER)
3044                poAxis.Bind(wx.EVT_TEXT_ENTER,OnPOhkl)
3045                poAxis.Bind(wx.EVT_KILL_FOCUS,OnPOhkl)
3046                POhklSizer.Add(poAxis,0,wx.ALIGN_CENTER_VERTICAL)
3047                plotSizer.Add(POhklSizer)           
3048            return plotSizer
3049           
3050        def ScaleSizer():
3051           
3052            def OnScaleRef(event):
3053                Obj = event.GetEventObject()
3054                UseList[Indx[Obj.GetId()]]['Scale'][1] = Obj.GetValue()
3055               
3056            def OnScaleVal(event):
3057                Obj = event.GetEventObject()
3058                try:
3059                    scale = float(Obj.GetValue())
3060                    if scale > 0:
3061                        UseList[Indx[Obj.GetId()]]['Scale'][0] = scale
3062                except ValueError:
3063                    pass
3064                Obj.SetValue("%.4f"%(UseList[Indx[Obj.GetId()]]['Scale'][0]))          #reset in case of error
3065                           
3066            scaleSizer = wx.BoxSizer(wx.HORIZONTAL)
3067            if 'PWDR' in item:
3068                scaleRef = wx.CheckBox(DData,-1,label=' Phase fraction: ')
3069            elif 'HKLF' in item:
3070                scaleRef = wx.CheckBox(DData,-1,label=' Scale factor: ')               
3071            scaleRef.SetValue(UseList[item]['Scale'][1])
3072            Indx[scaleRef.GetId()] = item
3073            scaleRef.Bind(wx.EVT_CHECKBOX, OnScaleRef)
3074            scaleSizer.Add(scaleRef,0,wx.ALIGN_CENTER_VERTICAL)
3075            scaleVal = wx.TextCtrl(DData,wx.ID_ANY,
3076                '%.4f'%(UseList[item]['Scale'][0]),style=wx.TE_PROCESS_ENTER)
3077            Indx[scaleVal.GetId()] = item
3078            scaleVal.Bind(wx.EVT_TEXT_ENTER,OnScaleVal)
3079            scaleVal.Bind(wx.EVT_KILL_FOCUS,OnScaleVal)
3080            scaleSizer.Add(scaleVal,0,wx.ALIGN_CENTER_VERTICAL)
3081            return scaleSizer
3082           
3083        def OnUseData(event):
3084            Obj = event.GetEventObject()
3085            hist = Indx[Obj.GetId()]
3086            UseList[hist]['Use'] = Obj.GetValue()
3087           
3088        def OnShowData(event):
3089            Obj = event.GetEventObject()
3090            hist = Indx[Obj.GetId()]
3091            UseList[hist]['Show'] = Obj.GetValue()
3092            wx.CallAfter(UpdateDData)
3093            G2plt.PlotSizeStrainPO(G2frame,data)
3094           
3095        def OnCopyData(event):
3096            #how about HKLF data? This is only for PWDR data
3097            Obj = event.GetEventObject()
3098            hist = Indx[Obj.GetId()]
3099            sourceDict = UseList[hist]
3100            copyNames = ['Scale','Pref.Ori.','Size','Mustrain','HStrain','Extinction']
3101            copyDict = {}
3102            for name in copyNames: 
3103                copyDict[name] = copy.deepcopy(sourceDict[name])        #force copy
3104            keyList = ['All',]+UseList.keys()
3105            if UseList:
3106                copyList = []
3107                dlg = wx.MultiChoiceDialog(G2frame, 
3108                    'Copy parameters to which histograms?', 'Copy parameters', 
3109                    keyList, wx.CHOICEDLG_STYLE)
3110                try:
3111                    if dlg.ShowModal() == wx.ID_OK:
3112                        result = dlg.GetSelections()
3113                        for i in result: 
3114                            copyList.append(keyList[i])
3115                        if 'All' in copyList: 
3116                            copyList = keyList[1:]
3117                        for item in copyList:
3118                            UseList[item].update(copy.deepcopy(copyDict))
3119                        wx.CallAfter(UpdateDData)
3120                finally:
3121                    dlg.Destroy()
3122                   
3123        def OnCopyFlags(event):
3124            Obj = event.GetEventObject()
3125            hist = Indx[Obj.GetId()]
3126            sourceDict = UseList[hist]
3127            copyDict = {}
3128            copyNames = ['Scale','Pref.Ori.','Size','Mustrain','HStrain','Extinction']
3129            for name in copyNames:
3130                if name in ['Scale','Extinction','HStrain']:
3131                    copyDict[name] = sourceDict[name][1]
3132                elif name in ['Size','Mustrain']:
3133                    copyDict[name] = [sourceDict[name][0],sourceDict[name][2],sourceDict[name][4]]
3134                elif name == 'Pref.Ori.':
3135                    copyDict[name] = [sourceDict[name][0],sourceDict[name][2]]
3136                    if sourceDict[name][0] == 'SH':
3137                        SHterms = sourceDict[name][5]
3138                        SHflags = {}
3139                        for item in SHterms:
3140                            SHflags[item] = SHterms[item][1]
3141                        copyDict[name].append(SHflags)                       
3142            keyList = ['All',]+UseList.keys()
3143            if UseList:
3144                copyList = []
3145                dlg = wx.MultiChoiceDialog(G2frame, 
3146                    'Copy parameters to which histograms?', 'Copy parameters', 
3147                    keyList, wx.CHOICEDLG_STYLE)
3148                try:
3149                    if dlg.ShowModal() == wx.ID_OK:
3150                        result = dlg.GetSelections()
3151                        for i in result: 
3152                            copyList.append(keyList[i])
3153                        if 'All' in copyList: 
3154                            copyList = keyList[1:]
3155                        for item in copyList:
3156                            UseList[item]                           
3157                            for name in copyNames:
3158                                if name in ['Scale','Extinction','HStrain']:
3159                                    UseList[item][name][1] = copy.copy(copyDict[name])
3160                                elif name in ['Size','Mustrain']:
3161                                    UseList[item][name][0] = copy.copy(copyDict[name][0])
3162                                    UseList[item][name][2] = copy.copy(copyDict[name][1])
3163                                    UseList[item][name][4] = copy.copy(copyDict[name][2])
3164                                elif name == 'Pref.Ori.':
3165                                    UseList[item][name][0] = copy.copy(copyDict[name][0])
3166                                    UseList[item][name][2] = copy.copy(copyDict[name][1])
3167                                    if sourceDict[name][0] == 'SH':
3168                                        SHflags = copy.copy(copyDict[name][2])
3169                                        SHterms = copy.copy(sourceDict[name][5])
3170                                        for item in SHflags:
3171                                            SHterms[item][1] = copy.copy(SHflags[item])                                             
3172                        wx.CallAfter(UpdateDData)
3173                finally:
3174                    dlg.Destroy()
3175           
3176           
3177        def OnLGmixRef(event):
3178            Obj = event.GetEventObject()
3179            hist,name = Indx[Obj.GetId()]
3180            UseList[hist][name][2][2] = Obj.GetValue()
3181           
3182        def OnLGmixVal(event):
3183            Obj = event.GetEventObject()
3184            hist,name = Indx[Obj.GetId()]
3185            try:
3186                value = float(Obj.GetValue())
3187                if 0.1 <= value <= 1:
3188                    UseList[hist][name][1][2] = value
3189                else:
3190                    raise ValueError
3191            except ValueError:
3192                pass
3193            Obj.SetValue("%.4f"%(UseList[hist][name][1][2]))          #reset in case of error
3194
3195        def OnSizeType(event):
3196            Obj = event.GetEventObject()
3197            hist = Indx[Obj.GetId()]
3198            UseList[hist]['Size'][0] = Obj.GetValue()
3199            G2plt.PlotSizeStrainPO(G2frame,data)
3200            wx.CallAfter(UpdateDData)
3201           
3202        def OnSizeRef(event):
3203            Obj = event.GetEventObject()
3204            hist,pid = Indx[Obj.GetId()]
3205            if UseList[hist]['Size'][0] == 'ellipsoidal':
3206                UseList[hist]['Size'][5][pid] = Obj.GetValue()               
3207            else:
3208                UseList[hist]['Size'][2][pid] = Obj.GetValue()
3209           
3210        def OnSizeVal(event):
3211            Obj = event.GetEventObject()
3212            hist,pid = Indx[Obj.GetId()]
3213            if UseList[hist]['Size'][0] == 'ellipsoidal':
3214                try:
3215                    size = float(Obj.GetValue())
3216                    if pid < 3 and size <= 0.001:            #10A lower limit!
3217                        raise ValueError
3218                    UseList[hist]['Size'][4][pid] = size                   
3219                except ValueError:
3220                    pass
3221                Obj.SetValue("%.3f"%(UseList[hist]['Size'][4][pid]))          #reset in case of error
3222            else:
3223                try:
3224                    size = float(Obj.GetValue())
3225                    if size <= 0.001:            #10A lower limit!
3226                        raise ValueError
3227                    UseList[hist]['Size'][1][pid] = size
3228                except ValueError:
3229                    pass
3230                Obj.SetValue("%.3f"%(UseList[hist]['Size'][1][pid]))          #reset in case of error
3231            G2plt.PlotSizeStrainPO(G2frame,data)
3232           
3233        def OnSizeAxis(event):           
3234            Obj = event.GetEventObject()
3235            hist = Indx[Obj.GetId()]
3236            Saxis = Obj.GetValue().split()
3237            try:
3238                hkl = [int(Saxis[i]) for i in range(3)]
3239            except (ValueError,IndexError):
3240                hkl = UseList[hist]['Size'][3]
3241            if not np.any(np.array(hkl)):
3242                hkl = UseList[hist]['Size'][3]
3243            UseList[hist]['Size'][3] = hkl
3244            h,k,l = hkl
3245            Obj.SetValue('%3d %3d %3d'%(h,k,l)) 
3246                       
3247        def OnStrainType(event):
3248            Obj = event.GetEventObject()
3249            hist = Indx[Obj.GetId()]
3250            UseList[hist]['Mustrain'][0] = Obj.GetValue()
3251            wx.CallAfter(UpdateDData)
3252            G2plt.PlotSizeStrainPO(G2frame,data)
3253           
3254        def OnStrainRef(event):
3255            Obj = event.GetEventObject()
3256            hist,pid = Indx[Obj.GetId()]
3257            if UseList[hist]['Mustrain'][0] == 'generalized':
3258                UseList[hist]['Mustrain'][5][pid] = Obj.GetValue()
3259            else:
3260                UseList[hist]['Mustrain'][2][pid] = Obj.GetValue()
3261           
3262        def OnStrainVal(event):
3263            Snames = G2spc.MustrainNames(SGData)
3264            Obj = event.GetEventObject()
3265            hist,pid = Indx[Obj.GetId()]
3266            try:
3267                strain = float(Obj.GetValue())
3268                if UseList[hist]['Mustrain'][0] == 'generalized':
3269                    if '4' in Snames[pid] and strain < 0:
3270                        raise ValueError
3271                    UseList[hist]['Mustrain'][4][pid] = strain
3272                else:
3273                    if strain <= 0:
3274                        raise ValueError
3275                    UseList[hist]['Mustrain'][1][pid] = strain
3276            except ValueError:
3277                pass
3278            if UseList[hist]['Mustrain'][0] == 'generalized':
3279                Obj.SetValue("%.3f"%(UseList[hist]['Mustrain'][4][pid]))          #reset in case of error
3280            else:
3281                Obj.SetValue("%.1f"%(UseList[hist]['Mustrain'][1][pid]))          #reset in case of error
3282            G2plt.PlotSizeStrainPO(G2frame,data)
3283           
3284        def OnStrainAxis(event):
3285            Obj = event.GetEventObject()
3286            hist = Indx[Obj.GetId()]
3287            Saxis = Obj.GetValue().split()
3288            try:
3289                hkl = [int(Saxis[i]) for i in range(3)]
3290            except (ValueError,IndexError):
3291                hkl = UseList[hist]['Mustrain'][3]
3292            if not np.any(np.array(hkl)):
3293                hkl = UseList[hist]['Mustrain'][3]
3294            UseList[hist]['Mustrain'][3] = hkl
3295            h,k,l = hkl
3296            Obj.SetValue('%3d %3d %3d'%(h,k,l)) 
3297            G2plt.PlotSizeStrainPO(G2frame,data)
3298           
3299        def OnHstrainRef(event):
3300            Obj = event.GetEventObject()
3301            hist,pid = Indx[Obj.GetId()]
3302            UseList[hist]['HStrain'][1][pid] = Obj.GetValue()
3303           
3304        def OnHstrainVal(event):
3305            Snames = G2spc.HStrainNames(SGData)
3306            Obj = event.GetEventObject()
3307            hist,pid = Indx[Obj.GetId()]
3308            try:
3309                strain = float(Obj.GetValue())
3310                UseList[hist]['HStrain'][0][pid] = strain
3311            except ValueError:
3312                pass
3313            Obj.SetValue("%.5f"%(UseList[hist]['HStrain'][0][pid]))          #reset in case of error
3314
3315        def OnPOVal(event):
3316            Obj = event.GetEventObject()
3317            hist = Indx[Obj.GetId()]
3318            try:
3319                mdVal = float(Obj.GetValue())
3320                if mdVal > 0:
3321                    UseList[hist]['Pref.Ori.'][1] = mdVal
3322            except ValueError:
3323                pass
3324            Obj.SetValue("%.3f"%(UseList[hist]['Pref.Ori.'][1]))          #reset in case of error
3325           
3326        def OnPOAxis(event):
3327            Obj = event.GetEventObject()
3328            hist = Indx[Obj.GetId()]
3329            Saxis = Obj.GetValue().split()
3330            try:
3331                hkl = [int(Saxis[i]) for i in range(3)]
3332            except (ValueError,IndexError):
3333                hkl = UseList[hist]['Pref.Ori.'][3]
3334            if not np.any(np.array(hkl)):
3335                hkl = UseList[hist]['Pref.Ori.'][3]
3336            UseList[hist]['Pref.Ori.'][3] = hkl
3337            h,k,l = hkl
3338            Obj.SetValue('%3d %3d %3d'%(h,k,l)) 
3339           
3340        def OnPOOrder(event):
3341            Obj = event.GetEventObject()
3342            hist = Indx[Obj.GetId()]
3343            Order = int(Obj.GetValue())
3344            UseList[hist]['Pref.Ori.'][4] = Order
3345            UseList[hist]['Pref.Ori.'][5] = SetPOCoef(Order,hist)
3346            wx.CallAfter(UpdateDData)
3347
3348        def OnPOType(event):
3349            Obj = event.GetEventObject()
3350            hist = Indx[Obj.GetId()]
3351            if 'March' in Obj.GetValue():
3352                UseList[hist]['Pref.Ori.'][0] = 'MD'
3353            else:
3354                UseList[hist]['Pref.Ori.'][0] = 'SH'
3355            wx.CallAfter(UpdateDData)           
3356   
3357        def OnPORef(event):
3358            Obj = event.GetEventObject()
3359            hist = Indx[Obj.GetId()]
3360            UseList[hist]['Pref.Ori.'][2] = Obj.GetValue()
3361               
3362        def SetPOCoef(Order,hist):
3363            cofNames = G2lat.GenSHCoeff(SGData['SGLaue'],'0',Order,False)     #cylindrical & no M
3364            newPOCoef = dict(zip(cofNames,np.zeros(len(cofNames))))
3365            POCoeff = UseList[hist]['Pref.Ori.'][5]
3366            for cofName in POCoeff:
3367                if cofName in  cofNames:
3368                    newPOCoef[cofName] = POCoeff[cofName]
3369            return newPOCoef
3370       
3371        def OnExtRef(event):
3372            Obj = event.GetEventObject()
3373            UseList[Indx[Obj.GetId()]]['Extinction'][1] = Obj.GetValue()
3374           
3375        def OnExtVal(event):
3376            Obj = event.GetEventObject()
3377            try:
3378                ext = float(Obj.GetValue())
3379                if ext >= 0:
3380                    UseList[Indx[Obj.GetId()]]['Extinction'][0] = ext
3381            except ValueError:
3382                pass
3383            Obj.SetValue("%.2f"%(UseList[Indx[Obj.GetId()]]['Extinction'][0]))
3384           
3385        def OnTbarVal(event):
3386            Obj = event.GetEventObject()
3387            try:
3388                tbar = float(Obj.GetValue())
3389                if tbar >= 0:
3390                    UseList[Indx[Obj.GetId()]]['Extinction'][2]['Tbar'] = tbar
3391            except ValueError:
3392                pass
3393            Obj.SetValue("%.2f"%(UseList[Indx[Obj.GetId()]]['Extinction'][2]['Tbar']))
3394           
3395        def OnEval(event):
3396            Obj = event.GetEventObject()
3397            item = Indx[Obj.GetId()]
3398            try:
3399                val = float(Obj.GetValue())
3400                if val >= 0:
3401                    UseList[item[0]]['Extinction'][2][item[1]][0] = val
3402            except ValueError:
3403                pass
3404            Obj.SetValue("%9.3g"%(UseList[item[0]]['Extinction'][2][item[1]][0]))
3405           
3406        def OnEref(event):
3407            Obj = event.GetEventObject()
3408            item = Indx[Obj.GetId()]
3409            UseList[item[0]]['Extinction'][2][item[1]][1] = Obj.GetValue()
3410
3411        def OnSCExtType(event):
3412            Obj = event.GetEventObject()
3413            item = Indx[Obj.GetId()]
3414            UseList[item[0]]['Extinction'][item[1]] = Obj.GetValue()
3415            wx.CallAfter(UpdateDData)
3416               
3417        def checkAxis(axis):
3418            if not np.any(np.array(axis)):
3419                return False
3420            return axis
3421           
3422        def TopSizer(name,choices,parm,OnType):
3423            topSizer = wx.BoxSizer(wx.HORIZONTAL)
3424            topSizer.Add(wx.StaticText(DData,-1,name),0,wx.ALIGN_CENTER_VERTICAL)
3425            sizeType = wx.ComboBox(DData,wx.ID_ANY,value=UseList[item][parm][0],choices=choices,
3426                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3427            sizeType.Bind(wx.EVT_COMBOBOX, OnType)
3428            Indx[sizeType.GetId()] = item
3429            topSizer.Add(sizeType)
3430            topSizer.Add((5,0),0)
3431            return topSizer
3432           
3433        def LGmixSizer(name,OnVal,OnRef):
3434            lgmixSizer = wx.BoxSizer(wx.HORIZONTAL)
3435            lgmixRef = wx.CheckBox(DData,-1,label='LGmix')
3436            lgmixRef.thisown = False
3437            lgmixRef.SetValue(UseList[item][name][2][2])
3438            Indx[lgmixRef.GetId()] = [item,name]
3439            lgmixRef.Bind(wx.EVT_CHECKBOX, OnRef)
3440            lgmixSizer.Add(lgmixRef,0,wx.ALIGN_CENTER_VERTICAL)
3441            lgmixVal = wx.TextCtrl(DData,wx.ID_ANY,
3442                '%.4f'%(UseList[item][name][1][2]),style=wx.TE_PROCESS_ENTER)
3443            Indx[lgmixVal.GetId()] = [item,name]
3444            lgmixVal.Bind(wx.EVT_TEXT_ENTER,OnVal)
3445            lgmixVal.Bind(wx.EVT_KILL_FOCUS,OnVal)
3446            lgmixSizer.Add(lgmixVal,0,wx.ALIGN_CENTER_VERTICAL)
3447            return lgmixSizer
3448                       
3449        def IsoSizer(name,parm,fmt,OnVal,OnRef):
3450            isoSizer = wx.BoxSizer(wx.HORIZONTAL)
3451            sizeRef = wx.CheckBox(DData,-1,label=name)
3452            sizeRef.thisown = False
3453            sizeRef.SetValue(UseList[item][parm][2][0])
3454            Indx[sizeRef.GetId()] = [item,0]
3455            sizeRef.Bind(wx.EVT_CHECKBOX, OnRef)
3456            isoSizer.Add(sizeRef,0,wx.ALIGN_CENTER_VERTICAL)
3457            sizeVal = wx.TextCtrl(DData,wx.ID_ANY,
3458                fmt%(UseList[item][parm][1][0]),style=wx.TE_PROCESS_ENTER)
3459            Indx[sizeVal.GetId()] = [item,0]
3460            sizeVal.Bind(wx.EVT_TEXT_ENTER,OnVal)
3461            sizeVal.Bind(wx.EVT_KILL_FOCUS,OnVal)
3462            isoSizer.Add(sizeVal,0,wx.ALIGN_CENTER_VERTICAL)
3463            return isoSizer
3464           
3465        def UniSizer(parm,OnAxis):
3466            uniSizer = wx.BoxSizer(wx.HORIZONTAL)
3467            uniSizer.Add(wx.StaticText(DData,-1,' Unique axis, H K L: '),0,wx.ALIGN_CENTER_VERTICAL)
3468            h,k,l = UseList[item][parm][3]
3469            Axis = wx.TextCtrl(DData,-1,'%3d %3d %3d'%(h,k,l),style=wx.TE_PROCESS_ENTER)
3470            Indx[Axis.GetId()] = item
3471            Axis.Bind(wx.EVT_TEXT_ENTER,OnAxis)
3472            Axis.Bind(wx.EVT_KILL_FOCUS,OnAxis)
3473            uniSizer.Add(Axis,0,wx.ALIGN_CENTER_VERTICAL)
3474            return uniSizer
3475           
3476        def UniDataSizer(parmName,parm,fmt,OnVal,OnRef):
3477            dataSizer = wx.BoxSizer(wx.HORIZONTAL)
3478            parms = zip([' Equatorial '+parmName,' Axial '+parmName],
3479                UseList[item][parm][1],UseList[item][parm][2],range(2))
3480            for Pa,val,ref,id in parms:
3481                sizeRef = wx.CheckBox(DData,-1,label=Pa)
3482                sizeRef.thisown = False
3483                sizeRef.SetValue(ref)
3484                Indx[sizeRef.GetId()] = [item,id]
3485                sizeRef.Bind(wx.EVT_CHECKBOX, OnRef)
3486                dataSizer.Add(sizeRef,0,wx.ALIGN_CENTER_VERTICAL)
3487                sizeVal = wx.TextCtrl(DData,wx.ID_ANY,fmt%(val),style=wx.TE_PROCESS_ENTER)
3488                Indx[sizeVal.GetId()] = [item,id]
3489                sizeVal.Bind(wx.EVT_TEXT_ENTER,OnVal)
3490                sizeVal.Bind(wx.EVT_KILL_FOCUS,OnVal)
3491                dataSizer.Add(sizeVal,0,wx.ALIGN_CENTER_VERTICAL)
3492                dataSizer.Add((5,0),0)
3493            return dataSizer
3494           
3495        def EllSizeDataSizer():
3496            parms = zip(['S11','S22','S33','S12','S13','S23'],UseList[item]['Size'][4],
3497                UseList[item]['Size'][5],range(6))
3498            dataSizer = wx.FlexGridSizer(1,6,5,5)
3499            for Pa,val,ref,id in parms:
3500                sizeRef = wx.CheckBox(DData,-1,label=Pa)
3501                sizeRef.thisown = False
3502                sizeRef.SetValue(ref)
3503                Indx[sizeRef.GetId()] = [item,id]
3504                sizeRef.Bind(wx.EVT_CHECKBOX, OnSizeRef)
3505                dataSizer.Add(sizeRef,0,wx.ALIGN_CENTER_VERTICAL)
3506                sizeVal = wx.TextCtrl(DData,wx.ID_ANY,'%.3f'%(val),style=wx.TE_PROCESS_ENTER)
3507                Indx[sizeVal.GetId()] = [item,id]
3508                sizeVal.Bind(wx.EVT_TEXT_ENTER,OnSizeVal)
3509                sizeVal.Bind(wx.EVT_KILL_FOCUS,OnSizeVal)
3510                dataSizer.Add(sizeVal,0,wx.ALIGN_CENTER_VERTICAL)
3511            return dataSizer
3512           
3513        def GenStrainDataSizer():
3514            Snames = G2spc.MustrainNames(SGData)
3515            numb = len(Snames)
3516            if len(UseList[item]['Mustrain'][4]) < numb:
3517                UseList[item]['Mustrain'][4] = numb*[0.0,]
3518                UseList[item]['Mustrain'][5] = numb*[False,]
3519            parms = zip(Snames,UseList[item]['Mustrain'][4],UseList[item]['Mustrain'][5],range(numb))
3520            dataSizer = wx.FlexGridSizer(1,6,5,5)
3521            for Pa,val,ref,id in parms:
3522                strainRef = wx.CheckBox(DData,-1,label=Pa)
3523                strainRef.thisown = False
3524                strainRef.SetValue(ref)
3525                Indx[strainRef.GetId()] = [item,id]
3526                strainRef.Bind(wx.EVT_CHECKBOX, OnStrainRef)
3527                dataSizer.Add(strainRef,0,wx.ALIGN_CENTER_VERTICAL)
3528                strainVal = wx.TextCtrl(DData,wx.ID_ANY,'%.5f'%(val),style=wx.TE_PROCESS_ENTER)
3529                Indx[strainVal.GetId()] = [item,id]
3530                strainVal.Bind(wx.EVT_TEXT_ENTER,OnStrainVal)
3531                strainVal.Bind(wx.EVT_KILL_FOCUS,OnStrainVal)
3532                dataSizer.Add(strainVal,0,wx.ALIGN_CENTER_VERTICAL)
3533            return dataSizer
3534           
3535        def HstrainSizer():
3536            hstrainSizer = wx.FlexGridSizer(1,6,5,5)
3537            Hsnames = G2spc.HStrainNames(SGData)
3538            parms = zip(Hsnames,UseList[item]['HStrain'][0],UseList[item]['HStrain'][1],range(len(Hsnames)))
3539            for Pa,val,ref,id in parms:
3540                hstrainRef = wx.CheckBox(DData,-1,label=Pa)
3541                hstrainRef.thisown = False
3542                hstrainRef.SetValue(ref)
3543                Indx[hstrainRef.GetId()] = [item,id]
3544                hstrainRef.Bind(wx.EVT_CHECKBOX, OnHstrainRef)
3545                hstrainSizer.Add(hstrainRef,0,wx.ALIGN_CENTER_VERTICAL)
3546                hstrainVal = wx.TextCtrl(DData,wx.ID_ANY,'%.5f'%(val),style=wx.TE_PROCESS_ENTER)
3547                Indx[hstrainVal.GetId()] = [item,id]
3548                hstrainVal.Bind(wx.EVT_TEXT_ENTER,OnHstrainVal)
3549                hstrainVal.Bind(wx.EVT_KILL_FOCUS,OnHstrainVal)
3550                hstrainSizer.Add(hstrainVal,0,wx.ALIGN_CENTER_VERTICAL)
3551            return hstrainSizer
3552           
3553        def PoTopSizer(POData):
3554            poSizer = wx.FlexGridSizer(1,6,5,5)
3555            choice = ['March-Dollase','Spherical harmonics']
3556            POtype = choice[['MD','SH'].index(POData[0])]
3557            poSizer.Add(wx.StaticText(DData,-1,' Preferred orientation model '),0,wx.ALIGN_CENTER_VERTICAL)
3558            POType = wx.ComboBox(DData,wx.ID_ANY,value=POtype,choices=choice,
3559                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3560            Indx[POType.GetId()] = item
3561            POType.Bind(wx.EVT_COMBOBOX, OnPOType)
3562            poSizer.Add(POType)
3563            if POData[0] == 'SH':
3564                poSizer.Add(wx.StaticText(DData,-1,' Harmonic order: '),0,wx.ALIGN_CENTER_VERTICAL)
3565                poOrder = wx.ComboBox(DData,wx.ID_ANY,value=str(POData[4]),choices=[str(2*i) for i in range(18)],
3566                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
3567                Indx[poOrder.GetId()] = item
3568                poOrder.Bind(wx.EVT_COMBOBOX,OnPOOrder)
3569                poSizer.Add(poOrder,0,wx.ALIGN_CENTER_VERTICAL)
3570                poRef = wx.CheckBox(DData,-1,label=' Refine? ')
3571                poRef.SetValue(POData[2])
3572                Indx[poRef.GetId()] = item
3573                poRef.Bind(wx.EVT_CHECKBOX,OnPORef)
3574                poSizer.Add(poRef,0,wx.ALIGN_CENTER_VERTICAL)
3575            return poSizer
3576           
3577        def MDDataSizer(POData):
3578            poSizer = wx.BoxSizer(wx.HORIZONTAL)
3579            poRef = wx.CheckBox(DData,-1,label=' March-Dollase ratio: ')
3580            poRef.SetValue(POData[2])
3581            Indx[poRef.GetId()] = item
3582            poRef.Bind(wx.EVT_CHECKBOX,OnPORef)
3583            poSizer.Add(poRef,0,wx.ALIGN_CENTER_VERTICAL)
3584            poVal = wx.TextCtrl(DData,wx.ID_ANY,
3585                '%.3f'%(POData[1]),style=wx.TE_PROCESS_ENTER)
3586            Indx[poVal.GetId()] = item
3587            poVal.Bind(wx.EVT_TEXT_ENTER,OnPOVal)
3588            poVal.Bind(wx.EVT_KILL_FOCUS,OnPOVal)
3589            poSizer.Add(poVal,0,wx.ALIGN_CENTER_VERTICAL)
3590            poSizer.Add(wx.StaticText(DData,-1,' Unique axis, H K L: '),0,wx.ALIGN_CENTER_VERTICAL)
3591            h,k,l =POData[3]
3592            poAxis = wx.TextCtrl(DData,-1,'%3d %3d %3d'%(h,k,l),style=wx.TE_PROCESS_ENTER)
3593            Indx[poAxis.GetId()] = item
3594            poAxis.Bind(wx.EVT_TEXT_ENTER,OnPOAxis)
3595            poAxis.Bind(wx.EVT_KILL_FOCUS,OnPOAxis)
3596            poSizer.Add(poAxis,0,wx.ALIGN_CENTER_VERTICAL)
3597            return poSizer
3598           
3599        def SHDataSizer(POData):
3600            textJ = G2lat.textureIndex(POData[5])
3601            mainSizer.Add(wx.StaticText(DData,-1,' Spherical harmonic coefficients: '+'Texture index: %.3f'%(textJ)),0,wx.ALIGN_CENTER_VERTICAL)
3602            mainSizer.Add((0,5),0)
3603            ODFSizer = wx.FlexGridSizer(2,8,2,2)
3604            ODFIndx = {}
3605            ODFkeys = POData[5].keys()
3606            ODFkeys.sort()
3607            for odf in ODFkeys:
3608                ODFSizer.Add(wx.StaticText(DData,-1,odf),0,wx.ALIGN_CENTER_VERTICAL)
3609                ODFval = wx.TextCtrl(DData,wx.ID_ANY,'%8.3f'%(POData[5][odf]),style=wx.TE_PROCESS_ENTER)
3610                ODFIndx[ODFval.GetId()] = odf
3611#                ODFval.Bind(wx.EVT_TEXT_ENTER,OnODFValue)
3612#                ODFval.Bind(wx.EVT_KILL_FOCUS,OnODFValue)
3613                ODFSizer.Add(ODFval,0,wx.ALIGN_CENTER_VERTICAL)
3614            return ODFSizer
3615           
3616        def ExtSizer():           
3617            extSizer = wx.BoxSizer(wx.HORIZONTAL)
3618            extRef = wx.CheckBox(DData,-1,label=' Extinction: ')
3619            extRef.SetValue(UseList[item]['Extinction'][1])
3620            Indx[extRef.GetId()] = item
3621            extRef.Bind(wx.EVT_CHECKBOX, OnExtRef)
3622            extSizer.Add(extRef,0,wx.ALIGN_CENTER_VERTICAL)
3623            extVal = wx.TextCtrl(DData,wx.ID_ANY,
3624                '%.2f'%(UseList[item]['Extinction'][0]),style=wx.TE_PROCESS_ENTER)
3625            Indx[extVal.GetId()] = item
3626            extVal.Bind(wx.EVT_TEXT_ENTER,OnExtVal)
3627            extVal.Bind(wx.EVT_KILL_FOCUS,OnExtVal)
3628            extSizer.Add(extVal,0,wx.ALIGN_CENTER_VERTICAL)
3629            return extSizer
3630       
3631        def SCExtSizer():
3632            extSizer = wx.BoxSizer(wx.VERTICAL)
3633            typeSizer = wx.BoxSizer(wx.HORIZONTAL)           
3634            typeSizer.Add(wx.StaticText(DData,-1,' Extinction type: '),0,wx.ALIGN_CENTER_VERTICAL)
3635            Choices = ['Primary','Secondary Type I','Secondary Type II','Secondary Type I & II']
3636            typeTxt = wx.ComboBox(DData,-1,choices=Choices,value=UseList[item]['Extinction'][1],
3637                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3638            Indx[typeTxt.GetId()] = [item,1]
3639            typeTxt.Bind(wx.EVT_COMBOBOX,OnSCExtType)
3640            typeSizer.Add(typeTxt)
3641            typeSizer.Add(wx.StaticText(DData,-1,' Approx: '),0,wx.ALIGN_CENTER_VERTICAL)
3642            Choices=['Lorentzian','Gaussian']
3643            approxTxT = wx.ComboBox(DData,-1,choices=Choices,value=UseList[item]['Extinction'][0],
3644                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3645            Indx[approxTxT.GetId()] = [item,0]
3646            approxTxT.Bind(wx.EVT_COMBOBOX,OnSCExtType)
3647            typeSizer.Add(approxTxT)
3648            extSizer.Add(typeSizer,0,wx.ALIGN_CENTER_VERTICAL)
3649            extSizer.Add((0,5),)
3650            valSizer =wx.BoxSizer(wx.HORIZONTAL)
3651            valSizer.Add(wx.StaticText(DData,-1,' Tbar(mm):'),0,wx.ALIGN_CENTER_VERTICAL)
3652            tbarVal = wx.TextCtrl(DData,wx.ID_ANY,
3653                '%.3f'%(UseList[item]['Extinction'][2]['Tbar']),style=wx.TE_PROCESS_ENTER)
3654            Indx[tbarVal.GetId()] = item
3655            tbarVal.Bind(wx.EVT_TEXT_ENTER,OnTbarVal)
3656            tbarVal.Bind(wx.EVT_KILL_FOCUS,OnTbarVal)
3657            valSizer.Add(tbarVal,0,wx.ALIGN_CENTER_VERTICAL)
3658            if 'Primary' in UseList[item]['Extinction'][1]:
3659                Ekey = ['Ep',]
3660            elif 'Secondary Type II' == UseList[item]['Extinction'][1]:
3661                Ekey = ['Es',]
3662            elif 'Secondary Type I' == UseList[item]['Extinction'][1]:
3663                Ekey = ['Eg',]
3664            else:
3665                Ekey = ['Eg','Es']
3666            for ekey in Ekey:
3667                Eref = wx.CheckBox(DData,-1,label=ekey+' : ')
3668                Eref.SetValue(UseList[item]['Extinction'][2][ekey][1])
3669                Indx[Eref.GetId()] = [item,ekey]
3670                Eref.Bind(wx.EVT_CHECKBOX, OnEref)
3671                valSizer.Add(Eref,0,wx.ALIGN_CENTER_VERTICAL)
3672                Eval = wx.TextCtrl(DData,wx.ID_ANY,
3673                    '%9.3g'%(UseList[item]['Extinction'][2][ekey][0]),style=wx.TE_PROCESS_ENTER)
3674                Indx[Eval.GetId()] = [item,ekey]
3675                Eval.Bind(wx.EVT_TEXT_ENTER,OnEval)
3676                Eval.Bind(wx.EVT_KILL_FOCUS,OnEval)
3677                valSizer.Add(Eval,0,wx.ALIGN_CENTER_VERTICAL)
3678
3679            extSizer.Add(valSizer,0,wx.ALIGN_CENTER_VERTICAL)
3680            return extSizer
3681           
3682        if DData.GetSizer():
3683            DData.GetSizer().Clear(True)
3684        mainSizer = wx.BoxSizer(wx.VERTICAL)
3685        mainSizer.Add(wx.StaticText(DData,-1,'Histogram data for '+PhaseName+':'),0,wx.ALIGN_CENTER_VERTICAL)
3686        if PWDR:
3687            mainSizer.Add(PlotSizer())           
3688           
3689        for item in keyList:
3690            histData = UseList[item]
3691            if 'Use' not in UseList[item]:      #patch
3692                UseList[item]['Use'] = True
3693            showSizer = wx.BoxSizer(wx.HORIZONTAL)
3694            showData = wx.CheckBox(DData,-1,label=' Show '+item)
3695            showData.SetValue(UseList[item]['Show'])
3696            Indx[showData.GetId()] = item
3697            showData.Bind(wx.EVT_CHECKBOX, OnShowData)
3698            showSizer.Add(showData,0,wx.ALIGN_CENTER_VERTICAL)
3699            useData = wx.CheckBox(DData,-1,label='Use?')
3700            Indx[useData.GetId()] = item
3701            showSizer.Add(useData,0,wx.ALIGN_CENTER_VERTICAL)
3702            useData.Bind(wx.EVT_CHECKBOX, OnUseData)
3703            useData.SetValue(UseList[item]['Use'])
3704            copyData = wx.Button(DData,-1,label=' Copy?')
3705            Indx[copyData.GetId()] = item
3706            copyData.Bind(wx.EVT_BUTTON,OnCopyData)
3707            showSizer.Add(copyData,wx.ALIGN_CENTER_VERTICAL)
3708            copyFlags = wx.Button(DData,-1,label=' Copy flags?')
3709            Indx[copyFlags.GetId()] = item
3710            copyFlags.Bind(wx.EVT_BUTTON,OnCopyFlags)
3711            showSizer.Add(copyFlags,wx.ALIGN_CENTER_VERTICAL)
3712            mainSizer.Add((5,5),0)
3713            mainSizer.Add(showSizer,0,wx.ALIGN_CENTER_VERTICAL)
3714            mainSizer.Add((0,5),0)
3715           
3716            if UseList[item]['Show']:
3717                mainSizer.Add(ScaleSizer())
3718                mainSizer.Add((0,5),0)
3719               
3720            if item[:4] == 'PWDR' and UseList[item]['Show']:
3721                if UseList[item]['Size'][0] == 'isotropic':
3722                    isoSizer = wx.BoxSizer(wx.HORIZONTAL)
3723                    isoSizer.Add(TopSizer(' Size model: ',['isotropic','uniaxial','ellipsoidal'],
3724                        'Size',OnSizeType),0,wx.ALIGN_CENTER_VERTICAL)
3725                    isoSizer.Add(LGmixSizer('Size',OnLGmixVal,OnLGmixRef))
3726                    mainSizer.Add(isoSizer)
3727                    mainSizer.Add(IsoSizer(u' Cryst. size(\xb5m): ','Size','%.3f',
3728                        OnSizeVal,OnSizeRef),0,wx.ALIGN_CENTER_VERTICAL)
3729                elif UseList[item]['Size'][0] == 'uniaxial':
3730                    uniSizer = wx.BoxSizer(wx.HORIZONTAL)
3731                    uniSizer.Add(TopSizer(' Size model: ',['isotropic','uniaxial','ellipsoidal'],
3732                        'Size',OnSizeType),0,wx.ALIGN_CENTER_VERTICAL)
3733                    uniSizer.Add(LGmixSizer('Size',OnLGmixVal,OnLGmixRef))
3734                    uniSizer.Add(UniSizer('Size',OnSizeAxis),0,wx.ALIGN_CENTER_VERTICAL)
3735                    mainSizer.Add(uniSizer)
3736                    mainSizer.Add(UniDataSizer(u'size(\xb5m): ','Size','%.3f',OnSizeVal,OnSizeRef))
3737                elif UseList[item]['Size'][0] == 'ellipsoidal':
3738                    ellSizer = wx.BoxSizer(wx.HORIZONTAL)
3739                    ellSizer.Add(TopSizer(' Size model: ',['isotropic','uniaxial','ellipsoidal'],
3740                        'Size',OnSizeType),0,wx.ALIGN_CENTER_VERTICAL)
3741                    ellSizer.Add(LGmixSizer('Size',OnLGmixVal,OnLGmixRef))
3742                    mainSizer.Add(ellSizer)
3743                    mainSizer.Add(EllSizeDataSizer())
3744                mainSizer.Add((0,5),0)                   
3745               
3746                if UseList[item]['Mustrain'][0] == 'isotropic':
3747                    isoSizer = wx.BoxSizer(wx.HORIZONTAL)
3748                    isoSizer.Add(TopSizer(' Mustrain model: ',['isotropic','uniaxial','generalized',],
3749                        'Mustrain',OnStrainType),0,wx.ALIGN_CENTER_VERTICAL)
3750                    isoSizer.Add(LGmixSizer('Mustrain',OnLGmixVal,OnLGmixRef))
3751                    mainSizer.Add(isoSizer)
3752                    mainSizer.Add(IsoSizer(' microstrain: ','Mustrain','%.1f',
3753                        OnStrainVal,OnStrainRef),0,wx.ALIGN_CENTER_VERTICAL)                   
3754                    mainSizer.Add((0,5),0)
3755                elif UseList[item]['Mustrain'][0] == 'uniaxial':
3756                    uniSizer = wx.BoxSizer(wx.HORIZONTAL)
3757                    uniSizer.Add(TopSizer(' Mustrain model: ',['isotropic','uniaxial','generalized',],
3758                        'Mustrain',OnStrainType),0,wx.ALIGN_CENTER_VERTICAL)
3759                    uniSizer.Add(LGmixSizer('Mustrain',OnLGmixVal,OnLGmixRef))
3760                    uniSizer.Add(UniSizer('Mustrain',OnStrainAxis),0,wx.ALIGN_CENTER_VERTICAL)
3761                    mainSizer.Add(uniSizer)
3762                    mainSizer.Add(UniDataSizer('mustrain: ','Mustrain','%.1f',OnStrainVal,OnStrainRef))
3763                elif UseList[item]['Mustrain'][0] == 'generalized':
3764                    genSizer = wx.BoxSizer(wx.HORIZONTAL)
3765                    genSizer.Add(TopSizer(' Mustrain model: ',['isotropic','uniaxial','generalized',],
3766                        'Mustrain',OnStrainType),0,wx.ALIGN_CENTER_VERTICAL)
3767                    genSizer.Add(LGmixSizer('Mustrain',OnLGmixVal,OnLGmixRef))
3768                    mainSizer.Add(genSizer)
3769                    mainSizer.Add(GenStrainDataSizer())                       
3770                mainSizer.Add((0,5),0)
3771               
3772                mainSizer.Add(wx.StaticText(DData,-1,' Hydrostatic/elastic strain:'))
3773                mainSizer.Add(HstrainSizer())
3774                   
3775                #texture  'Pref. Ori.':['MD',1.0,False,[0,0,1],0,[]] last two for 'SH' are SHorder & coeff
3776                poSizer = wx.BoxSizer(wx.VERTICAL)
3777                POData = UseList[item]['Pref.Ori.']
3778                poSizer.Add(PoTopSizer(POData))
3779                if POData[0] == 'MD':
3780                    poSizer.Add(MDDataSizer(POData))
3781                else:           #'SH'
3782                    if POData[4]:       #SH order > 0
3783                        poSizer.Add(SHDataSizer(POData))
3784                       
3785                mainSizer.Add(poSizer)
3786                mainSizer.Add((0,5),0)               
3787                #Extinction  'Extinction':[0.0,False]
3788                mainSizer.Add(ExtSizer())
3789                mainSizer.Add((0,5),0)
3790            elif item[:4] == 'HKLF' and UseList[item]['Show']:
3791                mainSizer.Add((0,5),0)               
3792                mainSizer.Add(SCExtSizer())
3793                mainSizer.Add((0,5),0)
3794                pass
3795        mainSizer.Add((5,5),0)
3796
3797        DData.SetSizer(mainSizer,True)
3798        mainSizer.FitInside(G2frame.dataFrame)
3799        Size = mainSizer.GetMinSize()
3800        Size[0] += 40
3801        Size[1] = max(Size[1],290) + 35
3802        DData.SetSize(Size)
3803        DData.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3804        Size[1] = min(Size[1],450)
3805        G2frame.dataFrame.setSizePosLeft(Size)
3806       
3807    def OnHklfAdd(event):
3808        UseList = data['Histograms']
3809        keyList = UseList.keys()
3810        TextList = []
3811        if G2frame.PatternTree.GetCount():
3812            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3813            while item:
3814                name = G2frame.PatternTree.GetItemText(item)
3815                if name not in keyList and 'HKLF' in name:
3816                    TextList.append(name)
3817                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                       
3818            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3819            try:
3820                if dlg.ShowModal() == wx.ID_OK:
3821                    result = dlg.GetSelections()
3822                    for i in result:
3823                        histoName = TextList[i]
3824                        UseList[histoName] = {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
3825                            'Extinction':['Lorentzian','Secondary Type I',
3826                            {'Tbar':0.0,'Eg':[0.0,False],'Es':[0.0,False],'Ep':[0.0,False]},]}                       
3827                    data['Histograms'] = UseList
3828                    wx.BeginBusyCursor()
3829                    UpdateHKLFdata(histoName)
3830                    wx.EndBusyCursor()
3831                    wx.CallAfter(UpdateDData)
3832            finally:
3833                dlg.Destroy()
3834               
3835    def UpdateHKLFdata(histoName):
3836        generalData = data['General']
3837        Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3838        reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
3839        SGData = generalData['SGData']
3840        Cell = generalData['Cell'][1:7]
3841        G,g = G2lat.cell2Gmat(Cell)
3842        for ref in reflData:
3843            H = ref[:3]
3844            ref[4] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
3845            iabsnt,ref[3],ref[11],ref[12] = G2spc.GenHKLf(H,SGData)
3846        G2frame.PatternTree.SetItemPyData(Id,[histoName,reflData])
3847       
3848    def OnPwdrAdd(event):
3849        generalData = data['General']
3850        SGData = generalData['SGData']
3851        UseList = data['Histograms']
3852        newList = []
3853        NShkl = len(G2spc.MustrainNames(SGData))
3854        NDij = len(G2spc.HStrainNames(SGData))
3855        keyList = UseList.keys()
3856        TextList = ['All PWDR']
3857        if G2frame.PatternTree.GetCount():
3858            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3859            while item:
3860                name = G2frame.PatternTree.GetItemText(item)
3861                if name not in keyList and 'PWDR' in name:
3862                    TextList.append(name)
3863                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3864            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3865            try:
3866                if dlg.ShowModal() == wx.ID_OK:
3867                    result = dlg.GetSelections()
3868                    for i in result: newList.append(TextList[i])
3869                    if 'All PWDR' in newList:
3870                        newList = TextList[1:]
3871                    for histoName in newList:
3872                        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3873                        UseList[histoName] = {'Histogram':histoName,'Show':False,
3874                            'Scale':[1.0,False],'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{}],
3875                            'Size':['isotropic',[4.,4.,1.0],[False,False,False],[0,0,1],
3876                                [4.,4.,4.,0.,0.,0.],6*[False,]],
3877                            'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
3878                                NShkl*[0.01,],NShkl*[False,]],
3879                            'HStrain':[NDij*[0.0,],NDij*[False,]],                         
3880                            'Extinction':[0.0,False]}
3881                        refList = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,pId,'Reflection Lists'))
3882                        refList[generalData['Name']] = []                       
3883                    data['Histograms'] = UseList
3884                    wx.CallAfter(UpdateDData)
3885            finally:
3886                dlg.Destroy()
3887       
3888    def OnDataDelete(event):
3889        UseList = data['Histograms']
3890        keyList = ['All',]+UseList.keys()
3891        keyList.sort()
3892        DelList = []
3893        if UseList:
3894            DelList = []
3895            dlg = wx.MultiChoiceDialog(G2frame, 
3896                'Which histogram to delete from this phase?', 'Delete histogram', 
3897                keyList, wx.CHOICEDLG_STYLE)
3898            try:
3899                if dlg.ShowModal() == wx.ID_OK:
3900                    result = dlg.GetSelections()
3901                    for i in result: 
3902                        DelList.append(keyList[i])
3903                    if 'All' in DelList:
3904                        DelList = keyList[1:]
3905                    for i in DelList:
3906                        del UseList[i]
3907                    wx.CallAfter(UpdateDData)
3908            finally:
3909                dlg.Destroy()
3910
3911################################################################################
3912##### Pawley routines
3913################################################################################
3914
3915    def FillPawleyReflectionsGrid():
3916        G2frame.dataFrame.SetStatusText('')
3917                       
3918        def KeyEditPawleyGrid(event):
3919            colList = G2frame.PawleyRefl.GetSelectedCols()
3920            PawleyPeaks = data['Pawley ref']
3921            if event.GetKeyCode() == wx.WXK_RETURN:
3922                event.Skip(True)
3923            elif event.GetKeyCode() == wx.WXK_CONTROL:
3924                event.Skip(True)
3925            elif event.GetKeyCode() == wx.WXK_SHIFT:
3926                event.Skip(True)
3927            elif colList:
3928                G2frame.PawleyRefl.ClearSelection()
3929                key = event.GetKeyCode()
3930                for col in colList:
3931                    if PawleyTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
3932                        if key == 89: #'Y'
3933                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=True
3934                        elif key == 78:  #'N'
3935                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=False
3936                        FillPawleyReflectionsGrid()
3937           
3938        if 'Pawley ref' in data:
3939            PawleyPeaks = data['Pawley ref']                       
3940            rowLabels = []
3941            for i in range(len(PawleyPeaks)): rowLabels.append(str(i))
3942            colLabels = ['h','k','l','mul','d','refine','Fsq(hkl)','sig(Fsq)']
3943            Types = 4*[wg.GRID_VALUE_LONG,]+[wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,]+ \
3944                2*[wg.GRID_VALUE_FLOAT+':10,2',]
3945            PawleyTable = G2gd.Table(PawleyPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3946            G2frame.PawleyRefl.SetTable(PawleyTable, True)
3947            G2frame.PawleyRefl.Bind(wx.EVT_KEY_DOWN, KeyEditPawleyGrid)                 
3948            for r in range(G2frame.PawleyRefl.GetNumberRows()):
3949                for c in range(G2frame.PawleyRefl.GetNumberCols()):
3950                    if c in [5,6]:
3951                        G2frame.PawleyRefl.SetReadOnly(r,c,isReadOnly=False)
3952                    else:
3953                        G2frame.PawleyRefl.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
3954            G2frame.PawleyRefl.SetMargins(0,0)
3955            G2frame.PawleyRefl.AutoSizeColumns(False)
3956            G2frame.dataFrame.setSizePosLeft([500,300])
3957                   
3958    def OnPawleyLoad(event):
3959        generalData = data['General']
3960        dmin = generalData['Pawley dmin']
3961        cell = generalData['Cell'][1:7]
3962        A = G2lat.cell2A(cell)
3963        SGData = generalData['SGData']
3964        HKLd = np.array(G2lat.GenHLaue(dmin,SGData,A))
3965        PawleyPeaks = []
3966        wx.BeginBusyCursor()
3967        try:
3968            for h,k,l,d in HKLd:
3969                ext,mul = G2spc.GenHKLf([h,k,l],SGData)[:2]
3970                if not ext:
3971                    mul *= 2        #for powder multiplicity
3972                    PawleyPeaks.append([h,k,l,mul,d,False,100.0,1.0])
3973        finally:
3974            wx.EndBusyCursor()
3975        data['Pawley ref'] = PawleyPeaks
3976        FillPawleyReflectionsGrid()
3977       
3978    def OnPawleyEstimate(event):
3979        try:
3980            Refs = data['Pawley ref']
3981            Histograms = data['Histograms']
3982        except KeyError:
3983            print '**** Error - no histograms defined for this phase ****'
3984            return
3985        HistoNames = Histograms.keys()
3986        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
3987        xdata = G2frame.PatternTree.GetItemPyData(PatternId)[1]
3988        Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Instrument Parameters'))
3989        Inst = dict(zip(Inst[3],Inst[1]))
3990        Sample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Sample Parameters'))
3991        if 'Lam' in Inst:
3992            wave = Inst['Lam']
3993        else:
3994            wave = Inst['Lam1']
3995        posCorr = Inst['Zero']
3996        const = 9.e-2/(np.pi*Sample['Gonio. radius'])                  #shifts in microns
3997       
3998        wx.BeginBusyCursor()
3999        try:
4000            for ref in Refs:
4001                pos = 2.0*asind(wave/(2.0*ref[4]))
4002                if 'Bragg' in Sample['Type']:
4003                    pos -= const*(4.*Sample['Shift'][0]*cosd(pos/2.0)+ \
4004                        Sample['Transparency'][0]*sind(pos)*100.0)            #trans(=1/mueff) in cm
4005                else:               #Debye-Scherrer - simple but maybe not right
4006                    pos -= const*(Sample['DisplaceX'][0]*cosd(pos)+Sample['DisplaceY'][0]*sind(pos))
4007                indx = np.searchsorted(xdata[0],pos)
4008                try:
4009                    FWHM = max(0.001,G2pwd.getFWHM(pos,Inst))/2.
4010                    dx = xdata[0][indx+1]-xdata[0][indx]
4011                    ref[6] = FWHM*(xdata[1][indx]-xdata[4][indx])*cosd(pos/2.)**3/dx
4012                    Lorenz = 1./(2.*sind(xdata[0][indx]/2.)**2*cosd(xdata[0][indx]/2.))           #Lorentz correction
4013                    pola,dIdPola = G2pwd.Polarization(Inst['Polariz.'],xdata[0][indx],Inst['Azimuth'])
4014                    ref[6] /= (Lorenz*pola*ref[3])
4015                except IndexError:
4016                    pass
4017        finally:
4018            wx.EndBusyCursor()
4019        FillPawleyReflectionsGrid()
4020
4021    def OnPawleyUpdate(event):
4022        try:
4023            Refs = data['Pawley ref']
4024            Histograms = data['Histograms']
4025        except KeyError:
4026            print '**** Error - no histograms defined for this phase ****'
4027            return
4028        HistoNames = Histograms.keys()
4029        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
4030        refData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))[PhaseName]
4031        wx.BeginBusyCursor()
4032        try:
4033            for iref,ref in enumerate(Refs):
4034                try:
4035                    ref[6] = abs(refData[iref][9])
4036                    ref[7] = 1.0
4037                except IndexError:
4038                    pass
4039        finally:
4040            wx.EndBusyCursor()
4041        FillPawleyReflectionsGrid()
4042                           
4043    def OnPawleyDelete(event):          #doesn't work
4044        dlg = wx.MessageDialog(G2frame,'Do you really want to delete selected Pawley reflections?','Delete', 
4045            wx.YES_NO | wx.ICON_QUESTION)
4046        try:
4047            result = dlg.ShowModal()
4048            if result == wx.ID_YES: 
4049                Refs = data['Pawley ref']
4050                Ind = G2frame.PawleyRefl.GetSelectedRows()
4051                Ind.sort()
4052                Ind.reverse()
4053                for ind in Ind:
4054                    Refs = np.delete(Refs,ind,0)
4055                data['Pawley ref'] = Refs
4056                FillPawleyReflectionsGrid()
4057        finally:
4058            dlg.Destroy()
4059
4060################################################################################
4061##### Fourier routines
4062################################################################################
4063
4064    def FillMapPeaksGrid():
4065                       
4066        def RowSelect(event):
4067            r,c =  event.GetRow(),event.GetCol()
4068            if r < 0 and c < 0:
4069                if MapPeaks.IsSelection():
4070                    MapPeaks.ClearSelection()
4071                else:
4072                    for row in range(MapPeaks.GetNumberRows()):
4073                        MapPeaks.SelectRow(row,True)
4074                   
4075            elif c < 0:                   #only row clicks
4076                if event.ControlDown():                   
4077                    if r in MapPeaks.GetSelectedRows():
4078                        MapPeaks.DeselectRow(r)
4079                    else:
4080                        MapPeaks.SelectRow(r,True)
4081                elif event.ShiftDown():
4082                    for row in range(r+1):
4083                        MapPeaks.SelectRow(row,True)
4084                else:
4085                    MapPeaks.ClearSelection()
4086                    MapPeaks.SelectRow(r,True)
4087            elif r < 0:                 #a column pick
4088                mapPeaks = data['Map Peaks']
4089                c =  event.GetCol()
4090                if colLabels[c] == 'mag':
4091                    mapPeaks = G2mth.sortArray(mapPeaks,0,reverse=True)
4092                elif colLabels[c] == 'dzero':
4093                    mapPeaks = G2mth.sortArray(mapPeaks,4)
4094                else:
4095                    return
4096                data['Map Peaks'] = mapPeaks
4097                wx.CallAfter(FillMapPeaksGrid)
4098            G2plt.PlotStructure(G2frame,data)                   
4099           
4100        G2frame.dataFrame.setSizePosLeft([450,300])
4101        G2frame.dataFrame.SetStatusText('')
4102        if 'Map Peaks' in data:
4103            G2frame.dataFrame.SetStatusText('Select mag or dzero columns to sort')
4104            mapPeaks = data['Map Peaks']                       
4105            rowLabels = []
4106            for i in range(len(mapPeaks)): rowLabels.append(str(i))
4107            colLabels = ['mag','x','y','z','dzero']
4108            Types = 5*[wg.GRID_VALUE_FLOAT+':10,4',]
4109            G2frame.MapPeaksTable = G2gd.Table(mapPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
4110            MapPeaks.SetTable(G2frame.MapPeaksTable, True)
4111            MapPeaks.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
4112            for r in range(MapPeaks.GetNumberRows()):
4113                for c in range(MapPeaks.GetNumberCols()):
4114                    MapPeaks.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
4115            MapPeaks.SetMargins(0,0)
4116            MapPeaks.AutoSizeColumns(False)
4117                   
4118    def OnPeaksMove(event):
4119        if 'Map Peaks' in data:
4120            mapPeaks = data['Map Peaks']                       
4121            Ind = MapPeaks.GetSelectedRows()
4122            for ind in Ind:
4123                x,y,z,d = mapPeaks[ind][1:]
4124                AtomAdd(x,y,z,'C')
4125   
4126    def OnPeaksClear(event):
4127        data['Map Peaks'] = []
4128        FillMapPeaksGrid()
4129        G2plt.PlotStructure(G2frame,data)
4130       
4131    def OnPeaksDelete(event):
4132        if 'Map Peaks' in data:
4133            mapPeaks = data['Map Peaks']
4134            Ind = MapPeaks.GetSelectedRows()
4135            Ind.sort()
4136            Ind.reverse()
4137            for ind in Ind:
4138                mapPeaks = np.delete(mapPeaks,ind,0)
4139            data['Map Peaks'] = mapPeaks
4140        FillMapPeaksGrid()
4141        G2plt.PlotStructure(G2frame,data)
4142               
4143    def OnPeaksUnique(event):
4144        if 'Map Peaks' in data:
4145            mapPeaks = data['Map Peaks']
4146            Ind = MapPeaks.GetSelectedRows()
4147            if Ind:
4148                wx.BeginBusyCursor()
4149                try:
4150                    Ind = G2mth.PeaksUnique(data,Ind)
4151                    for r in range(MapPeaks.GetNumberRows()):
4152                        if r in Ind:
4153                            MapPeaks.SelectRow(r,addToSelected=True)
4154                        else: