source: trunk/GSASIIgrid.py @ 2326

Last change on this file since 2326 was 2326, checked in by vondreele, 7 years ago

add more to angle calc

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 200.2 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIgrid - data display routines
3########### SVN repository information ###################
4# $Date: 2016-06-16 02:21:13 +0000 (Thu, 16 Jun 2016) $
5# $Author: vondreele $
6# $Revision: 2326 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 2326 2016-06-16 02:21:13Z vondreele $
9########### SVN repository information ###################
10'''
11*GSASIIgrid: Basic GUI routines*
12--------------------------------
13
14'''
15import wx
16import wx.grid as wg
17#import wx.wizard as wz
18#import wx.aui
19import wx.lib.scrolledpanel as wxscroll
20import time
21import copy
22import cPickle
23import sys
24import os
25import random as ran
26import numpy as np
27import numpy.ma as ma
28import scipy.optimize as so
29import GSASIIpath
30GSASIIpath.SetVersionNumber("$Revision: 2326 $")
31import GSASIImath as G2mth
32import GSASIIIO as G2IO
33import GSASIIstrIO as G2stIO
34import GSASIIlattice as G2lat
35import GSASIIplot as G2plt
36import GSASIIpwdGUI as G2pdG
37import GSASIIimgGUI as G2imG
38import GSASIIphsGUI as G2phG
39import GSASIIspc as G2spc
40import GSASIImapvars as G2mv
41import GSASIIconstrGUI as G2cnstG
42import GSASIIrestrGUI as G2restG
43import GSASIIpy3 as G2py3
44import GSASIIobj as G2obj
45import GSASIIexprGUI as G2exG
46import GSASIIlog as log
47import GSASIIctrls as G2G
48
49# trig functions in degrees
50sind = lambda x: np.sin(x*np.pi/180.)
51tand = lambda x: np.tan(x*np.pi/180.)
52cosd = lambda x: np.cos(x*np.pi/180.)
53
54# Define a short name for convenience
55WACV = wx.ALIGN_CENTER_VERTICAL
56
57[ wxID_FOURCALC, wxID_FOURSEARCH, wxID_FOURCLEAR, wxID_PEAKSMOVE, wxID_PEAKSCLEAR, 
58    wxID_CHARGEFLIP, wxID_PEAKSUNIQUE, wxID_PEAKSDELETE, wxID_PEAKSDA,
59    wxID_PEAKSDISTVP, wxID_PEAKSVIEWPT, wxID_FINDEQVPEAKS,wxID_SHOWBONDS,wxID_MULTIMCSA,
60    wxID_SINGLEMCSA,wxID_4DCHARGEFLIP,wxID_TRANSFORMSTRUCTURE,
61] = [wx.NewId() for item in range(17)]
62
63[ wxID_PWDRADD, wxID_HKLFADD, wxID_PWDANALYSIS, wxID_PWDCOPY, wxID_PLOTCTRLCOPY, 
64    wxID_DATADELETE,wxID_DATACOPY,wxID_DATACOPYFLAGS,wxID_DATASELCOPY,wxID_DATAUSE,
65] = [wx.NewId() for item in range(10)]
66
67[ wxID_ATOMSEDITADD, wxID_ATOMSEDITINSERT, wxID_ATOMSEDITDELETE, wxID_ATOMSREFINE, 
68    wxID_ATOMSMODIFY, wxID_ATOMSTRANSFORM, wxID_ATOMSVIEWADD, wxID_ATOMVIEWINSERT,
69    wxID_RELOADDRAWATOMS,wxID_ATOMSDISAGL,wxID_ATOMMOVE,wxID_MAKEMOLECULE,
70    wxID_ASSIGNATMS2RB,wxID_ATOMSPDISAGL, wxID_ISODISP,wxID_ADDHATOM,wxID_UPDATEHATOM,
71    wxID_WAVEVARY,wxID_ATOMSROTATE,
72] = [wx.NewId() for item in range(19)]
73
74[ wxID_DRAWATOMSTYLE, wxID_DRAWATOMLABEL, wxID_DRAWATOMCOLOR, wxID_DRAWATOMRESETCOLOR, 
75    wxID_DRAWVIEWPOINT, wxID_DRAWTRANSFORM, wxID_DRAWDELETE, wxID_DRAWFILLCELL, 
76    wxID_DRAWADDEQUIV, wxID_DRAWFILLCOORD, wxID_DRAWDISAGLTOR,  wxID_DRAWPLANE,
77    wxID_DRAWDISTVP,
78] = [wx.NewId() for item in range(13)]
79
80[ wxID_DRAWRESTRBOND, wxID_DRAWRESTRANGLE, wxID_DRAWRESTRPLANE, wxID_DRAWRESTRCHIRAL,
81] = [wx.NewId() for item in range(4)]
82
83[ wxID_ADDMCSAATOM,wxID_ADDMCSARB,wxID_CLEARMCSARB,wxID_MOVEMCSA,wxID_MCSACLEARRESULTS,
84] = [wx.NewId() for item in range(5)]
85
86[ wxID_CLEARTEXTURE,wxID_REFINETEXTURE,
87] = [wx.NewId() for item in range(2)]
88
89[ wxID_LOADDIFFAX,wxID_LAYERSIMULATE,wxID_SEQUENCESIMULATE, wxID_COPYPHASE,
90] = [wx.NewId() for item in range(4)]
91
92[ wxID_PAWLEYLOAD, wxID_PAWLEYESTIMATE, wxID_PAWLEYUPDATE,
93] = [wx.NewId() for item in range(3)]
94
95[ wxID_IMCALIBRATE,wxID_IMRECALIBRATE,wxID_IMINTEGRATE, wxID_IMCLEARCALIB,wxID_IMRECALIBALL, 
96    wxID_IMCOPYCONTROLS, wxID_INTEGRATEALL, wxID_IMSAVECONTROLS, wxID_IMLOADCONTROLS, wxID_IMAUTOINTEG,
97    wxID_IMCOPYSELECTED,
98] = [wx.NewId() for item in range(11)]
99
100[ wxID_MASKCOPY, wxID_MASKSAVE, wxID_MASKLOAD, wxID_NEWMASKSPOT,wxID_NEWMASKARC,wxID_NEWMASKRING,
101    wxID_NEWMASKFRAME, wxID_NEWMASKPOLY,  wxID_MASKLOADNOT,
102] = [wx.NewId() for item in range(9)]
103
104[ wxID_STRSTACOPY, wxID_STRSTAFIT, wxID_STRSTASAVE, wxID_STRSTALOAD,wxID_STRSTSAMPLE,
105    wxID_APPENDDZERO,wxID_STRSTAALLFIT,wxID_UPDATEDZERO,
106] = [wx.NewId() for item in range(8)]
107
108[ wxID_BACKCOPY,wxID_LIMITCOPY, wxID_SAMPLECOPY, wxID_SAMPLECOPYSOME, wxID_BACKFLAGCOPY, wxID_SAMPLEFLAGCOPY,
109    wxID_SAMPLESAVE, wxID_SAMPLELOAD,wxID_ADDEXCLREGION,wxID_SETSCALE,wxID_SAMPLE1VAL,wxID_ALLSAMPLELOAD,
110] = [wx.NewId() for item in range(12)]
111
112[ wxID_INSTPRMRESET,wxID_CHANGEWAVETYPE,wxID_INSTCOPY, wxID_INSTFLAGCOPY, wxID_INSTLOAD,
113    wxID_INSTSAVE, wxID_INST1VAL, wxID_INSTCALIB,wxID_INSTSAVEALL,
114] = [wx.NewId() for item in range(9)]
115
116[ wxID_UNDO,wxID_LSQPEAKFIT,wxID_LSQONECYCLE,wxID_RESETSIGGAM,wxID_CLEARPEAKS,wxID_AUTOSEARCH,
117    wxID_PEAKSCOPY, wxID_SEQPEAKFIT,
118] = [wx.NewId() for item in range(8)]
119
120[  wxID_INDXRELOAD, wxID_INDEXPEAKS, wxID_REFINECELL, wxID_COPYCELL, wxID_MAKENEWPHASE,
121    wxID_EXPORTCELLS,
122] = [wx.NewId() for item in range(6)]
123
124[ wxID_CONSTRAINTADD,wxID_EQUIVADD,wxID_HOLDADD,wxID_FUNCTADD,wxID_ADDRIDING,
125  wxID_CONSPHASE, wxID_CONSHIST, wxID_CONSHAP, wxID_CONSGLOBAL,wxID_EQUIVALANCEATOMS,
126] = [wx.NewId() for item in range(10)]
127
128[ wxID_RESTRAINTADD, wxID_RESTSELPHASE,wxID_RESTDELETE, wxID_RESRCHANGEVAL, 
129    wxID_RESTCHANGEESD,wxID_AARESTRAINTADD,wxID_AARESTRAINTPLOT,
130] = [wx.NewId() for item in range(7)]
131
132[ wxID_RIGIDBODYADD,wxID_DRAWDEFINERB,wxID_RIGIDBODYIMPORT,wxID_RESIDUETORSSEQ,
133    wxID_AUTOFINDRESRB,wxID_GLOBALRESREFINE,wxID_RBREMOVEALL,wxID_COPYRBPARMS,
134    wxID_GLOBALTHERM,wxID_VECTORBODYADD
135] = [wx.NewId() for item in range(10)]
136
137[ wxID_RENAMESEQSEL,wxID_SAVESEQSEL,wxID_SAVESEQSELCSV,wxID_SAVESEQCSV,wxID_PLOTSEQSEL,
138  wxID_ORGSEQSEL,wxADDSEQVAR,wxDELSEQVAR,wxEDITSEQVAR,wxCOPYPARFIT,wxID_AVESEQSEL,
139  wxADDPARFIT,wxDELPARFIT,wxEDITPARFIT,wxDOPARFIT,wxADDSEQDIST,wxADDSEQANGLE
140] = [wx.NewId() for item in range(17)]
141
142[ wxID_MODELCOPY,wxID_MODELFIT,wxID_MODELADD,wxID_ELEMENTADD,wxID_ELEMENTDELETE,
143    wxID_ADDSUBSTANCE,wxID_LOADSUBSTANCE,wxID_DELETESUBSTANCE,wxID_COPYSUBSTANCE,
144    wxID_MODELUNDO,wxID_MODELFITALL,wxID_MODELCOPYFLAGS,
145] = [wx.NewId() for item in range(12)]
146
147[ wxID_SELECTPHASE,wxID_PWDHKLPLOT,wxID_PWD3DHKLPLOT,wxID_3DALLHKLPLOT,wxID_MERGEHKL,
148] = [wx.NewId() for item in range(5)]
149
150[ wxID_PDFCOPYCONTROLS, wxID_PDFSAVECONTROLS, wxID_PDFLOADCONTROLS, 
151    wxID_PDFCOMPUTE, wxID_PDFCOMPUTEALL, wxID_PDFADDELEMENT, wxID_PDFDELELEMENT,
152] = [wx.NewId() for item in range(7)]
153
154[ wxID_MCRON,wxID_MCRLIST,wxID_MCRSAVE,wxID_MCRPLAY,
155] = [wx.NewId() for item in range(4)]
156
157VERY_LIGHT_GREY = wx.Colour(235,235,235)
158
159commonTrans = {'abc':np.eye(3),'a-cb':np.array([[1,0,0],[0,0,-1],[0,1,0]]),
160    'ba-c':np.array([[0,1,0],[1,0,0],[0,0,-1]]),'-cba':np.array([[0,0,-1],[0,1,0],[1,0,0]]),
161    'bca':np.array([[0,1,0],[0,0,1],[1,0,0]]),'cab':np.array([[0,0,1],[1,0,0],[0,1,0]]),
162    'P->R':np.array([[1,-1,0],[0,1,-1],[1,1,1]]),'R->P':np.array([[2./3,1./3,1./3],[-1./3,1./3,1./3],[-1./3,-2./3,1./3]]),
163    'P->A':np.array([[-1,0,0],[0,-1,1],[0,1,1]]),'R->O':np.array([[-1,0,0],[0,-1,0],[0,0,1]]),
164    'P->B':np.array([[-1,0,1],[0,-1,0],[1,0,1]]),'B->P':np.array([[-.5,0,.5],[0,-1,0],[.5,0,.5]]),
165    'P->C':np.array([[1,1,0],[1,-1,0],[0,0,-1]]),'C->P':np.array([[.5,.5,0],[.5,-.5,0],[0,0,-1]]),
166    'P->F':np.array([[-1,1,1],[1,-1,1],[1,1,-1]]),'F->P':np.array([[0,.5,.5],[.5,0,.5],[.5,.5,0]]),   
167    'P->I':np.array([[0,1,1],[1,0,1],[1,1,0]]),'I->P':np.array([[-.5,.5,.5],[.5,-.5,.5],[.5,.5,-.5]]),   
168    'A->P':np.array([[-1,0,0],[0,-.5,.5],[0,.5,.5]]),'O->R':np.array([[-1,0,0],[0,-1,0],[0,0,1]]), 
169    'abc*':np.eye(3), }
170commonNames = ['abc','bca','cab','a-cb','ba-c','-cba','P->A','A->P','P->B','B->P','P->C','C->P',
171    'P->I','I->P','P->F','F->P','P->R','R->P','R->O','O->R','abc*',]
172
173# Should SGMessageBox, SymOpDialog, DisAglDialog be moved?
174
175################################################################################
176#### GSAS-II class definitions
177################################################################################
178
179class SGMessageBox(wx.Dialog):
180    ''' Special version of MessageBox that displays space group & super space group text
181    in two blocks
182    '''
183    def __init__(self,parent,title,text,table,):
184        wx.Dialog.__init__(self,parent,wx.ID_ANY,title,pos=wx.DefaultPosition,
185            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
186        self.text=text
187        self.table = table
188        self.panel = wx.Panel(self)
189        mainSizer = wx.BoxSizer(wx.VERTICAL)
190        mainSizer.Add((0,10))
191        for line in text:
192            mainSizer.Add(wx.StaticText(self.panel,label='     %s     '%(line)),0,WACV)
193        ncol = self.table[0].count(',')+1
194        tableSizer = wx.FlexGridSizer(0,2*ncol+3,0,0)
195        for j,item in enumerate(self.table):
196            num,flds = item.split(')')
197            tableSizer.Add(wx.StaticText(self.panel,label='     %s  '%(num+')')),0,WACV|wx.ALIGN_LEFT)           
198            flds = flds.replace(' ','').split(',')
199            for i,fld in enumerate(flds):
200                if i < ncol-1:
201                    tableSizer.Add(wx.StaticText(self.panel,label='%s, '%(fld)),0,WACV|wx.ALIGN_RIGHT)
202                else:
203                    tableSizer.Add(wx.StaticText(self.panel,label='%s'%(fld)),0,WACV|wx.ALIGN_RIGHT)
204            if not j%2:
205                tableSizer.Add((20,0))
206        mainSizer.Add(tableSizer,0,wx.ALIGN_LEFT)
207        btnsizer = wx.StdDialogButtonSizer()
208        OKbtn = wx.Button(self.panel, wx.ID_OK)
209        OKbtn.SetDefault()
210        btnsizer.AddButton(OKbtn)
211        btnsizer.Realize()
212        mainSizer.Add((0,10))
213        mainSizer.Add(btnsizer,0,wx.ALIGN_CENTER)
214        self.panel.SetSizer(mainSizer)
215        self.panel.Fit()
216        self.Fit()
217        size = self.GetSize()
218        self.SetSize([size[0]+20,size[1]])
219
220    def Show(self):
221        '''Use this method after creating the dialog to post it
222        '''
223        self.ShowModal()
224        return
225
226################################################################################
227class SymOpDialog(wx.Dialog):
228    '''Class to select a symmetry operator
229    '''
230    def __init__(self,parent,SGData,New=True,ForceUnit=False):
231        wx.Dialog.__init__(self,parent,-1,'Select symmetry operator',
232            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
233        panel = wx.Panel(self)
234        self.SGData = SGData
235        self.New = New
236        self.Force = ForceUnit
237        self.OpSelected = [0,0,0,[0,0,0],False,False]
238        mainSizer = wx.BoxSizer(wx.VERTICAL)
239        if ForceUnit:
240            choice = ['No','Yes']
241            self.force = wx.RadioBox(panel,-1,'Force to unit cell?',choices=choice)
242            self.force.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
243            mainSizer.Add(self.force,0,WACV|wx.TOP,5)
244#        if SGData['SGInv']:
245        choice = ['No','Yes']
246        self.inv = wx.RadioBox(panel,-1,'Choose inversion?',choices=choice)
247        self.inv.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
248        mainSizer.Add(self.inv,0,WACV)
249        if SGData['SGLatt'] != 'P':
250            LattOp = G2spc.Latt2text(SGData['SGLatt']).split(';')
251            self.latt = wx.RadioBox(panel,-1,'Choose cell centering?',choices=LattOp)
252            self.latt.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
253            mainSizer.Add(self.latt,0,WACV)
254        if SGData['SGLaue'] in ['-1','2/m','mmm','4/m','4/mmm']:
255            Ncol = 2
256        else:
257            Ncol = 3
258        OpList = []
259        for Opr in SGData['SGOps']:
260            OpList.append(G2spc.MT2text(Opr))
261        self.oprs = wx.RadioBox(panel,-1,'Choose space group operator?',choices=OpList,
262            majorDimension=Ncol)
263        self.oprs.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
264        mainSizer.Add(self.oprs,0,WACV|wx.BOTTOM,5)
265        mainSizer.Add(wx.StaticText(panel,-1,"   Choose unit cell?"),0,WACV)
266        cellSizer = wx.BoxSizer(wx.HORIZONTAL)
267        cellName = ['X','Y','Z']
268        self.cell = []
269        for i in range(3):
270            self.cell.append(wx.SpinCtrl(panel,-1,cellName[i],size=wx.Size(50,20)))
271            self.cell[-1].SetRange(-3,3)
272            self.cell[-1].SetValue(0)
273            self.cell[-1].Bind(wx.EVT_SPINCTRL, self.OnOpSelect)
274            cellSizer.Add(self.cell[-1],0,WACV)
275        mainSizer.Add(cellSizer,0,WACV|wx.BOTTOM,5)
276        if self.New:
277            choice = ['No','Yes']
278            self.new = wx.RadioBox(panel,-1,'Generate new positions?',choices=choice)
279            self.new.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
280            mainSizer.Add(self.new,0,WACV)
281
282        OkBtn = wx.Button(panel,-1,"Ok")
283        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
284        cancelBtn = wx.Button(panel,-1,"Cancel")
285        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
286        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
287        btnSizer.Add((20,20),1)
288        btnSizer.Add(OkBtn)
289        btnSizer.Add((20,20),1)
290        btnSizer.Add(cancelBtn)
291        btnSizer.Add((20,20),1)
292
293        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
294        panel.SetSizer(mainSizer)
295        panel.Fit()
296        self.Fit()
297
298    def OnOpSelect(self,event):
299#        if self.SGData['SGInv']:
300        self.OpSelected[0] = self.inv.GetSelection()
301        if self.SGData['SGLatt'] != 'P':
302            self.OpSelected[1] = self.latt.GetSelection()
303        self.OpSelected[2] = self.oprs.GetSelection()
304        for i in range(3):
305            self.OpSelected[3][i] = float(self.cell[i].GetValue())
306        if self.New:
307            self.OpSelected[4] = self.new.GetSelection()
308        if self.Force:
309            self.OpSelected[5] = self.force.GetSelection()
310
311    def GetSelection(self):
312        return self.OpSelected
313
314    def OnOk(self,event):
315        parent = self.GetParent()
316        parent.Raise()
317        self.EndModal(wx.ID_OK)
318
319    def OnCancel(self,event):
320        parent = self.GetParent()
321        parent.Raise()
322        self.EndModal(wx.ID_CANCEL)
323       
324################################################################################
325class TransformDialog(wx.Dialog):
326    ''' Phaae transformation
327   
328    :param wx.Frame parent: reference to parent frame (or None)
329    :param phase: phase data
330   
331    #NB: commonNames & commonTrans defined at top of this file
332    '''
333    def __init__(self,parent,phase):
334        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Setup phase transformation', 
335            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
336        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
337        self.Phase = copy.deepcopy(phase)   #will be a new phase!
338#        self.Super = phase['General']['Super']
339#        if self.Super:
340#            self.Trans = np.eye(4)
341#            self.Vec = np.zeros(4)
342#        else:
343        self.Trans = np.eye(3)
344        self.Vec = np.zeros(3)
345        self.oldSpGrp = phase['General']['SGData']['SpGrp']
346        self.oldSGdata = phase['General']['SGData']
347        self.newSpGrp = self.Phase['General']['SGData']['SpGrp']
348        self.oldCell = phase['General']['Cell'][1:8]
349        self.newCell = self.Phase['General']['Cell'][1:8]
350        self.Common = 'abc'
351        self.Draw()
352
353    def Draw(self):
354               
355        def OnMatValue(event):
356            Obj = event.GetEventObject()
357            ix,iy = Ind[Obj.GetId()]
358            val = Obj.GetValue()
359            try:
360                if '/' in val:
361                    vals = val.split('/')
362                    self.Trans[iy,ix] = float(vals[0])/float(vals[1])
363                else:   
364                    self.Trans[iy,ix] = float(Obj.GetValue())
365            except ValueError:
366                pass
367            Obj.SetValue('%5.3f'%(self.Trans[iy,ix]))
368           
369        def OnVecValue(event):
370            Obj = event.GetEventObject()
371            iy = Ind[Obj.GetId()]
372            val = Obj.GetValue()
373            try:
374                if '/' in val:
375                    vals = val.split('/')
376                    self.Vec[iy] = float(vals[0])/float(vals[1])
377                else:   
378                    self.Vec[iy] = float(Obj.GetValue())
379            except ValueError:
380                pass
381            Obj.SetValue('%5.3f'%(self.Vec[iy]))
382               
383        def OnCommon(event):
384            Obj = event.GetEventObject()
385            self.Common = Obj.GetValue()
386            if '*' in self.Common:
387                A,B = G2lat.cell2AB(self.oldCell[:6])
388                self.newCell[2:5] = [A[2,2],90.,90.]
389                a,b = G2lat.cell2AB(self.newCell[:6])
390                self.Trans = np.inner(a.T,B)    #correct!
391                self.newSpGrp = 'P 1'
392                SGErr,SGData = G2spc.SpcGroup(self.newSpGrp)
393                self.Phase['General']['SGData'] = SGData
394            else:
395                self.Trans = commonTrans[self.Common]
396            OnTest(event)
397       
398        def OnSpaceGroup(event):
399            Flds = SGTxt.GetValue().split()
400            #get rid of extra spaces between fields first
401            for fld in Flds: fld = fld.strip()
402            SpcGp = ' '.join(Flds)
403            if SpcGp == self.newSpGrp: #didn't change it!
404                return
405            # try a lookup on the user-supplied name
406            SpGrpNorm = G2spc.StandardizeSpcName(SpcGp)
407            if SpGrpNorm:
408                SGErr,SGData = G2spc.SpcGroup(SpGrpNorm)
409            else:
410                SGErr,SGData = G2spc.SpcGroup(SpcGp)
411            if SGErr:
412                text = [G2spc.SGErrors(SGErr)+'\nSpace Group set to previous']
413                SGTxt.SetValue(self.newSpGrp)
414                msg = 'Space Group Error'
415                Style = wx.ICON_EXCLAMATION
416                Text = '\n'.join(text)
417                wx.MessageBox(Text,caption=msg,style=Style)
418            else:
419                text,table = G2spc.SGPrint(SGData)
420                self.Phase['General']['SGData'] = SGData
421                self.newSpGrp = SpcGp
422                SGTxt.SetValue(self.Phase['General']['SGData']['SpGrp'])
423                msg = 'Space Group Information'
424                dlg = SGMessageBox(self.panel,msg,text,table)
425                dlg.Show()
426                dlg.Destroy()
427#            if self.Phase['General']['Type'] in ['modulated',]:
428#                self.Phase['General']['SuperSg'] = SetDefaultSSsymbol()
429#                self.Phase['General']['SSGData'] = G2spc.SSpcGroup(generalData['SGData'],generalData['SuperSg'])[1]
430
431        def OnTest(event):
432            self.newCell = G2lat.TransformCell(self.oldCell[:6],self.Trans)
433            wx.CallAfter(self.Draw)
434
435        self.panel.Destroy()
436        self.panel = wx.Panel(self)
437        Ind = {}
438        mainSizer = wx.BoxSizer(wx.VERTICAL)
439        MatSizer = wx.BoxSizer(wx.HORIZONTAL)
440        transSizer = wx.BoxSizer(wx.VERTICAL)
441        transSizer.Add(wx.StaticText(self.panel,label=" XYZ Transformation matrix & vector: M*X+V = X'"))
442#        if self.Super:
443#            Trmat = wx.FlexGridSizer(4,4,0,0)
444#        else:
445        commonSizer = wx.BoxSizer(wx.HORIZONTAL)
446        commonSizer.Add(wx.StaticText(self.panel,label=' Common transformations: '),0,WACV)
447        common = wx.ComboBox(self.panel,value=self.Common,choices=commonNames,
448            style=wx.CB_READONLY|wx.CB_DROPDOWN)
449        common.Bind(wx.EVT_COMBOBOX,OnCommon)
450        commonSizer.Add(common,0,WACV)
451        transSizer.Add(commonSizer)
452        Trmat = wx.FlexGridSizer(3,5,0,0)
453        for iy,line in enumerate(self.Trans):
454            for ix,val in enumerate(line):
455                item = wx.TextCtrl(self.panel,value='%5.3f'%(val),
456                    size=(50,25),style=wx.TE_PROCESS_ENTER)
457                Ind[item.GetId()] = [ix,iy]
458                item.Bind(wx.EVT_TEXT_ENTER,OnMatValue)
459                item.Bind(wx.EVT_KILL_FOCUS,OnMatValue)
460                Trmat.Add(item)
461            Trmat.Add((25,0),0)
462            vec = wx.TextCtrl(self.panel,value='%5.3f'%(self.Vec[iy]),
463                    size=(50,25),style=wx.TE_PROCESS_ENTER)
464            Ind[vec.GetId()] = [iy]       
465            vec.Bind(wx.EVT_TEXT_ENTER,OnVecValue)
466            vec.Bind(wx.EVT_KILL_FOCUS,OnVecValue)
467            Trmat.Add(vec)
468        transSizer.Add(Trmat)
469        MatSizer.Add((10,0),0)
470        MatSizer.Add(transSizer)
471        mainSizer.Add(MatSizer)
472        mainSizer.Add(wx.StaticText(self.panel,label=' Old lattice parameters:'),0,WACV)
473        mainSizer.Add(wx.StaticText(self.panel,label=
474            ' a = %.5f       b = %.5f      c = %.5f'%(self.oldCell[0],self.oldCell[1],self.oldCell[2])),0,WACV)
475        mainSizer.Add(wx.StaticText(self.panel,label=' alpha = %.3f beta = %.3f gamma = %.3f'%
476            (self.oldCell[3],self.oldCell[4],self.oldCell[5])),0,WACV)
477        mainSizer.Add(wx.StaticText(self.panel,label=' volume = %.3f'%(self.oldCell[6])),0,WACV)
478        mainSizer.Add(wx.StaticText(self.panel,label=' New lattice parameters:'),0,WACV)
479        mainSizer.Add(wx.StaticText(self.panel,label=
480            ' a = %.5f       b = %.5f      c = %.5f'%(self.newCell[0],self.newCell[1],self.newCell[2])),0,WACV)
481        mainSizer.Add(wx.StaticText(self.panel,label=' alpha = %.3f beta = %.3f gamma = %.3f'%
482            (self.newCell[3],self.newCell[4],self.newCell[5])),0,WACV)
483        mainSizer.Add(wx.StaticText(self.panel,label=' volume = %.3f'%(self.newCell[6])),0,WACV)
484        sgSizer = wx.BoxSizer(wx.HORIZONTAL)
485        sgSizer.Add(wx.StaticText(self.panel,label='  Space group: '),0,WACV)
486        SGTxt = wx.TextCtrl(self.panel,value=self.newSpGrp,style=wx.TE_PROCESS_ENTER)
487        SGTxt.Bind(wx.EVT_TEXT_ENTER,OnSpaceGroup)
488        SGTxt.Bind(wx.EVT_KILL_FOCUS,OnSpaceGroup)
489        sgSizer.Add(SGTxt,0,WACV)
490        mainSizer.Add(sgSizer,0,WACV)
491
492        TestBtn = wx.Button(self.panel,-1,"Test")
493        TestBtn.Bind(wx.EVT_BUTTON, OnTest)
494        OkBtn = wx.Button(self.panel,-1,"Ok")
495        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
496        cancelBtn = wx.Button(self.panel,-1,"Cancel")
497        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
498        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
499        btnSizer.Add((20,20),1)
500        btnSizer.Add(TestBtn)
501        btnSizer.Add((20,20),1)
502        btnSizer.Add(OkBtn)
503        btnSizer.Add((20,20),1)
504        btnSizer.Add(cancelBtn)
505        btnSizer.Add((20,20),1)
506       
507        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
508        self.panel.SetSizer(mainSizer)
509        self.panel.Fit()
510        self.Fit()
511       
512    def GetSelection(self):
513        self.Phase['General']['Name'] += ' %s'%(self.Common)
514        self.Phase['General']['Cell'][1:] = G2lat.TransformCell(self.oldCell[:6],self.Trans)           
515        return self.Phase,self.Trans,self.Vec
516
517    def OnOk(self,event):
518        parent = self.GetParent()
519        parent.Raise()
520        self.EndModal(wx.ID_OK)
521
522    def OnCancel(self,event):
523        parent = self.GetParent()
524        parent.Raise()
525        self.EndModal(wx.ID_CANCEL)
526       
527################################################################################
528class RotationDialog(wx.Dialog):
529    ''' Get Rotate & translate matrix & vector - currently not used
530    needs rethinking - possible use to rotate a group of atoms about some
531    vector/origin + translation
532   
533    '''
534    def __init__(self,parent):
535        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Atom group rotation/translation', 
536            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
537        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
538        self.Trans = np.eye(3)
539        self.Vec = np.zeros(3)
540        self.rotAngle = 0.
541        self.rotVec = np.array([0.,0.,1.])
542        self.Expand = ''
543        self.Draw()
544
545    def Draw(self):
546
547        def OnMatValue(event):
548            Obj = event.GetEventObject()
549            ix,iy = Ind[Obj.GetId()]
550            val = Obj.GetValue()
551            if '/' in val:
552                vals = val.split('/')
553                self.Trans[iy,ix] = float(vals[0])/float(vals[1])
554            else:   
555                self.Trans[iy,ix] = float(Obj.GetValue())
556            Obj.SetValue('%5.3f'%(self.Trans[iy,ix]))
557           
558           
559        def OnVecValue(event):
560            Obj = event.GetEventObject()
561            iy = Ind[Obj.GetId()]
562            val = Obj.GetValue()
563            if '/' in val:
564                vals = val.split('/')
565                self.Vec[iy] = float(vals[0])/float(vals[1])
566            else:   
567                self.Vec[iy] = float(Obj.GetValue())
568            Obj.SetValue('%5.3f'%(self.Vec[iy]))
569           
570        def OnExpand(event):
571            self.Expand = expand.GetValue()
572           
573        def OnRotAngle(event):
574            self.rotAngle = float(rotangle.GetValue())
575            rotangle.SetValue('%5.3f'%(self.rotAngle))
576            Q = G2mth.AVdeg2Q(self.rotAngle,self.rotVec)
577            self.Trans = G2mth.Q2Mat(Q)
578            self.Draw()
579           
580        def OnRotVec(event):
581            vals = rotvec.GetValue()
582            vals = vals.split()
583            self.rotVec = np.array([float(val) for val in vals])
584            rotvec.SetValue('%5.3f %5.3f %5.3f'%(self.rotVec[0],self.rotVec[1],self.rotVec[2]))
585            Q = G2mth.AVdeg2Q(self.rotAngle,self.rotVec)
586            self.Trans = G2mth.Q2Mat(Q)
587            self.Draw()
588           
589        self.panel.Destroy()
590        self.panel = wx.Panel(self)
591        Ind = {}
592        mainSizer = wx.BoxSizer(wx.VERTICAL)
593        MatSizer = wx.BoxSizer(wx.HORIZONTAL)
594        transSizer = wx.BoxSizer(wx.VERTICAL)
595        transSizer.Add(wx.StaticText(self.panel,label=" XYZ Transformation matrix && vector: "+ \
596            "\n B*M*A*(X-V)+V = X'\n A,B: Cartesian transformation matrices"))
597        Trmat = wx.FlexGridSizer(3,5,0,0)
598        for iy,line in enumerate(self.Trans):
599            for ix,val in enumerate(line):
600                item = wx.TextCtrl(self.panel,value='%5.3f'%(val),
601                    size=(50,25),style=wx.TE_PROCESS_ENTER)
602                Ind[item.GetId()] = [ix,iy]
603                item.Bind(wx.EVT_TEXT_ENTER,OnMatValue)
604                item.Bind(wx.EVT_KILL_FOCUS,OnMatValue)
605                Trmat.Add(item)
606            Trmat.Add((25,0),0)
607            vec = wx.TextCtrl(self.panel,value='%5.3f'%(self.Vec[iy]),
608                    size=(50,25),style=wx.TE_PROCESS_ENTER)
609            Ind[vec.GetId()] = [iy]       
610            vec.Bind(wx.EVT_TEXT_ENTER,OnVecValue)
611            vec.Bind(wx.EVT_KILL_FOCUS,OnVecValue)
612            Trmat.Add(vec)
613        transSizer.Add(Trmat)
614        MatSizer.Add((10,0),0)
615        MatSizer.Add(transSizer)
616        mainSizer.Add(MatSizer)
617        rotationBox = wx.BoxSizer(wx.HORIZONTAL)
618        rotationBox.Add(wx.StaticText(self.panel,label=' Rotation angle: '),0,WACV)
619        rotangle = wx.TextCtrl(self.panel,value='%5.3f'%(self.rotAngle),
620            size=(50,25),style=wx.TE_PROCESS_ENTER)
621        rotangle.Bind(wx.EVT_TEXT_ENTER,OnRotAngle)
622        rotangle.Bind(wx.EVT_KILL_FOCUS,OnRotAngle)
623        rotationBox.Add(rotangle,0,WACV)
624        rotationBox.Add(wx.StaticText(self.panel,label=' about vector: '),0,WACV)
625        rotvec = wx.TextCtrl(self.panel,value='%5.3f %5.3f %5.3f'%(self.rotVec[0],self.rotVec[1],self.rotVec[2]),
626            size=(100,25),style=wx.TE_PROCESS_ENTER)
627        rotvec.Bind(wx.EVT_TEXT_ENTER,OnRotVec)
628        rotvec.Bind(wx.EVT_KILL_FOCUS,OnRotVec)
629        rotationBox.Add(rotvec,0,WACV)
630        mainSizer.Add(rotationBox,0,WACV)
631        expandChoice = ['','xy','xz','yz','xyz']
632        expandBox = wx.BoxSizer(wx.HORIZONTAL)
633        expandBox.Add(wx.StaticText(self.panel,label=' Expand -1 to +1 on: '),0,WACV)
634        expand = wx.ComboBox(self.panel,value=self.Expand,choices=expandChoice,
635            style=wx.CB_READONLY|wx.CB_DROPDOWN)
636        expand.Bind(wx.EVT_COMBOBOX,OnExpand)
637        expandBox.Add(expand,0,WACV)
638        expandBox.Add(wx.StaticText(self.panel,label=' and find unique atoms '),0,WACV)       
639        mainSizer.Add(expandBox)
640               
641        OkBtn = wx.Button(self.panel,-1,"Ok")
642        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
643        cancelBtn = wx.Button(self.panel,-1,"Cancel")
644        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
645        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
646        btnSizer.Add((20,20),1)
647        btnSizer.Add(OkBtn)
648        btnSizer.Add((20,20),1)
649        btnSizer.Add(cancelBtn)
650        btnSizer.Add((20,20),1)
651       
652        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
653        self.panel.SetSizer(mainSizer)
654        self.panel.Fit()
655        self.Fit()
656
657    def GetSelection(self):
658        return self.Trans,self.Vec,self.Expand
659
660    def OnOk(self,event):
661        parent = self.GetParent()
662        parent.Raise()
663        self.EndModal(wx.ID_OK)
664
665    def OnCancel(self,event):
666        parent = self.GetParent()
667        parent.Raise()
668        self.EndModal(wx.ID_CANCEL)   
669       
670################################################################################
671class DIFFaXcontrols(wx.Dialog):
672    ''' Solicit items needed to prepare DIFFaX control.dif file
673    '''
674    def __init__(self,parent,ctrls,parms=None):
675        wx.Dialog.__init__(self,parent,wx.ID_ANY,'DIFFaX controls', 
676            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
677        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
678        self.ctrls = ctrls
679        self.calcType = 'powder pattern'
680        self.plane = 'h0l'
681        self.planeChoice = ['h0l','0kl','hhl','h-hl',]
682        self.lmax = '2'
683        self.lmaxChoice = [str(i+1) for i in range(6)]
684        self.Parms = parms
685        self.Parm = None
686        if self.Parms != None:
687            self.Parm = self.Parms[0]
688        self.parmRange = [0.,1.]
689        self.parmStep = 2
690        self.Inst = 'Gaussian'
691        self.Draw()
692       
693    def Draw(self):
694       
695        def OnCalcType(event):
696            self.calcType = calcType.GetValue()
697            wx.CallAfter(self.Draw)
698           
699        def OnPlane(event):
700            self.plane = plane.GetValue()
701           
702        def OnMaxL(event):
703            self.lmax = lmax.GetValue()
704           
705        def OnParmSel(event):
706            self.Parm = parmsel.GetValue()
707           
708        def OnNumStep(event):
709            self.parmStep = int(numStep.GetValue())
710           
711        def OnParmRange(event):
712            vals = parmrange.GetValue().split()
713            try:
714                vals = [float(vals[0]),float(vals[1])]
715            except ValueError:
716                vals = self.parmRange
717            parmrange.SetValue('%.3f %.3f'%(vals[0],vals[1]))
718            self.parmRange = vals
719           
720        def OnInstSel(event):
721            self.Inst = instsel.GetValue()
722       
723        self.panel.Destroy()
724        self.panel = wx.Panel(self)
725        mainSizer = wx.BoxSizer(wx.VERTICAL)
726        mainSizer.Add(wx.StaticText(self.panel,label=' Controls for DIFFaX'),0,WACV)
727        if self.Parms:
728            mainSizer.Add(wx.StaticText(self.panel,label=' Sequential powder pattern simulation'),0,WACV)
729        else:
730            calcChoice = ['powder pattern','selected area']
731            calcSizer = wx.BoxSizer(wx.HORIZONTAL)
732            calcSizer.Add(wx.StaticText(self.panel,label=' Select calculation type: '),0,WACV)
733            calcType = wx.ComboBox(self.panel,value=self.calcType,choices=calcChoice,
734                style=wx.CB_READONLY|wx.CB_DROPDOWN)
735            calcType.Bind(wx.EVT_COMBOBOX,OnCalcType)
736            calcSizer.Add(calcType,0,WACV)
737            mainSizer.Add(calcSizer)
738        if self.Parms:
739            parmSel = wx.BoxSizer(wx.HORIZONTAL)
740            parmSel.Add(wx.StaticText(self.panel,label=' Select parameter to vary: '),0,WACV)
741            parmsel = wx.ComboBox(self.panel,value=self.Parm,choices=self.Parms,
742                style=wx.CB_READONLY|wx.CB_DROPDOWN)
743            parmsel.Bind(wx.EVT_COMBOBOX,OnParmSel)
744            parmSel.Add(parmsel,0,WACV)
745            mainSizer.Add(parmSel)
746            mainSizer.Add(wx.StaticText(self.panel,label=' Enter parameter range & no. steps: '),0,WACV)
747            parmRange =  wx.BoxSizer(wx.HORIZONTAL)
748            numChoice = [str(i+1) for i in range(10)]
749            parmrange = wx.TextCtrl(self.panel,value='%.3f %.3f'%(self.parmRange[0],self.parmRange[1]),
750                style=wx.TE_PROCESS_ENTER)
751            parmrange.Bind(wx.EVT_TEXT_ENTER,OnParmRange)
752            parmrange.Bind(wx.EVT_KILL_FOCUS,OnParmRange)
753            parmRange.Add(parmrange,0,WACV)
754            numStep = wx.ComboBox(self.panel,value=str(self.parmStep),choices=numChoice,
755                style=wx.CB_READONLY|wx.CB_DROPDOWN)
756            numStep.Bind(wx.EVT_COMBOBOX,OnNumStep)
757            parmRange.Add(numStep,0,WACV)
758            mainSizer.Add(parmRange)           
759        if 'selected' in self.calcType:
760            planeSizer = wx.BoxSizer(wx.HORIZONTAL)
761            planeSizer.Add(wx.StaticText(self.panel,label=' Select plane: '),0,WACV)
762            plane = wx.ComboBox(self.panel,value=self.plane,choices=self.planeChoice,
763                style=wx.CB_READONLY|wx.CB_DROPDOWN)
764            plane.Bind(wx.EVT_COMBOBOX,OnPlane)
765            planeSizer.Add(plane,0,WACV)
766            planeSizer.Add(wx.StaticText(self.panel,label=' Max. l index: '),0,WACV)
767            lmax = wx.ComboBox(self.panel,value=self.lmax,choices=self.lmaxChoice,
768                style=wx.CB_READONLY|wx.CB_DROPDOWN)
769            lmax.Bind(wx.EVT_COMBOBOX,OnMaxL)
770            planeSizer.Add(lmax,0,WACV)           
771            mainSizer.Add(planeSizer)
772        else:
773            instChoice = ['None','Mean Gaussian','Gaussian',]
774            instSizer = wx.BoxSizer(wx.HORIZONTAL)
775            instSizer.Add(wx.StaticText(self.panel,label=' Select instrument broadening: '),0,WACV)
776            instsel = wx.ComboBox(self.panel,value=self.Inst,choices=instChoice,
777                style=wx.CB_READONLY|wx.CB_DROPDOWN)
778            instsel.Bind(wx.EVT_COMBOBOX,OnInstSel)
779            instSizer.Add(instsel,0,WACV)
780            mainSizer.Add(instSizer)
781        OkBtn = wx.Button(self.panel,-1,"Ok")
782        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
783        cancelBtn = wx.Button(self.panel,-1,"Cancel")
784        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
785        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
786        btnSizer.Add((20,20),1)
787        btnSizer.Add(OkBtn)
788        btnSizer.Add((20,20),1)
789        btnSizer.Add(cancelBtn)
790        btnSizer.Add((20,20),1)
791       
792        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
793        self.panel.SetSizer(mainSizer)
794        self.panel.Fit()
795        self.Fit()
796       
797    def GetSelection(self):
798        if 'powder' in self.calcType:
799            return 'PWDR',self.Inst,self.Parm,self.parmRange,self.parmStep
800        elif 'selected' in self.calcType:
801            return 'SADP',self.plane,self.lmax
802
803    def OnOk(self,event):
804        parent = self.GetParent()
805        parent.Raise()
806        self.EndModal(wx.ID_OK)
807
808    def OnCancel(self,event):
809        parent = self.GetParent()
810        parent.Raise()
811        self.EndModal(wx.ID_CANCEL)
812           
813       
814################################################################################
815class MergeDialog(wx.Dialog):
816    ''' HKL transformation & merge dialog
817   
818    :param wx.Frame parent: reference to parent frame (or None)
819    :param data: HKLF data
820   
821    #NB: commonNames & commonTrans defined at top of this file     
822    '''       
823    def __init__(self,parent,data):
824        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Setup HKLF merge', 
825            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
826        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
827        self.data = data
828        self.Super = data[1]['Super']
829        if self.Super:
830            self.Trans = np.eye(4)
831        else:
832            self.Trans = np.eye(3)
833        self.Cent = 'noncentrosymmetric'
834        self.Laue = '1'
835        self.Class = 'triclinic'
836        self.Common = 'abc'
837        self.Draw()
838       
839    def Draw(self):
840               
841        def OnMatValue(event):
842            Obj = event.GetEventObject()
843            ix,iy = Ind[Obj.GetId()]
844            self.Trans[ix,iy] = float(Obj.GetValue())
845               
846        def OnCent(event):
847            Obj = event.GetEventObject()
848            self.Cent = Obj.GetValue()
849            self.Laue = ''
850            wx.CallAfter(self.Draw)
851           
852        def OnLaue(event):
853            Obj = event.GetEventObject()
854            self.Laue = Obj.GetValue()
855            wx.CallAfter(self.Draw)
856           
857        def OnClass(event):
858            Obj = event.GetEventObject()
859            self.Class = Obj.GetValue()
860            self.Laue = ''
861            wx.CallAfter(self.Draw)
862           
863        def OnCommon(event):
864            Obj = event.GetEventObject()
865            self.Common = Obj.GetValue()
866            self.Trans = commonTrans[self.Common]
867            wx.CallAfter(self.Draw)
868       
869        self.panel.Destroy()
870        self.panel = wx.Panel(self)
871        Ind = {}
872        mainSizer = wx.BoxSizer(wx.VERTICAL)
873        MatSizer = wx.BoxSizer(wx.HORIZONTAL)
874        transSizer = wx.BoxSizer(wx.VERTICAL)
875        transSizer.Add(wx.StaticText(self.panel,label=" HKL Transformation matrix: M*H = H'"))
876        if self.Super:
877            Trmat = wx.FlexGridSizer(4,4,0,0)
878        else:
879            commonSizer = wx.BoxSizer(wx.HORIZONTAL)
880            commonSizer.Add(wx.StaticText(self.panel,label=' Common transformations: '),0,WACV)
881            common = wx.ComboBox(self.panel,value=self.Common,choices=commonNames[:-1], #not the last one!
882                style=wx.CB_READONLY|wx.CB_DROPDOWN)
883            common.Bind(wx.EVT_COMBOBOX,OnCommon)
884            commonSizer.Add(common,0,WACV)
885            transSizer.Add(commonSizer)
886            Trmat = wx.FlexGridSizer(3,3,0,0)
887        for iy,line in enumerate(self.Trans):
888            for ix,val in enumerate(line):
889                item = wx.TextCtrl(self.panel,value='%5.3f'%(val),
890                    size=(50,25),style=wx.TE_PROCESS_ENTER)
891                Ind[item.GetId()] = [ix,iy]
892                item.Bind(wx.EVT_TEXT_ENTER,OnMatValue)
893                item.Bind(wx.EVT_KILL_FOCUS,OnMatValue)
894                Trmat.Add(item)
895        transSizer.Add(Trmat)
896        MatSizer.Add((10,0),0)
897        MatSizer.Add(transSizer)
898        mainSizer.Add(MatSizer)
899        laueClass = ['triclinic','monoclinic','orthorhombic','trigonal(H)','tetragonal','hexagonal','cubic']
900        centroLaue = {'triclinic':['-1',],'monoclinic':['2/m','1 1 2/m','2/m 1 1',],
901            'orthorhombic':['m m m',],'trigonal(H)':['-3','-3 m 1','-3 1 m',],    \
902            'tetragonal':['4/m','4/m m m',],'hexagonal':['6/m','6/m m m',],'cubic':['m 3','m 3 m']}
903        noncentroLaue = {'triclinic':['1',],'monoclinic':['2','2 1 1','1 1 2','m','m 1 1','1 1 m',],
904            'orthorhombic':['2 2 2','m m 2','m 2 m','2 m m',],
905            'trigonal(H)':['3','3 1 2','3 2 1','3 m 1','3 1 m',],
906            'tetragonal':['4','-4','4 2 2','4 m m','-4 2 m','-4 m 2',], \
907            'hexagonal':['6','-6','6 2 2','6 m m','-6 m 2','-6 2 m',],'cubic':['2 3','4 3 2','-4 3 m']}
908        centChoice = ['noncentrosymmetric','centrosymmetric']
909        mainSizer.Add(wx.StaticText(self.panel,label=' Select Laue class for new lattice:'),0,WACV)
910        Class = wx.ComboBox(self.panel,value=self.Class,choices=laueClass,
911            style=wx.CB_READONLY|wx.CB_DROPDOWN)
912        Class.Bind(wx.EVT_COMBOBOX,OnClass)
913        mainSizer.Add(Class,0,WACV)
914        mainSizer.Add(wx.StaticText(self.panel,label=' Target Laue symmetry:'),0,WACV)
915        Cent = wx.ComboBox(self.panel,value=self.Cent,choices=centChoice,
916            style=wx.CB_READONLY|wx.CB_DROPDOWN)
917        Cent.Bind(wx.EVT_COMBOBOX,OnCent)
918        mergeSizer = wx.BoxSizer(wx.HORIZONTAL)
919        mergeSizer.Add(Cent,0,WACV)
920        mergeSizer.Add((10,0),0)
921        Choice = centroLaue[self.Class]
922        if 'non' in self.Cent:
923            Choice = noncentroLaue[self.Class]
924        Laue = wx.ComboBox(self.panel,value=self.Laue,choices=Choice,
925            style=wx.CB_READONLY|wx.CB_DROPDOWN)
926        Laue.Bind(wx.EVT_COMBOBOX,OnLaue)
927        mergeSizer.Add(Laue,0,WACV)
928        mainSizer.Add(mergeSizer)
929
930        OkBtn = wx.Button(self.panel,-1,"Ok")
931        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
932        cancelBtn = wx.Button(self.panel,-1,"Cancel")
933        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
934        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
935        btnSizer.Add((20,20),1)
936        if self.Laue:
937            btnSizer.Add(OkBtn)
938            btnSizer.Add((20,20),1)
939        btnSizer.Add(cancelBtn)
940        btnSizer.Add((20,20),1)
941       
942        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
943        self.panel.SetSizer(mainSizer)
944        self.panel.Fit()
945        self.Fit()
946       
947    def GetSelection(self):
948        return self.Trans,self.Cent,self.Laue
949
950    def OnOk(self,event):
951        parent = self.GetParent()
952        parent.Raise()
953        self.EndModal(wx.ID_OK)
954
955    def OnCancel(self,event):
956        parent = self.GetParent()
957        parent.Raise()
958        self.EndModal(wx.ID_CANCEL)
959
960       
961################################################################################
962class AddHatomDialog(wx.Dialog):
963    '''H atom addition dialog. After :meth:`ShowModal` returns, the results
964    are found in dict :attr:`self.data`, which is accessed using :meth:`GetData`.
965   
966    :param wx.Frame parent: reference to parent frame (or None)
967    :param dict Neigh: a dict of atom names with list of atom name, dist pairs for neighboring atoms
968    :param dict phase: a dict containing the phase as defined by
969      :ref:`Phase Tree Item <Phase_table>`   
970    '''
971    def __init__(self,parent,Neigh,phase):
972        wx.Dialog.__init__(self,parent,wx.ID_ANY,'H atom add', 
973            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
974        self.panel = wxscroll.ScrolledPanel(self)         #just a dummy - gets destroyed in Draw!
975        self.Neigh = Neigh
976        self.phase = phase
977        self.Hatoms = []
978        self.Draw(self.Neigh,self.phase)
979           
980    def Draw(self,Neigh,phase):
981        '''Creates the contents of the dialog. Normally called
982        by :meth:`__init__`.
983        '''
984        def OnHSelect(event):
985            Obj = event.GetEventObject()
986            item,i = Indx[Obj.GetId()]
987            for obj in Indx[item]:
988                obj.SetValue(False)
989            Obj.SetValue(True)
990            self.Neigh[item][2] = i
991           
992        def OnBond(event):
993            Obj = event.GetEventObject()
994            inei,ibond = Indx[Obj.GetId()]
995            self.Neigh[inei][1][0][ibond][2] = Obj.GetValue()
996           
997        self.panel.Destroy()
998        self.panel = wxscroll.ScrolledPanel(self,style = wx.DEFAULT_DIALOG_STYLE)
999        mainSizer = wx.BoxSizer(wx.VERTICAL)
1000        mainSizer.Add(wx.StaticText(self.panel,-1,'H atom add controls for phase %s:'%(phase['General']['Name'])),
1001            0,wx.LEFT|wx.TOP,10)
1002        mainSizer.Add(wx.StaticText(self.panel,-1,'NB: Check selections as they may not be correct'),0,WACV|wx.LEFT,10)
1003        mainSizer.Add(wx.StaticText(self.panel,-1," Atom:  Add # H's          Use: Neighbors, dist"),0,wx.TOP|wx.LEFT,5)
1004        nHatms = ['0','1','2','3']
1005        dataSizer = wx.FlexGridSizer(0,3,0,0)
1006        Indx = {}
1007        for inei,neigh in enumerate(Neigh):
1008            dataSizer.Add(wx.StaticText(self.panel,-1,' %s:  '%(neigh[0])),0,WACV)
1009            nH = 1      #for O atom
1010            if 'C' in neigh[0] or 'N' in neigh[0]:
1011                nH = 4-len(neigh[1][0])
1012            checks = wx.BoxSizer(wx.HORIZONTAL)
1013            Ids = []
1014            for i in range(nH+1):
1015                nHs = wx.CheckBox(self.panel,-1,label=nHatms[i])
1016                if i == neigh[2]:
1017                    nHs.SetValue(True)
1018                Indx[nHs.GetId()] = [inei,i]
1019                Ids.append(nHs)
1020                nHs.Bind(wx.EVT_CHECKBOX, OnHSelect)
1021                checks.Add(nHs,0,WACV)
1022            Indx[inei] = Ids
1023            dataSizer.Add(checks,0,WACV)
1024            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
1025            for ib,bond in enumerate(neigh[1][0]):
1026                Bond = wx.CheckBox(self.panel,-1,label=': %s, %.3f'%(bond[0],bond[1]))
1027                Bond.SetValue(bond[2])
1028                Indx[Bond.GetId()] = [inei,ib]
1029                Bond.Bind(wx.EVT_CHECKBOX,OnBond)               
1030                lineSizer.Add(Bond,0,WACV)               
1031            dataSizer.Add(lineSizer,0,WACV|wx.RIGHT,10)
1032        mainSizer.Add(dataSizer,0,wx.LEFT,5)
1033
1034        CancelBtn = wx.Button(self.panel,-1,'Cancel')
1035        CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1036        OkBtn = wx.Button(self.panel,-1,'Ok')
1037        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1038        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1039        btnSizer.Add((20,20),1)
1040        btnSizer.Add(OkBtn)
1041        btnSizer.Add((20,20),1)
1042        btnSizer.Add(CancelBtn)
1043        btnSizer.Add((20,20),1)
1044        mainSizer.Add(btnSizer,0,wx.BOTTOM|wx.TOP, 10)
1045        size = np.array(self.GetSize())
1046        self.panel.SetupScrolling()
1047        self.panel.SetSizer(mainSizer)
1048        self.panel.SetAutoLayout(1)
1049        size = [size[0]-5,size[1]-20]       #this fiddling is needed for older wx!
1050        self.panel.SetSize(size)
1051       
1052    def GetData(self):
1053        'Returns the values from the dialog'
1054        for neigh in self.Neigh:
1055            for ibond,bond in enumerate(neigh[1][0]):
1056                if not bond[2]:
1057                    neigh[1][1][1][ibond] = 0   #deselected bond
1058            neigh[1][1][1] = [a for a in  neigh[1][1][1] if a]
1059        return self.Neigh       #has #Hs to add for each entry
1060       
1061    def OnOk(self,event):
1062        'Called when the OK button is pressed'
1063        parent = self.GetParent()
1064        parent.Raise()
1065        self.EndModal(wx.ID_OK)             
1066
1067    def OnCancel(self,event):
1068        parent = self.GetParent()
1069        parent.Raise()
1070        self.EndModal(wx.ID_CANCEL)
1071
1072################################################################################
1073class DisAglDialog(wx.Dialog):
1074    '''Distance/Angle Controls input dialog. After
1075    :meth:`ShowModal` returns, the results are found in
1076    dict :attr:`self.data`, which is accessed using :meth:`GetData`.
1077
1078    :param wx.Frame parent: reference to parent frame (or None)
1079    :param dict data: a dict containing the current
1080      search ranges or an empty dict, which causes default values
1081      to be used.
1082      Will be used to set element `DisAglCtls` in
1083      :ref:`Phase Tree Item <Phase_table>`
1084    :param dict default:  A dict containing the default
1085      search ranges for each element.
1086    '''
1087    def __init__(self,parent,data,default,Reset=True):
1088        wx.Dialog.__init__(self,parent,wx.ID_ANY,
1089                           'Distance Angle Controls', 
1090            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1091        self.default = default
1092        self.Reset = Reset
1093        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
1094        self._default(data,self.default)
1095        self.Draw(self.data)
1096               
1097    def _default(self,data,default):
1098        '''Set starting values for the search values, either from
1099        the input array or from defaults, if input is null
1100        '''
1101        if data:
1102            self.data = copy.deepcopy(data) # don't mess with originals
1103        else:
1104            self.data = {}
1105            self.data['Name'] = default['Name']
1106            self.data['Factors'] = [0.85,0.85]
1107            self.data['AtomTypes'] = default['AtomTypes']
1108            self.data['BondRadii'] = default['BondRadii'][:]
1109            self.data['AngleRadii'] = default['AngleRadii'][:]
1110
1111    def Draw(self,data):
1112        '''Creates the contents of the dialog. Normally called
1113        by :meth:`__init__`.
1114        '''
1115        self.panel.Destroy()
1116        self.panel = wx.Panel(self)
1117        mainSizer = wx.BoxSizer(wx.VERTICAL)
1118        mainSizer.Add(wx.StaticText(self.panel,-1,'Controls for phase '+data['Name']),
1119            0,WACV|wx.LEFT,10)
1120        mainSizer.Add((10,10),1)
1121       
1122        radiiSizer = wx.FlexGridSizer(0,3,5,5)
1123        radiiSizer.Add(wx.StaticText(self.panel,-1,' Type'),0,WACV)
1124        radiiSizer.Add(wx.StaticText(self.panel,-1,'Bond radii'),0,WACV)
1125        radiiSizer.Add(wx.StaticText(self.panel,-1,'Angle radii'),0,WACV)
1126        self.objList = {}
1127        for id,item in enumerate(self.data['AtomTypes']):
1128            radiiSizer.Add(wx.StaticText(self.panel,-1,' '+item),0,WACV)
1129            bRadii = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['BondRadii'][id]),style=wx.TE_PROCESS_ENTER)
1130            self.objList[bRadii.GetId()] = ['BondRadii',id]
1131            bRadii.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
1132            bRadii.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
1133            radiiSizer.Add(bRadii,0,WACV)
1134            aRadii = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['AngleRadii'][id]),style=wx.TE_PROCESS_ENTER)
1135            self.objList[aRadii.GetId()] = ['AngleRadii',id]
1136            aRadii.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
1137            aRadii.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
1138            radiiSizer.Add(aRadii,0,WACV)
1139        mainSizer.Add(radiiSizer,0,wx.EXPAND)
1140        factorSizer = wx.FlexGridSizer(0,2,5,5)
1141        Names = ['Bond','Angle']
1142        for i,name in enumerate(Names):
1143            factorSizer.Add(wx.StaticText(self.panel,-1,name+' search factor'),0,WACV)
1144            bondFact = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['Factors'][i]),style=wx.TE_PROCESS_ENTER)
1145            self.objList[bondFact.GetId()] = ['Factors',i]
1146            bondFact.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
1147            bondFact.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
1148            factorSizer.Add(bondFact)
1149        mainSizer.Add(factorSizer,0,wx.EXPAND)
1150       
1151        OkBtn = wx.Button(self.panel,-1,"Ok")
1152        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1153        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1154        btnSizer.Add((20,20),1)
1155        btnSizer.Add(OkBtn)
1156        if self.Reset:
1157            ResetBtn = wx.Button(self.panel,-1,'Reset')
1158            ResetBtn.Bind(wx.EVT_BUTTON, self.OnReset)
1159            btnSizer.Add(ResetBtn)
1160        btnSizer.Add((20,20),1)
1161        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1162        self.panel.SetSizer(mainSizer)
1163        self.panel.Fit()
1164        self.Fit()
1165   
1166    def OnRadiiVal(self,event):
1167        Obj = event.GetEventObject()
1168        item = self.objList[Obj.GetId()]
1169        try:
1170            self.data[item[0]][item[1]] = float(Obj.GetValue())
1171        except ValueError:
1172            pass
1173        Obj.SetValue("%.3f"%(self.data[item[0]][item[1]]))          #reset in case of error
1174       
1175    def GetData(self):
1176        'Returns the values from the dialog'
1177        return self.data
1178       
1179    def OnOk(self,event):
1180        'Called when the OK button is pressed'
1181        parent = self.GetParent()
1182        parent.Raise()
1183        self.EndModal(wx.ID_OK)             
1184       
1185    def OnReset(self,event):
1186        'Called when the Reset button is pressed'
1187        data = {}
1188        self._default(data,self.default)
1189        self.Draw(self.data)
1190               
1191################################################################################
1192class ShowLSParms(wx.Dialog):
1193    '''Create frame to show least-squares parameters
1194    '''
1195    def __init__(self,parent,title,parmDict,varyList,fullVaryList,
1196                 size=(300,430)):
1197        wx.Dialog.__init__(self,parent,wx.ID_ANY,title,size=size,
1198                           style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
1199        mainSizer = wx.BoxSizer(wx.VERTICAL)
1200
1201        panel = wxscroll.ScrolledPanel(
1202            self, wx.ID_ANY,
1203            #size=size,
1204            style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
1205        num = len(varyList)
1206        mainSizer.Add(wx.StaticText(self,wx.ID_ANY,'Number of refined variables: '+str(num)))
1207        if len(varyList) != len(fullVaryList):
1208            num = len(fullVaryList) - len(varyList)
1209            mainSizer.Add(wx.StaticText(self,wx.ID_ANY,' + '+str(num)+' parameters are varied via constraints'))
1210        subSizer = wx.FlexGridSizer(cols=4,hgap=2,vgap=2)
1211        parmNames = parmDict.keys()
1212        parmNames.sort()
1213        subSizer.Add((-1,-1))
1214        subSizer.Add(wx.StaticText(panel,wx.ID_ANY,'Parameter name  '))
1215        subSizer.Add(wx.StaticText(panel,wx.ID_ANY,'refine?'))
1216        subSizer.Add(wx.StaticText(panel,wx.ID_ANY,'value'),0,wx.ALIGN_RIGHT)
1217        explainRefine = False
1218        for name in parmNames:
1219            # skip entries without numerical values
1220            if isinstance(parmDict[name],basestring): continue
1221            try:
1222                value = G2py3.FormatSigFigs(parmDict[name])
1223            except TypeError:
1224                value = str(parmDict[name])+' -?' # unexpected
1225                #continue
1226            v = G2obj.getVarDescr(name)
1227            if v is None or v[-1] is None:
1228                subSizer.Add((-1,-1))
1229            else:               
1230                ch = G2G.HelpButton(panel,G2obj.fmtVarDescr(name))
1231                subSizer.Add(ch,0,wx.LEFT|wx.RIGHT|WACV|wx.ALIGN_CENTER,1)
1232            subSizer.Add(wx.StaticText(panel,wx.ID_ANY,str(name)))
1233            if name in varyList:
1234                subSizer.Add(wx.StaticText(panel,wx.ID_ANY,'R'))
1235            elif name in fullVaryList:
1236                subSizer.Add(wx.StaticText(panel,wx.ID_ANY,'C'))
1237                explainRefine = True
1238            else:
1239                subSizer.Add((-1,-1))
1240            subSizer.Add(wx.StaticText(panel,wx.ID_ANY,value),0,wx.ALIGN_RIGHT)
1241
1242        # finish up ScrolledPanel
1243        panel.SetSizer(subSizer)
1244        panel.SetAutoLayout(1)
1245        panel.SetupScrolling()
1246        mainSizer.Add(panel,1, wx.ALL|wx.EXPAND,1)
1247
1248        if explainRefine:
1249            mainSizer.Add(
1250                wx.StaticText(self,wx.ID_ANY,
1251                          '"R" indicates a refined variable\n'+
1252                          '"C" indicates generated from a constraint'
1253                          ),
1254                0, wx.ALL,0)
1255        # make OK button
1256        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
1257        btn = wx.Button(self, wx.ID_CLOSE,"Close") 
1258        btn.Bind(wx.EVT_BUTTON,self._onClose)
1259        btnsizer.Add(btn)
1260        mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)
1261        # Allow window to be enlarged but not made smaller
1262        self.SetSizer(mainSizer)
1263        self.SetMinSize(self.GetSize())
1264
1265    def _onClose(self,event):
1266        self.EndModal(wx.ID_CANCEL)
1267 
1268################################################################################
1269class DataFrame(wx.Frame):
1270    '''Create the data item window and all the entries in menus used in
1271    that window. For Linux and windows, the menu entries are created for the
1272    current data item window, but in the Mac the menu is accessed from all
1273    windows. This means that a different menu is posted depending on which
1274    data item is posted. On the Mac, all the menus contain the data tree menu
1275    items, but additional menus are added specific to the data item.
1276
1277    Note that while the menus are created here,
1278    the binding for the menus is done later in various GSASII*GUI modules,
1279    where the functions to be called are defined.
1280    '''
1281    def Bind(self,eventtype,handler,*args,**kwargs):
1282        '''Override the Bind() function: on the Mac the binding is to
1283        the main window, so that menus operate with any window on top.
1284        For other platforms, either wrap calls that will be logged
1285        or call the default wx.Frame Bind() to bind to the menu item directly.
1286
1287        Note that bindings can be made to objects by Id or by direct reference to the
1288        object. As a convention, when bindings are to objects, they are not logged
1289        but when bindings are by Id, they are logged.
1290        '''
1291        if sys.platform == "darwin": # mac
1292            self.G2frame.Bind(eventtype,handler,*args,**kwargs)
1293            return
1294        if eventtype == wx.EVT_MENU and 'id' in kwargs:
1295            menulabels = log.SaveMenuCommand(kwargs['id'],self.G2frame,handler)
1296            if menulabels:
1297                #print 'intercepting bind for',handler,menulabels,kwargs['id']
1298                wx.Frame.Bind(self,eventtype,self.G2frame.MenuBinding,*args,**kwargs)
1299                return
1300            wx.Frame.Bind(self,eventtype,handler,*args,**kwargs)     
1301       
1302    def PrefillDataMenu(self,menu,helpType,helpLbl=None,empty=False):
1303        '''Create the "standard" part of data frame menus. Note that on Linux and
1304        Windows nothing happens here. On Mac, this menu duplicates the
1305        tree menu, but adds an extra help command for the data item and a separator.
1306        '''
1307        self.datamenu = menu
1308        self.G2frame.dataMenuBars.append(menu)
1309        self.helpType = helpType
1310        self.helpLbl = helpLbl
1311        if sys.platform == "darwin": # mac                         
1312            self.G2frame.FillMainMenu(menu) # add the data tree menu items
1313            if not empty:
1314                menu.Append(wx.Menu(title=''),title='|') # add a separator
1315       
1316    def PostfillDataMenu(self,empty=False):
1317        '''Create the "standard" part of data frame menus. Note that on Linux and
1318        Windows, this is the standard help Menu. On Mac, this menu duplicates the
1319        tree menu, but adds an extra help command for the data item and a separator.
1320        '''
1321        menu = self.datamenu
1322        helpType = self.helpType
1323        helpLbl = self.helpLbl
1324        if sys.platform == "darwin": # mac
1325            if not empty:
1326                menu.Append(wx.Menu(title=''),title='|') # add another separator
1327            menu.Append(G2G.AddHelp(self.G2frame,helpType=helpType, helpLbl=helpLbl),
1328                        title='&Help')
1329        else: # other
1330            menu.Append(menu=G2G.MyHelp(self,helpType=helpType, helpLbl=helpLbl),
1331                        title='&Help')
1332
1333    def _init_menus(self):
1334        'define all GSAS-II data frame menus'
1335
1336        # for use where no menu or data frame help is provided
1337        self.BlankMenu = wx.MenuBar()
1338       
1339        # Controls
1340        self.ControlsMenu = wx.MenuBar()
1341        self.PrefillDataMenu(self.ControlsMenu,helpType='Controls',empty=True)
1342        self.PostfillDataMenu(empty=True)
1343       
1344        # Notebook
1345        self.DataNotebookMenu = wx.MenuBar() 
1346        self.PrefillDataMenu(self.DataNotebookMenu,helpType='Notebook',empty=True)
1347        self.PostfillDataMenu(empty=True)
1348       
1349        # Comments
1350        self.DataCommentsMenu = wx.MenuBar()
1351        self.PrefillDataMenu(self.DataCommentsMenu,helpType='Comments',empty=True)
1352        self.PostfillDataMenu(empty=True)
1353       
1354        # Constraints - something amiss here - get weird wx C++ error after refine!
1355        self.ConstraintMenu = wx.MenuBar()
1356        self.PrefillDataMenu(self.ConstraintMenu,helpType='Constraints')
1357        self.ConstraintTab = wx.Menu(title='')
1358        self.ConstraintMenu.Append(menu=self.ConstraintTab, title='Select tab')
1359        for id,txt in (
1360            (wxID_CONSPHASE,'Phase'),
1361            (wxID_CONSHAP,'Histogram/Phase'),
1362            (wxID_CONSHIST,'Histogram'),
1363            (wxID_CONSGLOBAL,'Global')):
1364            self.ConstraintTab.Append(
1365                id=id, kind=wx.ITEM_NORMAL,text=txt,
1366                help='Select '+txt+' constraint editing tab')
1367        self.ConstraintEdit = wx.Menu(title='')
1368        self.ConstraintMenu.Append(menu=self.ConstraintEdit, title='Edit')
1369        self.ConstraintEdit.Append(id=wxID_HOLDADD, kind=wx.ITEM_NORMAL,text='Add hold',
1370            help='Add hold on a parameter value')
1371        self.ConstraintEdit.Append(id=wxID_EQUIVADD, kind=wx.ITEM_NORMAL,text='Add equivalence',
1372            help='Add equivalence between parameter values')
1373        self.ConstraintEdit.Append(id=wxID_CONSTRAINTADD, kind=wx.ITEM_NORMAL,text='Add constraint',
1374            help='Add constraint on parameter values')
1375        self.ConstraintEdit.Append(id=wxID_FUNCTADD, kind=wx.ITEM_NORMAL,text='Add New Var',
1376            help='Add variable composed of existing parameter')
1377        self.ConstraintEdit.Append(id=wxID_EQUIVALANCEATOMS, kind=wx.ITEM_NORMAL,text='Add atom equivalence',
1378            help='Add equivalences between atom parameter values')
1379        self.ConstraintEdit.Enable(wxID_EQUIVALANCEATOMS,False)
1380#        self.ConstraintEdit.Append(id=wxID_ADDRIDING, kind=wx.ITEM_NORMAL,text='Add H riding constraints',
1381#            help='Add H atom riding constraints between atom parameter values')
1382#        self.ConstraintEdit.Enable(wxID_ADDRIDING,False)
1383        self.PostfillDataMenu()
1384
1385        # item = self.ConstraintEdit.Append(id=wx.ID_ANY,kind=wx.ITEM_NORMAL,text='Update GUI')
1386        # def UpdateGSASIIconstrGUI(event):
1387        #     import GSASIIconstrGUI
1388        #     reload(GSASIIconstrGUI)
1389        #     import GSASIIobj
1390        #     reload(GSASIIobj)
1391        # self.Bind(wx.EVT_MENU,UpdateGSASIIconstrGUI,id=item.GetId())
1392
1393        # Rigid bodies
1394        self.RigidBodyMenu = wx.MenuBar()
1395        self.PrefillDataMenu(self.RigidBodyMenu,helpType='Rigid bodies')
1396        self.ResidueRBMenu = wx.Menu(title='')
1397        self.ResidueRBMenu.Append(id=wxID_RIGIDBODYIMPORT, kind=wx.ITEM_NORMAL,text='Import XYZ',
1398            help='Import rigid body XYZ from file')
1399        self.ResidueRBMenu.Append(id=wxID_RESIDUETORSSEQ, kind=wx.ITEM_NORMAL,text='Define sequence',
1400            help='Define torsion sequence')
1401        self.ResidueRBMenu.Append(id=wxID_RIGIDBODYADD, kind=wx.ITEM_NORMAL,text='Import residues',
1402            help='Import residue rigid bodies from macro file')
1403        self.RigidBodyMenu.Append(menu=self.ResidueRBMenu, title='Edit Body')
1404        self.PostfillDataMenu()
1405
1406        self.VectorBodyMenu = wx.MenuBar()
1407        self.PrefillDataMenu(self.VectorBodyMenu,helpType='Vector rigid bodies')
1408        self.VectorRBEdit = wx.Menu(title='')
1409        self.VectorRBEdit.Append(id=wxID_VECTORBODYADD, kind=wx.ITEM_NORMAL,text='Add rigid body',
1410            help='Add vector rigid body')
1411        self.VectorBodyMenu.Append(menu=self.VectorRBEdit, title='Edit Vector Body')
1412        self.PostfillDataMenu()
1413
1414                   
1415        # Restraints
1416        self.RestraintTab = wx.Menu(title='')
1417        self.RestraintEdit = wx.Menu(title='')
1418        self.RestraintEdit.Append(id=wxID_RESTSELPHASE, kind=wx.ITEM_NORMAL,text='Select phase',
1419            help='Select phase')
1420        self.RestraintEdit.Append(id=wxID_RESTRAINTADD, kind=wx.ITEM_NORMAL,text='Add restraints',
1421            help='Add restraints')
1422        self.RestraintEdit.Enable(wxID_RESTRAINTADD,True)    #gets disabled if macromolecule phase
1423        self.RestraintEdit.Append(id=wxID_AARESTRAINTADD, kind=wx.ITEM_NORMAL,text='Add residue restraints',
1424            help='Add residue based restraints for macromolecules from macro file')
1425        self.RestraintEdit.Enable(wxID_AARESTRAINTADD,False)    #gets enabled if macromolecule phase
1426        self.RestraintEdit.Append(id=wxID_AARESTRAINTPLOT, kind=wx.ITEM_NORMAL,text='Plot residue restraints',
1427            help='Plot selected residue based restraints for macromolecules from macro file')
1428        self.RestraintEdit.Enable(wxID_AARESTRAINTPLOT,False)    #gets enabled if macromolecule phase
1429        self.RestraintEdit.Append(id=wxID_RESRCHANGEVAL, kind=wx.ITEM_NORMAL,text='Change value',
1430            help='Change observed value')
1431        self.RestraintEdit.Append(id=wxID_RESTCHANGEESD, kind=wx.ITEM_NORMAL,text='Change esd',
1432            help='Change esd in observed value')
1433        self.RestraintEdit.Append(id=wxID_RESTDELETE, kind=wx.ITEM_NORMAL,text='Delete restraints',
1434            help='Delete selected restraints')
1435
1436        self.RestraintMenu = wx.MenuBar()
1437        self.PrefillDataMenu(self.RestraintMenu,helpType='Restraints')
1438        self.RestraintMenu.Append(menu=self.RestraintTab, title='Select tab')
1439        self.RestraintMenu.Append(menu=self.RestraintEdit, title='Edit')
1440        self.PostfillDataMenu()
1441           
1442        # Sequential results
1443        self.SequentialMenu = wx.MenuBar()
1444        self.PrefillDataMenu(self.SequentialMenu,helpType='Sequential',helpLbl='Sequential Refinement')
1445        self.SequentialFile = wx.Menu(title='')
1446        self.SequentialMenu.Append(menu=self.SequentialFile, title='Columns')
1447        self.SequentialFile.Append(id=wxID_RENAMESEQSEL, kind=wx.ITEM_NORMAL,text='Rename selected',
1448            help='Rename selected sequential refinement columns')
1449        self.SequentialFile.Append(id=wxID_SAVESEQSEL, kind=wx.ITEM_NORMAL,text='Save selected as text',
1450            help='Save selected sequential refinement results as a text file')
1451        self.SequentialFile.Append(id=wxID_SAVESEQCSV, kind=wx.ITEM_NORMAL,text='Save all as CSV',
1452            help='Save all sequential refinement results as a CSV spreadsheet file')
1453        self.SequentialFile.Append(id=wxID_SAVESEQSELCSV, kind=wx.ITEM_NORMAL,text='Save selected as CSV',
1454            help='Save selected sequential refinement results as a CSV spreadsheet file')
1455        self.SequentialFile.Append(id=wxID_PLOTSEQSEL, kind=wx.ITEM_NORMAL,text='Plot selected',
1456            help='Plot selected sequential refinement results')
1457        self.SequentialFile.Append(id=wxID_AVESEQSEL, kind=wx.ITEM_NORMAL,text='Compute average',
1458            help='Compute average for selected parameter')           
1459        self.SequentialFile.Append(id=wxID_ORGSEQSEL, kind=wx.ITEM_NORMAL,text='Reorganize',
1460            help='Reorganize variables where variables change')
1461        self.SequentialPvars = wx.Menu(title='')
1462        self.SequentialMenu.Append(menu=self.SequentialPvars, title='Pseudo Vars')
1463        self.SequentialPvars.Append(
1464            id=wxADDSEQVAR, kind=wx.ITEM_NORMAL,text='Add Formula',
1465            help='Add a new custom pseudo-variable')
1466        self.SequentialPvars.Append(
1467            id=wxADDSEQDIST, kind=wx.ITEM_NORMAL,text='Add Distance',
1468            help='Add a new bond distance pseudo-variable')
1469        self.SequentialPvars.Append(
1470            id=wxADDSEQANGLE, kind=wx.ITEM_NORMAL,text='Add Angle',
1471            help='Add a new bond angle pseudo-variable')
1472        self.SequentialPvars.Append(
1473            id=wxDELSEQVAR, kind=wx.ITEM_NORMAL,text='Delete',
1474            help='Delete an existing pseudo-variable')
1475        self.SequentialPvars.Append(
1476            id=wxEDITSEQVAR, kind=wx.ITEM_NORMAL,text='Edit',
1477            help='Edit an existing pseudo-variable')
1478
1479        self.SequentialPfit = wx.Menu(title='')
1480        self.SequentialMenu.Append(menu=self.SequentialPfit, title='Parametric Fit')
1481        self.SequentialPfit.Append(
1482            id=wxADDPARFIT, kind=wx.ITEM_NORMAL,text='Add equation',
1483            help='Add a new equation to minimize')
1484        self.SequentialPfit.Append(
1485            id=wxCOPYPARFIT, kind=wx.ITEM_NORMAL,text='Copy equation',
1486            help='Copy an equation to minimize - edit it next')
1487        self.SequentialPfit.Append(
1488            id=wxDELPARFIT, kind=wx.ITEM_NORMAL,text='Delete equation',
1489            help='Delete an equation for parametric minimization')
1490        self.SequentialPfit.Append(
1491            id=wxEDITPARFIT, kind=wx.ITEM_NORMAL,text='Edit equation',
1492            help='Edit an existing parametric minimization equation')
1493        self.SequentialPfit.Append(
1494            id=wxDOPARFIT, kind=wx.ITEM_NORMAL,text='Fit to equation(s)',
1495            help='Perform a parametric minimization')
1496        self.PostfillDataMenu()
1497           
1498        # PWDR & SASD
1499        self.PWDRMenu = wx.MenuBar()
1500        self.PrefillDataMenu(self.PWDRMenu,helpType='PWDR Analysis',helpLbl='Powder Fit Error Analysis')
1501        self.ErrorAnal = wx.Menu(title='')
1502        self.PWDRMenu.Append(menu=self.ErrorAnal,title='Commands')
1503        self.ErrorAnal.Append(id=wxID_PWDANALYSIS,kind=wx.ITEM_NORMAL,text='Error Analysis',
1504            help='Error analysis on powder pattern')
1505        self.ErrorAnal.Append(id=wxID_PWDCOPY,kind=wx.ITEM_NORMAL,text='Copy params',
1506            help='Copy of PWDR parameters')
1507        self.ErrorAnal.Append(id=wxID_PLOTCTRLCOPY,kind=wx.ITEM_NORMAL,text='Copy plot controls',
1508            help='Copy of PWDR plot controls')
1509           
1510        self.PostfillDataMenu()
1511           
1512        # HKLF
1513        self.HKLFMenu = wx.MenuBar()
1514        self.PrefillDataMenu(self.HKLFMenu,helpType='HKLF Analysis',helpLbl='HKLF Fit Error Analysis')
1515        self.ErrorAnal = wx.Menu(title='')
1516        self.HKLFMenu.Append(menu=self.ErrorAnal,title='Commands')
1517        self.ErrorAnal.Append(id=wxID_PWDANALYSIS,kind=wx.ITEM_NORMAL,text='Error Analysis',
1518            help='Error analysis on single crystal data')
1519        self.ErrorAnal.Append(id=wxID_MERGEHKL,kind=wx.ITEM_NORMAL,text='Merge HKLs',
1520            help='Transform & merge HKLF data to new histogram')
1521        self.ErrorAnal.Append(id=wxID_PWD3DHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot 3D HKLs',
1522            help='Plot HKLs from single crystal data in 3D')
1523        self.ErrorAnal.Append(id=wxID_3DALLHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot all 3D HKLs',
1524            help='Plot HKLs from all single crystal data in 3D')
1525        self.ErrorAnal.Append(id=wxID_PWDCOPY,kind=wx.ITEM_NORMAL,text='Copy params',
1526            help='Copy of HKLF parameters')
1527        self.PostfillDataMenu()
1528           
1529        # PDR / Limits
1530        self.LimitMenu = wx.MenuBar()
1531        self.PrefillDataMenu(self.LimitMenu,helpType='Limits')
1532        self.LimitEdit = wx.Menu(title='')
1533        self.LimitMenu.Append(menu=self.LimitEdit, title='Edit')
1534        self.LimitEdit.Append(id=wxID_LIMITCOPY, kind=wx.ITEM_NORMAL,text='Copy',
1535            help='Copy limits to other histograms')
1536        self.LimitEdit.Append(id=wxID_ADDEXCLREGION, kind=wx.ITEM_NORMAL,text='Add exclude',
1537            help='Add excluded region - select a point on plot; drag to adjust')           
1538        self.PostfillDataMenu()
1539           
1540        # PDR / Background
1541        self.BackMenu = wx.MenuBar()
1542        self.PrefillDataMenu(self.BackMenu,helpType='Background')
1543        self.BackEdit = wx.Menu(title='')
1544        self.BackMenu.Append(menu=self.BackEdit, title='File')
1545        self.BackEdit.Append(id=wxID_BACKCOPY, kind=wx.ITEM_NORMAL,text='Copy',
1546            help='Copy background parameters to other histograms')
1547        self.BackEdit.Append(id=wxID_BACKFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
1548            help='Copy background refinement flags to other histograms')
1549        self.BackEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks',
1550            help='Move background peaks to Peak List')
1551        self.BackFixed = wx.Menu(title='') # fixed background point menu
1552        self.BackMenu.Append(menu=self.BackFixed, title='Fixed Points')
1553        self.wxID_BackPts = {}
1554        self.wxID_BackPts['Add'] = wx.NewId() # N.B. not using wxID_ global as for other menu items
1555        self.BackFixed.Append(id=self.wxID_BackPts['Add'], kind=wx.ITEM_RADIO,text='Add',
1556            help='Add fixed background points with mouse clicks')
1557        self.wxID_BackPts['Move'] = wx.NewId() 
1558        item = self.BackFixed.Append(id=self.wxID_BackPts['Move'], kind=wx.ITEM_RADIO,text='Move',
1559            help='Move selected fixed background points with mouse drags')
1560        item.Check(True)
1561        self.wxID_BackPts['Del'] = wx.NewId()
1562        self.BackFixed.Append(id=self.wxID_BackPts['Del'], kind=wx.ITEM_RADIO,text='Delete',
1563            help='Delete fixed background points with mouse clicks')
1564        self.wxID_BackPts['Clear'] = wx.NewId() 
1565        self.BackFixed.Append(id=self.wxID_BackPts['Clear'], kind=wx.ITEM_NORMAL,text='Clear',
1566            help='Clear fixed background points')
1567        self.wxID_BackPts['Fit'] = wx.NewId() 
1568        self.BackFixed.Append(id=self.wxID_BackPts['Fit'], kind=wx.ITEM_NORMAL,text='Fit background',
1569            help='Fit background function to fixed background points')
1570        self.PostfillDataMenu()
1571           
1572        # PDR / Instrument Parameters
1573        self.InstMenu = wx.MenuBar()
1574        self.PrefillDataMenu(self.InstMenu,helpType='Instrument Parameters')
1575        self.InstEdit = wx.Menu(title='')
1576        self.InstMenu.Append(menu=self.InstEdit, title='Operations')
1577        self.InstEdit.Append(help='Calibrate from indexed peaks', 
1578            id=wxID_INSTCALIB, kind=wx.ITEM_NORMAL,text='Calibrate')           
1579        self.InstEdit.Append(help='Reset instrument profile parameters to default', 
1580            id=wxID_INSTPRMRESET, kind=wx.ITEM_NORMAL,text='Reset profile')           
1581        self.InstEdit.Append(help='Load instrument profile parameters from file', 
1582            id=wxID_INSTLOAD, kind=wx.ITEM_NORMAL,text='Load profile...')           
1583        self.InstEdit.Append(help='Save all instrument profile parameters to one file', 
1584            id=wxID_INSTSAVE, kind=wx.ITEM_NORMAL,text='Save profile...')
1585        self.InstEdit.Append(help='Save instrument profile parameters to file', 
1586            id=wxID_INSTSAVEALL, kind=wx.ITEM_NORMAL,text='Save all profile...')           
1587        self.InstEdit.Append(help='Copy instrument profile parameters to other histograms', 
1588            id=wxID_INSTCOPY, kind=wx.ITEM_NORMAL,text='Copy')
1589        self.InstEdit.Append(id=wxID_INSTFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
1590            help='Copy instrument parameter refinement flags to other histograms')
1591#        self.InstEdit.Append(help='Change radiation type (Ka12 - synch)',
1592#            id=wxID_CHANGEWAVETYPE, kind=wx.ITEM_NORMAL,text='Change radiation')
1593        self.InstEdit.Append(id=wxID_INST1VAL, kind=wx.ITEM_NORMAL,text='Set one value',
1594            help='Set one instrument parameter value across multiple histograms')
1595
1596        self.PostfillDataMenu()
1597       
1598        # PDR / Sample Parameters
1599        self.SampleMenu = wx.MenuBar()
1600        self.PrefillDataMenu(self.SampleMenu,helpType='Sample Parameters')
1601        self.SampleEdit = wx.Menu(title='')
1602        self.SampleMenu.Append(menu=self.SampleEdit, title='Command')
1603        self.SetScale = self.SampleEdit.Append(id=wxID_SETSCALE, kind=wx.ITEM_NORMAL,text='Set scale',
1604            help='Set scale by matching to another histogram')
1605        self.SampleEdit.Append(id=wxID_SAMPLELOAD, kind=wx.ITEM_NORMAL,text='Load',
1606            help='Load sample parameters from file')
1607        self.SampleEdit.Append(id=wxID_SAMPLESAVE, kind=wx.ITEM_NORMAL,text='Save',
1608            help='Save sample parameters to file')
1609        self.SampleEdit.Append(id=wxID_SAMPLECOPY, kind=wx.ITEM_NORMAL,text='Copy',
1610            help='Copy refinable and most other sample parameters to other histograms')
1611        self.SampleEdit.Append(id=wxID_SAMPLECOPYSOME, kind=wx.ITEM_NORMAL,text='Copy selected...',
1612            help='Copy selected sample parameters to other histograms')
1613        self.SampleEdit.Append(id=wxID_SAMPLEFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
1614            help='Copy sample parameter refinement flags to other histograms')
1615        self.SampleEdit.Append(id=wxID_SAMPLE1VAL, kind=wx.ITEM_NORMAL,text='Set one value',
1616            help='Set one sample parameter value across multiple histograms')
1617        self.SampleEdit.Append(id=wxID_ALLSAMPLELOAD, kind=wx.ITEM_NORMAL,text='Load all',
1618            help='Load sample parmameters over multiple histograms')
1619
1620        self.PostfillDataMenu()
1621        self.SetScale.Enable(False)
1622
1623        # PDR / Peak List
1624        self.PeakMenu = wx.MenuBar()
1625        self.PrefillDataMenu(self.PeakMenu,helpType='Peak List')
1626        self.PeakEdit = wx.Menu(title='')
1627        self.PeakMenu.Append(menu=self.PeakEdit, title='Peak Fitting')
1628        self.AutoSearch = self.PeakEdit.Append(help='Automatic peak search', 
1629            id=wxID_AUTOSEARCH, kind=wx.ITEM_NORMAL,text='Auto search')
1630        self.UnDo = self.PeakEdit.Append(help='Undo last least squares refinement', 
1631            id=wxID_UNDO, kind=wx.ITEM_NORMAL,text='UnDo')
1632        self.PeakFit = self.PeakEdit.Append(id=wxID_LSQPEAKFIT, kind=wx.ITEM_NORMAL,text='Peakfit', 
1633            help='Peak fitting' )
1634        self.PFOneCycle = self.PeakEdit.Append(id=wxID_LSQONECYCLE, kind=wx.ITEM_NORMAL,text='Peakfit one cycle', 
1635            help='One cycle of Peak fitting' )
1636        self.PeakEdit.Append(id=wxID_RESETSIGGAM, kind=wx.ITEM_NORMAL, 
1637            text='Reset sig and gam',help='Reset sigma and gamma to global fit' )
1638        self.PeakCopy = self.PeakEdit.Append(help='Copy peaks to other histograms', 
1639            id=wxID_PEAKSCOPY, kind=wx.ITEM_NORMAL,text='Peak copy')
1640        self.SeqPeakFit = self.PeakEdit.Append(id=wxID_SEQPEAKFIT, kind=wx.ITEM_NORMAL,text='Seq PeakFit', 
1641            help='Sequential Peak fitting for all histograms' )
1642        self.PeakEdit.Append(id=wxID_CLEARPEAKS, kind=wx.ITEM_NORMAL,text='Clear peaks', 
1643            help='Clear the peak list' )
1644        self.PostfillDataMenu()
1645        self.UnDo.Enable(False)
1646        self.PeakFit.Enable(False)
1647        self.PFOneCycle.Enable(False)
1648        self.AutoSearch.Enable(True)
1649       
1650        # PDR / Index Peak List
1651        self.IndPeaksMenu = wx.MenuBar()
1652        self.PrefillDataMenu(self.IndPeaksMenu,helpType='Index Peak List')
1653        self.IndPeaksEdit = wx.Menu(title='')
1654        self.IndPeaksMenu.Append(menu=self.IndPeaksEdit,title='Operations')
1655        self.IndPeaksEdit.Append(help='Load/Reload index peaks from peak list',id=wxID_INDXRELOAD, 
1656            kind=wx.ITEM_NORMAL,text='Load/Reload')
1657        self.PostfillDataMenu()
1658       
1659        # PDR / Unit Cells List
1660        self.IndexMenu = wx.MenuBar()
1661        self.PrefillDataMenu(self.IndexMenu,helpType='Unit Cells List')
1662        self.IndexEdit = wx.Menu(title='')
1663        self.IndexMenu.Append(menu=self.IndexEdit, title='Cell Index/Refine')
1664        self.IndexPeaks = self.IndexEdit.Append(help='', id=wxID_INDEXPEAKS, kind=wx.ITEM_NORMAL,
1665            text='Index Cell')
1666        self.CopyCell = self.IndexEdit.Append( id=wxID_COPYCELL, kind=wx.ITEM_NORMAL,text='Copy Cell', 
1667            help='Copy selected unit cell from indexing to cell refinement fields')
1668        self.RefineCell = self.IndexEdit.Append( id=wxID_REFINECELL, kind=wx.ITEM_NORMAL, 
1669            text='Refine Cell',help='Refine unit cell parameters from indexed peaks')
1670        self.MakeNewPhase = self.IndexEdit.Append( id=wxID_MAKENEWPHASE, kind=wx.ITEM_NORMAL,
1671            text='Make new phase',help='Make new phase from selected unit cell')
1672        self.ExportCells = self.IndexEdit.Append( id=wxID_EXPORTCELLS, kind=wx.ITEM_NORMAL,
1673            text='Export cell list',help='Export cell list to csv file')
1674        self.PostfillDataMenu()
1675        self.IndexPeaks.Enable(False)
1676        self.CopyCell.Enable(False)
1677        self.RefineCell.Enable(False)
1678        self.MakeNewPhase.Enable(False)
1679       
1680        # PDR / Reflection Lists
1681        self.ReflMenu = wx.MenuBar()
1682        self.PrefillDataMenu(self.ReflMenu,helpType='Reflection List')
1683        self.ReflEdit = wx.Menu(title='')
1684        self.ReflMenu.Append(menu=self.ReflEdit, title='Reflection List')
1685        self.SelectPhase = self.ReflEdit.Append(help='Select phase for reflection list',id=wxID_SELECTPHASE, 
1686            kind=wx.ITEM_NORMAL,text='Select phase')
1687        self.ReflEdit.Append(id=wxID_PWDHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot HKLs',
1688            help='Plot HKLs from powder pattern')
1689        self.ReflEdit.Append(id=wxID_PWD3DHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot 3D HKLs',
1690            help='Plot HKLs from powder pattern in 3D')
1691        self.PostfillDataMenu()
1692       
1693        # SASD / Instrument Parameters
1694        self.SASDInstMenu = wx.MenuBar()
1695        self.PrefillDataMenu(self.SASDInstMenu,helpType='Instrument Parameters')
1696        self.SASDInstEdit = wx.Menu(title='')
1697        self.SASDInstMenu.Append(menu=self.SASDInstEdit, title='Operations')
1698        self.InstEdit.Append(help='Reset instrument profile parameters to default', 
1699            id=wxID_INSTPRMRESET, kind=wx.ITEM_NORMAL,text='Reset profile')
1700        self.SASDInstEdit.Append(help='Copy instrument profile parameters to other histograms', 
1701            id=wxID_INSTCOPY, kind=wx.ITEM_NORMAL,text='Copy')
1702        self.PostfillDataMenu()
1703       
1704        #SASD & REFL/ Substance editor
1705        self.SubstanceMenu = wx.MenuBar()
1706        self.PrefillDataMenu(self.SubstanceMenu,helpType='Substances')
1707        self.SubstanceEdit = wx.Menu(title='')
1708        self.SubstanceMenu.Append(menu=self.SubstanceEdit, title='Edit')
1709        self.SubstanceEdit.Append(id=wxID_LOADSUBSTANCE, kind=wx.ITEM_NORMAL,text='Load substance',
1710            help='Load substance from file')
1711        self.SubstanceEdit.Append(id=wxID_ADDSUBSTANCE, kind=wx.ITEM_NORMAL,text='Add substance',
1712            help='Add new substance to list')
1713        self.SubstanceEdit.Append(id=wxID_COPYSUBSTANCE, kind=wx.ITEM_NORMAL,text='Copy substances',
1714            help='Copy substances')
1715        self.SubstanceEdit.Append(id=wxID_DELETESUBSTANCE, kind=wx.ITEM_NORMAL,text='Delete substance',
1716            help='Delete substance from list')           
1717        self.SubstanceEdit.Append(id=wxID_ELEMENTADD, kind=wx.ITEM_NORMAL,text='Add elements',
1718            help='Add elements to substance')
1719        self.SubstanceEdit.Append(id=wxID_ELEMENTDELETE, kind=wx.ITEM_NORMAL,text='Delete elements',
1720            help='Delete elements from substance')
1721        self.PostfillDataMenu()
1722       
1723        # SASD/ Models
1724        self.ModelMenu = wx.MenuBar()
1725        self.PrefillDataMenu(self.ModelMenu,helpType='Models')
1726        self.ModelEdit = wx.Menu(title='')
1727        self.ModelMenu.Append(menu=self.ModelEdit, title='Models')
1728        self.ModelEdit.Append(id=wxID_MODELADD,kind=wx.ITEM_NORMAL,text='Add',
1729            help='Add new term to model')
1730        self.ModelEdit.Append(id=wxID_MODELFIT, kind=wx.ITEM_NORMAL,text='Fit',
1731            help='Fit model parameters to data')
1732        self.SasdUndo = self.ModelEdit.Append(id=wxID_MODELUNDO, kind=wx.ITEM_NORMAL,text='Undo',
1733            help='Undo model fit')
1734        self.SasdUndo.Enable(False)           
1735        self.ModelEdit.Append(id=wxID_MODELFITALL, kind=wx.ITEM_NORMAL,text='Sequential fit',
1736            help='Sequential fit of model parameters to all SASD data')
1737        self.ModelEdit.Append(id=wxID_MODELCOPY, kind=wx.ITEM_NORMAL,text='Copy',
1738            help='Copy model parameters to other histograms')
1739        self.ModelEdit.Append(id=wxID_MODELCOPYFLAGS, kind=wx.ITEM_NORMAL,text='Copy flags',
1740            help='Copy model refinement flags to other histograms')
1741        self.PostfillDataMenu()
1742       
1743        # IMG / Image Controls
1744        self.ImageMenu = wx.MenuBar()
1745        self.PrefillDataMenu(self.ImageMenu,helpType='Image Controls')
1746        self.ImageEdit = wx.Menu(title='')
1747        self.ImageMenu.Append(menu=self.ImageEdit, title='Operations')
1748        self.ImageEdit.Append(help='Calibrate detector by fitting to calibrant lines', 
1749            id=wxID_IMCALIBRATE, kind=wx.ITEM_NORMAL,text='Calibrate')
1750        self.ImageEdit.Append(help='Recalibrate detector by fitting to calibrant lines', 
1751            id=wxID_IMRECALIBRATE, kind=wx.ITEM_NORMAL,text='Recalibrate')
1752        self.ImageEdit.Append(help='Recalibrate all images by fitting to calibrant lines', 
1753            id=wxID_IMRECALIBALL, kind=wx.ITEM_NORMAL,text='Recalibrate all')           
1754        self.ImageEdit.Append(help='Clear calibration data points and rings',id=wxID_IMCLEARCALIB, 
1755            kind=wx.ITEM_NORMAL,text='Clear calibration')
1756        self.ImageEdit.Append(help='Integrate selected image',id=wxID_IMINTEGRATE, 
1757            kind=wx.ITEM_NORMAL,text='Integrate')
1758        self.ImageEdit.Append(help='Integrate all images selected from list',id=wxID_INTEGRATEALL,
1759            kind=wx.ITEM_NORMAL,text='Integrate all')
1760        self.ImageEdit.Append(help='Copy image controls to other images', 
1761            id=wxID_IMCOPYCONTROLS, kind=wx.ITEM_NORMAL,text='Copy Controls')
1762        self.ImageEdit.Append(help='Copy selected image controls to other images', 
1763            id=wxID_IMCOPYSELECTED, kind=wx.ITEM_NORMAL,text='Copy Selected')
1764        self.ImageEdit.Append(help='Save image controls to file', 
1765            id=wxID_IMSAVECONTROLS, kind=wx.ITEM_NORMAL,text='Save Controls')
1766        self.ImageEdit.Append(help='Load image controls from file', 
1767            id=wxID_IMLOADCONTROLS, kind=wx.ITEM_NORMAL,text='Load Controls')
1768        self.ImageEdit.Append(help='Open Auto-integration window to integrate a series of images', 
1769            id=wxID_IMAUTOINTEG, kind=wx.ITEM_NORMAL,text='Auto Integrate')
1770        self.PostfillDataMenu()
1771           
1772        # IMG / Masks
1773        self.MaskMenu = wx.MenuBar()
1774        self.PrefillDataMenu(self.MaskMenu,helpType='Image Masks')
1775        self.MaskEdit = wx.Menu(title='')
1776        self.MaskMenu.Append(menu=self.MaskEdit, title='Operations')
1777        submenu = wx.Menu()
1778        self.MaskEdit.AppendMenu(
1779            wx.ID_ANY,'Create new', submenu,
1780            help=''
1781            )
1782        self.MaskEdit.Append(help='Copy mask to other images', 
1783            id=wxID_MASKCOPY, kind=wx.ITEM_NORMAL,text='Copy mask')
1784        self.MaskEdit.Append(help='Save mask to file', 
1785            id=wxID_MASKSAVE, kind=wx.ITEM_NORMAL,text='Save mask')
1786        self.MaskEdit.Append(help='Load mask from file', 
1787            id=wxID_MASKLOAD, kind=wx.ITEM_NORMAL,text='Load mask')
1788        self.MaskEdit.Append(help='Load mask from file; ignore threshold', 
1789            id=wxID_MASKLOADNOT, kind=wx.ITEM_NORMAL,text='Load mask w/o threshold')
1790        submenu.Append(help='Create an arc mask with mouse input', 
1791            id=wxID_NEWMASKARC, kind=wx.ITEM_NORMAL,text='Arc mask')
1792        submenu.Append(help='Create a frame mask with mouse input', 
1793            id=wxID_NEWMASKFRAME, kind=wx.ITEM_NORMAL,text='Frame mask')
1794        submenu.Append(help='Create a polygon mask with mouse input', 
1795            id=wxID_NEWMASKPOLY, kind=wx.ITEM_NORMAL,text='Polygon mask')
1796        submenu.Append(help='Create a ring mask with mouse input', 
1797            id=wxID_NEWMASKRING, kind=wx.ITEM_NORMAL,text='Ring mask')
1798        submenu.Append(help='Create a spot mask with mouse input', 
1799            id=wxID_NEWMASKSPOT, kind=wx.ITEM_NORMAL,text='Spot mask')
1800        self.PostfillDataMenu()
1801           
1802        # IMG / Stress/Strain
1803        self.StrStaMenu = wx.MenuBar()
1804        self.PrefillDataMenu(self.StrStaMenu,helpType='Stress/Strain')
1805        self.StrStaEdit = wx.Menu(title='')
1806        self.StrStaMenu.Append(menu=self.StrStaEdit, title='Operations')
1807        self.StrStaEdit.Append(help='Append d-zero for one ring', 
1808            id=wxID_APPENDDZERO, kind=wx.ITEM_NORMAL,text='Append d-zero')
1809        self.StrStaEdit.Append(help='Fit stress/strain data', 
1810            id=wxID_STRSTAFIT, kind=wx.ITEM_NORMAL,text='Fit stress/strain')
1811        self.StrStaEdit.Append(help='Update d-zero from ave d-zero',
1812            id=wxID_UPDATEDZERO, kind=wx.ITEM_NORMAL,text='Update d-zero')       
1813        self.StrStaEdit.Append(help='Fit stress/strain data for all images', 
1814            id=wxID_STRSTAALLFIT, kind=wx.ITEM_NORMAL,text='All image fit')
1815        self.StrStaEdit.Append(help='Copy stress/strain data to other images', 
1816            id=wxID_STRSTACOPY, kind=wx.ITEM_NORMAL,text='Copy stress/strain')
1817        self.StrStaEdit.Append(help='Save stress/strain data to file', 
1818            id=wxID_STRSTASAVE, kind=wx.ITEM_NORMAL,text='Save stress/strain')
1819        self.StrStaEdit.Append(help='Load stress/strain data from file', 
1820            id=wxID_STRSTALOAD, kind=wx.ITEM_NORMAL,text='Load stress/strain')
1821        self.StrStaEdit.Append(help='Load sample data from file', 
1822            id=wxID_STRSTSAMPLE, kind=wx.ITEM_NORMAL,text='Load sample data')
1823        self.PostfillDataMenu()
1824           
1825        # PDF / PDF Controls
1826        self.PDFMenu = wx.MenuBar()
1827        self.PrefillDataMenu(self.PDFMenu,helpType='PDF Controls')
1828        self.PDFEdit = wx.Menu(title='')
1829        self.PDFMenu.Append(menu=self.PDFEdit, title='PDF Controls')
1830        self.PDFEdit.Append(help='Add element to sample composition',id=wxID_PDFADDELEMENT, kind=wx.ITEM_NORMAL,
1831            text='Add element')
1832        self.PDFEdit.Append(help='Delete element from sample composition',id=wxID_PDFDELELEMENT, kind=wx.ITEM_NORMAL,
1833            text='Delete element')
1834        self.PDFEdit.Append(help='Copy PDF controls', id=wxID_PDFCOPYCONTROLS, kind=wx.ITEM_NORMAL,
1835            text='Copy controls')
1836        self.PDFEdit.Append(help='Load PDF controls from file',id=wxID_PDFLOADCONTROLS, kind=wx.ITEM_NORMAL,
1837            text='Load Controls')
1838        self.PDFEdit.Append(help='Save PDF controls to file', id=wxID_PDFSAVECONTROLS, kind=wx.ITEM_NORMAL,
1839            text='Save controls')
1840        self.PDFEdit.Append(help='Compute PDF', id=wxID_PDFCOMPUTE, kind=wx.ITEM_NORMAL,
1841            text='Compute PDF')
1842        self.PDFEdit.Append(help='Compute all PDFs', id=wxID_PDFCOMPUTEALL, kind=wx.ITEM_NORMAL,
1843            text='Compute all PDFs')
1844        self.PostfillDataMenu()
1845       
1846        # Phase / General tab
1847        self.DataGeneral = wx.MenuBar()
1848        self.PrefillDataMenu(self.DataGeneral,helpType='General', helpLbl='Phase/General')
1849        self.DataGeneral.Append(menu=wx.Menu(title=''),title='Select tab')
1850        self.GeneralCalc = wx.Menu(title='')
1851        self.DataGeneral.Append(menu=self.GeneralCalc,title='Compute')
1852        self.GeneralCalc.Append(help='Compute Fourier map',id=wxID_FOURCALC, kind=wx.ITEM_NORMAL,
1853            text='Fourier map')
1854        self.GeneralCalc.Append(help='Search Fourier map',id=wxID_FOURSEARCH, kind=wx.ITEM_NORMAL,
1855            text='Search map')
1856        self.GeneralCalc.Append(help='Run charge flipping',id=wxID_CHARGEFLIP, kind=wx.ITEM_NORMAL,
1857            text='Charge flipping')
1858        self.GeneralCalc.Append(help='Run 4D charge flipping',id=wxID_4DCHARGEFLIP, kind=wx.ITEM_NORMAL,
1859            text='4D Charge flipping')
1860        self.GeneralCalc.Enable(wxID_4DCHARGEFLIP,False)   
1861        self.GeneralCalc.Append(help='Clear map',id=wxID_FOURCLEAR, kind=wx.ITEM_NORMAL,
1862            text='Clear map')
1863        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing',id=wxID_SINGLEMCSA, kind=wx.ITEM_NORMAL,
1864            text='MC/SA')
1865        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing on multiprocessors',id=wxID_MULTIMCSA, kind=wx.ITEM_NORMAL,
1866            text='Multi MC/SA')            #currently not useful
1867        self.GeneralCalc.Append(help='Transform crystal structure',id=wxID_TRANSFORMSTRUCTURE, kind=wx.ITEM_NORMAL,
1868            text='Transform')
1869        self.PostfillDataMenu()
1870       
1871        # Phase / Data tab
1872        self.DataMenu = wx.MenuBar()
1873        self.PrefillDataMenu(self.DataMenu,helpType='Data', helpLbl='Phase/Data')
1874        self.DataMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1875        self.DataEdit = wx.Menu(title='')
1876        self.DataMenu.Append(menu=self.DataEdit, title='Edit')
1877        self.DataEdit.Append(id=wxID_DATACOPY, kind=wx.ITEM_NORMAL,text='Copy data',
1878            help='Copy phase data to other histograms')
1879        self.DataEdit.Append(id=wxID_DATACOPYFLAGS, kind=wx.ITEM_NORMAL,text='Copy flags',
1880            help='Copy phase data flags to other histograms')
1881        self.DataEdit.Append(id=wxID_DATASELCOPY, kind=wx.ITEM_NORMAL,text='Copy selected data',
1882            help='Copy selected phase data to other histograms')
1883        self.DataEdit.Append(id=wxID_DATAUSE, kind=wx.ITEM_NORMAL,text='Select used data',
1884            help='Select all histograms to use')
1885        self.DataEdit.Append(id=wxID_PWDRADD, kind=wx.ITEM_NORMAL,text='Add powder histograms',
1886            help='Select new powder histograms to be used for this phase')
1887        self.DataEdit.Append(id=wxID_HKLFADD, kind=wx.ITEM_NORMAL,text='Add single crystal histograms',
1888            help='Select new single crystal histograms to be used for this phase')
1889        self.DataEdit.Append(id=wxID_DATADELETE, kind=wx.ITEM_NORMAL,text='Remove histograms',
1890            help='Remove histograms from use for this phase')
1891        self.PostfillDataMenu()
1892           
1893        # Phase / Atoms tab
1894        self.AtomsMenu = wx.MenuBar()
1895        self.PrefillDataMenu(self.AtomsMenu,helpType='Atoms')
1896        self.AtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1897        self.AtomEdit = wx.Menu(title='')
1898        self.AtomCompute = wx.Menu(title='')
1899        self.AtomsMenu.Append(menu=self.AtomEdit, title='Edit')
1900        self.AtomsMenu.Append(menu=self.AtomCompute, title='Compute')
1901        self.AtomEdit.Append(id=wxID_ATOMSEDITADD, kind=wx.ITEM_NORMAL,text='Append atom',
1902            help='Appended as an H atom')
1903        self.AtomEdit.Append(id=wxID_ATOMSVIEWADD, kind=wx.ITEM_NORMAL,text='Append view point',
1904            help='Appended as an H atom')
1905        self.AtomEdit.Append(id=wxID_ATOMSEDITINSERT, kind=wx.ITEM_NORMAL,text='Insert atom',
1906            help='Select atom row to insert before; inserted as an H atom')
1907        self.AtomEdit.Append(id=wxID_ATOMVIEWINSERT, kind=wx.ITEM_NORMAL,text='Insert view point',
1908            help='Select atom row to insert before; inserted as an H atom')
1909        self.AtomEdit.Append(id=wxID_ADDHATOM, kind=wx.ITEM_NORMAL,text='Insert H atoms',
1910            help='Insert H atoms in standard positions bonded to selected atoms')
1911        self.AtomEdit.Append(id=wxID_UPDATEHATOM, kind=wx.ITEM_NORMAL,text='Update H atoms',
1912            help='Update H atoms in standard positions')
1913        self.AtomEdit.Append(id=wxID_ATOMMOVE, kind=wx.ITEM_NORMAL,text='Move atom to view point',
1914            help='Select single atom to move')
1915        self.AtomEdit.Append(id=wxID_ATOMSEDITDELETE, kind=wx.ITEM_NORMAL,text='Delete atom',
1916            help='Select atoms to delete first')
1917        self.AtomEdit.Append(id=wxID_ATOMSREFINE, kind=wx.ITEM_NORMAL,text='Set atom refinement flags',
1918            help='Select atoms to refine first')
1919        self.AtomEdit.Append(id=wxID_ATOMSMODIFY, kind=wx.ITEM_NORMAL,text='Modify atom parameters',
1920            help='Select atoms to modify first')
1921        self.AtomEdit.Append(id=wxID_ATOMSTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform atoms',
1922            help='Select atoms to transform first')
1923#        self.AtomEdit.Append(id=wxID_ATOMSROTATE, kind=wx.ITEM_NORMAL,text='Rotate atoms',
1924#            help='Select atoms to rotate first')
1925        self.AtomEdit.Append(id=wxID_MAKEMOLECULE, kind=wx.ITEM_NORMAL,text='Assemble molecule',
1926            help='Assemble molecule from scatterd atom positions')
1927        self.AtomEdit.Append(id=wxID_RELOADDRAWATOMS, kind=wx.ITEM_NORMAL,text='Reload draw atoms',
1928            help='Reload atom drawing list')
1929        submenu = wx.Menu()
1930        self.AtomEdit.AppendMenu(wx.ID_ANY, 'Reimport atoms', submenu, 
1931            help='Reimport atoms from file; sequence must match')
1932        # setup a cascade menu for the formats that have been defined
1933        self.ReImportMenuId = {}  # points to readers for each menu entry
1934        for reader in self.G2frame.ImportPhaseReaderlist:
1935            item = submenu.Append(
1936                wx.ID_ANY,help=reader.longFormatName,
1937                kind=wx.ITEM_NORMAL,text='reimport coordinates from '+reader.formatName+' file')
1938            self.ReImportMenuId[item.GetId()] = reader
1939        item = submenu.Append(
1940            wx.ID_ANY,
1941            help='Reimport coordinates, try to determine format from file',
1942            kind=wx.ITEM_NORMAL,
1943            text='guess format from file')
1944        self.ReImportMenuId[item.GetId()] = None # try all readers
1945
1946        self.AtomCompute.Append(id=wxID_ATOMSDISAGL, kind=wx.ITEM_NORMAL,text='Show Distances && Angles',
1947            help='Compute distances & angles for selected atoms')
1948        self.AtomCompute.Append(id=wxID_ATOMSPDISAGL, kind=wx.ITEM_NORMAL,text='Save Distances && Angles',
1949            help='Compute distances & angles for selected atoms')
1950        self.AtomCompute.ISOcalc = self.AtomCompute.Append(
1951            id=wxID_ISODISP, kind=wx.ITEM_NORMAL,
1952            text='Compute ISODISTORT mode values',
1953            help='Compute values of ISODISTORT modes from atom parameters')
1954        self.PostfillDataMenu()
1955       
1956        # Phase / Imcommensurate "waves" tab
1957        self.WavesData = wx.MenuBar()
1958        self.PrefillDataMenu(self.WavesData,helpType='Wave Data', helpLbl='Imcommensurate wave data')
1959        self.WavesData.Append(menu=wx.Menu(title=''),title='Select tab')
1960        self.WavesDataEdit = wx.Menu(title='')
1961        self.WavesData.Append(menu=self.WavesDataEdit, title='Edit')
1962        self.WavesDataEdit.Append(id=wxID_WAVEVARY, kind=wx.ITEM_NORMAL,text='Global wave vary',
1963            help='Global setting of wave vary flags')
1964        self.PostfillDataMenu()
1965       
1966        # Phase / Layer tab
1967        self.LayerData = wx.MenuBar()
1968        self.PrefillDataMenu(self.LayerData,helpType='Layer Data', helpLbl='Stacking fault layers')
1969        self.LayerData.Append(menu=wx.Menu(title=''),title='Select tab')
1970        self.LayerDataEdit = wx.Menu(title='')
1971        self.LayerData.Append(menu=self.LayerDataEdit, title='Operations')
1972        self.LayerDataEdit.Append(id=wxID_LOADDIFFAX, kind=wx.ITEM_NORMAL,text='Load from DIFFaX file',
1973            help='Load layer info from DIFFaX file')
1974        self.LayerDataEdit.Append(id=wxID_COPYPHASE, kind=wx.ITEM_NORMAL,text='Copy phase cell',
1975            help='Copy phase cell from another project')
1976        self.LayerDataEdit.Append(id=wxID_LAYERSIMULATE, kind=wx.ITEM_NORMAL,text='Simulate pattern',
1977            help='Simulate diffraction pattern from layer stacking')
1978        self.LayerDataEdit.Append(id=wxID_SEQUENCESIMULATE, kind=wx.ITEM_NORMAL,text='Sequence simulations',
1979            help='Sequence simulation changing one parameter')
1980        self.PostfillDataMenu()
1981                 
1982        # Phase / Draw Options tab
1983        self.DataDrawOptions = wx.MenuBar()
1984        self.PrefillDataMenu(self.DataDrawOptions,helpType='Draw Options', helpLbl='Phase/Draw Options')
1985        self.DataDrawOptions.Append(menu=wx.Menu(title=''),title='Select tab')
1986        self.PostfillDataMenu()
1987       
1988        # Phase / Draw Atoms tab
1989        self.DrawAtomsMenu = wx.MenuBar()
1990        self.PrefillDataMenu(self.DrawAtomsMenu,helpType='Draw Atoms')
1991        self.DrawAtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1992        self.DrawAtomEdit = wx.Menu(title='')
1993        self.DrawAtomCompute = wx.Menu(title='')
1994        self.DrawAtomRestraint = wx.Menu(title='')
1995        self.DrawAtomRigidBody = wx.Menu(title='')
1996        self.DrawAtomsMenu.Append(menu=self.DrawAtomEdit, title='Edit')
1997        self.DrawAtomsMenu.Append(menu=self.DrawAtomCompute,title='Compute')
1998        self.DrawAtomsMenu.Append(menu=self.DrawAtomRestraint, title='Restraints')
1999        self.DrawAtomsMenu.Append(menu=self.DrawAtomRigidBody, title='Rigid body')
2000        self.DrawAtomEdit.Append(id=wxID_DRAWATOMSTYLE, kind=wx.ITEM_NORMAL,text='Atom style',
2001            help='Select atoms first')
2002        self.DrawAtomEdit.Append(id=wxID_DRAWATOMLABEL, kind=wx.ITEM_NORMAL,text='Atom label',
2003            help='Select atoms first')
2004        self.DrawAtomEdit.Append(id=wxID_DRAWATOMCOLOR, kind=wx.ITEM_NORMAL,text='Atom color',
2005            help='Select atoms first')
2006        self.DrawAtomEdit.Append(id=wxID_DRAWATOMRESETCOLOR, kind=wx.ITEM_NORMAL,text='Reset atom colors',
2007            help='Resets all atom colors to defaults')
2008        self.DrawAtomEdit.Append(id=wxID_DRAWVIEWPOINT, kind=wx.ITEM_NORMAL,text='View point',
2009            help='View point is 1st atom selected')
2010        self.DrawAtomEdit.Append(id=wxID_DRAWADDEQUIV, kind=wx.ITEM_NORMAL,text='Add atoms',
2011            help='Add symmetry & cell equivalents to drawing set from selected atoms')
2012        self.DrawAtomEdit.Append(id=wxID_DRAWTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform draw atoms',
2013            help='Transform selected atoms by symmetry & cell translations')
2014        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCOORD, kind=wx.ITEM_NORMAL,text='Fill CN-sphere',
2015            help='Fill coordination sphere for selected atoms')           
2016        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCELL, kind=wx.ITEM_NORMAL,text='Fill unit cell',
2017            help='Fill unit cell with selected atoms')
2018        self.DrawAtomEdit.Append(id=wxID_DRAWDELETE, kind=wx.ITEM_NORMAL,text='Delete atoms',
2019            help='Delete atoms from drawing set')
2020        self.DrawAtomCompute.Append(id=wxID_DRAWDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2021            help='Compute distance of selected atoms from view point')   
2022        self.DrawAtomCompute.Append(id=wxID_DRAWDISAGLTOR, kind=wx.ITEM_NORMAL,text='Dist. Ang. Tors.',
2023            help='Compute distance, angle or torsion for 2-4 selected atoms')   
2024        self.DrawAtomCompute.Append(id=wxID_DRAWPLANE, kind=wx.ITEM_NORMAL,text='Best plane',
2025            help='Compute best plane for 4+ selected atoms')   
2026        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRBOND, kind=wx.ITEM_NORMAL,text='Add bond restraint',
2027            help='Add bond restraint for selected atoms (2)')
2028        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRANGLE, kind=wx.ITEM_NORMAL,text='Add angle restraint',
2029            help='Add angle restraint for selected atoms (3: one end 1st)')
2030        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRPLANE, kind=wx.ITEM_NORMAL,text='Add plane restraint',
2031            help='Add plane restraint for selected atoms (4+)')
2032        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRCHIRAL, kind=wx.ITEM_NORMAL,text='Add chiral restraint',
2033            help='Add chiral restraint for selected atoms (4: center atom 1st)')
2034        self.DrawAtomRigidBody.Append(id=wxID_DRAWDEFINERB, kind=wx.ITEM_NORMAL,text='Define rigid body',
2035            help='Define rigid body with selected atoms')
2036        self.PostfillDataMenu()
2037
2038        # Phase / MCSA tab
2039        self.MCSAMenu = wx.MenuBar()
2040        self.PrefillDataMenu(self.MCSAMenu,helpType='MC/SA')
2041        self.MCSAMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2042        self.MCSAEdit = wx.Menu(title='')
2043        self.MCSAMenu.Append(menu=self.MCSAEdit, title='MC/SA')
2044        self.MCSAEdit.Append(id=wxID_ADDMCSAATOM, kind=wx.ITEM_NORMAL,text='Add atom', 
2045            help='Add single atom to MC/SA model')
2046        self.MCSAEdit.Append(id=wxID_ADDMCSARB, kind=wx.ITEM_NORMAL,text='Add rigid body', 
2047            help='Add rigid body to MC/SA model' )
2048        self.MCSAEdit.Append(id=wxID_CLEARMCSARB, kind=wx.ITEM_NORMAL,text='Clear rigid bodies', 
2049            help='Clear all atoms & rigid bodies from MC/SA model' )
2050        self.MCSAEdit.Append(id=wxID_MOVEMCSA, kind=wx.ITEM_NORMAL,text='Move MC/SA solution', 
2051            help='Move MC/SA solution to atom list' )
2052        self.MCSAEdit.Append(id=wxID_MCSACLEARRESULTS, kind=wx.ITEM_NORMAL,text='Clear results', 
2053            help='Clear table of MC/SA results' )
2054        self.PostfillDataMenu()
2055           
2056        # Phase / Texture tab
2057        self.TextureMenu = wx.MenuBar()
2058        self.PrefillDataMenu(self.TextureMenu,helpType='Texture')
2059        self.TextureMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2060        self.TextureEdit = wx.Menu(title='')
2061        self.TextureMenu.Append(menu=self.TextureEdit, title='Texture')
2062        self.TextureEdit.Append(id=wxID_REFINETEXTURE, kind=wx.ITEM_NORMAL,text='Refine texture', 
2063            help='Refine the texture coefficients from sequential results')
2064#        self.TextureEdit.Append(id=wxID_CLEARTEXTURE, kind=wx.ITEM_NORMAL,text='Clear texture',
2065#            help='Clear the texture coefficients' )
2066        self.PostfillDataMenu()
2067           
2068        # Phase / Pawley tab
2069        self.PawleyMenu = wx.MenuBar()
2070        self.PrefillDataMenu(self.PawleyMenu,helpType='Pawley')
2071        self.PawleyMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2072        self.PawleyEdit = wx.Menu(title='')
2073        self.PawleyMenu.Append(menu=self.PawleyEdit,title='Operations')
2074        self.PawleyEdit.Append(id=wxID_PAWLEYLOAD, kind=wx.ITEM_NORMAL,text='Pawley create',
2075            help='Initialize Pawley reflection list')
2076        self.PawleyEdit.Append(id=wxID_PAWLEYESTIMATE, kind=wx.ITEM_NORMAL,text='Pawley estimate',
2077            help='Estimate initial Pawley intensities')
2078        self.PawleyEdit.Append(id=wxID_PAWLEYUPDATE, kind=wx.ITEM_NORMAL,text='Pawley update',
2079            help='Update negative Pawley intensities with -0.5*Fobs and turn off refinemnt')
2080        self.PostfillDataMenu()
2081           
2082        # Phase / Map peaks tab
2083        self.MapPeaksMenu = wx.MenuBar()
2084        self.PrefillDataMenu(self.MapPeaksMenu,helpType='Map peaks')
2085        self.MapPeaksMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2086        self.MapPeaksEdit = wx.Menu(title='')
2087        self.MapPeaksMenu.Append(menu=self.MapPeaksEdit, title='Map peaks')
2088        self.MapPeaksEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks', 
2089            help='Move selected peaks to atom list')
2090        self.MapPeaksEdit.Append(id=wxID_PEAKSVIEWPT, kind=wx.ITEM_NORMAL,text='View point',
2091            help='View point is 1st peak selected')
2092        self.MapPeaksEdit.Append(id=wxID_PEAKSDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2093            help='Compute distance of selected peaks from view point')   
2094        self.MapPeaksEdit.Append(id=wxID_SHOWBONDS, kind=wx.ITEM_NORMAL,text='Hide bonds',
2095            help='Hide or show bonds between peak positions')   
2096        self.MapPeaksEdit.Append(id=wxID_PEAKSDA, kind=wx.ITEM_NORMAL,text='Calc dist/ang', 
2097            help='Calculate distance or angle for selection')
2098        self.MapPeaksEdit.Append(id=wxID_FINDEQVPEAKS, kind=wx.ITEM_NORMAL,text='Equivalent peaks', 
2099            help='Find equivalent peaks')
2100        self.MapPeaksEdit.Append(id=wxID_PEAKSUNIQUE, kind=wx.ITEM_NORMAL,text='Unique peaks', 
2101            help='Select unique set')
2102        self.MapPeaksEdit.Append(id=wxID_PEAKSDELETE, kind=wx.ITEM_NORMAL,text='Delete peaks', 
2103            help='Delete selected peaks')
2104        self.MapPeaksEdit.Append(id=wxID_PEAKSCLEAR, kind=wx.ITEM_NORMAL,text='Clear peaks', 
2105            help='Clear the map peak list')
2106        self.PostfillDataMenu()
2107
2108        # Phase / Rigid bodies tab
2109        self.RigidBodiesMenu = wx.MenuBar()
2110        self.PrefillDataMenu(self.RigidBodiesMenu,helpType='Rigid bodies')
2111        self.RigidBodiesMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2112        self.RigidBodiesEdit = wx.Menu(title='')
2113        self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit')
2114        self.RigidBodiesEdit.Append(id=wxID_ASSIGNATMS2RB, kind=wx.ITEM_NORMAL,text='Assign atoms to rigid body',
2115            help='Select & position rigid body in structure of existing atoms')
2116        self.RigidBodiesEdit.Append(id=wxID_AUTOFINDRESRB, kind=wx.ITEM_NORMAL,text='Auto find residues',
2117            help='Auto find of residue RBs in macromolecule')
2118        self.RigidBodiesEdit.Append(id=wxID_COPYRBPARMS, kind=wx.ITEM_NORMAL,text='Copy rigid body parms',
2119            help='Copy rigid body location & TLS parameters')
2120        self.RigidBodiesEdit.Append(id=wxID_GLOBALTHERM, kind=wx.ITEM_NORMAL,text='Global thermal motion',
2121            help='Global setting of residue thermal motion models')
2122        self.RigidBodiesEdit.Append(id=wxID_GLOBALRESREFINE, kind=wx.ITEM_NORMAL,text='Global residue refine',
2123            help='Global setting of residue RB refinement flags')
2124        self.RigidBodiesEdit.Append(id=wxID_RBREMOVEALL, kind=wx.ITEM_NORMAL,text='Remove all rigid bodies',
2125            help='Remove all rigid body assignment for atoms')
2126        self.PostfillDataMenu()
2127    # end of GSAS-II menu definitions
2128       
2129    def _init_ctrls(self, parent,name=None,size=None,pos=None):
2130        wx.Frame.__init__(
2131            self,parent=parent,
2132            #style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT ,
2133            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX,
2134            size=size,pos=pos,title='GSAS-II data display')
2135        self._init_menus()
2136        if name:
2137            self.SetLabel(name)
2138        self.Show()
2139       
2140    def __init__(self,parent,frame,data=None,name=None, size=None,pos=None):
2141        self.G2frame = frame
2142        self._init_ctrls(parent,name,size,pos)
2143        self.data = data
2144        clientSize = wx.ClientDisplayRect()
2145        Size = self.GetSize()
2146        xPos = clientSize[2]-Size[0]
2147        self.SetPosition(wx.Point(xPos,clientSize[1]+250))
2148        self.AtomGrid = []
2149        self.selectedRow = 0
2150       
2151    def setSizePosLeft(self,Width):
2152        clientSize = wx.ClientDisplayRect()
2153        Width[1] = min(Width[1],clientSize[2]-300)
2154        Width[0] = max(Width[0],300)
2155        self.SetSize(Width)
2156#        self.SetPosition(wx.Point(clientSize[2]-Width[0],clientSize[1]+250))
2157       
2158    def Clear(self):
2159        self.ClearBackground()
2160        self.DestroyChildren()
2161                   
2162
2163################################################################################
2164#####  Notebook Tree Item editor
2165################################################################################                 
2166def UpdateNotebook(G2frame,data):
2167    '''Called when the data tree notebook entry is selected. Allows for
2168    editing of the text in that tree entry
2169    '''
2170    def OnNoteBook(event):
2171        data = G2frame.dataDisplay.GetValue().split('\n')
2172        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Notebook'),data)
2173        if 'nt' not in os.name:
2174            G2frame.dataDisplay.AppendText('\n')
2175                   
2176    if G2frame.dataDisplay:
2177        G2frame.dataDisplay.Destroy()
2178    G2frame.dataFrame.SetLabel('Notebook')
2179    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2180        style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
2181    G2frame.dataDisplay.Bind(wx.EVT_TEXT_ENTER,OnNoteBook)
2182    G2frame.dataDisplay.Bind(wx.EVT_KILL_FOCUS,OnNoteBook)
2183    for line in data:
2184        G2frame.dataDisplay.AppendText(line+"\n")
2185    G2frame.dataDisplay.AppendText('Notebook entry @ '+time.ctime()+"\n")
2186    G2frame.dataFrame.setSizePosLeft([400,250])
2187           
2188################################################################################
2189#####  Controls Tree Item editor
2190################################################################################           
2191def UpdateControls(G2frame,data):
2192    '''Edit overall GSAS-II controls in main Controls data tree entry
2193    '''
2194    #patch
2195    if 'deriv type' not in data:
2196        data = {}
2197        data['deriv type'] = 'analytic Hessian'
2198        data['min dM/M'] = 0.0001
2199        data['shift factor'] = 1.
2200        data['max cyc'] = 3       
2201        data['F**2'] = False
2202    if 'shift factor' not in data:
2203        data['shift factor'] = 1.
2204    if 'max cyc' not in data:
2205        data['max cyc'] = 3
2206    if 'F**2' not in data:
2207        data['F**2'] = False
2208    if 'Author' not in data:
2209        data['Author'] = 'no name'
2210    if 'FreePrm1' not in data:
2211        data['FreePrm1'] = 'Sample humidity (%)'
2212    if 'FreePrm2' not in data:
2213        data['FreePrm2'] = 'Sample voltage (V)'
2214    if 'FreePrm3' not in data:
2215        data['FreePrm3'] = 'Applied load (MN)'
2216    if 'Copy2Next' not in data:
2217        data['Copy2Next'] = False
2218    if 'Reverse Seq' not in data:
2219        data['Reverse Seq'] = False
2220    if 'UsrReject' not in data:
2221        data['UsrReject'] = {'minF/sig':0,'MinExt':0.01,'MaxDF/F':20.,'MaxD':500.,'MinD':0.05}
2222    if 'HatomFix' not in data:
2223        data['HatomFix'] = False
2224   
2225    #end patch
2226
2227    def SeqSizer():
2228       
2229        def OnSelectData(event):
2230            choices = GetPatternTreeDataNames(G2frame,['PWDR','HKLF',])
2231            sel = []
2232            try:
2233                if 'Seq Data' in data:
2234                    for item in data['Seq Data']:
2235                        sel.append(choices.index(item))
2236                    sel = [choices.index(item) for item in data['Seq Data']]
2237            except ValueError:  #data changed somehow - start fresh
2238                sel = []
2239            dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential refinement',
2240                'Select dataset to include',choices)
2241            dlg.SetSelections(sel)
2242            names = []
2243            if dlg.ShowModal() == wx.ID_OK:
2244                for sel in dlg.GetSelections():
2245                    names.append(choices[sel])
2246                data['Seq Data'] = names               
2247                G2frame.EnableSeqRefineMenu()
2248            dlg.Destroy()
2249            wx.CallAfter(UpdateControls,G2frame,data)
2250           
2251        def OnReverse(event):
2252            data['Reverse Seq'] = reverseSel.GetValue()
2253           
2254        def OnCopySel(event):
2255            data['Copy2Next'] = copySel.GetValue() 
2256                   
2257        seqSizer = wx.BoxSizer(wx.VERTICAL)
2258        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
2259        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Sequential Refinement: '),0,WACV)
2260        selSeqData = wx.Button(G2frame.dataDisplay,-1,label=' Select data')
2261        selSeqData.Bind(wx.EVT_BUTTON,OnSelectData)
2262        dataSizer.Add(selSeqData,0,WACV)
2263        SeqData = data.get('Seq Data',[])
2264        if not SeqData:
2265            lbl = ' (no data selected)'
2266        else:
2267            lbl = ' ('+str(len(SeqData))+' dataset(s) selected)'
2268
2269        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=lbl),0,WACV)
2270        seqSizer.Add(dataSizer,0)
2271        if SeqData:
2272            selSizer = wx.BoxSizer(wx.HORIZONTAL)
2273            reverseSel = wx.CheckBox(G2frame.dataDisplay,-1,label=' Reverse order?')
2274            reverseSel.Bind(wx.EVT_CHECKBOX,OnReverse)
2275            reverseSel.SetValue(data['Reverse Seq'])
2276            selSizer.Add(reverseSel,0,WACV)
2277            copySel =  wx.CheckBox(G2frame.dataDisplay,-1,label=' Copy results to next histogram?')
2278            copySel.Bind(wx.EVT_CHECKBOX,OnCopySel)
2279            copySel.SetValue(data['Copy2Next'])
2280            selSizer.Add(copySel,0,WACV)
2281            seqSizer.Add(selSizer,0)
2282        return seqSizer
2283       
2284    def LSSizer():       
2285       
2286        def OnDerivType(event):
2287            data['deriv type'] = derivSel.GetValue()
2288            derivSel.SetValue(data['deriv type'])
2289            wx.CallAfter(UpdateControls,G2frame,data)
2290           
2291        def OnConvergence(event):
2292            try:
2293                value = max(1.e-9,min(1.0,float(Cnvrg.GetValue())))
2294            except ValueError:
2295                value = 0.0001
2296            data['min dM/M'] = value
2297            Cnvrg.SetValue('%.2g'%(value))
2298           
2299        def OnMaxCycles(event):
2300            data['max cyc'] = int(maxCyc.GetValue())
2301            maxCyc.SetValue(str(data['max cyc']))
2302                       
2303        def OnFactor(event):
2304            try:
2305                value = min(max(float(Factr.GetValue()),0.00001),100.)
2306            except ValueError:
2307                value = 1.0
2308            data['shift factor'] = value
2309            Factr.SetValue('%.5f'%(value))
2310           
2311        def OnFsqRef(event):
2312            data['F**2'] = fsqRef.GetValue()
2313           
2314        def OnHatomFix(event):
2315            data['HatomFix'] = Hfix.GetValue()
2316       
2317        def OnUsrRej(event):
2318            Obj = event.GetEventObject()
2319            item,limits = Indx[Obj]
2320            try:
2321                value = min(max(float(Obj.GetValue()),limits[0]),limits[1])
2322            except ValueError:
2323                value = data['UsrReject'][item]
2324            data['UsrReject'][item] = value
2325            Obj.SetValue('%.2f'%(value))
2326
2327        LSSizer = wx.FlexGridSizer(cols=4,vgap=5,hgap=5)
2328        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement derivatives: '),0,WACV)
2329        Choice=['analytic Jacobian','numeric','analytic Hessian']
2330        derivSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['deriv type'],choices=Choice,
2331            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2332        derivSel.SetValue(data['deriv type'])
2333        derivSel.Bind(wx.EVT_COMBOBOX, OnDerivType)
2334           
2335        LSSizer.Add(derivSel,0,WACV)
2336        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min delta-M/M: '),0,WACV)
2337        Cnvrg = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2g'%(data['min dM/M']),style=wx.TE_PROCESS_ENTER)
2338        Cnvrg.Bind(wx.EVT_TEXT_ENTER,OnConvergence)
2339        Cnvrg.Bind(wx.EVT_KILL_FOCUS,OnConvergence)
2340        LSSizer.Add(Cnvrg,0,WACV)
2341        Indx = {}
2342        if 'Hessian' in data['deriv type']:
2343            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max cycles: '),0,WACV)
2344            Choice = ['0','1','2','3','5','10','15','20']
2345            maxCyc = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['max cyc']),choices=Choice,
2346                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2347            maxCyc.SetValue(str(data['max cyc']))
2348            maxCyc.Bind(wx.EVT_COMBOBOX, OnMaxCycles)
2349            LSSizer.Add(maxCyc,0,WACV)
2350        else:
2351            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial shift factor: '),0,WACV)
2352            Factr = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.5f'%(data['shift factor']),style=wx.TE_PROCESS_ENTER)
2353            Factr.Bind(wx.EVT_TEXT_ENTER,OnFactor)
2354            Factr.Bind(wx.EVT_KILL_FOCUS,OnFactor)
2355            LSSizer.Add(Factr,0,WACV)
2356        if G2frame.Sngl:
2357            userReject = data['UsrReject']
2358            usrRej = {'minF/sig':[' Min obs/sig (0-5): ',[0,5], ],'MinExt':[' Min extinct. (0-.9): ',[0,.9],],
2359                'MaxDF/F':[' Max delt-F/sig (3-1000): ',[3.,1000.],],'MaxD':[' Max d-spacing (3-500): ',[3,500],],
2360                'MinD':[' Min d-spacing (0.1-2.0): ',[0.1,2.0],]}
2361
2362            fsqRef = wx.CheckBox(G2frame.dataDisplay,-1,label='Refine HKLF as F^2? ')
2363            fsqRef.SetValue(data['F**2'])
2364            fsqRef.Bind(wx.EVT_CHECKBOX,OnFsqRef)
2365            LSSizer.Add(fsqRef,0,WACV)
2366            LSSizer.Add((1,0),)
2367            for item in usrRej:
2368                LSSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=usrRej[item][0]),0,WACV)
2369                usrrej = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(userReject[item]),style=wx.TE_PROCESS_ENTER)
2370                Indx[usrrej] = [item,usrRej[item][1]]
2371                usrrej.Bind(wx.EVT_TEXT_ENTER,OnUsrRej)
2372                usrrej.Bind(wx.EVT_KILL_FOCUS,OnUsrRej)
2373                LSSizer.Add(usrrej,0,WACV)
2374#        Hfix = wx.CheckBox(G2frame.dataDisplay,-1,label='Regularize H atoms? ')
2375#        Hfix.SetValue(data['HatomFix'])
2376#        Hfix.Bind(wx.EVT_CHECKBOX,OnHatomFix)
2377#        LSSizer.Add(Hfix,0,WACV)   #for now
2378        return LSSizer
2379       
2380    def AuthSizer():
2381
2382        def OnAuthor(event):
2383            data['Author'] = auth.GetValue()
2384
2385        Author = data['Author']
2386        authSizer = wx.BoxSizer(wx.HORIZONTAL)
2387        authSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' CIF Author (last, first):'),0,WACV)
2388        auth = wx.TextCtrl(G2frame.dataDisplay,-1,value=Author,style=wx.TE_PROCESS_ENTER)
2389        auth.Bind(wx.EVT_TEXT_ENTER,OnAuthor)
2390        auth.Bind(wx.EVT_KILL_FOCUS,OnAuthor)
2391        authSizer.Add(auth,0,WACV)
2392        return authSizer
2393       
2394       
2395    if G2frame.dataDisplay:
2396        G2frame.dataDisplay.Destroy()
2397    if not G2frame.dataFrame.GetStatusBar():
2398        Status = G2frame.dataFrame.CreateStatusBar()
2399        Status.SetStatusText('')
2400    G2frame.dataFrame.SetLabel('Controls')
2401    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2402    SetDataMenuBar(G2frame,G2frame.dataFrame.ControlsMenu)
2403    mainSizer = wx.BoxSizer(wx.VERTICAL)
2404    mainSizer.Add((5,5),0)
2405    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement Controls:'),0,WACV)   
2406    mainSizer.Add(LSSizer())
2407    mainSizer.Add((5,5),0)
2408    mainSizer.Add(SeqSizer())
2409    mainSizer.Add((5,5),0)
2410    mainSizer.Add(AuthSizer())
2411    mainSizer.Add((5,5),0)
2412       
2413    mainSizer.Layout()   
2414    G2frame.dataDisplay.SetSizer(mainSizer)
2415    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
2416    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
2417     
2418################################################################################
2419#####  Comments
2420################################################################################           
2421       
2422def UpdateComments(G2frame,data):                   
2423
2424    if G2frame.dataDisplay:
2425        G2frame.dataDisplay.Destroy()
2426    G2frame.dataFrame.SetLabel('Comments')
2427    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2428        style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP)
2429    for line in data:
2430        G2frame.dataDisplay.AppendText(line+'\n')
2431    G2frame.dataFrame.setSizePosLeft([400,250])
2432           
2433################################################################################
2434#####  Display of Sequential Results
2435################################################################################           
2436       
2437def UpdateSeqResults(G2frame,data,prevSize=None):
2438    """
2439    Called when the Sequential Results data tree entry is selected
2440    to show results from a sequential refinement.
2441   
2442    :param wx.Frame G2frame: main GSAS-II data tree windows
2443
2444    :param dict data: a dictionary containing the following items: 
2445
2446            * 'histNames' - list of histogram names in order as processed by Sequential Refinement
2447            * 'varyList' - list of variables - identical over all refinements in sequence
2448              note that this is the original list of variables, prior to processing
2449              constraints.
2450            * 'variableLabels' -- a dict of labels to be applied to each parameter
2451              (this is created as an empty dict if not present in data).
2452            * keyed by histName - dictionaries for all data sets processed, which contains:
2453
2454              * 'variables'- result[0] from leastsq call
2455              * 'varyList' - list of variables passed to leastsq call (not same as above)
2456              * 'sig' - esds for variables
2457              * 'covMatrix' - covariance matrix from individual refinement
2458              * 'title' - histogram name; same as dict item name
2459              * 'newAtomDict' - new atom parameters after shifts applied
2460              * 'newCellDict' - refined cell parameters after shifts to A0-A5 from Dij terms applied'
2461    """
2462
2463    def GetSampleParms():
2464        '''Make a dictionary of the sample parameters are not the same over the
2465        refinement series.
2466        '''
2467        if 'IMG' in histNames[0]:
2468            sampleParmDict = {'Sample load':[],}
2469        else:
2470            sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[],
2471                'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[],
2472                'Chi':[],'Phi':[],'Azimuth':[],}
2473        Controls = G2frame.PatternTree.GetItemPyData(
2474            GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2475        sampleParm = {}
2476        for name in histNames:
2477            if 'IMG' in name:
2478                for item in sampleParmDict:
2479                    sampleParmDict[item].append(data[name]['parmDict'].get(item,0))
2480            else:
2481                Id = GetPatternTreeItemId(G2frame,G2frame.root,name)
2482                sampleData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2483                for item in sampleParmDict:
2484                    sampleParmDict[item].append(sampleData.get(item,0))
2485        for item in sampleParmDict:
2486            frstValue = sampleParmDict[item][0]
2487            if np.any(np.array(sampleParmDict[item])-frstValue):
2488                if item.startswith('FreePrm'):
2489                    sampleParm[Controls[item]] = sampleParmDict[item]
2490                else:
2491                    sampleParm[item] = sampleParmDict[item]
2492        return sampleParm
2493
2494    def GetColumnInfo(col):
2495        '''returns column label, lists of values and errors (or None) for each column in the table
2496        for plotting. The column label is reformatted from Unicode to MatPlotLib encoding
2497        '''
2498        colName = G2frame.SeqTable.GetColLabelValue(col)
2499        plotName = variableLabels.get(colName,colName)
2500        plotName = plotSpCharFix(plotName)
2501        return plotName,colList[col],colSigs[col]
2502           
2503    def PlotSelect(event):
2504        'Plots a row (covariance) or column on double-click'
2505        cols = G2frame.dataDisplay.GetSelectedCols()
2506        rows = G2frame.dataDisplay.GetSelectedRows()
2507        if cols:
2508            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2509        elif rows:
2510            name = histNames[rows[0]]       #only does 1st one selected
2511            G2plt.PlotCovariance(G2frame,data[name])
2512        else:
2513            G2frame.ErrorDialog(
2514                'Select row or columns',
2515                'Nothing selected in table. Click on column or row label(s) to plot. N.B. Grid selection can be a bit funky.'
2516                )
2517           
2518    def OnPlotSelSeq(event):
2519        'plot the selected columns or row from menu command'
2520        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2521        rows = G2frame.dataDisplay.GetSelectedRows()
2522        if cols:
2523            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2524        elif rows:
2525            name = histNames[rows[0]]       #only does 1st one selected
2526            G2plt.PlotCovariance(G2frame,data[name])
2527        else:
2528            G2frame.ErrorDialog(
2529                'Select columns',
2530                'No columns or rows selected in table. Click on row or column labels to select fields for plotting.'
2531                )
2532               
2533    def OnAveSelSeq(event):
2534        'average the selected columns from menu command'
2535        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2536        if cols:
2537            for col in cols:
2538                ave = np.mean(GetColumnInfo(col)[1])
2539                sig = np.std(GetColumnInfo(col)[1])
2540                print ' Average for '+G2frame.SeqTable.GetColLabelValue(col)+': '+'%.6g'%(ave)+' +/- '+'%.6g'%(sig)
2541        else:
2542            G2frame.ErrorDialog(
2543                'Select columns',
2544                'No columns selected in table. Click on column labels to select fields for averaging.'
2545                )
2546               
2547    def OnRenameSelSeq(event):
2548        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2549        colNames = [G2frame.SeqTable.GetColLabelValue(c) for c in cols]
2550        newNames = colNames[:]
2551        for i,name in enumerate(colNames):
2552            if name in variableLabels:
2553                newNames[i] = variableLabels[name]
2554        if not cols:
2555            G2frame.ErrorDialog('Select columns',
2556                'No columns selected in table. Click on column labels to select fields for rename.')
2557            return
2558        dlg = G2G.MultiStringDialog(G2frame.dataDisplay,'Set column names',colNames,newNames)
2559        if dlg.Show():
2560            newNames = dlg.GetValues()           
2561            variableLabels.update(dict(zip(colNames,newNames)))
2562        data['variableLabels'] = variableLabels
2563        dlg.Destroy()
2564        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2565        G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2566           
2567    def OnReOrgSelSeq(event):
2568        'Reorder the columns'
2569        G2G.GetItemOrder(G2frame,VaryListChanges,vallookup,posdict)   
2570        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2571
2572    def OnSaveSelSeqCSV(event):
2573        'export the selected columns to a .csv file from menu command'
2574        OnSaveSelSeq(event,csv=True)
2575       
2576    def OnSaveSeqCSV(event):
2577        'export all columns to a .csv file from menu command'
2578        OnSaveSelSeq(event,csv=True,allcols=True)
2579       
2580    def OnSaveSelSeq(event,csv=False,allcols=False):
2581        'export the selected columns to a .txt or .csv file from menu command'
2582        def WriteCSV():
2583            def WriteList(headerItems):
2584                line = ''
2585                for lbl in headerItems:
2586                    if line: line += ','
2587                    line += '"'+lbl+'"'
2588                return line
2589            head = ['name']
2590            for col in cols:
2591                item = G2frame.SeqTable.GetColLabelValue(col)
2592                # get rid of labels that have Unicode characters
2593                if not all([ord(c) < 128 and ord(c) != 0 for c in item]): item = '?'
2594                if col in havesig:
2595                    head += [item,'esd-'+item]
2596                else:
2597                    head += [item]
2598            SeqFile.write(WriteList(head)+'\n')
2599            for row,name in enumerate(saveNames):
2600                line = '"'+saveNames[row]+'"'
2601                for col in cols:
2602                    if col in havesig:
2603                        line += ','+str(saveData[col][row])+','+str(saveSigs[col][row])
2604                    else:
2605                        line += ','+str(saveData[col][row])
2606                SeqFile.write(line+'\n')
2607        def WriteSeq():
2608            lenName = len(saveNames[0])
2609            line = %s  '%('name'.center(lenName))
2610            for col in cols:
2611                item = G2frame.SeqTable.GetColLabelValue(col)
2612                if col in havesig:
2613                    line += ' %12s %12s '%(item.center(12),'esd'.center(12))
2614                else:
2615                    line += ' %12s '%(item.center(12))
2616            SeqFile.write(line+'\n')
2617            for row,name in enumerate(saveNames):
2618                line = " '%s' "%(saveNames[row])
2619                for col in cols:
2620                    if col in havesig:
2621                        line += ' %12.6f %12.6f '%(saveData[col][row],saveSigs[col][row])
2622                    else:
2623                        line += ' %12.6f '%saveData[col][row]
2624                SeqFile.write(line+'\n')
2625
2626        # start of OnSaveSelSeq code
2627        if allcols:
2628            cols = range(G2frame.SeqTable.GetNumberCols())
2629        else:
2630            cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2631        nrows = G2frame.SeqTable.GetNumberRows()
2632        if not cols:
2633            G2frame.ErrorDialog('Select columns',
2634                             'No columns selected in table. Click on column labels to select fields for output.')
2635            return
2636        saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(nrows)]
2637        saveData = {}
2638        saveSigs = {}
2639        havesig = []
2640        for col in cols:
2641            name,vals,sigs = GetColumnInfo(col)
2642            saveData[col] = vals
2643            if sigs:
2644                havesig.append(col)
2645                saveSigs[col] = sigs
2646        if csv:
2647            wild = 'CSV output file (*.csv)|*.csv'
2648        else:
2649            wild = 'Text output file (*.txt)|*.txt'
2650        pth = G2G.GetExportPath(G2frame)
2651        dlg = wx.FileDialog(
2652            G2frame,
2653            'Choose text output file for your selection', pth, '', 
2654            wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
2655        try:
2656            if dlg.ShowModal() == wx.ID_OK:
2657                SeqTextFile = dlg.GetPath()
2658                SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) 
2659                SeqFile = open(SeqTextFile,'w')
2660                if csv:
2661                    WriteCSV()
2662                else:
2663                    WriteSeq()
2664                SeqFile.close()
2665        finally:
2666            dlg.Destroy()
2667               
2668    def striphist(var,insChar=''):
2669        'strip a histogram number from a var name'
2670        sv = var.split(':')
2671        if len(sv) <= 1: return var
2672        if sv[1]:
2673            sv[1] = insChar
2674        return ':'.join(sv)
2675       
2676    def plotSpCharFix(lbl):
2677        'Change selected unicode characters to their matplotlib equivalent'
2678        for u,p in [
2679            (u'\u03B1',r'$\alpha$'),
2680            (u'\u03B2',r'$\beta$'),
2681            (u'\u03B3',r'$\gamma$'),
2682            (u'\u0394\u03C7',r'$\Delta\chi$'),
2683            ]:
2684            lbl = lbl.replace(u,p)
2685        return lbl
2686   
2687    def SelectXaxis():
2688        'returns a selected column number (or None) as the X-axis selection'
2689        ncols = G2frame.SeqTable.GetNumberCols()
2690        colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)]
2691        dlg = G2G.G2SingleChoiceDialog(
2692            G2frame.dataDisplay,
2693            'Select x-axis parameter for plot or Cancel for sequence number',
2694            'Select X-axis',
2695            colNames)
2696        try:
2697            if dlg.ShowModal() == wx.ID_OK:
2698                col = dlg.GetSelection()
2699            else:
2700                col = None
2701        finally:
2702            dlg.Destroy()
2703        return col
2704   
2705    def EnablePseudoVarMenus():
2706        'Enables or disables the PseudoVar menu items that require existing defs'
2707        if Controls['SeqPseudoVars']:
2708            val = True
2709        else:
2710            val = False
2711        G2frame.dataFrame.SequentialPvars.Enable(wxDELSEQVAR,val)
2712        G2frame.dataFrame.SequentialPvars.Enable(wxEDITSEQVAR,val)
2713
2714    def DelPseudoVar(event):
2715        'Ask the user to select a pseudo var expression to delete'
2716        choices = Controls['SeqPseudoVars'].keys()
2717        selected = G2G.ItemSelector(
2718            choices,G2frame.dataFrame,
2719            multiple=True,
2720            title='Select expressions to remove',
2721            header='Delete expression')
2722        if selected is None: return
2723        for item in selected:
2724            del Controls['SeqPseudoVars'][choices[item]]
2725        if selected:
2726            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2727
2728    def EditPseudoVar(event):
2729        'Edit an existing pseudo var expression'
2730        choices = Controls['SeqPseudoVars'].keys()
2731        if len(choices) == 1:
2732            selected = 0
2733        else:
2734            selected = G2G.ItemSelector(
2735                choices,G2frame.dataFrame,
2736                multiple=False,
2737                title='Select an expression to edit',
2738                header='Edit expression')
2739        if selected is not None:
2740            dlg = G2exG.ExpressionDialog(
2741                G2frame.dataDisplay,PSvarDict,
2742                Controls['SeqPseudoVars'][choices[selected]],
2743                header="Edit the PseudoVar expression",
2744                VarLabel="PseudoVar #"+str(selected+1),
2745                fit=False)
2746            newobj = dlg.Show(True)
2747            if newobj:
2748                calcobj = G2obj.ExpressionCalcObj(newobj)
2749                del Controls['SeqPseudoVars'][choices[selected]]
2750                Controls['SeqPseudoVars'][calcobj.eObj.expression] = newobj
2751                UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2752       
2753    def AddNewPseudoVar(event):
2754        'Create a new pseudo var expression'
2755        dlg = G2exG.ExpressionDialog(
2756            G2frame.dataDisplay,PSvarDict,
2757            header='Enter an expression for a PseudoVar here',
2758            VarLabel = "New PseudoVar",
2759            fit=False)
2760        obj = dlg.Show(True)
2761        dlg.Destroy()
2762        if obj:
2763            calcobj = G2obj.ExpressionCalcObj(obj)
2764            Controls['SeqPseudoVars'][calcobj.eObj.expression] = obj
2765            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2766           
2767    def AddNewDistPseudoVar(event):
2768        obj = None
2769        dlg = G2exG.BondDialog(
2770            G2frame.dataDisplay,Phases,PSvarDict,
2771            header='Select a Bond here',
2772            VarLabel = "New Bond")
2773        if dlg.ShowModal() == wx.ID_OK:
2774            pName,Oatom,Tatom = dlg.GetSelection()
2775            if Tatom:
2776                Phase = Phases[pName]
2777                General = Phase['General']
2778                cx,ct = General['AtomPtrs'][:2]
2779                pId = Phase['pId']
2780                SGData = General['SGData']
2781                sB = Tatom.find('(')+1
2782                symNo = 0
2783                if sB:
2784                    sF = Tatom.find(')')
2785                    symNo = int(Tatom[sB:sF])
2786                cellNo = [0,0,0]
2787                cB = Tatom.find('[')
2788                if cB>0:
2789                    cF = Tatom.find(']')+1
2790                    cellNo = eval(Tatom[cB:cF])
2791                Atoms = Phase['Atoms']
2792                aNames = [atom[ct-1] for atom in Atoms]
2793                oId = aNames.index(Oatom)
2794                tId = aNames.index(Tatom.split(' +')[0])
2795                # create an expression object
2796                obj = G2obj.ExpressionObj()
2797                obj.expression = 'Dist(%s,\n%s)'%(Oatom,Tatom.split(' d=')[0].replace(' ',''))
2798                obj.distance_dict = {'pId':pId,'SGData':SGData,'symNo':symNo,'cellNo':cellNo}
2799                obj.distance_atoms = [oId,tId]
2800        else: 
2801            dlg.Destroy()
2802            return
2803        dlg.Destroy()
2804        if obj:
2805            Controls['SeqPseudoVars'][obj.expression] = obj
2806            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2807
2808    def AddNewAnglePseudoVar(event):
2809        dlg = G2exG.AngleDialog(
2810            G2frame.dataDisplay,Phases,PSvarDict,
2811            header='Enter an Angle here',
2812            VarLabel = "New Angle")
2813        if dlg.ShowModal() == wx.ID_OK:
2814            pName,Oatom,Tatoms = dlg.GetSelection()
2815            if Tatoms:
2816                Phase = Phases[pName]
2817                General = Phase['General']
2818                cx,ct = General['AtomPtrs'][:2]
2819                pId = Phase['pId']
2820                SGData = General['SGData']
2821                Atoms = Phase['Atoms']
2822                aNames = [atom[ct-1] for atom in Atoms]
2823                tIds = []
2824                symNos = []
2825                cellNos = []
2826                oId = aNames.index(Oatom)
2827                Tatoms = Tatoms.split(';')
2828                for Tatom in Tatoms:
2829                    sB = Tatom.find('(')+1
2830                    symNo = 0
2831                    if sB:
2832                        sF = Tatom.find(')')
2833                        symNo = int(Tatom[sB:sF])
2834                    symNos.append(symNo)
2835                    cellNo = [0,0,0]
2836                    cB = Tatom.find('[')
2837                    if cB>0:
2838                        cF = Tatom.find(']')+1
2839                        cellNo = eval(Tatom[cB:cF])
2840                    cellNos.append(cellNo)
2841                    tIds.append(aNames.index(Tatom.split('+')[0]))
2842                # create an expression object
2843                obj = G2obj.ExpressionObj()
2844                obj.expression = 'Angle(%s,%s,\n%s)'%(Tatoms[0],Oatom,Tatoms[1])
2845                obj.angle_dict = {'pId':pId,'SGData':SGData,'symNo':symNos,'cellNo':cellNos}
2846                obj.angle_atoms = [oId,tIds]
2847        else: 
2848            dlg.Destroy()
2849            return
2850        dlg.Destroy()
2851        if obj:
2852            Controls['SeqPseudoVars'][obj.expression] = obj
2853            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2854           
2855    def UpdateParmDict(parmDict):
2856        '''generate the atom positions and the direct & reciprocal cell values,
2857        because they might be needed to evaluate the pseudovar
2858        '''
2859        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2860                         ['A'+str(i) for i in range(6)])
2861                     )
2862        delList = []
2863        phaselist = []
2864        for item in parmDict: 
2865            if ':' not in item: continue
2866            key = item.split(':')
2867            if len(key) < 3: continue
2868            # remove the dA[xyz] terms, they would only bring confusion
2869            if key[2].startswith('dA'):
2870                delList.append(item)
2871            # compute and update the corrected reciprocal cell terms using the Dij values
2872            elif key[2] in Ddict:
2873                if key[0] not in phaselist: phaselist.append(key[0])
2874                akey = key[0]+'::'+Ddict[key[2]]
2875                parmDict[akey] -= parmDict[item]
2876                delList.append(item)
2877        for item in delList:
2878            del parmDict[item]               
2879        for i in phaselist:
2880            pId = int(i)
2881            # apply cell symmetry
2882            A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId])
2883            # convert to direct cell & add the unique terms to the dictionary
2884            for i,val in enumerate(G2lat.A2cell(A)):
2885                if i in uniqCellIndx[pId]:
2886                    lbl = str(pId)+'::'+cellUlbl[i]
2887                    parmDict[lbl] = val
2888            lbl = str(pId)+'::'+'vol'
2889            parmDict[lbl] = G2lat.calc_V(A)
2890        return parmDict
2891
2892    def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD):
2893        '''Evaluate an expression derivative with respect to a
2894        GSAS-II variable name.
2895
2896        Note this likely could be faster if the loop over calcobjs were done
2897        inside after the Dict was created.
2898        '''
2899        step = ESD/10
2900        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2901                         ['A'+str(i) for i in range(6)])
2902                     )
2903        results = []
2904        phaselist = []
2905        VparmDict = sampleDict.copy()
2906        for incr in step,-step:
2907            VparmDict.update(parmDict.copy())           
2908            # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]'
2909            # values are not zeroed: fix that!
2910            VparmDict.update({item:0.0 for item in parmDict if 'dA' in item})
2911            VparmDict[var] += incr
2912            G2mv.Dict2Map(VparmDict,[]) # apply constraints
2913            # generate the atom positions and the direct & reciprocal cell values now, because they might
2914            # needed to evaluate the pseudovar
2915            for item in VparmDict:
2916                if item in sampleDict:
2917                    continue 
2918                if ':' not in item: continue
2919                key = item.split(':')
2920                if len(key) < 3: continue
2921                # apply any new shifts to atom positions
2922                if key[2].startswith('dA'):
2923                    VparmDict[''.join(item.split('d'))] += VparmDict[item]
2924                    VparmDict[item] = 0.0
2925                # compute and update the corrected reciprocal cell terms using the Dij values
2926                if key[2] in Ddict:
2927                    if key[0] not in phaselist: phaselist.append(key[0])
2928                    akey = key[0]+'::'+Ddict[key[2]]
2929                    VparmDict[akey] -= VparmDict[item]
2930            for i in phaselist:
2931                pId = int(i)
2932                # apply cell symmetry
2933                A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId])
2934                # convert to direct cell & add the unique terms to the dictionary
2935                for i,val in enumerate(G2lat.A2cell(A)):
2936                    if i in uniqCellIndx[pId]:
2937                        lbl = str(pId)+'::'+cellUlbl[i]
2938                        VparmDict[lbl] = val
2939                lbl = str(pId)+'::'+'vol'
2940                VparmDict[lbl] = G2lat.calc_V(A)
2941            # dict should be fully updated, use it & calculate
2942            calcobj.SetupCalc(VparmDict)
2943            results.append(calcobj.EvalExpression())
2944        return (results[0] - results[1]) / (2.*step)
2945       
2946    def EnableParFitEqMenus():
2947        'Enables or disables the Parametric Fit menu items that require existing defs'
2948        if Controls['SeqParFitEqList']:
2949            val = True
2950        else:
2951            val = False
2952        G2frame.dataFrame.SequentialPfit.Enable(wxDELPARFIT,val)
2953        G2frame.dataFrame.SequentialPfit.Enable(wxEDITPARFIT,val)
2954        G2frame.dataFrame.SequentialPfit.Enable(wxDOPARFIT,val)
2955
2956    def ParEqEval(Values,calcObjList,varyList):
2957        '''Evaluate the parametric expression(s)
2958        :param list Values: a list of values for each variable parameter
2959        :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj`
2960          expression objects to evaluate
2961        :param list varyList: a list of variable names for each value in Values
2962        '''
2963        result = []
2964        for calcobj in calcObjList:
2965            calcobj.UpdateVars(varyList,Values)
2966            result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig)
2967        return result
2968
2969    def DoParEqFit(event,eqObj=None):
2970        'Parametric fit minimizer'
2971        varyValueDict = {} # dict of variables and their initial values
2972        calcObjList = [] # expression objects, ready to go for each data point
2973        if eqObj is not None:
2974            eqObjList = [eqObj,]
2975        else:
2976            eqObjList = Controls['SeqParFitEqList']
2977        UseFlags = G2frame.SeqTable.GetColValues(0)         
2978        for obj in eqObjList:
2979            expr = obj.expression
2980            # assemble refined vars for this equation
2981            varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()})
2982            # lookup dependent var position
2983            depVar = obj.GetDepVar()
2984            if depVar in colLabels:
2985                indx = colLabels.index(depVar)
2986            else:
2987                raise Exception('Dependent variable '+depVar+' not found')
2988            # assemble a list of the independent variables
2989            indepVars = obj.GetIndependentVars()
2990            # loop over each datapoint
2991            for j,row in enumerate(zip(*colList)):
2992                if not UseFlags[j]: continue
2993                # assemble equations to fit
2994                calcobj = G2obj.ExpressionCalcObj(obj)
2995                # prepare a dict of needed independent vars for this expression
2996                indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
2997                calcobj.SetupCalc(indepVarDict)               
2998                # values and sigs for current value of dependent var
2999                calcobj.depVal = row[indx]
3000                calcobj.depSig = colSigs[indx][j]
3001                calcObjList.append(calcobj)
3002        # varied parameters
3003        varyList = varyValueDict.keys()
3004        values = varyValues = [varyValueDict[key] for key in varyList]
3005        if not varyList:
3006            print 'no variables to refine!'
3007            return
3008        try:
3009            result = so.leastsq(ParEqEval,varyValues,full_output=True,   #ftol=Ftol,
3010                                args=(calcObjList,varyList)
3011                                )
3012            values = result[0]
3013            covar = result[1]
3014            if covar is None:
3015                raise Exception
3016            esdDict = {}
3017            for i,avar in enumerate(varyList):
3018                esdDict[avar] = np.sqrt(covar[i,i])
3019        except:
3020            print('====> Fit failed')
3021            return
3022        print('==== Fit Results ====')
3023        for obj in eqObjList:
3024            obj.UpdateVariedVars(varyList,values)
3025            ind = '      '
3026            print('  '+obj.GetDepVar()+' = '+obj.expression)
3027            for var in obj.assgnVars:
3028                print(ind+var+' = '+obj.assgnVars[var])
3029            for var in obj.freeVars:
3030                avar = "::"+obj.freeVars[var][0]
3031                val = obj.freeVars[var][1]
3032                if obj.freeVars[var][2]:
3033                    print(ind+var+' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar]))
3034                else:
3035                    print(ind+var+' = '+avar + " =" + G2mth.ValEsd(val,0))
3036        # create a plot for each parametric variable
3037        for fitnum,obj in enumerate(eqObjList):
3038            calcobj = G2obj.ExpressionCalcObj(obj)
3039            # lookup dependent var position
3040            indx = colLabels.index(obj.GetDepVar())
3041            # assemble a list of the independent variables
3042            indepVars = obj.GetIndependentVars()           
3043            # loop over each datapoint
3044            fitvals = []
3045            for j,row in enumerate(zip(*colList)):
3046                calcobj.SetupCalc(
3047                    {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
3048                    )
3049                fitvals.append(calcobj.EvalExpression())
3050            G2plt.PlotSelectedSequence(
3051                G2frame,[indx],GetColumnInfo,SelectXaxis,
3052                fitnum,fitvals)
3053
3054    def SingleParEqFit(eqObj):
3055        DoParEqFit(None,eqObj)
3056
3057    def DelParFitEq(event):
3058        'Ask the user to select function to delete'
3059        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
3060        selected = G2G.ItemSelector(
3061            txtlst,G2frame.dataFrame,
3062            multiple=True,
3063            title='Select a parametric equation(s) to remove',
3064            header='Delete equation')
3065        if selected is None: return
3066        Controls['SeqParFitEqList'] = [obj for i,obj in enumerate(Controls['SeqParFitEqList']) if i not in selected]
3067        EnableParFitEqMenus()
3068        if Controls['SeqParFitEqList']: DoParEqFit(event)
3069       
3070    def EditParFitEq(event):
3071        'Edit an existing parametric equation'
3072        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
3073        if len(txtlst) == 1:
3074            selected = 0
3075        else:
3076            selected = G2G.ItemSelector(
3077                txtlst,G2frame.dataFrame,
3078                multiple=False,
3079                title='Select a parametric equation to edit',
3080                header='Edit equation')
3081        if selected is not None:
3082            dlg = G2exG.ExpressionDialog(
3083                G2frame.dataDisplay,indepVarDict,
3084                Controls['SeqParFitEqList'][selected],
3085                depVarDict=depVarDict,
3086                header="Edit the formula for this minimization function",
3087                ExtraButton=['Fit',SingleParEqFit])
3088            newobj = dlg.Show(True)
3089            if newobj:
3090                calcobj = G2obj.ExpressionCalcObj(newobj)
3091                Controls['SeqParFitEqList'][selected] = newobj
3092                EnableParFitEqMenus()
3093            if Controls['SeqParFitEqList']: DoParEqFit(event)
3094
3095    def AddNewParFitEq(event):
3096        'Create a new parametric equation to be fit to sequential results'
3097
3098        # compile the variable names used in previous freevars to avoid accidental name collisions
3099        usedvarlist = []
3100        for obj in Controls['SeqParFitEqList']:
3101            for var in obj.freeVars:
3102                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3103
3104        dlg = G2exG.ExpressionDialog(
3105            G2frame.dataDisplay,indepVarDict,
3106            depVarDict=depVarDict,
3107            header='Define an equation to minimize in the parametric fit',
3108            ExtraButton=['Fit',SingleParEqFit],
3109            usedVars=usedvarlist)
3110        obj = dlg.Show(True)
3111        dlg.Destroy()
3112        if obj:
3113            Controls['SeqParFitEqList'].append(obj)
3114            EnableParFitEqMenus()
3115            if Controls['SeqParFitEqList']: DoParEqFit(event)
3116               
3117    def CopyParFitEq(event):
3118        'Copy an existing parametric equation to be fit to sequential results'
3119        # compile the variable names used in previous freevars to avoid accidental name collisions
3120        usedvarlist = []
3121        for obj in Controls['SeqParFitEqList']:
3122            for var in obj.freeVars:
3123                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3124        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
3125        if len(txtlst) == 1:
3126            selected = 0
3127        else:
3128            selected = G2G.ItemSelector(
3129                txtlst,G2frame.dataFrame,
3130                multiple=False,
3131                title='Select a parametric equation to copy',
3132                header='Copy equation')
3133        if selected is not None:
3134            newEqn = copy.deepcopy(Controls['SeqParFitEqList'][selected])
3135            for var in newEqn.freeVars:
3136                newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist)
3137            dlg = G2exG.ExpressionDialog(
3138                G2frame.dataDisplay,indepVarDict,
3139                newEqn,
3140                depVarDict=depVarDict,
3141                header="Edit the formula for this minimization function",
3142                ExtraButton=['Fit',SingleParEqFit])
3143            newobj = dlg.Show(True)
3144            if newobj:
3145                calcobj = G2obj.ExpressionCalcObj(newobj)
3146                Controls['SeqParFitEqList'].append(newobj)
3147                EnableParFitEqMenus()
3148            if Controls['SeqParFitEqList']: DoParEqFit(event)
3149                                           
3150    def GridSetToolTip(row,col):
3151        '''Routine to show standard uncertainties for each element in table
3152        as a tooltip
3153        '''
3154        if colSigs[col]:
3155            return u'\u03c3 = '+str(colSigs[col][row])
3156        return ''
3157       
3158    def GridColLblToolTip(col):
3159        '''Define a tooltip for a column. This will be the user-entered value
3160        (from data['variableLabels']) or the default name
3161        '''
3162        if col < 0 or col > len(colLabels):
3163            print 'Illegal column #',col
3164            return
3165        var = colLabels[col]
3166        return variableLabels.get(var,G2obj.fmtVarDescr(var))
3167       
3168    def SetLabelString(event):
3169        '''Define or edit the label for a column in the table, to be used
3170        as a tooltip and for plotting
3171        '''
3172        col = event.GetCol()
3173        if col < 0 or col > len(colLabels):
3174            return
3175        var = colLabels[col]
3176        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
3177        dlg = G2G.SingleStringDialog(G2frame.dataFrame,'Set variable label',
3178                                 'Set a new name for variable '+var,lbl,size=(400,-1))
3179        if dlg.Show():
3180            variableLabels[var] = dlg.GetValue()
3181        dlg.Destroy()
3182       
3183    #def GridRowLblToolTip(row): return 'Row ='+str(row)
3184   
3185    # lookup table for unique cell parameters by symmetry
3186    cellGUIlist = [
3187        [['m3','m3m'],(0,)],
3188        [['3R','3mR'],(0,3)],
3189        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
3190        [['mmm'],(0,1,2)],
3191        [['2/m'+'a'],(0,1,2,3)],
3192        [['2/m'+'b'],(0,1,2,4)],
3193        [['2/m'+'c'],(0,1,2,5)],
3194        [['-1'],(0,1,2,3,4,5)],
3195        ]
3196    # cell labels
3197    cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
3198
3199    #======================================================================
3200    # start processing sequential results here (UpdateSeqResults)
3201    #======================================================================
3202    if not data:
3203        print 'No sequential refinement results'
3204        return
3205    variableLabels = data.get('variableLabels',{})
3206    data['variableLabels'] = variableLabels
3207    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
3208    Controls = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
3209    # create a place to store Pseudo Vars & Parametric Fit functions, if not present
3210    if 'SeqPseudoVars' not in Controls: Controls['SeqPseudoVars'] = {}
3211    if 'SeqParFitEqList' not in Controls: Controls['SeqParFitEqList'] = []
3212    histNames = data['histNames']
3213    if G2frame.dataDisplay:
3214        G2frame.dataDisplay.Destroy()
3215    if not G2frame.dataFrame.GetStatusBar():
3216        Status = G2frame.dataFrame.CreateStatusBar()
3217        Status.SetStatusText("Select column to export; Double click on column to plot data; on row for Covariance")
3218    sampleParms = GetSampleParms()
3219
3220    # make dict of varied atom coords keyed by absolute position
3221    newAtomDict = data[histNames[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
3222    # Possible error: the next might need to be data[histNames[0]]['varyList']
3223    # error will arise if there constraints on coordinates?
3224    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in data['varyList']}
3225   
3226    # make dict of varied cell parameters equivalents
3227    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
3228    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
3229    # N.B. These Dij vars are missing a histogram #
3230    newCellDict = data[histNames[0]].get('newCellDict',{})
3231    for item in newCellDict:
3232        if item in data['varyList']:
3233            ESDlookup[newCellDict[item][0]] = item
3234            Dlookup[item] = newCellDict[item][0]
3235    # add coordinate equivalents to lookup table
3236    for parm in atomLookup:
3237        Dlookup[atomLookup[parm]] = parm
3238        ESDlookup[parm] = atomLookup[parm]
3239
3240    # get unit cell & symmetry for all phases & initial stuff for later use
3241    RecpCellTerms = {}
3242    SGdata = {}
3243    uniqCellIndx = {}
3244    initialCell = {}
3245    RcellLbls = {}
3246    zeroDict = {}
3247    Rcelldict = {}
3248    for phase in Phases:
3249        phasedict = Phases[phase]
3250        pId = phasedict['pId']
3251        pfx = str(pId)+'::' # prefix for A values from phase
3252        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
3253        RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7])
3254        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
3255        SGdata[pId] = phasedict['General']['SGData']
3256        Rcelldict.update({lbl:val for lbl,val in zip(RcellLbls[pId],RecpCellTerms[pId])})
3257        laue = SGdata[pId]['SGLaue']
3258        if laue == '2/m':
3259            laue += SGdata[pId]['SGUniq']
3260        for symlist,celllist in cellGUIlist:
3261            if laue in symlist:
3262                uniqCellIndx[pId] = celllist
3263                break
3264        else: # should not happen
3265            uniqCellIndx[pId] = range(6)
3266        for i in uniqCellIndx[pId]:
3267            initialCell[str(pId)+'::A'+str(i)] =  RecpCellTerms[pId][i]
3268
3269    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
3270    G2frame.dataFrame.SetLabel('Sequential refinement results')
3271    if not G2frame.dataFrame.GetStatusBar():
3272        Status = G2frame.dataFrame.CreateStatusBar()
3273        Status.SetStatusText('')
3274    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=wxID_RENAMESEQSEL)
3275    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
3276    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=wxID_SAVESEQSELCSV)
3277    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=wxID_SAVESEQCSV)
3278    G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=wxID_PLOTSEQSEL)
3279    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAveSelSeq, id=wxID_AVESEQSEL)
3280    G2frame.dataFrame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=wxID_ORGSEQSEL)
3281    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=wxADDSEQVAR)
3282    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewDistPseudoVar, id=wxADDSEQDIST)
3283    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewAnglePseudoVar, id=wxADDSEQANGLE)
3284    G2frame.dataFrame.Bind(wx.EVT_MENU, DelPseudoVar, id=wxDELSEQVAR)
3285    G2frame.dataFrame.Bind(wx.EVT_MENU, EditPseudoVar, id=wxEDITSEQVAR)
3286    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewParFitEq, id=wxADDPARFIT)
3287    G2frame.dataFrame.Bind(wx.EVT_MENU, CopyParFitEq, id=wxCOPYPARFIT)
3288    G2frame.dataFrame.Bind(wx.EVT_MENU, DelParFitEq, id=wxDELPARFIT)
3289    G2frame.dataFrame.Bind(wx.EVT_MENU, EditParFitEq, id=wxEDITPARFIT)
3290    G2frame.dataFrame.Bind(wx.EVT_MENU, DoParEqFit, id=wxDOPARFIT)
3291    EnablePseudoVarMenus()
3292    EnableParFitEqMenus()
3293
3294    # scan for locations where the variables change
3295    VaryListChanges = [] # histograms where there is a change
3296    combinedVaryList = []
3297    firstValueDict = {}
3298    vallookup = {}
3299    posdict = {}
3300    prevVaryList = []
3301    for i,name in enumerate(histNames):
3302        for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']):
3303            svar = striphist(var,'*') # wild-carded
3304            if svar not in combinedVaryList:
3305                # add variables to list as they appear
3306                combinedVaryList.append(svar)
3307                firstValueDict[svar] = (val,sig)
3308        if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous
3309            prevVaryList = data[name]['varyList']
3310            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
3311            posdict[name] = {}
3312            for var in data[name]['varyList']:
3313                svar = striphist(var,'*')
3314                posdict[name][combinedVaryList.index(svar)] = svar
3315            VaryListChanges.append(name)
3316    if len(VaryListChanges) > 1:
3317        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,True)
3318    else:
3319        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,False)
3320    #-----------------------------------------------------------------------------------
3321    # build up the data table by columns -----------------------------------------------
3322    nRows = len(histNames)
3323    colList = [nRows*[True]]
3324    colSigs = [None]
3325    colLabels = ['Use']
3326    Types = [wg.GRID_VALUE_BOOL]
3327    # start with Rwp values
3328    if 'IMG ' not in histNames[0][:4]:
3329        colList += [[data[name]['Rvals']['Rwp'] for name in histNames]]
3330        colSigs += [None]
3331        colLabels += ['Rwp']
3332        Types += [wg.GRID_VALUE_FLOAT+':10,3',]
3333    # add % change in Chi^2 in last cycle
3334    if histNames[0][:4] not in ['SASD','IMG '] and Controls.get('ShowCell'):
3335        colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]]
3336        colSigs += [None]
3337        colLabels += [u'\u0394\u03C7\u00B2 (%)']
3338        Types += [wg.GRID_VALUE_FLOAT,]
3339    deltaChiCol = len(colLabels)-1
3340    # add changing sample parameters to table
3341    for key in sampleParms:
3342        colList += [sampleParms[key]]
3343        colSigs += [None]
3344        colLabels += [key]
3345        Types += [wg.GRID_VALUE_FLOAT,]
3346    sampleDict = {}
3347    for i,name in enumerate(histNames):
3348        sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) 
3349    # add unique cell parameters TODO: review this where the cell symmetry changes (when possible)
3350    if Controls.get('ShowCell',False):
3351        for pId in sorted(RecpCellTerms):
3352            pfx = str(pId)+'::' # prefix for A values from phase
3353            cells = []
3354            cellESDs = []
3355            colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
3356            colLabels += [pfx+'Vol']
3357            Types += (1+len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT,]
3358            for name in histNames:
3359                covData = {
3360                    'varyList': [Dlookup.get(striphist(v),v) for v in data[name]['varyList']],
3361                    'covMatrix': data[name]['covMatrix']
3362                    }
3363                A = RecpCellTerms[pId][:] # make copy of starting A values
3364                # update with refined values
3365                for i in range(6):
3366                    var = str(pId)+'::A'+str(i)
3367                    if var in ESDlookup:
3368                        val = data[name]['newCellDict'][ESDlookup[var]][1] # get refined value
3369                        A[i] = val # override with updated value
3370                # apply symmetry
3371                Albls = [pfx+'A'+str(i) for i in range(6)]
3372                cellDict = dict(zip(Albls,A))
3373                A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
3374                # convert to direct cell & add only unique values to table
3375                c = G2lat.A2cell(A)
3376                vol = G2lat.calc_V(A)
3377                cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
3378                cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
3379                cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
3380            colList += zip(*cells)
3381            colSigs += zip(*cellESDs)
3382    # sort out the variables in their selected order
3383    varcols = 0
3384    for d in posdict.itervalues():
3385        varcols = max(varcols,max(d.keys())+1)
3386    # get labels for each column
3387    for i in range(varcols):
3388        lbl = ''
3389        for h in VaryListChanges:
3390            if posdict[h].get(i):
3391                if posdict[h].get(i) in lbl: continue
3392                if lbl != "": lbl += '/'
3393                lbl += posdict[h].get(i)
3394        colLabels.append(lbl)
3395    Types += varcols*[wg.GRID_VALUE_FLOAT]
3396    vals = []
3397    esds = []
3398    varsellist = None        # will be a list of variable names in the order they are selected to appear
3399    # tabulate values for each hist, leaving None for blank columns
3400    for name in histNames:
3401        if name in posdict:
3402            varsellist = [posdict[name].get(i) for i in range(varcols)]
3403            # translate variable names to how they will be used in the headings
3404            vs = [striphist(v,'*') for v in data[name]['varyList']]
3405            # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists
3406            sellist = [vs.index(v) if v is not None else None for v in varsellist]
3407            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])]
3408        if not varsellist: raise Exception()
3409        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
3410        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
3411        #GSASIIpath.IPyBreak()
3412    colList += zip(*vals)
3413    colSigs += zip(*esds)
3414               
3415    # tabulate constrained variables, removing histogram numbers if needed
3416    # from parameter label
3417    depValDict = {}
3418    depSigDict = {}
3419    for name in histNames:
3420        for var in data[name].get('depParmDict',{}):
3421            val,sig = data[name]['depParmDict'][var]
3422            svar = striphist(var,'*')
3423            if svar not in depValDict:
3424               depValDict[svar] = [val]
3425               depSigDict[svar] = [sig]
3426            else:
3427               depValDict[svar].append(val)
3428               depSigDict[svar].append(sig)
3429    # add the dependent constrained variables to the table
3430    for var in sorted(depValDict):
3431        if len(depValDict[var]) != len(histNames): continue
3432        colLabels.append(var)
3433        Types += [wg.GRID_VALUE_FLOAT,]
3434        colSigs += [depSigDict[var]]
3435        colList += [depValDict[var]]
3436
3437    # add atom parameters to table
3438    colLabels += atomLookup.keys()
3439    Types += len(atomLookup)*[wg.GRID_VALUE_FLOAT]
3440    for parm in sorted(atomLookup):
3441        colList += [[data[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
3442        if atomLookup[parm] in data[histNames[0]]['varyList']:
3443            col = data[histNames[0]]['varyList'].index(atomLookup[parm])
3444            colSigs += [[data[name]['sig'][col] for name in histNames]]
3445        else:
3446            colSigs += [None] # should not happen
3447    # evaluate Pseudovars, their ESDs and add them to grid
3448    for expr in Controls['SeqPseudoVars']:
3449        obj = Controls['SeqPseudoVars'][expr]
3450        calcobj = G2obj.ExpressionCalcObj(obj)
3451        valList = []
3452        esdList = []
3453        for seqnum,name in enumerate(histNames):
3454            sigs = data[name]['sig']
3455            G2mv.InitVars()
3456            parmDict = data[name].get('parmDict')
3457            badVary = data[name].get('badVary',[])
3458            constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum])
3459            groups,parmlist,constrDict,fixedList,ihst = constraintInfo
3460            varyList = data[name]['varyList']
3461            parmDict = data[name]['parmDict']
3462            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmDict,SeqHist=ihst)
3463            derivs = np.array(
3464                [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD)
3465                 for var,ESD in zip(varyList,sigs)])
3466            esdList.append(np.sqrt(
3467                np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T)) ))
3468            PSvarDict = parmDict.copy()
3469            PSvarDict.update(sampleDict[name])
3470            UpdateParmDict(PSvarDict)
3471            calcobj.UpdateDict(PSvarDict)
3472            valList.append(calcobj.EvalExpression())
3473            # if calcobj.su is not None: esdList[-1] = calcobj.su
3474        if not esdList:
3475            esdList = None
3476        colList += [valList]
3477        colSigs += [esdList]
3478        colLabels += [expr]
3479        Types += [wg.GRID_VALUE_FLOAT,]
3480    #---- table build done -------------------------------------------------------------
3481
3482    # Make dict needed for creating & editing pseudovars (PSvarDict).
3483    name = histNames[0]
3484    parmDict = data[name].get('parmDict',{})
3485    PSvarDict = parmDict.copy()
3486    PSvarDict.update(sampleParms)
3487    UpdateParmDict(PSvarDict)
3488    # Also dicts of dependent (depVarDict) & independent vars (indepVarDict)
3489    # for Parametric fitting from the data table
3490    parmDict = dict(zip(colLabels,zip(*colList)[0])) # scratch dict w/all values in table
3491    parmDict.update(
3492        {var:val for var,val in data[name].get('newCellDict',{}).values()} #  add varied reciprocal cell terms
3493    )
3494    name = histNames[0]
3495
3496    #******************************************************************************
3497    # create a set of values for example evaluation of pseudovars and
3498    # this does not work for refinements that have differing numbers of variables.
3499    #raise Exception
3500    indepVarDict = {}     #  values in table w/o ESDs
3501    depVarDict = {}
3502    for i,var in enumerate(colLabels):
3503        if var == 'Use': continue
3504        if colList[i][0] is None:
3505            val,sig = firstValueDict.get(var,[None,None])
3506        elif colSigs[i]:
3507            val,sig = colList[i][0],colSigs[i][0]
3508        else:
3509            val,sig = colList[i][0],None
3510        if val is None:
3511            continue
3512        elif sig is None:
3513            indepVarDict[var] = val
3514        elif striphist(var) not in Dlookup:
3515            depVarDict[var] = val
3516    # add recip cell coeff. values
3517    depVarDict.update({var:val for var,val in data[name].get('newCellDict',{}).values()})
3518
3519    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
3520    G2frame.SeqTable = G2G.Table(
3521        [list(c) for c in zip(*colList)],     # convert from columns to rows
3522        colLabels=colLabels,rowLabels=histNames,types=Types)
3523    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
3524    #G2frame.dataDisplay.EnableEditing(False)
3525    # make all but first column read-only
3526    for c in range(1,len(colLabels)):
3527        for r in range(nRows):
3528            G2frame.dataDisplay.SetCellReadOnly(r,c)
3529    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, PlotSelect)
3530    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, SetLabelString)
3531    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
3532    G2frame.dataDisplay.SetMargins(0,0)
3533    G2frame.dataDisplay.AutoSizeColumns(True)
3534    if prevSize:
3535        G2frame.dataDisplay.SetSize(prevSize)
3536    else:
3537        G2frame.dataFrame.setSizePosLeft([700,350])
3538    # highlight unconverged shifts
3539    if histNames[0][:4] not in ['SASD','IMG ']:
3540        for row,name in enumerate(histNames):
3541            deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol)
3542            if deltaChi > 10.:
3543                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0))
3544            elif deltaChi > 1.0:
3545                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0))
3546    G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip)
3547    G2frame.dataDisplay.SendSizeEvent() # resize needed on mac
3548    G2frame.dataDisplay.Refresh() # shows colored text on mac
3549   
3550################################################################################
3551#####  Main PWDR panel
3552################################################################################           
3553       
3554def UpdatePWHKPlot(G2frame,kind,item):
3555    '''Called when the histogram main tree entry is called. Displays the
3556    histogram weight factor, refinement statistics for the histogram
3557    and the range of data for a simulation.
3558
3559    Also invokes a plot of the histogram.
3560    '''
3561    def onEditSimRange(event):
3562        'Edit simulation range'
3563        inp = [
3564            min(data[1][0]),
3565            max(data[1][0]),
3566            None
3567            ]
3568        inp[2] = (inp[1] - inp[0])/(len(data[1][0])-1.)
3569        names = ('start angle', 'end angle', 'step size')
3570        dictlst = [inp] * len(inp)
3571        elemlst = range(len(inp))
3572        dlg = G2G.ScrolledMultiEditor(
3573            G2frame,[inp] * len(inp), range(len(inp)), names,
3574            header='Edit simulation range',
3575            minvals=(0.001,0.001,0.0001),
3576            maxvals=(180.,180.,.1),
3577            )
3578        dlg.CenterOnParent()
3579        val = dlg.ShowModal()
3580        dlg.Destroy()
3581        if val != wx.ID_OK: return
3582        if inp[0] > inp[1]:
3583            end,start,step = inp
3584        else:               
3585            start,end,step = inp
3586        step = abs(step)
3587        N = int((end-start)/step)+1
3588        newdata = np.linspace(start,end,N,True)
3589        if len(newdata) < 2: return # too small a range - reject
3590        data[1] = [newdata,np.zeros_like(newdata),np.ones_like(newdata),
3591            np.zeros_like(newdata),np.zeros_like(newdata),np.zeros_like(newdata)]
3592        Tmin = newdata[0]
3593        Tmax = newdata[-1]
3594        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,item,'Limits'),
3595            [(Tmin,Tmax),[Tmin,Tmax]])
3596        UpdatePWHKPlot(G2frame,kind,item) # redisplay data screen
3597
3598    def OnPlot3DHKL(event):
3599        refList = data[1]['RefList']
3600        FoMax = np.max(refList.T[8+Super])
3601        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3602        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3603        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3604        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
3605            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3606            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3607            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3608        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3609       
3610    def OnPlotAll3DHKL(event):
3611        choices = GetPatternTreeDataNames(G2frame,['HKLF',])
3612        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select reflection sets to plot',
3613            'Use data',choices)
3614        try:
3615            if dlg.ShowModal() == wx.ID_OK:
3616                refNames = [choices[i] for i in dlg.GetSelections()]
3617            else:
3618                return
3619        finally:
3620            dlg.Destroy()
3621        refList = np.zeros(0)
3622        for name in refNames:
3623            Id = GetPatternTreeItemId(G2frame,G2frame.root, name)
3624            reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
3625            if len(refList):
3626                refList = np.concatenate((refList,reflData['RefList']))
3627            else:
3628                refList = reflData['RefList']
3629           
3630        FoMax = np.max(refList.T[8+Super])
3631        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3632        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3633        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3634        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
3635            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3636            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3637            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
3638        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3639                 
3640    def OnMergeHKL(event):
3641        Name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3642        Inst = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,
3643            G2frame.PatternId,'Instrument Parameters'))
3644        CId = GetPatternTreeItemId(G2frame,G2frame.PatternId,'Comments')
3645        if CId:
3646            Comments = G2frame.PatternTree.GetItemPyData(CId)
3647        else:
3648            Comments = []
3649        refList = np.copy(data[1]['RefList'])
3650        Comments.append(' Merging %d reflections from %s'%(len(refList),Name))
3651        dlg = MergeDialog(G2frame,data)
3652        try:
3653            if dlg.ShowModal() == wx.ID_OK:
3654                Trans,Cent,Laue = dlg.GetSelection()
3655            else:
3656                return
3657        finally:
3658            dlg.Destroy()
3659        Super = data[1]['Super']
3660        refList,badRefs = G2lat.transposeHKLF(Trans,Super,refList)
3661        if len(badRefs):    #do I want to list badRefs?
3662            G2frame.ErrorDialog('Failed transformation','Matrix yields fractional hkl indices')
3663            return
3664        Comments.append(" Transformation M*H = H' applied; M=")
3665        Comments.append(str(Trans))
3666        SG = 'P '+Laue
3667        SGData = G2spc.SpcGroup(SG)[1]
3668        refList = G2lat.LaueUnique(Laue,refList)
3669        dlg = wx.ProgressDialog('Build HKL dictonary','',len(refList)+1, 
3670            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
3671        HKLdict = {}
3672        for ih,hkl in enumerate(refList):
3673            if str(hkl[:3+Super]) not in HKLdict:
3674                HKLdict[str(hkl[:3+Super])] = [hkl[:3+Super],[hkl[3+Super:],]]
3675            else:
3676                HKLdict[str(hkl[:3+Super])][1].append(hkl[3+Super:])
3677            dlg.Update(ih)
3678        dlg.Destroy()
3679        mergeRef = []
3680        dlg = wx.ProgressDialog('Processing merge','',len(HKLdict)+1, 
3681            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
3682        sumDf = 0.
3683        sumFo = 0.
3684        for ih,hkl in enumerate(HKLdict):
3685            HKL = HKLdict[hkl]
3686            newHKL = list(HKL[0])+list(HKL[1][0])
3687            if len(HKL[1]) > 1:
3688                fos = np.array(HKL[1])
3689                wFo = 1/fos[:,3]**2
3690                Fo = np.average(fos[:,2],weights=wFo)
3691                std = np.std(fos[:,2])
3692                sig = np.sqrt(np.mean(fos[:,3])**2+std**2)
3693                sumFo += np.sum(fos[:,2])
3694                sumDf += np.sum(np.abs(fos[:,2]-Fo))
3695                dlg.Update(ih)
3696                newHKL[5+Super] = Fo
3697                newHKL[6+Super] = sig
3698                newHKL[8+Super] = Fo
3699            if newHKL[5+Super] > 0.:
3700                mergeRef.append(list(newHKL)) 
3701        dlg.Destroy()
3702        if Super:
3703            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,3),2),1),0)
3704        else:
3705            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,2),1),0)
3706        mergeRef = np.array(mergeRef)
3707        if sumFo:
3708            mtext = ' merge R = %6.2f%s for %d reflections in %s'%(100.*sumDf/sumFo,'%',mergeRef.shape[0],Laue)
3709            print mtext
3710            Comments.append(mtext)
3711        else:
3712            print 'nothing to merge for %s reflections'%(mergeRef.shape[0])
3713        HKLFlist = []
3714        newName = Name+' '+Laue
3715        if G2frame.PatternTree.GetCount():
3716            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3717            while item:
3718                name = G2frame.PatternTree.GetItemText(item)
3719                if name.startswith('HKLF ') and name not in HKLFlist:
3720                    HKLFlist.append(name)
3721                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3722        newName = G2obj.MakeUniqueLabel(newName,HKLFlist)
3723        newData = copy.deepcopy(data)
3724        newData[0]['ranId'] = ran.randint(0,sys.maxint)
3725        newData[1]['RefList'] = mergeRef
3726        Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=newName)
3727        G2frame.PatternTree.SetItemPyData(
3728            G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)
3729        G2frame.PatternTree.SetItemPyData(Id,newData)
3730        G2frame.PatternTree.SetItemPyData(
3731            G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
3732        G2frame.PatternTree.SetItemPyData(
3733            G2frame.PatternTree.AppendItem(Id,text='Reflection List'),{})  #dummy entry for GUI use
3734                   
3735    def OnErrorAnalysis(event):
3736        G2plt.PlotDeltSig(G2frame,kind)
3737       
3738    def OnWtFactor(event):
3739        try:
3740            val = float(wtval.GetValue())
3741        except ValueError:
3742            val = data[0]['wtFactor']
3743        data[0]['wtFactor'] = val
3744        wtval.SetValue('%.3f'%(val))
3745       
3746    def OnCompression(event):
3747        data[0] = int(comp.GetValue())
3748       
3749    def onCopyPlotCtrls(event):
3750        '''Respond to menu item to copy multiple sections from a histogram.
3751        Need this here to pass on the G2frame object.
3752        '''
3753        G2pdG.CopyPlotCtrls(G2frame)
3754
3755    def onCopySelectedItems(event):
3756        '''Respond to menu item to copy multiple sections from a histogram.
3757        Need this here to pass on the G2frame object.
3758        '''
3759        G2pdG.CopySelectedHistItems(G2frame)
3760           
3761    data = G2frame.PatternTree.GetItemPyData(item)
3762#patches
3763    if 'wtFactor' not in data[0]:
3764        data[0] = {'wtFactor':1.0}
3765#    if kind == 'PWDR' and 'Compression' not in data[0]:
3766#        data[0]['Compression'] = 1
3767    #if isinstance(data[1],list) and kind == 'HKLF':
3768    if 'list' in str(type(data[1])) and kind == 'HKLF':
3769        RefData = {'RefList':[],'FF':[]}
3770        for ref in data[1]:
3771            RefData['RefList'].append(ref[:11]+[ref[13],])
3772            RefData['FF'].append(ref[14])
3773        data[1] = RefData
3774        G2frame.PatternTree.SetItemPyData(item,data)
3775#end patches
3776    if G2frame.dataDisplay:
3777        G2frame.dataDisplay.Destroy()
3778    if kind in ['PWDR','SASD']:
3779        SetDataMenuBar(G2frame,G2frame.dataFrame.PWDRMenu)
3780        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
3781        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
3782        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopyPlotCtrls, id=wxID_PLOTCTRLCOPY)
3783    elif kind in ['HKLF',]:
3784        SetDataMenuBar(G2frame,G2frame.dataFrame.HKLFMenu)
3785        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
3786        G2frame.dataFrame.Bind(wx.EVT_MENU, OnMergeHKL, id=wxID_MERGEHKL)
3787        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=wxID_PWD3DHKLPLOT)
3788        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotAll3DHKL, id=wxID_3DALLHKLPLOT)
3789#        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
3790    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
3791   
3792    mainSizer = wx.BoxSizer(wx.VERTICAL)
3793    mainSizer.Add((5,5),)
3794    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
3795    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,WACV)
3796    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
3797    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
3798    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
3799    wtSizer.Add(wtval,0,WACV)
3800#    if kind == 'PWDR':         #possible future compression feature; NB above patch as well
3801#        wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Compression factor: '),0,WACV)
3802#        choice = ['1','2','3','4','5','6']
3803#        comp = wx.ComboBox(parent=G2frame.dataDisplay,choices=choice,
3804#            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3805#        comp.SetValue(str(data[0]['Compression']))
3806#        comp.Bind(wx.EVT_COMBOBOX, OnCompression)
3807#        wtSizer.Add(comp,0,WACV)
3808    mainSizer.Add(wtSizer)
3809    if data[0].get('Dummy'):
3810        simSizer = wx.BoxSizer(wx.HORIZONTAL)
3811        Tmin = min(data[1][0])
3812        Tmax = max(data[1][0])
3813        num = len(data[1][0])
3814        step = (Tmax - Tmin)/(num-1)
3815        t = u'2\u03b8' # 2theta
3816        lbl =  u'Simulation range: {:.2f} to {:.2f} {:s}\nwith {:.4f} steps ({:d} points)'
3817        lbl += u'\n(Edit range resets observed intensities).'
3818        lbl = lbl.format(Tmin,Tmax,t,step,num)
3819        simSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,lbl),
3820                    0,WACV)
3821        but = wx.Button(G2frame.dataDisplay,wx.ID_ANY,"Edit range")
3822        but.Bind(wx.EVT_BUTTON,onEditSimRange)
3823        simSizer.Add(but,0,WACV)
3824        mainSizer.Add(simSizer)
3825    if 'Nobs' in data[0]:
3826        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3827            ' Data residual wR: %.3f%% on %d observations'%(data[0]['wR'],data[0]['Nobs'])))
3828        for value in data[0]:
3829            if 'Nref' in value:
3830                pfx = value.split('Nref')[0]
3831                name = data[0].get(pfx.split(':')[0]+'::Name','?')
3832                if 'SS' in value:
3833                    mainSizer.Add((5,5),)
3834                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For incommensurate phase '+name+':'))
3835                    for m,(Rf2,Rf,Nobs) in enumerate(zip(data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])):
3836                        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3837                            u' m = +/- %d: RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
3838                            (m,Rf2,Rf,Nobs)))
3839                else:
3840                    mainSizer.Add((5,5),)
3841                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For phase '+name+':'))
3842                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3843                        u' Unweighted phase residuals RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
3844                        (data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])))
3845                   
3846    mainSizer.Add((5,5),)
3847    mainSizer.Layout()   
3848    G2frame.dataDisplay.SetSizer(mainSizer)
3849    Size = mainSizer.Fit(G2frame.dataFrame)
3850    Size[1] += 10
3851    G2frame.dataFrame.setSizePosLeft(Size)
3852    G2frame.PatternTree.SetItemPyData(item,data)
3853    if kind in ['PWDR','SASD']:
3854        NewPlot = True
3855        if 'xylim' in dir(G2frame):
3856            NewPlot = False
3857        G2plt.PlotPatterns(G2frame,plotType=kind,newPlot=NewPlot)
3858    elif kind == 'HKLF':
3859        Name = G2frame.PatternTree.GetItemText(item)
3860        phaseName = G2pdG.IsHistogramInAnyPhase(G2frame,Name)
3861        if phaseName:
3862            pId = GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3863            phaseId =  GetPatternTreeItemId(G2frame,pId,phaseName)
3864            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3865            Super = General.get('Super',0)
3866            SuperVec = General.get('SuperVec',[])
3867        else:
3868            Super = 0
3869            SuperVec = []       
3870        refList = data[1]['RefList']
3871#        GSASIIpath.IPyBreak()
3872        FoMax = np.max(refList.T[5+data[1].get('Super',0)])
3873        page = G2frame.G2plotNB.nb.GetSelection()
3874        tab = ''
3875        if page >= 0:
3876            tab = G2frame.G2plotNB.nb.GetPageText(page)
3877        if '3D' in tab:
3878            Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3879            Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3880            Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3881            Page = G2frame.G2plotNB.nb.GetPage(page)
3882            controls = Page.controls
3883            G2plt.Plot3DSngl(G2frame,newPlot=False,Data=controls,hklRef=refList,Title=phaseName)
3884        else:
3885            controls = {'Type' : 'Fo','ifFc' : True,     
3886                'HKLmax' : [int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))],
3887                'HKLmin' : [int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))],
3888                'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3889            G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList)
3890                 
3891################################################################################
3892#####  Pattern tree routines
3893################################################################################           
3894       
3895def GetPatternTreeDataNames(G2frame,dataTypes):
3896    '''Finds all items in tree that match a 4 character prefix
3897   
3898    :param wx.Frame G2frame: Data tree frame object
3899    :param list dataTypes: Contains one or more data tree item types to be matched
3900      such as ['IMG '] or ['PWDR','HKLF']
3901    :returns: a list of tree item names for the matching items 
3902    '''
3903    names = []
3904    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
3905    while item:
3906        name = G2frame.PatternTree.GetItemText(item)
3907        if name[:4] in dataTypes:
3908            names.append(name)
3909        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3910    return names
3911                         
3912def GetPatternTreeItemId(G2frame, parentId, itemText):
3913    '''Find the tree item that matches the text in itemText starting with parentId
3914
3915    :param wx.Frame G2frame: Data tree frame object
3916    :param wx.TreeItemId parentId: tree item to start search with
3917    :param str itemText: text for tree item
3918    '''
3919    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
3920    while item:
3921        if G2frame.PatternTree.GetItemText(item) == itemText:
3922            return item
3923        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
3924    return 0               
3925
3926def MovePatternTreeToGrid(G2frame,item):
3927    '''Called from GSASII.OnPatternTreeSelChanged when a item is selected on the tree
3928    '''
3929    pickName = G2frame.PatternTree.GetItemText(item)
3930    if G2frame.PickIdText == pickName:
3931        return
3932   
3933    oldPage = None # will be set later if already on a Phase item
3934    if G2frame.dataFrame:
3935        SetDataMenuBar(G2frame)
3936        if G2frame.dataFrame.GetLabel() == 'Comments':
3937            try:
3938                data = [G2frame.dataDisplay.GetValue()]
3939                G2frame.dataDisplay.Clear() 
3940                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
3941                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3942            except:     #clumsy but avoids dead window problem when opening another project
3943                pass
3944        elif G2frame.dataFrame.GetLabel() == 'Notebook':
3945            try:
3946                data = [G2frame.dataDisplay.GetValue()]
3947                G2frame.dataDisplay.Clear() 
3948                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
3949                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3950            except:     #clumsy but avoids dead window problem when opening another project
3951                pass
3952        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
3953            if G2frame.dataDisplay: 
3954                oldPage = G2frame.dataDisplay.GetSelection()
3955        G2frame.dataFrame.Clear()
3956        G2frame.dataFrame.SetLabel('')
3957    else:
3958        #create the frame for the data item window
3959        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
3960        G2frame.dataFrame.PhaseUserSize = None
3961       
3962    G2frame.dataFrame.Raise()           
3963    G2frame.PickId = item
3964    G2frame.PickIdText = None
3965    parentID = G2frame.root
3966    #for i in G2frame.ExportPattern: i.Enable(False)
3967    defWid = [250,150]
3968    if item != G2frame.root:
3969        parentID = G2frame.PatternTree.GetItemParent(item)
3970    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
3971        G2frame.PatternId = item
3972        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
3973            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
3974            G2frame.PatternId = 0
3975            #for i in G2frame.ExportPattern: i.Enable(False)
3976            data = G2frame.PatternTree.GetItemPyData(item)
3977            UpdateNotebook(G2frame,data)
3978        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
3979            G2frame.PatternId = 0
3980            #for i in G2frame.ExportPattern: i.Enable(False)
3981            data = G2frame.PatternTree.GetItemPyData(item)
3982            if not data:           #fill in defaults
3983                data = copy.copy(G2obj.DefaultControls)    #least squares controls
3984                G2frame.PatternTree.SetItemPyData(item,data)                             
3985            for i in G2frame.Refine: i.Enable(True)
3986            G2frame.EnableSeqRefineMenu()
3987            UpdateControls(G2frame,data)
3988        elif G2frame.PatternTree.GetItemText(item) == 'Sequential results':
3989            data = G2frame.PatternTree.GetItemPyData(item)
3990            UpdateSeqResults(G2frame,data)
3991        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
3992            data = G2frame.PatternTree.GetItemPyData(item)
3993            G2frame.dataFrame.setSizePosLeft(defWid)
3994            text = ''
3995            if 'Rvals' in data:
3996                Nvars = len(data['varyList'])
3997                Rvals = data['Rvals']
3998                text = '\nFinal residuals: \nwR = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
3999                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
4000                if 'lamMax' in Rvals:
4001                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
4002            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
4003                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
4004            G2plt.PlotCovariance(G2frame,data)
4005        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
4006            data = G2frame.PatternTree.GetItemPyData(item)
4007            G2cnstG.UpdateConstraints(G2frame,data)
4008        elif G2frame.PatternTree.GetItemText(item) == 'Rigid bodies':
4009            data = G2frame.PatternTree.GetItemPyData(item)
4010            G2cnstG.UpdateRigidBodies(G2frame,data)
4011        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
4012            data = G2frame.PatternTree.GetItemPyData(item)
4013            Phases = G2frame.GetPhaseData()
4014            phase = ''
4015            phaseName = ''
4016            if Phases:
4017                phaseName = Phases.keys()[0]
4018            G2frame.dataFrame.setSizePosLeft(defWid)
4019            G2restG.UpdateRestraints(G2frame,data,Phases,phaseName)
4020        elif 'IMG' in G2frame.PatternTree.GetItemText(item):
4021            G2frame.Image = item
4022            G2frame.dataFrame.SetTitle('Image Data')
4023            data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(
4024                G2frame,item,'Image Controls'))
4025            G2imG.UpdateImageData(G2frame,data)
4026            G2plt.PlotImage(G2frame,newPlot=True)
4027        elif 'PKS' in G2frame.PatternTree.GetItemText(item):
4028            G2plt.PlotPowderLines(G2frame)
4029        elif 'PWDR' in G2frame.PatternTree.GetItemText(item):
4030            #for i in G2frame.ExportPattern: i.Enable(True)
4031            if G2frame.EnablePlot:
4032                UpdatePWHKPlot(G2frame,'PWDR',item)
4033        elif 'SASD' in G2frame.PatternTree.GetItemText(item):
4034            #for i in G2frame.ExportPattern: i.Enable(True)
4035            if G2frame.EnablePlot:
4036                UpdatePWHKPlot(G2frame,'SASD',item)
4037        elif 'HKLF' in G2frame.PatternTree.GetItemText(item):
4038            G2frame.Sngl = True
4039            UpdatePWHKPlot(G2frame,'HKLF',item)
4040        elif 'PDF' in G2frame.PatternTree.GetItemText(item):
4041            G2frame.PatternId = item
4042            for i in G2frame.ExportPDF: i.Enable(True)
4043            G2plt.PlotISFG(G2frame,type='S(Q)')
4044        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
4045            G2frame.dataFrame.setSizePosLeft(defWid)
4046            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
4047                value='Select one phase to see its parameters')           
4048    elif 'I(Q)' in G2frame.PatternTree.GetItemText(item):
4049        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4050        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4051        G2pdG.UpdatePDFGrid(G2frame,data)
4052        G2plt.PlotISFG(G2frame,type='I(Q)',newPlot=True)
4053    elif 'S(Q)' in G2frame.PatternTree.GetItemText(item):
4054        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4055        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4056        G2pdG.UpdatePDFGrid(G2frame,data)
4057        G2plt.PlotISFG(G2frame,type='S(Q)',newPlot=True)
4058    elif 'F(Q)' in G2frame.PatternTree.GetItemText(item):
4059        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4060        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4061        G2pdG.UpdatePDFGrid(G2frame,data)
4062        G2plt.PlotISFG(G2frame,type='F(Q)',newPlot=True)
4063    elif 'G(R)' in G2frame.PatternTree.GetItemText(item):
4064        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4065        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4066        G2pdG.UpdatePDFGrid(G2frame,data)
4067        G2plt.PlotISFG(G2frame,type='G(R)',newPlot=True)           
4068    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
4069        data = G2frame.PatternTree.GetItemPyData(item)
4070        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
4071    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
4072        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
4073        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4074        data = G2frame.PatternTree.GetItemPyData(item)
4075        UpdateComments(G2frame,data)
4076    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
4077        G2frame.dataFrame.SetTitle('Image Controls')
4078        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4079        masks = G2frame.PatternTree.GetItemPyData(
4080            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
4081        data = G2frame.PatternTree.GetItemPyData(item)
4082        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4083        G2imG.UpdateImageControls(G2frame,data,masks)
4084        G2plt.PlotImage(G2frame,newPlot=True)
4085    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
4086        G2frame.dataFrame.SetTitle('Masks')
4087        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4088        masks = G2frame.PatternTree.GetItemPyData(item)
4089        data = G2frame.PatternTree.GetItemPyData(
4090            GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4091        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4092        G2imG.UpdateMasks(G2frame,masks)
4093        G2plt.PlotImage(G2frame,newPlot=True)
4094    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
4095        G2frame.dataFrame.SetTitle('Stress/Strain')
4096        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4097        data = G2frame.PatternTree.GetItemPyData(
4098            GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4099        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4100        strsta = G2frame.PatternTree.GetItemPyData(item)
4101        G2plt.PlotImage(G2frame,newPlot=True)
4102        G2plt.PlotStrain(G2frame,strsta,newPlot=True)
4103        G2imG.UpdateStressStrain(G2frame,strsta)
4104    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
4105        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4106        for i in G2frame.ExportPDF: i.Enable(True)
4107        data = G2frame.PatternTree.GetItemPyData(item)
4108        G2pdG.UpdatePDFGrid(G2frame,data)
4109        G2plt.PlotISFG(G2frame,type='I(Q)')
4110        G2plt.PlotISFG(G2frame,type='S(Q)')
4111        G2plt.PlotISFG(G2frame,type='F(Q)')
4112        G2plt.PlotISFG(G2frame,type='G(R)')
4113    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
4114        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4115        for i in G2frame.ExportPeakList: i.Enable(True)
4116        data = G2frame.PatternTree.GetItemPyData(item)
4117#patch
4118        if 'list' in str(type(data)):
4119            data = {'peaks':data,'sigDict':{}}
4120            G2frame.PatternTree.SetItemPyData(item,data)
4121#end patch
4122        G2pdG.UpdatePeakGrid(G2frame,data)
4123        G2plt.PlotPatterns(G2frame)
4124    elif G2frame.PatternTree.GetItemText(item) == 'Background':
4125        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4126        data = G2frame.PatternTree.GetItemPyData(item)
4127        G2pdG.UpdateBackground(G2frame,data)
4128        G2plt.PlotPatterns(G2frame)
4129    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
4130        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4131        datatype = G2frame.PatternTree.GetItemText(G2frame.PatternId)[:4]
4132        data = G2frame.PatternTree.GetItemPyData(item)
4133        G2pdG.UpdateLimitsGrid(G2frame,data,datatype)
4134        G2plt.PlotPatterns(G2frame,plotType=datatype)
4135    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
4136        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4137        data = G2frame.PatternTree.GetItemPyData(item)[0]
4138        G2pdG.UpdateInstrumentGrid(G2frame,data)
4139        if 'P' in data['Type'][0]:          #powder data only
4140            G2plt.PlotPeakWidths(G2frame)
4141    elif G2frame.PatternTree.GetItemText(item) == 'Models':
4142        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4143        data = G2frame.PatternTree.GetItemPyData(item)
4144        G2pdG.UpdateModelsGrid(G2frame,data)
4145        G2plt.PlotPatterns(G2frame,plotType='SASD')
4146        if len(data['Size']['Distribution']):
4147            G2plt.PlotSASDSizeDist(G2frame)
4148    elif G2frame.PatternTree.GetItemText(item) == 'Substances':
4149        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4150        data = G2frame.PatternTree.GetItemPyData(item)
4151        G2pdG.UpdateSubstanceGrid(G2frame,data)
4152    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
4153        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4154        data = G2frame.PatternTree.GetItemPyData(item)
4155        datatype = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[2][:4]
4156
4157        if 'Temperature' not in data:           #temp fix for old gpx files
4158            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
4159                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,
4160                    'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
4161                    'Gonio. radius':200.0}
4162            G2frame.PatternTree.SetItemPyData(item,data)
4163   
4164        G2pdG.UpdateSampleGrid(G2frame,data)
4165        G2plt.PlotPatterns(G2frame,plotType=datatype)
4166    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
4167        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4168        for i in G2frame.ExportPeakList: i.Enable(True)
4169        data = G2frame.PatternTree.GetItemPyData(item)
4170#patch
4171        if len(data) != 2:
4172            data = [data,[]]
4173            G2frame.PatternTree.SetItemPyData(item,data)
4174#end patch
4175        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
4176        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4177            G2plt.PlotPowderLines(G2frame)
4178        else:
4179            G2plt.PlotPatterns(G2frame)
4180    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
4181        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4182        data = G2frame.PatternTree.GetItemPyData(item)
4183        if not data:
4184            data.append([0,0.0,4,25.0,0,'P1',1,1,1,90,90,90]) #zero error flag, zero value, max Nc/No, start volume
4185            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
4186            data.append([])                                 #empty cell list
4187            data.append([])                                 #empty dmin
4188            data.append({})                                 #empty superlattice stuff
4189            G2frame.PatternTree.SetItemPyData(item,data)                             
4190#patch
4191        if len(data) < 5:
4192            data.append({'Use':False,'ModVec':[0,0,0.1],'maxH':1,'ssSymb':''})                                 #empty superlattice stuff
4193            G2frame.PatternTree.SetItemPyData(item,data) 
4194#end patch
4195        G2pdG.UpdateUnitCellsGrid(G2frame,data)
4196        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4197            G2plt.PlotPowderLines(G2frame)
4198        else:
4199            G2plt.PlotPatterns(G2frame)
4200    elif G2frame.PatternTree.GetItemText(item) == 'Reflection Lists':   #powder reflections
4201        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4202        data = G2frame.PatternTree.GetItemPyData(item)
4203        G2frame.RefList = ''
4204        if len(data):
4205            G2frame.RefList = data.keys()[0]
4206        G2pdG.UpdateReflectionGrid(G2frame,data)
4207        G2plt.PlotPatterns(G2frame)
4208    elif G2frame.PatternTree.GetItemText(item) == 'Reflection List':    #HKLF reflections
4209        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4210        name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
4211        data = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
4212        G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
4213
4214    if G2frame.PickId:
4215        G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
4216    G2frame.dataFrame.Raise()
4217
4218def SetDataMenuBar(G2frame,menu=None):
4219    '''Set the menu for the data frame. On the Mac put this
4220    menu for the data tree window instead.
4221
4222    Note that data frame items do not have menus, for these (menu=None)
4223    display a blank menu or on the Mac display the standard menu for
4224    the data tree window.
4225    '''
4226    if sys.platform == "darwin":
4227        if menu is None:
4228            G2frame.SetMenuBar(G2frame.GSASIIMenu)
4229        else:
4230            G2frame.SetMenuBar(menu)
4231    else:
4232        if menu is None:
4233            G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
4234        else:
4235            G2frame.dataFrame.SetMenuBar(menu)
4236
4237def HowDidIgetHere():
4238    '''Show a traceback with calls that brought us to the current location.
4239    Used for debugging.
4240    '''
4241    import traceback
4242    print 70*'*'   
4243    for i in traceback.format_list