source: trunk/GSASIIphsGUI.py @ 863

Last change on this file since 863 was 863, checked in by vondreele, 9 years ago

fix to notebook & comment (not allowed) editing
avoid a dead window problem with comments/notebook
fix atom editing problems with no rigid bodies
work on help text

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