source: trunk/GSASIIgrid.py @ 2340

Last change on this file since 2340 was 2340, checked in by toby, 7 years ago

write multiple control files

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 201.6 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIgrid - data display routines
3########### SVN repository information ###################
4# $Date: 2016-06-23 19:54:24 +0000 (Thu, 23 Jun 2016) $
5# $Author: toby $
6# $Revision: 2340 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 2340 2016-06-23 19:54:24Z toby $
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: 2340 $")
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, wxID_SAVESELECTEDCONTROLS,
98] = [wx.NewId() for item in range(12)]
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='Save controls from selected images to file', 
1767            id=wxID_SAVESELECTEDCONTROLS, kind=wx.ITEM_NORMAL,text='Save Multiple Controls')
1768        self.ImageEdit.Append(help='Load image controls from file', 
1769            id=wxID_IMLOADCONTROLS, kind=wx.ITEM_NORMAL,text='Load Controls')
1770        self.ImageEdit.Append(help='Open Auto-integration window to integrate a series of images', 
1771            id=wxID_IMAUTOINTEG, kind=wx.ITEM_NORMAL,text='Auto Integrate')
1772        self.PostfillDataMenu()
1773           
1774        # IMG / Masks
1775        self.MaskMenu = wx.MenuBar()
1776        self.PrefillDataMenu(self.MaskMenu,helpType='Image Masks')
1777        self.MaskEdit = wx.Menu(title='')
1778        self.MaskMenu.Append(menu=self.MaskEdit, title='Operations')
1779        submenu = wx.Menu()
1780        self.MaskEdit.AppendMenu(
1781            wx.ID_ANY,'Create new', submenu,
1782            help=''
1783            )
1784        self.MaskEdit.Append(help='Copy mask to other images', 
1785            id=wxID_MASKCOPY, kind=wx.ITEM_NORMAL,text='Copy mask')
1786        self.MaskEdit.Append(help='Save mask to file', 
1787            id=wxID_MASKSAVE, kind=wx.ITEM_NORMAL,text='Save mask')
1788        self.MaskEdit.Append(help='Load mask from file', 
1789            id=wxID_MASKLOAD, kind=wx.ITEM_NORMAL,text='Load mask')
1790        self.MaskEdit.Append(help='Load mask from file; ignore threshold', 
1791            id=wxID_MASKLOADNOT, kind=wx.ITEM_NORMAL,text='Load mask w/o threshold')
1792        submenu.Append(help='Create an arc mask with mouse input', 
1793            id=wxID_NEWMASKARC, kind=wx.ITEM_NORMAL,text='Arc mask')
1794        submenu.Append(help='Create a frame mask with mouse input', 
1795            id=wxID_NEWMASKFRAME, kind=wx.ITEM_NORMAL,text='Frame mask')
1796        submenu.Append(help='Create a polygon mask with mouse input', 
1797            id=wxID_NEWMASKPOLY, kind=wx.ITEM_NORMAL,text='Polygon mask')
1798        submenu.Append(help='Create a ring mask with mouse input', 
1799            id=wxID_NEWMASKRING, kind=wx.ITEM_NORMAL,text='Ring mask')
1800        submenu.Append(help='Create a spot mask with mouse input', 
1801            id=wxID_NEWMASKSPOT, kind=wx.ITEM_NORMAL,text='Spot mask')
1802        self.PostfillDataMenu()
1803           
1804        # IMG / Stress/Strain
1805        self.StrStaMenu = wx.MenuBar()
1806        self.PrefillDataMenu(self.StrStaMenu,helpType='Stress/Strain')
1807        self.StrStaEdit = wx.Menu(title='')
1808        self.StrStaMenu.Append(menu=self.StrStaEdit, title='Operations')
1809        self.StrStaEdit.Append(help='Append d-zero for one ring', 
1810            id=wxID_APPENDDZERO, kind=wx.ITEM_NORMAL,text='Append d-zero')
1811        self.StrStaEdit.Append(help='Fit stress/strain data', 
1812            id=wxID_STRSTAFIT, kind=wx.ITEM_NORMAL,text='Fit stress/strain')
1813        self.StrStaEdit.Append(help='Update d-zero from ave d-zero',
1814            id=wxID_UPDATEDZERO, kind=wx.ITEM_NORMAL,text='Update d-zero')       
1815        self.StrStaEdit.Append(help='Fit stress/strain data for all images', 
1816            id=wxID_STRSTAALLFIT, kind=wx.ITEM_NORMAL,text='All image fit')
1817        self.StrStaEdit.Append(help='Copy stress/strain data to other images', 
1818            id=wxID_STRSTACOPY, kind=wx.ITEM_NORMAL,text='Copy stress/strain')
1819        self.StrStaEdit.Append(help='Save stress/strain data to file', 
1820            id=wxID_STRSTASAVE, kind=wx.ITEM_NORMAL,text='Save stress/strain')
1821        self.StrStaEdit.Append(help='Load stress/strain data from file', 
1822            id=wxID_STRSTALOAD, kind=wx.ITEM_NORMAL,text='Load stress/strain')
1823        self.StrStaEdit.Append(help='Load sample data from file', 
1824            id=wxID_STRSTSAMPLE, kind=wx.ITEM_NORMAL,text='Load sample data')
1825        self.PostfillDataMenu()
1826           
1827        # PDF / PDF Controls
1828        self.PDFMenu = wx.MenuBar()
1829        self.PrefillDataMenu(self.PDFMenu,helpType='PDF Controls')
1830        self.PDFEdit = wx.Menu(title='')
1831        self.PDFMenu.Append(menu=self.PDFEdit, title='PDF Controls')
1832        self.PDFEdit.Append(help='Add element to sample composition',id=wxID_PDFADDELEMENT, kind=wx.ITEM_NORMAL,
1833            text='Add element')
1834        self.PDFEdit.Append(help='Delete element from sample composition',id=wxID_PDFDELELEMENT, kind=wx.ITEM_NORMAL,
1835            text='Delete element')
1836        self.PDFEdit.Append(help='Copy PDF controls', id=wxID_PDFCOPYCONTROLS, kind=wx.ITEM_NORMAL,
1837            text='Copy controls')
1838        self.PDFEdit.Append(help='Load PDF controls from file',id=wxID_PDFLOADCONTROLS, kind=wx.ITEM_NORMAL,
1839            text='Load Controls')
1840        self.PDFEdit.Append(help='Save PDF controls to file', id=wxID_PDFSAVECONTROLS, kind=wx.ITEM_NORMAL,
1841            text='Save controls')
1842        self.PDFEdit.Append(help='Compute PDF', id=wxID_PDFCOMPUTE, kind=wx.ITEM_NORMAL,
1843            text='Compute PDF')
1844        self.PDFEdit.Append(help='Compute all PDFs', id=wxID_PDFCOMPUTEALL, kind=wx.ITEM_NORMAL,
1845            text='Compute all PDFs')
1846        self.PostfillDataMenu()
1847       
1848        # Phase / General tab
1849        self.DataGeneral = wx.MenuBar()
1850        self.PrefillDataMenu(self.DataGeneral,helpType='General', helpLbl='Phase/General')
1851        self.DataGeneral.Append(menu=wx.Menu(title=''),title='Select tab')
1852        self.GeneralCalc = wx.Menu(title='')
1853        self.DataGeneral.Append(menu=self.GeneralCalc,title='Compute')
1854        self.GeneralCalc.Append(help='Compute Fourier map',id=wxID_FOURCALC, kind=wx.ITEM_NORMAL,
1855            text='Fourier map')
1856        self.GeneralCalc.Append(help='Search Fourier map',id=wxID_FOURSEARCH, kind=wx.ITEM_NORMAL,
1857            text='Search map')
1858        self.GeneralCalc.Append(help='Run charge flipping',id=wxID_CHARGEFLIP, kind=wx.ITEM_NORMAL,
1859            text='Charge flipping')
1860        self.GeneralCalc.Append(help='Run 4D charge flipping',id=wxID_4DCHARGEFLIP, kind=wx.ITEM_NORMAL,
1861            text='4D Charge flipping')
1862        self.GeneralCalc.Enable(wxID_4DCHARGEFLIP,False)   
1863        self.GeneralCalc.Append(help='Clear map',id=wxID_FOURCLEAR, kind=wx.ITEM_NORMAL,
1864            text='Clear map')
1865        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing',id=wxID_SINGLEMCSA, kind=wx.ITEM_NORMAL,
1866            text='MC/SA')
1867        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing on multiprocessors',id=wxID_MULTIMCSA, kind=wx.ITEM_NORMAL,
1868            text='Multi MC/SA')            #currently not useful
1869        self.GeneralCalc.Append(help='Transform crystal structure',id=wxID_TRANSFORMSTRUCTURE, kind=wx.ITEM_NORMAL,
1870            text='Transform')
1871        self.PostfillDataMenu()
1872       
1873        # Phase / Data tab
1874        self.DataMenu = wx.MenuBar()
1875        self.PrefillDataMenu(self.DataMenu,helpType='Data', helpLbl='Phase/Data')
1876        self.DataMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1877        self.DataEdit = wx.Menu(title='')
1878        self.DataMenu.Append(menu=self.DataEdit, title='Edit')
1879        self.DataEdit.Append(id=wxID_DATACOPY, kind=wx.ITEM_NORMAL,text='Copy data',
1880            help='Copy phase data to other histograms')
1881        self.DataEdit.Append(id=wxID_DATACOPYFLAGS, kind=wx.ITEM_NORMAL,text='Copy flags',
1882            help='Copy phase data flags to other histograms')
1883        self.DataEdit.Append(id=wxID_DATASELCOPY, kind=wx.ITEM_NORMAL,text='Copy selected data',
1884            help='Copy selected phase data to other histograms')
1885        self.DataEdit.Append(id=wxID_DATAUSE, kind=wx.ITEM_NORMAL,text='Select used data',
1886            help='Select all histograms to use')
1887        self.DataEdit.Append(id=wxID_PWDRADD, kind=wx.ITEM_NORMAL,text='Add powder histograms',
1888            help='Select new powder histograms to be used for this phase')
1889        self.DataEdit.Append(id=wxID_HKLFADD, kind=wx.ITEM_NORMAL,text='Add single crystal histograms',
1890            help='Select new single crystal histograms to be used for this phase')
1891        self.DataEdit.Append(id=wxID_DATADELETE, kind=wx.ITEM_NORMAL,text='Remove histograms',
1892            help='Remove histograms from use for this phase')
1893        self.PostfillDataMenu()
1894           
1895        # Phase / Atoms tab
1896        self.AtomsMenu = wx.MenuBar()
1897        self.PrefillDataMenu(self.AtomsMenu,helpType='Atoms')
1898        self.AtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1899        self.AtomEdit = wx.Menu(title='')
1900        self.AtomCompute = wx.Menu(title='')
1901        self.AtomsMenu.Append(menu=self.AtomEdit, title='Edit')
1902        self.AtomsMenu.Append(menu=self.AtomCompute, title='Compute')
1903        self.AtomEdit.Append(id=wxID_ATOMSEDITADD, kind=wx.ITEM_NORMAL,text='Append atom',
1904            help='Appended as an H atom')
1905        self.AtomEdit.Append(id=wxID_ATOMSVIEWADD, kind=wx.ITEM_NORMAL,text='Append view point',
1906            help='Appended as an H atom')
1907        self.AtomEdit.Append(id=wxID_ATOMSEDITINSERT, kind=wx.ITEM_NORMAL,text='Insert atom',
1908            help='Select atom row to insert before; inserted as an H atom')
1909        self.AtomEdit.Append(id=wxID_ATOMVIEWINSERT, kind=wx.ITEM_NORMAL,text='Insert view point',
1910            help='Select atom row to insert before; inserted as an H atom')
1911        self.AtomEdit.Append(id=wxID_ADDHATOM, kind=wx.ITEM_NORMAL,text='Insert H atoms',
1912            help='Insert H atoms in standard positions bonded to selected atoms')
1913        self.AtomEdit.Append(id=wxID_UPDATEHATOM, kind=wx.ITEM_NORMAL,text='Update H atoms',
1914            help='Update H atoms in standard positions')
1915        self.AtomEdit.Append(id=wxID_ATOMMOVE, kind=wx.ITEM_NORMAL,text='Move atom to view point',
1916            help='Select single atom to move')
1917        self.AtomEdit.Append(id=wxID_ATOMSEDITDELETE, kind=wx.ITEM_NORMAL,text='Delete atom',
1918            help='Select atoms to delete first')
1919        self.AtomEdit.Append(id=wxID_ATOMSREFINE, kind=wx.ITEM_NORMAL,text='Set atom refinement flags',
1920            help='Select atoms to refine first')
1921        self.AtomEdit.Append(id=wxID_ATOMSMODIFY, kind=wx.ITEM_NORMAL,text='Modify atom parameters',
1922            help='Select atoms to modify first')
1923        self.AtomEdit.Append(id=wxID_ATOMSTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform atoms',
1924            help='Select atoms to transform first')
1925#        self.AtomEdit.Append(id=wxID_ATOMSROTATE, kind=wx.ITEM_NORMAL,text='Rotate atoms',
1926#            help='Select atoms to rotate first')
1927        self.AtomEdit.Append(id=wxID_MAKEMOLECULE, kind=wx.ITEM_NORMAL,text='Assemble molecule',
1928            help='Assemble molecule from scatterd atom positions')
1929        self.AtomEdit.Append(id=wxID_RELOADDRAWATOMS, kind=wx.ITEM_NORMAL,text='Reload draw atoms',
1930            help='Reload atom drawing list')
1931        submenu = wx.Menu()
1932        self.AtomEdit.AppendMenu(wx.ID_ANY, 'Reimport atoms', submenu, 
1933            help='Reimport atoms from file; sequence must match')
1934        # setup a cascade menu for the formats that have been defined
1935        self.ReImportMenuId = {}  # points to readers for each menu entry
1936        for reader in self.G2frame.ImportPhaseReaderlist:
1937            item = submenu.Append(
1938                wx.ID_ANY,help=reader.longFormatName,
1939                kind=wx.ITEM_NORMAL,text='reimport coordinates from '+reader.formatName+' file')
1940            self.ReImportMenuId[item.GetId()] = reader
1941        item = submenu.Append(
1942            wx.ID_ANY,
1943            help='Reimport coordinates, try to determine format from file',
1944            kind=wx.ITEM_NORMAL,
1945            text='guess format from file')
1946        self.ReImportMenuId[item.GetId()] = None # try all readers
1947
1948        self.AtomCompute.Append(id=wxID_ATOMSDISAGL, kind=wx.ITEM_NORMAL,text='Show Distances && Angles',
1949            help='Compute distances & angles for selected atoms')
1950        self.AtomCompute.Append(id=wxID_ATOMSPDISAGL, kind=wx.ITEM_NORMAL,text='Save Distances && Angles',
1951            help='Compute distances & angles for selected atoms')
1952        self.AtomCompute.ISOcalc = self.AtomCompute.Append(
1953            id=wxID_ISODISP, kind=wx.ITEM_NORMAL,
1954            text='Compute ISODISTORT mode values',
1955            help='Compute values of ISODISTORT modes from atom parameters')
1956        self.PostfillDataMenu()
1957       
1958        # Phase / Imcommensurate "waves" tab
1959        self.WavesData = wx.MenuBar()
1960        self.PrefillDataMenu(self.WavesData,helpType='Wave Data', helpLbl='Imcommensurate wave data')
1961        self.WavesData.Append(menu=wx.Menu(title=''),title='Select tab')
1962        self.WavesDataEdit = wx.Menu(title='')
1963        self.WavesData.Append(menu=self.WavesDataEdit, title='Edit')
1964        self.WavesDataEdit.Append(id=wxID_WAVEVARY, kind=wx.ITEM_NORMAL,text='Global wave vary',
1965            help='Global setting of wave vary flags')
1966        self.PostfillDataMenu()
1967       
1968        # Phase / Layer tab
1969        self.LayerData = wx.MenuBar()
1970        self.PrefillDataMenu(self.LayerData,helpType='Layer Data', helpLbl='Stacking fault layers')
1971        self.LayerData.Append(menu=wx.Menu(title=''),title='Select tab')
1972        self.LayerDataEdit = wx.Menu(title='')
1973        self.LayerData.Append(menu=self.LayerDataEdit, title='Operations')
1974        self.LayerDataEdit.Append(id=wxID_LOADDIFFAX, kind=wx.ITEM_NORMAL,text='Load from DIFFaX file',
1975            help='Load layer info from DIFFaX file')
1976        self.LayerDataEdit.Append(id=wxID_COPYPHASE, kind=wx.ITEM_NORMAL,text='Copy phase cell',
1977            help='Copy phase cell from another project')
1978        self.LayerDataEdit.Append(id=wxID_LAYERSIMULATE, kind=wx.ITEM_NORMAL,text='Simulate pattern',
1979            help='Simulate diffraction pattern from layer stacking')
1980        self.LayerDataEdit.Append(id=wxID_SEQUENCESIMULATE, kind=wx.ITEM_NORMAL,text='Sequence simulations',
1981            help='Sequence simulation changing one parameter')
1982        self.PostfillDataMenu()
1983                 
1984        # Phase / Draw Options tab
1985        self.DataDrawOptions = wx.MenuBar()
1986        self.PrefillDataMenu(self.DataDrawOptions,helpType='Draw Options', helpLbl='Phase/Draw Options')
1987        self.DataDrawOptions.Append(menu=wx.Menu(title=''),title='Select tab')
1988        self.PostfillDataMenu()
1989       
1990        # Phase / Draw Atoms tab
1991        self.DrawAtomsMenu = wx.MenuBar()
1992        self.PrefillDataMenu(self.DrawAtomsMenu,helpType='Draw Atoms')
1993        self.DrawAtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1994        self.DrawAtomEdit = wx.Menu(title='')
1995        self.DrawAtomCompute = wx.Menu(title='')
1996        self.DrawAtomRestraint = wx.Menu(title='')
1997        self.DrawAtomRigidBody = wx.Menu(title='')
1998        self.DrawAtomsMenu.Append(menu=self.DrawAtomEdit, title='Edit')
1999        self.DrawAtomsMenu.Append(menu=self.DrawAtomCompute,title='Compute')
2000        self.DrawAtomsMenu.Append(menu=self.DrawAtomRestraint, title='Restraints')
2001        self.DrawAtomsMenu.Append(menu=self.DrawAtomRigidBody, title='Rigid body')
2002        self.DrawAtomEdit.Append(id=wxID_DRAWATOMSTYLE, kind=wx.ITEM_NORMAL,text='Atom style',
2003            help='Select atoms first')
2004        self.DrawAtomEdit.Append(id=wxID_DRAWATOMLABEL, kind=wx.ITEM_NORMAL,text='Atom label',
2005            help='Select atoms first')
2006        self.DrawAtomEdit.Append(id=wxID_DRAWATOMCOLOR, kind=wx.ITEM_NORMAL,text='Atom color',
2007            help='Select atoms first')
2008        self.DrawAtomEdit.Append(id=wxID_DRAWATOMRESETCOLOR, kind=wx.ITEM_NORMAL,text='Reset atom colors',
2009            help='Resets all atom colors to defaults')
2010        self.DrawAtomEdit.Append(id=wxID_DRAWVIEWPOINT, kind=wx.ITEM_NORMAL,text='View point',
2011            help='View point is 1st atom selected')
2012        self.DrawAtomEdit.Append(id=wxID_DRAWADDEQUIV, kind=wx.ITEM_NORMAL,text='Add atoms',
2013            help='Add symmetry & cell equivalents to drawing set from selected atoms')
2014        self.DrawAtomEdit.Append(id=wxID_DRAWTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform draw atoms',
2015            help='Transform selected atoms by symmetry & cell translations')
2016        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCOORD, kind=wx.ITEM_NORMAL,text='Fill CN-sphere',
2017            help='Fill coordination sphere for selected atoms')           
2018        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCELL, kind=wx.ITEM_NORMAL,text='Fill unit cell',
2019            help='Fill unit cell with selected atoms')
2020        self.DrawAtomEdit.Append(id=wxID_DRAWDELETE, kind=wx.ITEM_NORMAL,text='Delete atoms',
2021            help='Delete atoms from drawing set')
2022        self.DrawAtomCompute.Append(id=wxID_DRAWDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2023            help='Compute distance of selected atoms from view point')   
2024        self.DrawAtomCompute.Append(id=wxID_DRAWDISAGLTOR, kind=wx.ITEM_NORMAL,text='Dist. Ang. Tors.',
2025            help='Compute distance, angle or torsion for 2-4 selected atoms')   
2026        self.DrawAtomCompute.Append(id=wxID_DRAWPLANE, kind=wx.ITEM_NORMAL,text='Best plane',
2027            help='Compute best plane for 4+ selected atoms')   
2028        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRBOND, kind=wx.ITEM_NORMAL,text='Add bond restraint',
2029            help='Add bond restraint for selected atoms (2)')
2030        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRANGLE, kind=wx.ITEM_NORMAL,text='Add angle restraint',
2031            help='Add angle restraint for selected atoms (3: one end 1st)')
2032        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRPLANE, kind=wx.ITEM_NORMAL,text='Add plane restraint',
2033            help='Add plane restraint for selected atoms (4+)')
2034        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRCHIRAL, kind=wx.ITEM_NORMAL,text='Add chiral restraint',
2035            help='Add chiral restraint for selected atoms (4: center atom 1st)')
2036        self.DrawAtomRigidBody.Append(id=wxID_DRAWDEFINERB, kind=wx.ITEM_NORMAL,text='Define rigid body',
2037            help='Define rigid body with selected atoms')
2038        self.PostfillDataMenu()
2039
2040        # Phase / MCSA tab
2041        self.MCSAMenu = wx.MenuBar()
2042        self.PrefillDataMenu(self.MCSAMenu,helpType='MC/SA')
2043        self.MCSAMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2044        self.MCSAEdit = wx.Menu(title='')
2045        self.MCSAMenu.Append(menu=self.MCSAEdit, title='MC/SA')
2046        self.MCSAEdit.Append(id=wxID_ADDMCSAATOM, kind=wx.ITEM_NORMAL,text='Add atom', 
2047            help='Add single atom to MC/SA model')
2048        self.MCSAEdit.Append(id=wxID_ADDMCSARB, kind=wx.ITEM_NORMAL,text='Add rigid body', 
2049            help='Add rigid body to MC/SA model' )
2050        self.MCSAEdit.Append(id=wxID_CLEARMCSARB, kind=wx.ITEM_NORMAL,text='Clear rigid bodies', 
2051            help='Clear all atoms & rigid bodies from MC/SA model' )
2052        self.MCSAEdit.Append(id=wxID_MOVEMCSA, kind=wx.ITEM_NORMAL,text='Move MC/SA solution', 
2053            help='Move MC/SA solution to atom list' )
2054        self.MCSAEdit.Append(id=wxID_MCSACLEARRESULTS, kind=wx.ITEM_NORMAL,text='Clear results', 
2055            help='Clear table of MC/SA results' )
2056        self.PostfillDataMenu()
2057           
2058        # Phase / Texture tab
2059        self.TextureMenu = wx.MenuBar()
2060        self.PrefillDataMenu(self.TextureMenu,helpType='Texture')
2061        self.TextureMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2062        self.TextureEdit = wx.Menu(title='')
2063        self.TextureMenu.Append(menu=self.TextureEdit, title='Texture')
2064        self.TextureEdit.Append(id=wxID_REFINETEXTURE, kind=wx.ITEM_NORMAL,text='Refine texture', 
2065            help='Refine the texture coefficients from sequential results')
2066#        self.TextureEdit.Append(id=wxID_CLEARTEXTURE, kind=wx.ITEM_NORMAL,text='Clear texture',
2067#            help='Clear the texture coefficients' )
2068        self.PostfillDataMenu()
2069           
2070        # Phase / Pawley tab
2071        self.PawleyMenu = wx.MenuBar()
2072        self.PrefillDataMenu(self.PawleyMenu,helpType='Pawley')
2073        self.PawleyMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2074        self.PawleyEdit = wx.Menu(title='')
2075        self.PawleyMenu.Append(menu=self.PawleyEdit,title='Operations')
2076        self.PawleyEdit.Append(id=wxID_PAWLEYLOAD, kind=wx.ITEM_NORMAL,text='Pawley create',
2077            help='Initialize Pawley reflection list')
2078        self.PawleyEdit.Append(id=wxID_PAWLEYESTIMATE, kind=wx.ITEM_NORMAL,text='Pawley estimate',
2079            help='Estimate initial Pawley intensities')
2080        self.PawleyEdit.Append(id=wxID_PAWLEYUPDATE, kind=wx.ITEM_NORMAL,text='Pawley update',
2081            help='Update negative Pawley intensities with -0.5*Fobs and turn off refinemnt')
2082        self.PostfillDataMenu()
2083           
2084        # Phase / Map peaks tab
2085        self.MapPeaksMenu = wx.MenuBar()
2086        self.PrefillDataMenu(self.MapPeaksMenu,helpType='Map peaks')
2087        self.MapPeaksMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2088        self.MapPeaksEdit = wx.Menu(title='')
2089        self.MapPeaksMenu.Append(menu=self.MapPeaksEdit, title='Map peaks')
2090        self.MapPeaksEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks', 
2091            help='Move selected peaks to atom list')
2092        self.MapPeaksEdit.Append(id=wxID_PEAKSVIEWPT, kind=wx.ITEM_NORMAL,text='View point',
2093            help='View point is 1st peak selected')
2094        self.MapPeaksEdit.Append(id=wxID_PEAKSDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2095            help='Compute distance of selected peaks from view point')   
2096        self.MapPeaksEdit.Append(id=wxID_SHOWBONDS, kind=wx.ITEM_NORMAL,text='Hide bonds',
2097            help='Hide or show bonds between peak positions')   
2098        self.MapPeaksEdit.Append(id=wxID_PEAKSDA, kind=wx.ITEM_NORMAL,text='Calc dist/ang', 
2099            help='Calculate distance or angle for selection')
2100        self.MapPeaksEdit.Append(id=wxID_FINDEQVPEAKS, kind=wx.ITEM_NORMAL,text='Equivalent peaks', 
2101            help='Find equivalent peaks')
2102        self.MapPeaksEdit.Append(id=wxID_PEAKSUNIQUE, kind=wx.ITEM_NORMAL,text='Unique peaks', 
2103            help='Select unique set')
2104        self.MapPeaksEdit.Append(id=wxID_PEAKSDELETE, kind=wx.ITEM_NORMAL,text='Delete peaks', 
2105            help='Delete selected peaks')
2106        self.MapPeaksEdit.Append(id=wxID_PEAKSCLEAR, kind=wx.ITEM_NORMAL,text='Clear peaks', 
2107            help='Clear the map peak list')
2108        self.PostfillDataMenu()
2109
2110        # Phase / Rigid bodies tab
2111        self.RigidBodiesMenu = wx.MenuBar()
2112        self.PrefillDataMenu(self.RigidBodiesMenu,helpType='Rigid bodies')
2113        self.RigidBodiesMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2114        self.RigidBodiesEdit = wx.Menu(title='')
2115        self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit')
2116        self.RigidBodiesEdit.Append(id=wxID_ASSIGNATMS2RB, kind=wx.ITEM_NORMAL,text='Assign atoms to rigid body',
2117            help='Select & position rigid body in structure of existing atoms')
2118        self.RigidBodiesEdit.Append(id=wxID_AUTOFINDRESRB, kind=wx.ITEM_NORMAL,text='Auto find residues',
2119            help='Auto find of residue RBs in macromolecule')
2120        self.RigidBodiesEdit.Append(id=wxID_COPYRBPARMS, kind=wx.ITEM_NORMAL,text='Copy rigid body parms',
2121            help='Copy rigid body location & TLS parameters')
2122        self.RigidBodiesEdit.Append(id=wxID_GLOBALTHERM, kind=wx.ITEM_NORMAL,text='Global thermal motion',
2123            help='Global setting of residue thermal motion models')
2124        self.RigidBodiesEdit.Append(id=wxID_GLOBALRESREFINE, kind=wx.ITEM_NORMAL,text='Global residue refine',
2125            help='Global setting of residue RB refinement flags')
2126        self.RigidBodiesEdit.Append(id=wxID_RBREMOVEALL, kind=wx.ITEM_NORMAL,text='Remove all rigid bodies',
2127            help='Remove all rigid body assignment for atoms')
2128        self.PostfillDataMenu()
2129    # end of GSAS-II menu definitions
2130       
2131    def _init_ctrls(self, parent,name=None,size=None,pos=None):
2132        wx.Frame.__init__(
2133            self,parent=parent,
2134            #style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT ,
2135            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX,
2136            size=size,pos=pos,title='GSAS-II data display')
2137        self._init_menus()
2138        if name:
2139            self.SetLabel(name)
2140        self.Show()
2141       
2142    def __init__(self,parent,frame,data=None,name=None, size=None,pos=None):
2143        self.G2frame = frame
2144        self._init_ctrls(parent,name,size,pos)
2145        self.data = data
2146        clientSize = wx.ClientDisplayRect()
2147        Size = self.GetSize()
2148        xPos = clientSize[2]-Size[0]
2149        self.SetPosition(wx.Point(xPos,clientSize[1]+250))
2150        self.AtomGrid = []
2151        self.selectedRow = 0
2152       
2153    def setSizePosLeft(self,Width):
2154        clientSize = wx.ClientDisplayRect()
2155        Width[1] = min(Width[1],clientSize[2]-300)
2156        Width[0] = max(Width[0],300)
2157        self.SetSize(Width)
2158#        self.SetPosition(wx.Point(clientSize[2]-Width[0],clientSize[1]+250))
2159       
2160    def Clear(self):
2161        self.ClearBackground()
2162        self.DestroyChildren()
2163                   
2164
2165################################################################################
2166#####  Notebook Tree Item editor
2167################################################################################                 
2168def UpdateNotebook(G2frame,data):
2169    '''Called when the data tree notebook entry is selected. Allows for
2170    editing of the text in that tree entry
2171    '''
2172    def OnNoteBook(event):
2173        data = G2frame.dataDisplay.GetValue().split('\n')
2174        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Notebook'),data)
2175        if 'nt' not in os.name:
2176            G2frame.dataDisplay.AppendText('\n')
2177                   
2178    if G2frame.dataDisplay:
2179        G2frame.dataDisplay.Destroy()
2180    G2frame.dataFrame.SetLabel('Notebook')
2181    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2182        style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
2183    G2frame.dataDisplay.Bind(wx.EVT_TEXT_ENTER,OnNoteBook)
2184    G2frame.dataDisplay.Bind(wx.EVT_KILL_FOCUS,OnNoteBook)
2185    for line in data:
2186        G2frame.dataDisplay.AppendText(line+"\n")
2187    G2frame.dataDisplay.AppendText('Notebook entry @ '+time.ctime()+"\n")
2188    G2frame.dataFrame.setSizePosLeft([400,250])
2189           
2190################################################################################
2191#####  Controls Tree Item editor
2192################################################################################           
2193def UpdateControls(G2frame,data):
2194    '''Edit overall GSAS-II controls in main Controls data tree entry
2195    '''
2196    #patch
2197    if 'deriv type' not in data:
2198        data = {}
2199        data['deriv type'] = 'analytic Hessian'
2200        data['min dM/M'] = 0.0001
2201        data['shift factor'] = 1.
2202        data['max cyc'] = 3       
2203        data['F**2'] = False
2204    if 'shift factor' not in data:
2205        data['shift factor'] = 1.
2206    if 'max cyc' not in data:
2207        data['max cyc'] = 3
2208    if 'F**2' not in data:
2209        data['F**2'] = False
2210    if 'Author' not in data:
2211        data['Author'] = 'no name'
2212    if 'FreePrm1' not in data:
2213        data['FreePrm1'] = 'Sample humidity (%)'
2214    if 'FreePrm2' not in data:
2215        data['FreePrm2'] = 'Sample voltage (V)'
2216    if 'FreePrm3' not in data:
2217        data['FreePrm3'] = 'Applied load (MN)'
2218    if 'Copy2Next' not in data:
2219        data['Copy2Next'] = False
2220    if 'Reverse Seq' not in data:
2221        data['Reverse Seq'] = False
2222    if 'UsrReject' not in data:
2223        data['UsrReject'] = {'minF/sig':0,'MinExt':0.01,'MaxDF/F':20.,'MaxD':500.,'MinD':0.05}
2224    if 'HatomFix' not in data:
2225        data['HatomFix'] = False
2226   
2227    #end patch
2228
2229    def SeqSizer():
2230       
2231        def OnSelectData(event):
2232            choices = GetPatternTreeDataNames(G2frame,['PWDR','HKLF',])
2233            sel = []
2234            try:
2235                if 'Seq Data' in data:
2236                    for item in data['Seq Data']:
2237                        sel.append(choices.index(item))
2238                    sel = [choices.index(item) for item in data['Seq Data']]
2239            except ValueError:  #data changed somehow - start fresh
2240                sel = []
2241            dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential refinement',
2242                'Select dataset to include',choices)
2243            dlg.SetSelections(sel)
2244            names = []
2245            if dlg.ShowModal() == wx.ID_OK:
2246                for sel in dlg.GetSelections():
2247                    names.append(choices[sel])
2248                data['Seq Data'] = names               
2249                G2frame.EnableSeqRefineMenu()
2250            dlg.Destroy()
2251            wx.CallAfter(UpdateControls,G2frame,data)
2252           
2253        def OnReverse(event):
2254            data['Reverse Seq'] = reverseSel.GetValue()
2255           
2256        def OnCopySel(event):
2257            data['Copy2Next'] = copySel.GetValue() 
2258                   
2259        seqSizer = wx.BoxSizer(wx.VERTICAL)
2260        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
2261        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Sequential Refinement: '),0,WACV)
2262        selSeqData = wx.Button(G2frame.dataDisplay,-1,label=' Select data')
2263        selSeqData.Bind(wx.EVT_BUTTON,OnSelectData)
2264        dataSizer.Add(selSeqData,0,WACV)
2265        SeqData = data.get('Seq Data',[])
2266        if not SeqData:
2267            lbl = ' (no data selected)'
2268        else:
2269            lbl = ' ('+str(len(SeqData))+' dataset(s) selected)'
2270
2271        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=lbl),0,WACV)
2272        seqSizer.Add(dataSizer,0)
2273        if SeqData:
2274            selSizer = wx.BoxSizer(wx.HORIZONTAL)
2275            reverseSel = wx.CheckBox(G2frame.dataDisplay,-1,label=' Reverse order?')
2276            reverseSel.Bind(wx.EVT_CHECKBOX,OnReverse)
2277            reverseSel.SetValue(data['Reverse Seq'])
2278            selSizer.Add(reverseSel,0,WACV)
2279            copySel =  wx.CheckBox(G2frame.dataDisplay,-1,label=' Copy results to next histogram?')
2280            copySel.Bind(wx.EVT_CHECKBOX,OnCopySel)
2281            copySel.SetValue(data['Copy2Next'])
2282            selSizer.Add(copySel,0,WACV)
2283            seqSizer.Add(selSizer,0)
2284        return seqSizer
2285       
2286    def LSSizer():       
2287       
2288        def OnDerivType(event):
2289            data['deriv type'] = derivSel.GetValue()
2290            derivSel.SetValue(data['deriv type'])
2291            wx.CallAfter(UpdateControls,G2frame,data)
2292           
2293        def OnConvergence(event):
2294            try:
2295                value = max(1.e-9,min(1.0,float(Cnvrg.GetValue())))
2296            except ValueError:
2297                value = 0.0001
2298            data['min dM/M'] = value
2299            Cnvrg.SetValue('%.2g'%(value))
2300           
2301        def OnMaxCycles(event):
2302            data['max cyc'] = int(maxCyc.GetValue())
2303            maxCyc.SetValue(str(data['max cyc']))
2304                       
2305        def OnFactor(event):
2306            try:
2307                value = min(max(float(Factr.GetValue()),0.00001),100.)
2308            except ValueError:
2309                value = 1.0
2310            data['shift factor'] = value
2311            Factr.SetValue('%.5f'%(value))
2312           
2313        def OnFsqRef(event):
2314            data['F**2'] = fsqRef.GetValue()
2315           
2316        def OnHatomFix(event):
2317            data['HatomFix'] = Hfix.GetValue()
2318       
2319        def OnUsrRej(event):
2320            Obj = event.GetEventObject()
2321            item,limits = Indx[Obj]
2322            try:
2323                value = min(max(float(Obj.GetValue()),limits[0]),limits[1])
2324            except ValueError:
2325                value = data['UsrReject'][item]
2326            data['UsrReject'][item] = value
2327            Obj.SetValue('%.2f'%(value))
2328
2329        LSSizer = wx.FlexGridSizer(cols=4,vgap=5,hgap=5)
2330        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement derivatives: '),0,WACV)
2331        Choice=['analytic Jacobian','numeric','analytic Hessian']
2332        derivSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['deriv type'],choices=Choice,
2333            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2334        derivSel.SetValue(data['deriv type'])
2335        derivSel.Bind(wx.EVT_COMBOBOX, OnDerivType)
2336           
2337        LSSizer.Add(derivSel,0,WACV)
2338        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min delta-M/M: '),0,WACV)
2339        Cnvrg = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2g'%(data['min dM/M']),style=wx.TE_PROCESS_ENTER)
2340        Cnvrg.Bind(wx.EVT_TEXT_ENTER,OnConvergence)
2341        Cnvrg.Bind(wx.EVT_KILL_FOCUS,OnConvergence)
2342        LSSizer.Add(Cnvrg,0,WACV)
2343        Indx = {}
2344        if 'Hessian' in data['deriv type']:
2345            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max cycles: '),0,WACV)
2346            Choice = ['0','1','2','3','5','10','15','20']
2347            maxCyc = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['max cyc']),choices=Choice,
2348                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2349            maxCyc.SetValue(str(data['max cyc']))
2350            maxCyc.Bind(wx.EVT_COMBOBOX, OnMaxCycles)
2351            LSSizer.Add(maxCyc,0,WACV)
2352        else:
2353            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial shift factor: '),0,WACV)
2354            Factr = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.5f'%(data['shift factor']),style=wx.TE_PROCESS_ENTER)
2355            Factr.Bind(wx.EVT_TEXT_ENTER,OnFactor)
2356            Factr.Bind(wx.EVT_KILL_FOCUS,OnFactor)
2357            LSSizer.Add(Factr,0,WACV)
2358        if G2frame.Sngl:
2359            userReject = data['UsrReject']
2360            usrRej = {'minF/sig':[' Min obs/sig (0-5): ',[0,5], ],'MinExt':[' Min extinct. (0-.9): ',[0,.9],],
2361                'MaxDF/F':[' Max delt-F/sig (3-1000): ',[3.,1000.],],'MaxD':[' Max d-spacing (3-500): ',[3,500],],
2362                'MinD':[' Min d-spacing (0.1-2.0): ',[0.1,2.0],]}
2363
2364            fsqRef = wx.CheckBox(G2frame.dataDisplay,-1,label='Refine HKLF as F^2? ')
2365            fsqRef.SetValue(data['F**2'])
2366            fsqRef.Bind(wx.EVT_CHECKBOX,OnFsqRef)
2367            LSSizer.Add(fsqRef,0,WACV)
2368            LSSizer.Add((1,0),)
2369            for item in usrRej:
2370                LSSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=usrRej[item][0]),0,WACV)
2371                usrrej = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(userReject[item]),style=wx.TE_PROCESS_ENTER)
2372                Indx[usrrej] = [item,usrRej[item][1]]
2373                usrrej.Bind(wx.EVT_TEXT_ENTER,OnUsrRej)
2374                usrrej.Bind(wx.EVT_KILL_FOCUS,OnUsrRej)
2375                LSSizer.Add(usrrej,0,WACV)
2376#        Hfix = wx.CheckBox(G2frame.dataDisplay,-1,label='Regularize H atoms? ')
2377#        Hfix.SetValue(data['HatomFix'])
2378#        Hfix.Bind(wx.EVT_CHECKBOX,OnHatomFix)
2379#        LSSizer.Add(Hfix,0,WACV)   #for now
2380        return LSSizer
2381       
2382    def AuthSizer():
2383
2384        def OnAuthor(event):
2385            data['Author'] = auth.GetValue()
2386
2387        Author = data['Author']
2388        authSizer = wx.BoxSizer(wx.HORIZONTAL)
2389        authSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' CIF Author (last, first):'),0,WACV)
2390        auth = wx.TextCtrl(G2frame.dataDisplay,-1,value=Author,style=wx.TE_PROCESS_ENTER)
2391        auth.Bind(wx.EVT_TEXT_ENTER,OnAuthor)
2392        auth.Bind(wx.EVT_KILL_FOCUS,OnAuthor)
2393        authSizer.Add(auth,0,WACV)
2394        return authSizer
2395       
2396       
2397    if G2frame.dataDisplay:
2398        G2frame.dataDisplay.Destroy()
2399    if not G2frame.dataFrame.GetStatusBar():
2400        Status = G2frame.dataFrame.CreateStatusBar()
2401        Status.SetStatusText('')
2402    G2frame.dataFrame.SetLabel('Controls')
2403    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2404    SetDataMenuBar(G2frame,G2frame.dataFrame.ControlsMenu)
2405    mainSizer = wx.BoxSizer(wx.VERTICAL)
2406    mainSizer.Add((5,5),0)
2407    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement Controls:'),0,WACV)   
2408    mainSizer.Add(LSSizer())
2409    mainSizer.Add((5,5),0)
2410    mainSizer.Add(SeqSizer())
2411    mainSizer.Add((5,5),0)
2412    mainSizer.Add(AuthSizer())
2413    mainSizer.Add((5,5),0)
2414       
2415    mainSizer.Layout()   
2416    G2frame.dataDisplay.SetSizer(mainSizer)
2417    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
2418    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
2419     
2420################################################################################
2421#####  Comments
2422################################################################################           
2423       
2424def UpdateComments(G2frame,data):                   
2425
2426    if G2frame.dataDisplay:
2427        G2frame.dataDisplay.Destroy()
2428    G2frame.dataFrame.SetLabel('Comments')
2429    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2430        style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP)
2431    for line in data:
2432        G2frame.dataDisplay.AppendText(line+'\n')
2433    G2frame.dataFrame.setSizePosLeft([400,250])
2434           
2435################################################################################
2436#####  Display of Sequential Results
2437################################################################################           
2438       
2439def UpdateSeqResults(G2frame,data,prevSize=None):
2440    """
2441    Called when the Sequential Results data tree entry is selected
2442    to show results from a sequential refinement.
2443   
2444    :param wx.Frame G2frame: main GSAS-II data tree windows
2445
2446    :param dict data: a dictionary containing the following items: 
2447
2448            * 'histNames' - list of histogram names in order as processed by Sequential Refinement
2449            * 'varyList' - list of variables - identical over all refinements in sequence
2450              note that this is the original list of variables, prior to processing
2451              constraints.
2452            * 'variableLabels' -- a dict of labels to be applied to each parameter
2453              (this is created as an empty dict if not present in data).
2454            * keyed by histName - dictionaries for all data sets processed, which contains:
2455
2456              * 'variables'- result[0] from leastsq call
2457              * 'varyList' - list of variables passed to leastsq call (not same as above)
2458              * 'sig' - esds for variables
2459              * 'covMatrix' - covariance matrix from individual refinement
2460              * 'title' - histogram name; same as dict item name
2461              * 'newAtomDict' - new atom parameters after shifts applied
2462              * 'newCellDict' - refined cell parameters after shifts to A0-A5 from Dij terms applied'
2463    """
2464
2465    def GetSampleParms():
2466        '''Make a dictionary of the sample parameters are not the same over the
2467        refinement series.
2468        '''
2469        if 'IMG' in histNames[0]:
2470            sampleParmDict = {'Sample load':[],}
2471        else:
2472            sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[],
2473                'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[],
2474                'Chi':[],'Phi':[],'Azimuth':[],}
2475        Controls = G2frame.PatternTree.GetItemPyData(
2476            GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2477        sampleParm = {}
2478        for name in histNames:
2479            if 'IMG' in name:
2480                for item in sampleParmDict:
2481                    sampleParmDict[item].append(data[name]['parmDict'].get(item,0))
2482            else:
2483                Id = GetPatternTreeItemId(G2frame,G2frame.root,name)
2484                sampleData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2485                for item in sampleParmDict:
2486                    sampleParmDict[item].append(sampleData.get(item,0))
2487        for item in sampleParmDict:
2488            frstValue = sampleParmDict[item][0]
2489            if np.any(np.array(sampleParmDict[item])-frstValue):
2490                if item.startswith('FreePrm'):
2491                    sampleParm[Controls[item]] = sampleParmDict[item]
2492                else:
2493                    sampleParm[item] = sampleParmDict[item]
2494        return sampleParm
2495
2496    def GetColumnInfo(col):
2497        '''returns column label, lists of values and errors (or None) for each column in the table
2498        for plotting. The column label is reformatted from Unicode to MatPlotLib encoding
2499        '''
2500        colName = G2frame.SeqTable.GetColLabelValue(col)
2501        plotName = variableLabels.get(colName,colName)
2502        plotName = plotSpCharFix(plotName)
2503        return plotName,colList[col],colSigs[col]
2504           
2505    def PlotSelect(event):
2506        'Plots a row (covariance) or column on double-click'
2507        cols = G2frame.dataDisplay.GetSelectedCols()
2508        rows = G2frame.dataDisplay.GetSelectedRows()
2509        if cols:
2510            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2511        elif rows:
2512            name = histNames[rows[0]]       #only does 1st one selected
2513            G2plt.PlotCovariance(G2frame,data[name])
2514        else:
2515            G2frame.ErrorDialog(
2516                'Select row or columns',
2517                'Nothing selected in table. Click on column or row label(s) to plot. N.B. Grid selection can be a bit funky.'
2518                )
2519           
2520    def OnPlotSelSeq(event):
2521        'plot the selected columns or row from menu command'
2522        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2523        rows = G2frame.dataDisplay.GetSelectedRows()
2524        if cols:
2525            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2526        elif rows:
2527            name = histNames[rows[0]]       #only does 1st one selected
2528            G2plt.PlotCovariance(G2frame,data[name])
2529        else:
2530            G2frame.ErrorDialog(
2531                'Select columns',
2532                'No columns or rows selected in table. Click on row or column labels to select fields for plotting.'
2533                )
2534               
2535    def OnAveSelSeq(event):
2536        'average the selected columns from menu command'
2537        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2538        if cols:
2539            for col in cols:
2540                ave = np.mean(GetColumnInfo(col)[1])
2541                sig = np.std(GetColumnInfo(col)[1])
2542                print ' Average for '+G2frame.SeqTable.GetColLabelValue(col)+': '+'%.6g'%(ave)+' +/- '+'%.6g'%(sig)
2543        else:
2544            G2frame.ErrorDialog(
2545                'Select columns',
2546                'No columns selected in table. Click on column labels to select fields for averaging.'
2547                )
2548               
2549    def OnRenameSelSeq(event):
2550        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2551        colNames = [G2frame.SeqTable.GetColLabelValue(c) for c in cols]
2552        newNames = colNames[:]
2553        for i,name in enumerate(colNames):
2554            if name in variableLabels:
2555                newNames[i] = variableLabels[name]
2556        if not cols:
2557            G2frame.ErrorDialog('Select columns',
2558                'No columns selected in table. Click on column labels to select fields for rename.')
2559            return
2560        dlg = G2G.MultiStringDialog(G2frame.dataDisplay,'Set column names',colNames,newNames)
2561        if dlg.Show():
2562            newNames = dlg.GetValues()           
2563            variableLabels.update(dict(zip(colNames,newNames)))
2564        data['variableLabels'] = variableLabels
2565        dlg.Destroy()
2566        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2567        G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2568           
2569    def OnReOrgSelSeq(event):
2570        'Reorder the columns'
2571        G2G.GetItemOrder(G2frame,VaryListChanges,vallookup,posdict)   
2572        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2573
2574    def OnSaveSelSeqCSV(event):
2575        'export the selected columns to a .csv file from menu command'
2576        OnSaveSelSeq(event,csv=True)
2577       
2578    def OnSaveSeqCSV(event):
2579        'export all columns to a .csv file from menu command'
2580        OnSaveSelSeq(event,csv=True,allcols=True)
2581       
2582    def OnSaveSelSeq(event,csv=False,allcols=False):
2583        'export the selected columns to a .txt or .csv file from menu command'
2584        def WriteCSV():
2585            def WriteList(headerItems):
2586                line = ''
2587                for lbl in headerItems:
2588                    if line: line += ','
2589                    line += '"'+lbl+'"'
2590                return line
2591            head = ['name']
2592            for col in cols:
2593                item = G2frame.SeqTable.GetColLabelValue(col)
2594                # get rid of labels that have Unicode characters
2595                if not all([ord(c) < 128 and ord(c) != 0 for c in item]): item = '?'
2596                if col in havesig:
2597                    head += [item,'esd-'+item]
2598                else:
2599                    head += [item]
2600            SeqFile.write(WriteList(head)+'\n')
2601            for row,name in enumerate(saveNames):
2602                line = '"'+saveNames[row]+'"'
2603                for col in cols:
2604                    if col in havesig:
2605                        line += ','+str(saveData[col][row])+','+str(saveSigs[col][row])
2606                    else:
2607                        line += ','+str(saveData[col][row])
2608                SeqFile.write(line+'\n')
2609        def WriteSeq():
2610            lenName = len(saveNames[0])
2611            line = %s  '%('name'.center(lenName))
2612            for col in cols:
2613                item = G2frame.SeqTable.GetColLabelValue(col)
2614                if col in havesig:
2615                    line += ' %12s %12s '%(item.center(12),'esd'.center(12))
2616                else:
2617                    line += ' %12s '%(item.center(12))
2618            SeqFile.write(line+'\n')
2619            for row,name in enumerate(saveNames):
2620                line = " '%s' "%(saveNames[row])
2621                for col in cols:
2622                    if col in havesig:
2623                        line += ' %12.6f %12.6f '%(saveData[col][row],saveSigs[col][row])
2624                    else:
2625                        line += ' %12.6f '%saveData[col][row]
2626                SeqFile.write(line+'\n')
2627
2628        # start of OnSaveSelSeq code
2629        if allcols:
2630            cols = range(G2frame.SeqTable.GetNumberCols())
2631        else:
2632            cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2633        nrows = G2frame.SeqTable.GetNumberRows()
2634        if not cols:
2635            G2frame.ErrorDialog('Select columns',
2636                             'No columns selected in table. Click on column labels to select fields for output.')
2637            return
2638        saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(nrows)]
2639        saveData = {}
2640        saveSigs = {}
2641        havesig = []
2642        for col in cols:
2643            name,vals,sigs = GetColumnInfo(col)
2644            saveData[col] = vals
2645            if sigs:
2646                havesig.append(col)
2647                saveSigs[col] = sigs
2648        if csv:
2649            wild = 'CSV output file (*.csv)|*.csv'
2650        else:
2651            wild = 'Text output file (*.txt)|*.txt'
2652        pth = G2G.GetExportPath(G2frame)
2653        dlg = wx.FileDialog(
2654            G2frame,
2655            'Choose text output file for your selection', pth, '', 
2656            wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
2657        try:
2658            if dlg.ShowModal() == wx.ID_OK:
2659                SeqTextFile = dlg.GetPath()
2660                SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) 
2661                SeqFile = open(SeqTextFile,'w')
2662                if csv:
2663                    WriteCSV()
2664                else:
2665                    WriteSeq()
2666                SeqFile.close()
2667        finally:
2668            dlg.Destroy()
2669               
2670    def striphist(var,insChar=''):
2671        'strip a histogram number from a var name'
2672        sv = var.split(':')
2673        if len(sv) <= 1: return var
2674        if sv[1]:
2675            sv[1] = insChar
2676        return ':'.join(sv)
2677       
2678    def plotSpCharFix(lbl):
2679        'Change selected unicode characters to their matplotlib equivalent'
2680        for u,p in [
2681            (u'\u03B1',r'$\alpha$'),
2682            (u'\u03B2',r'$\beta$'),
2683            (u'\u03B3',r'$\gamma$'),
2684            (u'\u0394\u03C7',r'$\Delta\chi$'),
2685            ]:
2686            lbl = lbl.replace(u,p)
2687        return lbl
2688   
2689    def SelectXaxis():
2690        'returns a selected column number (or None) as the X-axis selection'
2691        ncols = G2frame.SeqTable.GetNumberCols()
2692        colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)]
2693        dlg = G2G.G2SingleChoiceDialog(
2694            G2frame.dataDisplay,
2695            'Select x-axis parameter for plot or Cancel for sequence number',
2696            'Select X-axis',
2697            colNames)
2698        try:
2699            if dlg.ShowModal() == wx.ID_OK:
2700                col = dlg.GetSelection()
2701            else:
2702                col = None
2703        finally:
2704            dlg.Destroy()
2705        return col
2706   
2707    def EnablePseudoVarMenus():
2708        'Enables or disables the PseudoVar menu items that require existing defs'
2709        if Controls['SeqPseudoVars']:
2710            val = True
2711        else:
2712            val = False
2713        G2frame.dataFrame.SequentialPvars.Enable(wxDELSEQVAR,val)
2714        G2frame.dataFrame.SequentialPvars.Enable(wxEDITSEQVAR,val)
2715
2716    def DelPseudoVar(event):
2717        'Ask the user to select a pseudo var expression to delete'
2718        choices = Controls['SeqPseudoVars'].keys()
2719        selected = G2G.ItemSelector(
2720            choices,G2frame.dataFrame,
2721            multiple=True,
2722            title='Select expressions to remove',
2723            header='Delete expression')
2724        if selected is None: return
2725        for item in selected:
2726            del Controls['SeqPseudoVars'][choices[item]]
2727        if selected:
2728            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2729
2730    def EditPseudoVar(event):
2731        'Edit an existing pseudo var expression'
2732        choices = Controls['SeqPseudoVars'].keys()
2733        if len(choices) == 1:
2734            selected = 0
2735        else:
2736            selected = G2G.ItemSelector(
2737                choices,G2frame.dataFrame,
2738                multiple=False,
2739                title='Select an expression to edit',
2740                header='Edit expression')
2741        if selected is not None:
2742            dlg = G2exG.ExpressionDialog(
2743                G2frame.dataDisplay,PSvarDict,
2744                Controls['SeqPseudoVars'][choices[selected]],
2745                header="Edit the PseudoVar expression",
2746                VarLabel="PseudoVar #"+str(selected+1),
2747                fit=False)
2748            newobj = dlg.Show(True)
2749            if newobj:
2750                calcobj = G2obj.ExpressionCalcObj(newobj)
2751                del Controls['SeqPseudoVars'][choices[selected]]
2752                Controls['SeqPseudoVars'][calcobj.eObj.expression] = newobj
2753                UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2754       
2755    def AddNewPseudoVar(event):
2756        'Create a new pseudo var expression'
2757        dlg = G2exG.ExpressionDialog(
2758            G2frame.dataDisplay,PSvarDict,
2759            header='Enter an expression for a PseudoVar here',
2760            VarLabel = "New PseudoVar",
2761            fit=False)
2762        obj = dlg.Show(True)
2763        dlg.Destroy()
2764        if obj:
2765            calcobj = G2obj.ExpressionCalcObj(obj)
2766            Controls['SeqPseudoVars'][calcobj.eObj.expression] = obj
2767            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2768           
2769    def AddNewDistPseudoVar(event):
2770        obj = None
2771        dlg = G2exG.BondDialog(
2772            G2frame.dataDisplay,Phases,PSvarDict,
2773            header='Select a Bond here',
2774            VarLabel = "New Bond")
2775        if dlg.ShowModal() == wx.ID_OK:
2776            pName,Oatom,Tatom = dlg.GetSelection()
2777            if Tatom:
2778                Phase = Phases[pName]
2779                General = Phase['General']
2780                cx,ct = General['AtomPtrs'][:2]
2781                pId = Phase['pId']
2782                SGData = General['SGData']
2783                sB = Tatom.find('(')+1
2784                symNo = 0
2785                if sB:
2786                    sF = Tatom.find(')')
2787                    symNo = int(Tatom[sB:sF])
2788                cellNo = [0,0,0]
2789                cB = Tatom.find('[')
2790                if cB>0:
2791                    cF = Tatom.find(']')+1
2792                    cellNo = eval(Tatom[cB:cF])
2793                Atoms = Phase['Atoms']
2794                aNames = [atom[ct-1] for atom in Atoms]
2795                oId = aNames.index(Oatom)
2796                tId = aNames.index(Tatom.split(' +')[0])
2797                # create an expression object
2798                obj = G2obj.ExpressionObj()
2799                obj.expression = 'Dist(%s,\n%s)'%(Oatom,Tatom.split(' d=')[0].replace(' ',''))
2800                obj.distance_dict = {'pId':pId,'SGData':SGData,'symNo':symNo,'cellNo':cellNo}
2801                obj.distance_atoms = [oId,tId]
2802        else: 
2803            dlg.Destroy()
2804            return
2805        dlg.Destroy()
2806        if obj:
2807            Controls['SeqPseudoVars'][obj.expression] = obj
2808            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2809
2810    def AddNewAnglePseudoVar(event):
2811        obj = None
2812        dlg = G2exG.AngleDialog(
2813            G2frame.dataDisplay,Phases,PSvarDict,
2814            header='Enter an Angle here',
2815            VarLabel = "New Angle")
2816        if dlg.ShowModal() == wx.ID_OK:
2817            pName,Oatom,Tatoms = dlg.GetSelection()
2818            if Tatoms:
2819                Phase = Phases[pName]
2820                General = Phase['General']
2821                cx,ct = General['AtomPtrs'][:2]
2822                pId = Phase['pId']
2823                SGData = General['SGData']
2824                Atoms = Phase['Atoms']
2825                aNames = [atom[ct-1] for atom in Atoms]
2826                tIds = []
2827                symNos = []
2828                cellNos = []
2829                oId = aNames.index(Oatom)
2830                Tatoms = Tatoms.split(';')
2831                for Tatom in Tatoms:
2832                    sB = Tatom.find('(')+1
2833                    symNo = 0
2834                    if sB:
2835                        sF = Tatom.find(')')
2836                        symNo = int(Tatom[sB:sF])
2837                    symNos.append(symNo)
2838                    cellNo = [0,0,0]
2839                    cB = Tatom.find('[')
2840                    if cB>0:
2841                        cF = Tatom.find(']')+1
2842                        cellNo = eval(Tatom[cB:cF])
2843                    cellNos.append(cellNo)
2844                    tIds.append(aNames.index(Tatom.split('+')[0]))
2845                # create an expression object
2846                obj = G2obj.ExpressionObj()
2847                obj.expression = 'Angle(%s,%s,\n%s)'%(Tatoms[0],Oatom,Tatoms[1])
2848                obj.angle_dict = {'pId':pId,'SGData':SGData,'symNo':symNos,'cellNo':cellNos}
2849                obj.angle_atoms = [oId,tIds]
2850        else: 
2851            dlg.Destroy()
2852            return
2853        dlg.Destroy()
2854        if obj:
2855            Controls['SeqPseudoVars'][obj.expression] = obj
2856            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2857           
2858    def UpdateParmDict(parmDict):
2859        '''generate the atom positions and the direct & reciprocal cell values,
2860        because they might be needed to evaluate the pseudovar
2861        '''
2862        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2863                         ['A'+str(i) for i in range(6)])
2864                     )
2865        delList = []
2866        phaselist = []
2867        for item in parmDict: 
2868            if ':' not in item: continue
2869            key = item.split(':')
2870            if len(key) < 3: continue
2871            # remove the dA[xyz] terms, they would only bring confusion
2872            if key[2].startswith('dA'):
2873                delList.append(item)
2874            # compute and update the corrected reciprocal cell terms using the Dij values
2875            elif key[2] in Ddict:
2876                if key[0] not in phaselist: phaselist.append(key[0])
2877                akey = key[0]+'::'+Ddict[key[2]]
2878                parmDict[akey] -= parmDict[item]
2879                delList.append(item)
2880        for item in delList:
2881            del parmDict[item]               
2882        for i in phaselist:
2883            pId = int(i)
2884            # apply cell symmetry
2885            A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId])
2886            # convert to direct cell & add the unique terms to the dictionary
2887            for i,val in enumerate(G2lat.A2cell(A)):
2888                if i in uniqCellIndx[pId]:
2889                    lbl = str(pId)+'::'+cellUlbl[i]
2890                    parmDict[lbl] = val
2891            lbl = str(pId)+'::'+'vol'
2892            parmDict[lbl] = G2lat.calc_V(A)
2893        return parmDict
2894
2895    def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD):
2896        '''Evaluate an expression derivative with respect to a
2897        GSAS-II variable name.
2898
2899        Note this likely could be faster if the loop over calcobjs were done
2900        inside after the Dict was created.
2901        '''
2902        step = ESD/10
2903        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2904                         ['A'+str(i) for i in range(6)])
2905                     )
2906        results = []
2907        phaselist = []
2908        VparmDict = sampleDict.copy()
2909        for incr in step,-step:
2910            VparmDict.update(parmDict.copy())           
2911            # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]'
2912            # values are not zeroed: fix that!
2913            VparmDict.update({item:0.0 for item in parmDict if 'dA' in item})
2914            VparmDict[var] += incr
2915            G2mv.Dict2Map(VparmDict,[]) # apply constraints
2916            # generate the atom positions and the direct & reciprocal cell values now, because they might
2917            # needed to evaluate the pseudovar
2918            for item in VparmDict:
2919                if item in sampleDict:
2920                    continue 
2921                if ':' not in item: continue
2922                key = item.split(':')
2923                if len(key) < 3: continue
2924                # apply any new shifts to atom positions
2925                if key[2].startswith('dA'):
2926                    VparmDict[''.join(item.split('d'))] += VparmDict[item]
2927                    VparmDict[item] = 0.0
2928                # compute and update the corrected reciprocal cell terms using the Dij values
2929                if key[2] in Ddict:
2930                    if key[0] not in phaselist: phaselist.append(key[0])
2931                    akey = key[0]+'::'+Ddict[key[2]]
2932                    VparmDict[akey] -= VparmDict[item]
2933            for i in phaselist:
2934                pId = int(i)
2935                # apply cell symmetry
2936                A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId])
2937                # convert to direct cell & add the unique terms to the dictionary
2938                for i,val in enumerate(G2lat.A2cell(A)):
2939                    if i in uniqCellIndx[pId]:
2940                        lbl = str(pId)+'::'+cellUlbl[i]
2941                        VparmDict[lbl] = val
2942                lbl = str(pId)+'::'+'vol'
2943                VparmDict[lbl] = G2lat.calc_V(A)
2944            # dict should be fully updated, use it & calculate
2945            calcobj.SetupCalc(VparmDict)
2946            results.append(calcobj.EvalExpression())
2947        return (results[0] - results[1]) / (2.*step)
2948       
2949    def EnableParFitEqMenus():
2950        'Enables or disables the Parametric Fit menu items that require existing defs'
2951        if Controls['SeqParFitEqList']:
2952            val = True
2953        else:
2954            val = False
2955        G2frame.dataFrame.SequentialPfit.Enable(wxDELPARFIT,val)
2956        G2frame.dataFrame.SequentialPfit.Enable(wxEDITPARFIT,val)
2957        G2frame.dataFrame.SequentialPfit.Enable(wxDOPARFIT,val)
2958
2959    def ParEqEval(Values,calcObjList,varyList):
2960        '''Evaluate the parametric expression(s)
2961        :param list Values: a list of values for each variable parameter
2962        :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj`
2963          expression objects to evaluate
2964        :param list varyList: a list of variable names for each value in Values
2965        '''
2966        result = []
2967        for calcobj in calcObjList:
2968            calcobj.UpdateVars(varyList,Values)
2969            result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig)
2970        return result
2971
2972    def DoParEqFit(event,eqObj=None):
2973        'Parametric fit minimizer'
2974        varyValueDict = {} # dict of variables and their initial values
2975        calcObjList = [] # expression objects, ready to go for each data point
2976        if eqObj is not None:
2977            eqObjList = [eqObj,]
2978        else:
2979            eqObjList = Controls['SeqParFitEqList']
2980        UseFlags = G2frame.SeqTable.GetColValues(0)         
2981        for obj in eqObjList:
2982            expr = obj.expression
2983            # assemble refined vars for this equation
2984            varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()})
2985            # lookup dependent var position
2986            depVar = obj.GetDepVar()
2987            if depVar in colLabels:
2988                indx = colLabels.index(depVar)
2989            else:
2990                raise Exception('Dependent variable '+depVar+' not found')
2991            # assemble a list of the independent variables
2992            indepVars = obj.GetIndependentVars()
2993            # loop over each datapoint
2994            for j,row in enumerate(zip(*colList)):
2995                if not UseFlags[j]: continue
2996                # assemble equations to fit
2997                calcobj = G2obj.ExpressionCalcObj(obj)
2998                # prepare a dict of needed independent vars for this expression
2999                indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
3000                calcobj.SetupCalc(indepVarDict)               
3001                # values and sigs for current value of dependent var
3002                calcobj.depVal = row[indx]
3003                calcobj.depSig = colSigs[indx][j]
3004                calcObjList.append(calcobj)
3005        # varied parameters
3006        varyList = varyValueDict.keys()
3007        values = varyValues = [varyValueDict[key] for key in varyList]
3008        if not varyList:
3009            print 'no variables to refine!'
3010            return
3011        try:
3012            result = so.leastsq(ParEqEval,varyValues,full_output=True,   #ftol=Ftol,
3013                                args=(calcObjList,varyList)
3014                                )
3015            values = result[0]
3016            covar = result[1]
3017            if covar is None:
3018                raise Exception
3019            esdDict = {}
3020            for i,avar in enumerate(varyList):
3021                esdDict[avar] = np.sqrt(covar[i,i])
3022        except:
3023            print('====> Fit failed')
3024            return
3025        print('==== Fit Results ====')
3026        for obj in eqObjList:
3027            obj.UpdateVariedVars(varyList,values)
3028            ind = '      '
3029            print('  '+obj.GetDepVar()+' = '+obj.expression)
3030            for var in obj.assgnVars:
3031                print(ind+var+' = '+obj.assgnVars[var])
3032            for var in obj.freeVars:
3033                avar = "::"+obj.freeVars[var][0]
3034                val = obj.freeVars[var][1]
3035                if obj.freeVars[var][2]:
3036                    print(ind+var+' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar]))
3037                else:
3038                    print(ind+var+' = '+avar + " =" + G2mth.ValEsd(val,0))
3039        # create a plot for each parametric variable
3040        for fitnum,obj in enumerate(eqObjList):
3041            calcobj = G2obj.ExpressionCalcObj(obj)
3042            # lookup dependent var position
3043            indx = colLabels.index(obj.GetDepVar())
3044            # assemble a list of the independent variables
3045            indepVars = obj.GetIndependentVars()           
3046            # loop over each datapoint
3047            fitvals = []
3048            for j,row in enumerate(zip(*colList)):
3049                calcobj.SetupCalc(
3050                    {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
3051                    )
3052                fitvals.append(calcobj.EvalExpression())
3053            G2plt.PlotSelectedSequence(
3054                G2frame,[indx],GetColumnInfo,SelectXaxis,
3055                fitnum,fitvals)
3056
3057    def SingleParEqFit(eqObj):
3058        DoParEqFit(None,eqObj)
3059
3060    def DelParFitEq(event):
3061        'Ask the user to select function to delete'
3062        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
3063        selected = G2G.ItemSelector(
3064            txtlst,G2frame.dataFrame,
3065            multiple=True,
3066            title='Select a parametric equation(s) to remove',
3067            header='Delete equation')
3068        if selected is None: return
3069        Controls['SeqParFitEqList'] = [obj for i,obj in enumerate(Controls['SeqParFitEqList']) if i not in selected]
3070        EnableParFitEqMenus()
3071        if Controls['SeqParFitEqList']: DoParEqFit(event)
3072       
3073    def EditParFitEq(event):
3074        'Edit an existing parametric equation'
3075        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
3076        if len(txtlst) == 1:
3077            selected = 0
3078        else:
3079            selected = G2G.ItemSelector(
3080                txtlst,G2frame.dataFrame,
3081                multiple=False,
3082                title='Select a parametric equation to edit',
3083                header='Edit equation')
3084        if selected is not None:
3085            dlg = G2exG.ExpressionDialog(
3086                G2frame.dataDisplay,indepVarDict,
3087                Controls['SeqParFitEqList'][selected],
3088                depVarDict=depVarDict,
3089                header="Edit the formula for this minimization function",
3090                ExtraButton=['Fit',SingleParEqFit])
3091            newobj = dlg.Show(True)
3092            if newobj:
3093                calcobj = G2obj.ExpressionCalcObj(newobj)
3094                Controls['SeqParFitEqList'][selected] = newobj
3095                EnableParFitEqMenus()
3096            if Controls['SeqParFitEqList']: DoParEqFit(event)
3097
3098    def AddNewParFitEq(event):
3099        'Create a new parametric equation to be fit to sequential results'
3100
3101        # compile the variable names used in previous freevars to avoid accidental name collisions
3102        usedvarlist = []
3103        for obj in Controls['SeqParFitEqList']:
3104            for var in obj.freeVars:
3105                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3106
3107        dlg = G2exG.ExpressionDialog(
3108            G2frame.dataDisplay,indepVarDict,
3109            depVarDict=depVarDict,
3110            header='Define an equation to minimize in the parametric fit',
3111            ExtraButton=['Fit',SingleParEqFit],
3112            usedVars=usedvarlist)
3113        obj = dlg.Show(True)
3114        dlg.Destroy()
3115        if obj:
3116            Controls['SeqParFitEqList'].append(obj)
3117            EnableParFitEqMenus()
3118            if Controls['SeqParFitEqList']: DoParEqFit(event)
3119               
3120    def CopyParFitEq(event):
3121        'Copy an existing parametric equation to be fit to sequential results'
3122        # compile the variable names used in previous freevars to avoid accidental name collisions
3123        usedvarlist = []
3124        for obj in Controls['SeqParFitEqList']:
3125            for var in obj.freeVars:
3126                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3127        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
3128        if len(txtlst) == 1:
3129            selected = 0
3130        else:
3131            selected = G2G.ItemSelector(
3132                txtlst,G2frame.dataFrame,
3133                multiple=False,
3134                title='Select a parametric equation to copy',
3135                header='Copy equation')
3136        if selected is not None:
3137            newEqn = copy.deepcopy(Controls['SeqParFitEqList'][selected])
3138            for var in newEqn.freeVars:
3139                newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist)
3140            dlg = G2exG.ExpressionDialog(
3141                G2frame.dataDisplay,indepVarDict,
3142                newEqn,
3143                depVarDict=depVarDict,
3144                header="Edit the formula for this minimization function",
3145                ExtraButton=['Fit',SingleParEqFit])
3146            newobj = dlg.Show(True)
3147            if newobj:
3148                calcobj = G2obj.ExpressionCalcObj(newobj)
3149                Controls['SeqParFitEqList'].append(newobj)
3150                EnableParFitEqMenus()
3151            if Controls['SeqParFitEqList']: DoParEqFit(event)
3152                                           
3153    def GridSetToolTip(row,col):
3154        '''Routine to show standard uncertainties for each element in table
3155        as a tooltip
3156        '''
3157        if colSigs[col]:
3158            return u'\u03c3 = '+str(colSigs[col][row])
3159        return ''
3160       
3161    def GridColLblToolTip(col):
3162        '''Define a tooltip for a column. This will be the user-entered value
3163        (from data['variableLabels']) or the default name
3164        '''
3165        if col < 0 or col > len(colLabels):
3166            print 'Illegal column #',col
3167            return
3168        var = colLabels[col]
3169        return variableLabels.get(var,G2obj.fmtVarDescr(var))
3170       
3171    def SetLabelString(event):
3172        '''Define or edit the label for a column in the table, to be used
3173        as a tooltip and for plotting
3174        '''
3175        col = event.GetCol()
3176        if col < 0 or col > len(colLabels):
3177            return
3178        var = colLabels[col]
3179        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
3180        dlg = G2G.SingleStringDialog(G2frame.dataFrame,'Set variable label',
3181                                 'Set a new name for variable '+var,lbl,size=(400,-1))
3182        if dlg.Show():
3183            variableLabels[var] = dlg.GetValue()
3184        dlg.Destroy()
3185       
3186    #def GridRowLblToolTip(row): return 'Row ='+str(row)
3187   
3188    # lookup table for unique cell parameters by symmetry
3189    cellGUIlist = [
3190        [['m3','m3m'],(0,)],
3191        [['3R','3mR'],(0,3)],
3192        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
3193        [['mmm'],(0,1,2)],
3194        [['2/m'+'a'],(0,1,2,3)],
3195        [['2/m'+'b'],(0,1,2,4)],
3196        [['2/m'+'c'],(0,1,2,5)],
3197        [['-1'],(0,1,2,3,4,5)],
3198        ]
3199    # cell labels
3200    cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
3201
3202    #======================================================================
3203    # start processing sequential results here (UpdateSeqResults)
3204    #======================================================================
3205    if not data:
3206        print 'No sequential refinement results'
3207        return
3208    variableLabels = data.get('variableLabels',{})
3209    data['variableLabels'] = variableLabels
3210    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
3211    Controls = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
3212    # create a place to store Pseudo Vars & Parametric Fit functions, if not present
3213    if 'SeqPseudoVars' not in Controls: Controls['SeqPseudoVars'] = {}
3214    if 'SeqParFitEqList' not in Controls: Controls['SeqParFitEqList'] = []
3215    histNames = data['histNames']
3216    if G2frame.dataDisplay:
3217        G2frame.dataDisplay.Destroy()
3218    if not G2frame.dataFrame.GetStatusBar():
3219        Status = G2frame.dataFrame.CreateStatusBar()
3220        Status.SetStatusText("Select column to export; Double click on column to plot data; on row for Covariance")
3221    sampleParms = GetSampleParms()
3222
3223    # make dict of varied atom coords keyed by absolute position
3224    newAtomDict = data[histNames[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
3225    # Possible error: the next might need to be data[histNames[0]]['varyList']
3226    # error will arise if there constraints on coordinates?
3227    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in data['varyList']}
3228   
3229    # make dict of varied cell parameters equivalents
3230    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
3231    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
3232    # N.B. These Dij vars are missing a histogram #
3233    newCellDict = data[histNames[0]].get('newCellDict',{})
3234    for item in newCellDict:
3235        if item in data['varyList']:
3236            ESDlookup[newCellDict[item][0]] = item
3237            Dlookup[item] = newCellDict[item][0]
3238    # add coordinate equivalents to lookup table
3239    for parm in atomLookup:
3240        Dlookup[atomLookup[parm]] = parm
3241        ESDlookup[parm] = atomLookup[parm]
3242
3243    # get unit cell & symmetry for all phases & initial stuff for later use
3244    RecpCellTerms = {}
3245    SGdata = {}
3246    uniqCellIndx = {}
3247    initialCell = {}
3248    RcellLbls = {}
3249    zeroDict = {}
3250    Rcelldict = {}
3251    for phase in Phases:
3252        phasedict = Phases[phase]
3253        pId = phasedict['pId']
3254        pfx = str(pId)+'::' # prefix for A values from phase
3255        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
3256        RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7])
3257        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
3258        SGdata[pId] = phasedict['General']['SGData']
3259        Rcelldict.update({lbl:val for lbl,val in zip(RcellLbls[pId],RecpCellTerms[pId])})
3260        laue = SGdata[pId]['SGLaue']
3261        if laue == '2/m':
3262            laue += SGdata[pId]['SGUniq']
3263        for symlist,celllist in cellGUIlist:
3264            if laue in symlist:
3265                uniqCellIndx[pId] = celllist
3266                break
3267        else: # should not happen
3268            uniqCellIndx[pId] = range(6)
3269        for i in uniqCellIndx[pId]:
3270            initialCell[str(pId)+'::A'+str(i)] =  RecpCellTerms[pId][i]
3271
3272    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
3273    G2frame.dataFrame.SetLabel('Sequential refinement results')
3274    if not G2frame.dataFrame.GetStatusBar():
3275        Status = G2frame.dataFrame.CreateStatusBar()
3276        Status.SetStatusText('')
3277    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=wxID_RENAMESEQSEL)
3278    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
3279    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=wxID_SAVESEQSELCSV)
3280    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=wxID_SAVESEQCSV)
3281    G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=wxID_PLOTSEQSEL)
3282    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAveSelSeq, id=wxID_AVESEQSEL)
3283    G2frame.dataFrame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=wxID_ORGSEQSEL)
3284    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=wxADDSEQVAR)
3285    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewDistPseudoVar, id=wxADDSEQDIST)
3286    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewAnglePseudoVar, id=wxADDSEQANGLE)
3287    G2frame.dataFrame.Bind(wx.EVT_MENU, DelPseudoVar, id=wxDELSEQVAR)
3288    G2frame.dataFrame.Bind(wx.EVT_MENU, EditPseudoVar, id=wxEDITSEQVAR)
3289    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewParFitEq, id=wxADDPARFIT)
3290    G2frame.dataFrame.Bind(wx.EVT_MENU, CopyParFitEq, id=wxCOPYPARFIT)
3291    G2frame.dataFrame.Bind(wx.EVT_MENU, DelParFitEq, id=wxDELPARFIT)
3292    G2frame.dataFrame.Bind(wx.EVT_MENU, EditParFitEq, id=wxEDITPARFIT)
3293    G2frame.dataFrame.Bind(wx.EVT_MENU, DoParEqFit, id=wxDOPARFIT)
3294    EnablePseudoVarMenus()
3295    EnableParFitEqMenus()
3296
3297    # scan for locations where the variables change
3298    VaryListChanges = [] # histograms where there is a change
3299    combinedVaryList = []
3300    firstValueDict = {}
3301    vallookup = {}
3302    posdict = {}
3303    prevVaryList = []
3304    for i,name in enumerate(histNames):
3305        for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']):
3306            svar = striphist(var,'*') # wild-carded
3307            if svar not in combinedVaryList:
3308                # add variables to list as they appear
3309                combinedVaryList.append(svar)
3310                firstValueDict[svar] = (val,sig)
3311        if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous
3312            prevVaryList = data[name]['varyList']
3313            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
3314            posdict[name] = {}
3315            for var in data[name]['varyList']:
3316                svar = striphist(var,'*')
3317                posdict[name][combinedVaryList.index(svar)] = svar
3318            VaryListChanges.append(name)
3319    if len(VaryListChanges) > 1:
3320        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,True)
3321    else:
3322        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,False)
3323    #-----------------------------------------------------------------------------------
3324    # build up the data table by columns -----------------------------------------------
3325    nRows = len(histNames)
3326    colList = [nRows*[True]]
3327    colSigs = [None]
3328    colLabels = ['Use']
3329    Types = [wg.GRID_VALUE_BOOL]
3330    # start with Rwp values
3331    if 'IMG ' not in histNames[0][:4]:
3332        colList += [[data[name]['Rvals']['Rwp'] for name in histNames]]
3333        colSigs += [None]
3334        colLabels += ['Rwp']
3335        Types += [wg.GRID_VALUE_FLOAT+':10,3',]
3336    # add % change in Chi^2 in last cycle
3337    if histNames[0][:4] not in ['SASD','IMG '] and Controls.get('ShowCell'):
3338        colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]]
3339        colSigs += [None]
3340        colLabels += [u'\u0394\u03C7\u00B2 (%)']
3341        Types += [wg.GRID_VALUE_FLOAT,]
3342    deltaChiCol = len(colLabels)-1
3343    # add changing sample parameters to table
3344    for key in sampleParms:
3345        colList += [sampleParms[key]]
3346        colSigs += [None]
3347        colLabels += [key]
3348        Types += [wg.GRID_VALUE_FLOAT,]
3349    sampleDict = {}
3350    for i,name in enumerate(histNames):
3351        sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) 
3352    # add unique cell parameters TODO: review this where the cell symmetry changes (when possible)
3353    if Controls.get('ShowCell',False):
3354        for pId in sorted(RecpCellTerms):
3355            pfx = str(pId)+'::' # prefix for A values from phase
3356            cells = []
3357            cellESDs = []
3358            colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
3359            colLabels += [pfx+'Vol']
3360            Types += (1+len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT,]
3361            for name in histNames:
3362                covData = {
3363                    'varyList': [Dlookup.get(striphist(v),v) for v in data[name]['varyList']],
3364                    'covMatrix': data[name]['covMatrix']
3365                    }
3366                A = RecpCellTerms[pId][:] # make copy of starting A values
3367                # update with refined values
3368                for i in range(6):
3369                    var = str(pId)+'::A'+str(i)
3370                    if var in ESDlookup:
3371                        val = data[name]['newCellDict'][ESDlookup[var]][1] # get refined value
3372                        A[i] = val # override with updated value
3373                # apply symmetry
3374                Albls = [pfx+'A'+str(i) for i in range(6)]
3375                cellDict = dict(zip(Albls,A))
3376                A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
3377                # convert to direct cell & add only unique values to table
3378                c = G2lat.A2cell(A)
3379                vol = G2lat.calc_V(A)
3380                cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
3381                cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
3382                cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
3383            colList += zip(*cells)
3384            colSigs += zip(*cellESDs)
3385    # sort out the variables in their selected order
3386    varcols = 0
3387    for d in posdict.itervalues():
3388        varcols = max(varcols,max(d.keys())+1)
3389    # get labels for each column
3390    for i in range(varcols):
3391        lbl = ''
3392        for h in VaryListChanges:
3393            if posdict[h].get(i):
3394                if posdict[h].get(i) in lbl: continue
3395                if lbl != "": lbl += '/'
3396                lbl += posdict[h].get(i)
3397        colLabels.append(lbl)
3398    Types += varcols*[wg.GRID_VALUE_FLOAT]
3399    vals = []
3400    esds = []
3401    varsellist = None        # will be a list of variable names in the order they are selected to appear
3402    # tabulate values for each hist, leaving None for blank columns
3403    for name in histNames:
3404        if name in posdict:
3405            varsellist = [posdict[name].get(i) for i in range(varcols)]
3406            # translate variable names to how they will be used in the headings
3407            vs = [striphist(v,'*') for v in data[name]['varyList']]
3408            # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists
3409            sellist = [vs.index(v) if v is not None else None for v in varsellist]
3410            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])]
3411        if not varsellist: raise Exception()
3412        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
3413        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
3414        #GSASIIpath.IPyBreak()
3415    colList += zip(*vals)
3416    colSigs += zip(*esds)
3417               
3418    # tabulate constrained variables, removing histogram numbers if needed
3419    # from parameter label
3420    depValDict = {}
3421    depSigDict = {}
3422    for name in histNames:
3423        for var in data[name].get('depParmDict',{}):
3424            val,sig = data[name]['depParmDict'][var]
3425            svar = striphist(var,'*')
3426            if svar not in depValDict:
3427               depValDict[svar] = [val]
3428               depSigDict[svar] = [sig]
3429            else:
3430               depValDict[svar].append(val)
3431               depSigDict[svar].append(sig)
3432    # add the dependent constrained variables to the table
3433    for var in sorted(depValDict):
3434        if len(depValDict[var]) != len(histNames): continue
3435        colLabels.append(var)
3436        Types += [wg.GRID_VALUE_FLOAT,]
3437        colSigs += [depSigDict[var]]
3438        colList += [depValDict[var]]
3439
3440    # add atom parameters to table
3441    colLabels += atomLookup.keys()
3442    Types += len(atomLookup)*[wg.GRID_VALUE_FLOAT]
3443    for parm in sorted(atomLookup):
3444        colList += [[data[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
3445        if atomLookup[parm] in data[histNames[0]]['varyList']:
3446            col = data[histNames[0]]['varyList'].index(atomLookup[parm])
3447            colSigs += [[data[name]['sig'][col] for name in histNames]]
3448        else:
3449            colSigs += [None] # should not happen
3450    # evaluate Pseudovars, their ESDs and add them to grid
3451    for expr in Controls['SeqPseudoVars']:
3452        obj = Controls['SeqPseudoVars'][expr]
3453        calcobj = G2obj.ExpressionCalcObj(obj)
3454        valList = []
3455        esdList = []
3456        for seqnum,name in enumerate(histNames):
3457            sigs = data[name]['sig']
3458            G2mv.InitVars()
3459            parmDict = data[name].get('parmDict')
3460            badVary = data[name].get('badVary',[])
3461            constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum])
3462            groups,parmlist,constrDict,fixedList,ihst = constraintInfo
3463            varyList = data[name]['varyList']
3464            parmDict = data[name]['parmDict']
3465            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmDict,SeqHist=ihst)
3466            if 'Dist' in expr:
3467                derivs = G2mth.CalcDistDeriv(obj.distance_dict,obj.distance_atoms, parmDict)
3468                pId = obj.distance_dict['pId']
3469                aId,bId = obj.distance_atoms
3470                varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']]
3471                varyNames += ['%d::dA%s:%d'%(pId,ip,bId) for ip in ['x','y','z']]
3472                VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix'])
3473                esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) ))
3474#                GSASIIpath.IPyBreak()
3475            elif 'Angle' in expr:
3476                derivs = G2mth.CalcAngleDeriv(obj.angle_dict,obj.angle_atoms, parmDict)
3477                pId = obj.angle_dict['pId']
3478                aId,bId = obj.angle_atoms
3479                varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']]
3480                varyNames += ['%d::dA%s:%d'%(pId,ip,bId[0]) for ip in ['x','y','z']]
3481                varyNames += ['%d::dA%s:%d'%(pId,ip,bId[1]) for ip in ['x','y','z']]
3482                VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix'])
3483                esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) ))
3484            else:
3485                derivs = np.array(
3486                    [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD)
3487                     for var,ESD in zip(varyList,sigs)])
3488                esdList.append(np.sqrt(
3489                    np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T)) ))
3490            PSvarDict = parmDict.copy()
3491            PSvarDict.update(sampleDict[name])
3492            UpdateParmDict(PSvarDict)
3493            calcobj.UpdateDict(PSvarDict)
3494            valList.append(calcobj.EvalExpression())
3495#            if calcobj.su is not None: esdList[-1] = calcobj.su
3496        if not esdList:
3497            esdList = None
3498        colList += [valList]
3499        colSigs += [esdList]
3500        colLabels += [expr]
3501        Types += [wg.GRID_VALUE_FLOAT,]
3502    #---- table build done -------------------------------------------------------------
3503
3504    # Make dict needed for creating & editing pseudovars (PSvarDict).
3505    name = histNames[0]
3506    parmDict = data[name].get('parmDict',{})
3507    PSvarDict = parmDict.copy()
3508    PSvarDict.update(sampleParms)
3509    UpdateParmDict(PSvarDict)
3510    # Also dicts of dependent (depVarDict) & independent vars (indepVarDict)
3511    # for Parametric fitting from the data table
3512    parmDict = dict(zip(colLabels,zip(*colList)[0])) # scratch dict w/all values in table
3513    parmDict.update(
3514        {var:val for var,val in data[name].get('newCellDict',{}).values()} #  add varied reciprocal cell terms
3515    )
3516    name = histNames[0]
3517
3518    #******************************************************************************
3519    # create a set of values for example evaluation of pseudovars and
3520    # this does not work for refinements that have differing numbers of variables.
3521    #raise Exception
3522    indepVarDict = {}     #  values in table w/o ESDs
3523    depVarDict = {}
3524    for i,var in enumerate(colLabels):
3525        if var == 'Use': continue
3526        if colList[i][0] is None:
3527            val,sig = firstValueDict.get(var,[None,None])
3528        elif colSigs[i]:
3529            val,sig = colList[i][0],colSigs[i][0]
3530        else:
3531            val,sig = colList[i][0],None
3532        if val is None:
3533            continue
3534        elif sig is None:
3535            indepVarDict[var] = val
3536        elif striphist(var) not in Dlookup:
3537            depVarDict[var] = val
3538    # add recip cell coeff. values
3539    depVarDict.update({var:val for var,val in data[name].get('newCellDict',{}).values()})
3540
3541    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
3542    G2frame.SeqTable = G2G.Table(
3543        [list(c) for c in zip(*colList)],     # convert from columns to rows
3544        colLabels=colLabels,rowLabels=histNames,types=Types)
3545    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
3546    #G2frame.dataDisplay.EnableEditing(False)
3547    # make all but first column read-only
3548    for c in range(1,len(colLabels)):
3549        for r in range(nRows):
3550            G2frame.dataDisplay.SetCellReadOnly(r,c)
3551    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, PlotSelect)
3552    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, SetLabelString)
3553    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
3554    G2frame.dataDisplay.SetMargins(0,0)
3555    G2frame.dataDisplay.AutoSizeColumns(True)
3556    if prevSize:
3557        G2frame.dataDisplay.SetSize(prevSize)
3558    else:
3559        G2frame.dataFrame.setSizePosLeft([700,350])
3560    # highlight unconverged shifts
3561    if histNames[0][:4] not in ['SASD','IMG ']:
3562        for row,name in enumerate(histNames):
3563            deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol)
3564            if deltaChi > 10.:
3565                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0))
3566            elif deltaChi > 1.0:
3567                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0))
3568    G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip)
3569    G2frame.dataDisplay.SendSizeEvent() # resize needed on mac
3570    G2frame.dataDisplay.Refresh() # shows colored text on mac
3571   
3572################################################################################
3573#####  Main PWDR panel
3574################################################################################           
3575       
3576def UpdatePWHKPlot(G2frame,kind,item):
3577    '''Called when the histogram main tree entry is called. Displays the
3578    histogram weight factor, refinement statistics for the histogram
3579    and the range of data for a simulation.
3580
3581    Also invokes a plot of the histogram.
3582    '''
3583    def onEditSimRange(event):
3584        'Edit simulation range'
3585        inp = [
3586            min(data[1][0]),
3587            max(data[1][0]),
3588            None
3589            ]
3590        inp[2] = (inp[1] - inp[0])/(len(data[1][0])-1.)
3591        names = ('start angle', 'end angle', 'step size')
3592        dictlst = [inp] * len(inp)
3593        elemlst = range(len(inp))
3594        dlg = G2G.ScrolledMultiEditor(
3595            G2frame,[inp] * len(inp), range(len(inp)), names,
3596            header='Edit simulation range',
3597            minvals=(0.001,0.001,0.0001),
3598            maxvals=(180.,180.,.1),
3599            )
3600        dlg.CenterOnParent()
3601        val = dlg.ShowModal()
3602        dlg.Destroy()
3603        if val != wx.ID_OK: return
3604        if inp[0] > inp[1]:
3605            end,start,step = inp
3606        else:               
3607            start,end,step = inp
3608        step = abs(step)
3609        N = int((end-start)/step)+1
3610        newdata = np.linspace(start,end,N,True)
3611        if len(newdata) < 2: return # too small a range - reject
3612        data[1] = [newdata,np.zeros_like(newdata),np.ones_like(newdata),
3613            np.zeros_like(newdata),np.zeros_like(newdata),np.zeros_like(newdata)]
3614        Tmin = newdata[0]
3615        Tmax = newdata[-1]
3616        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,item,'Limits'),
3617            [(Tmin,Tmax),[Tmin,Tmax]])
3618        UpdatePWHKPlot(G2frame,kind,item) # redisplay data screen
3619
3620    def OnPlot3DHKL(event):
3621        refList = data[1]['RefList']
3622        FoMax = np.max(refList.T[8+Super])
3623        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3624        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3625        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3626        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
3627            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3628            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3629            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3630        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3631       
3632    def OnPlotAll3DHKL(event):
3633        choices = GetPatternTreeDataNames(G2frame,['HKLF',])
3634        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select reflection sets to plot',
3635            'Use data',choices)
3636        try:
3637            if dlg.ShowModal() == wx.ID_OK:
3638                refNames = [choices[i] for i in dlg.GetSelections()]
3639            else:
3640                return
3641        finally:
3642            dlg.Destroy()
3643        refList = np.zeros(0)
3644        for name in refNames:
3645            Id = GetPatternTreeItemId(G2frame,G2frame.root, name)
3646            reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
3647            if len(refList):
3648                refList = np.concatenate((refList,reflData['RefList']))
3649            else:
3650                refList = reflData['RefList']
3651           
3652        FoMax = np.max(refList.T[8+Super])
3653        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3654        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3655        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3656        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
3657            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3658            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3659            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
3660        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3661                 
3662    def OnMergeHKL(event):
3663        Name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3664        Inst = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,
3665            G2frame.PatternId,'Instrument Parameters'))
3666        CId = GetPatternTreeItemId(G2frame,G2frame.PatternId,'Comments')
3667        if CId:
3668            Comments = G2frame.PatternTree.GetItemPyData(CId)
3669        else:
3670            Comments = []
3671        refList = np.copy(data[1]['RefList'])
3672        Comments.append(' Merging %d reflections from %s'%(len(refList),Name))
3673        dlg = MergeDialog(G2frame,data)
3674        try:
3675            if dlg.ShowModal() == wx.ID_OK:
3676                Trans,Cent,Laue = dlg.GetSelection()
3677            else:
3678                return
3679        finally:
3680            dlg.Destroy()
3681        Super = data[1]['Super']
3682        refList,badRefs = G2lat.transposeHKLF(Trans,Super,refList)
3683        if len(badRefs):    #do I want to list badRefs?
3684            G2frame.ErrorDialog('Failed transformation','Matrix yields fractional hkl indices')
3685            return
3686        Comments.append(" Transformation M*H = H' applied; M=")
3687        Comments.append(str(Trans))
3688        SG = 'P '+Laue
3689        SGData = G2spc.SpcGroup(SG)[1]
3690        refList = G2lat.LaueUnique(Laue,refList)
3691        dlg = wx.ProgressDialog('Build HKL dictonary','',len(refList)+1, 
3692            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
3693        HKLdict = {}
3694        for ih,hkl in enumerate(refList):
3695            if str(hkl[:3+Super]) not in HKLdict:
3696                HKLdict[str(hkl[:3+Super])] = [hkl[:3+Super],[hkl[3+Super:],]]
3697            else:
3698                HKLdict[str(hkl[:3+Super])][1].append(hkl[3+Super:])
3699            dlg.Update(ih)
3700        dlg.Destroy()
3701        mergeRef = []
3702        dlg = wx.ProgressDialog('Processing merge','',len(HKLdict)+1, 
3703            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
3704        sumDf = 0.
3705        sumFo = 0.
3706        for ih,hkl in enumerate(HKLdict):
3707            HKL = HKLdict[hkl]
3708            newHKL = list(HKL[0])+list(HKL[1][0])
3709            if len(HKL[1]) > 1:
3710                fos = np.array(HKL[1])
3711                wFo = 1/fos[:,3]**2
3712                Fo = np.average(fos[:,2],weights=wFo)
3713                std = np.std(fos[:,2])
3714                sig = np.sqrt(np.mean(fos[:,3])**2+std**2)
3715                sumFo += np.sum(fos[:,2])
3716                sumDf += np.sum(np.abs(fos[:,2]-Fo))
3717                dlg.Update(ih)
3718                newHKL[5+Super] = Fo
3719                newHKL[6+Super] = sig
3720                newHKL[8+Super] = Fo
3721            if newHKL[5+Super] > 0.:
3722                mergeRef.append(list(newHKL)) 
3723        dlg.Destroy()
3724        if Super:
3725            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,3),2),1),0)
3726        else:
3727            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,2),1),0)
3728        mergeRef = np.array(mergeRef)
3729        if sumFo:
3730            mtext = ' merge R = %6.2f%s for %d reflections in %s'%(100.*sumDf/sumFo,'%',mergeRef.shape[0],Laue)
3731            print mtext
3732            Comments.append(mtext)
3733        else:
3734            print 'nothing to merge for %s reflections'%(mergeRef.shape[0])
3735        HKLFlist = []
3736        newName = Name+' '+Laue
3737        if G2frame.PatternTree.GetCount():
3738            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3739            while item:
3740                name = G2frame.PatternTree.GetItemText(item)
3741                if name.startswith('HKLF ') and name not in HKLFlist:
3742                    HKLFlist.append(name)
3743                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3744        newName = G2obj.MakeUniqueLabel(newName,HKLFlist)
3745        newData = copy.deepcopy(data)
3746        newData[0]['ranId'] = ran.randint(0,sys.maxint)
3747        newData[1]['RefList'] = mergeRef
3748        Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=newName)
3749        G2frame.PatternTree.SetItemPyData(
3750            G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)
3751        G2frame.PatternTree.SetItemPyData(Id,newData)
3752        G2frame.PatternTree.SetItemPyData(
3753            G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
3754        G2frame.PatternTree.SetItemPyData(
3755            G2frame.PatternTree.AppendItem(Id,text='Reflection List'),{})  #dummy entry for GUI use
3756                   
3757    def OnErrorAnalysis(event):
3758        G2plt.PlotDeltSig(G2frame,kind)
3759       
3760    def OnWtFactor(event):
3761        try:
3762            val = float(wtval.GetValue())
3763        except ValueError:
3764            val = data[0]['wtFactor']
3765        data[0]['wtFactor'] = val
3766        wtval.SetValue('%.3f'%(val))
3767       
3768    def OnCompression(event):
3769        data[0] = int(comp.GetValue())
3770       
3771    def onCopyPlotCtrls(event):
3772        '''Respond to menu item to copy multiple sections from a histogram.
3773        Need this here to pass on the G2frame object.
3774        '''
3775        G2pdG.CopyPlotCtrls(G2frame)
3776
3777    def onCopySelectedItems(event):
3778        '''Respond to menu item to copy multiple sections from a histogram.
3779        Need this here to pass on the G2frame object.
3780        '''
3781        G2pdG.CopySelectedHistItems(G2frame)
3782           
3783    data = G2frame.PatternTree.GetItemPyData(item)
3784#patches
3785    if 'wtFactor' not in data[0]:
3786        data[0] = {'wtFactor':1.0}
3787#    if kind == 'PWDR' and 'Compression' not in data[0]:
3788#        data[0]['Compression'] = 1
3789    #if isinstance(data[1],list) and kind == 'HKLF':
3790    if 'list' in str(type(data[1])) and kind == 'HKLF':
3791        RefData = {'RefList':[],'FF':[]}
3792        for ref in data[1]:
3793            RefData['RefList'].append(ref[:11]+[ref[13],])
3794            RefData['FF'].append(ref[14])
3795        data[1] = RefData
3796        G2frame.PatternTree.SetItemPyData(item,data)
3797#end patches
3798    if G2frame.dataDisplay:
3799        G2frame.dataDisplay.Destroy()
3800    if kind in ['PWDR','SASD']:
3801        SetDataMenuBar(G2frame,G2frame.dataFrame.PWDRMenu)
3802        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
3803        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
3804        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopyPlotCtrls, id=wxID_PLOTCTRLCOPY)
3805    elif kind in ['HKLF',]:
3806        SetDataMenuBar(G2frame,G2frame.dataFrame.HKLFMenu)
3807        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
3808        G2frame.dataFrame.Bind(wx.EVT_MENU, OnMergeHKL, id=wxID_MERGEHKL)
3809        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=wxID_PWD3DHKLPLOT)
3810        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotAll3DHKL, id=wxID_3DALLHKLPLOT)
3811#        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
3812    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
3813   
3814    mainSizer = wx.BoxSizer(wx.VERTICAL)
3815    mainSizer.Add((5,5),)
3816    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
3817    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,WACV)
3818    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
3819    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
3820    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
3821    wtSizer.Add(wtval,0,WACV)
3822#    if kind == 'PWDR':         #possible future compression feature; NB above patch as well
3823#        wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Compression factor: '),0,WACV)
3824#        choice = ['1','2','3','4','5','6']
3825#        comp = wx.ComboBox(parent=G2frame.dataDisplay,choices=choice,
3826#            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3827#        comp.SetValue(str(data[0]['Compression']))
3828#        comp.Bind(wx.EVT_COMBOBOX, OnCompression)
3829#        wtSizer.Add(comp,0,WACV)
3830    mainSizer.Add(wtSizer)
3831    if data[0].get('Dummy'):
3832        simSizer = wx.BoxSizer(wx.HORIZONTAL)
3833        Tmin = min(data[1][0])
3834        Tmax = max(data[1][0])
3835        num = len(data[1][0])
3836        step = (Tmax - Tmin)/(num-1)
3837        t = u'2\u03b8' # 2theta
3838        lbl =  u'Simulation range: {:.2f} to {:.2f} {:s}\nwith {:.4f} steps ({:d} points)'
3839        lbl += u'\n(Edit range resets observed intensities).'
3840        lbl = lbl.format(Tmin,Tmax,t,step,num)
3841        simSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,lbl),
3842                    0,WACV)
3843        but = wx.Button(G2frame.dataDisplay,wx.ID_ANY,"Edit range")
3844        but.Bind(wx.EVT_BUTTON,onEditSimRange)
3845        simSizer.Add(but,0,WACV)
3846        mainSizer.Add(simSizer)
3847    if 'Nobs' in data[0]:
3848        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3849            ' Data residual wR: %.3f%% on %d observations'%(data[0]['wR'],data[0]['Nobs'])))
3850        for value in data[0]:
3851            if 'Nref' in value:
3852                pfx = value.split('Nref')[0]
3853                name = data[0].get(pfx.split(':')[0]+'::Name','?')
3854                if 'SS' in value:
3855                    mainSizer.Add((5,5),)
3856                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For incommensurate phase '+name+':'))
3857                    for m,(Rf2,Rf,Nobs) in enumerate(zip(data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])):
3858                        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3859                            u' m = +/- %d: RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
3860                            (m,Rf2,Rf,Nobs)))
3861                else:
3862                    mainSizer.Add((5,5),)
3863                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For phase '+name+':'))
3864                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3865                        u' Unweighted phase residuals RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
3866                        (data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])))
3867                   
3868    mainSizer.Add((5,5),)
3869    mainSizer.Layout()   
3870    G2frame.dataDisplay.SetSizer(mainSizer)
3871    Size = mainSizer.Fit(G2frame.dataFrame)
3872    Size[1] += 10
3873    G2frame.dataFrame.setSizePosLeft(Size)
3874    G2frame.PatternTree.SetItemPyData(item,data)
3875    if kind in ['PWDR','SASD']:
3876        NewPlot = True
3877        if 'xylim' in dir(G2frame):
3878            NewPlot = False
3879        G2plt.PlotPatterns(G2frame,plotType=kind,newPlot=NewPlot)
3880    elif kind == 'HKLF':
3881        Name = G2frame.PatternTree.GetItemText(item)
3882        phaseName = G2pdG.IsHistogramInAnyPhase(G2frame,Name)
3883        if phaseName:
3884            pId = GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3885            phaseId =  GetPatternTreeItemId(G2frame,pId,phaseName)
3886            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3887            Super = General.get('Super',0)
3888            SuperVec = General.get('SuperVec',[])
3889        else:
3890            Super = 0
3891            SuperVec = []       
3892        refList = data[1]['RefList']
3893#        GSASIIpath.IPyBreak()
3894        FoMax = np.max(refList.T[5+data[1].get('Super',0)])
3895        page = G2frame.G2plotNB.nb.GetSelection()
3896        tab = ''
3897        if page >= 0:
3898            tab = G2frame.G2plotNB.nb.GetPageText(page)
3899        if '3D' in tab:
3900            Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3901            Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3902            Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3903            Page = G2frame.G2plotNB.nb.GetPage(page)
3904            controls = Page.controls
3905            G2plt.Plot3DSngl(G2frame,newPlot=False,Data=controls,hklRef=refList,Title=phaseName)
3906        else:
3907            controls = {'Type' : 'Fo','ifFc' : True,     
3908                'HKLmax' : [int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))],
3909                'HKLmin' : [int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))],
3910                'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3911            G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList)
3912                 
3913################################################################################
3914#####  Pattern tree routines
3915################################################################################           
3916       
3917def GetPatternTreeDataNames(G2frame,dataTypes):
3918    '''Finds all items in tree that match a 4 character prefix
3919   
3920    :param wx.Frame G2frame: Data tree frame object
3921    :param list dataTypes: Contains one or more data tree item types to be matched
3922      such as ['IMG '] or ['PWDR','HKLF']
3923    :returns: a list of tree item names for the matching items 
3924    '''
3925    names = []
3926    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
3927    while item:
3928        name = G2frame.PatternTree.GetItemText(item)
3929        if name[:4] in dataTypes:
3930            names.append(name)
3931        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3932    return names
3933                         
3934def GetPatternTreeItemId(G2frame, parentId, itemText):
3935    '''Find the tree item that matches the text in itemText starting with parentId
3936
3937    :param wx.Frame G2frame: Data tree frame object
3938    :param wx.TreeItemId parentId: tree item to start search with
3939    :param str itemText: text for tree item
3940    '''
3941    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
3942    while item:
3943        if G2frame.PatternTree.GetItemText(item) == itemText:
3944            return item
3945        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
3946    return 0               
3947
3948def MovePatternTreeToGrid(G2frame,item):
3949    '''Called from GSASII.OnPatternTreeSelChanged when a item is selected on the tree
3950    '''
3951    pickName = G2frame.PatternTree.GetItemText(item)
3952    if G2frame.PickIdText == pickName:
3953        return
3954   
3955    oldPage = None # will be set later if already on a Phase item
3956    if G2frame.dataFrame:
3957        SetDataMenuBar(G2frame)
3958        if G2frame.dataFrame.GetLabel() == 'Comments':
3959            try:
3960                data = [G2frame.dataDisplay.GetValue()]
3961                G2frame.dataDisplay.Clear() 
3962                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
3963                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3964            except:     #clumsy but avoids dead window problem when opening another project
3965                pass
3966        elif G2frame.dataFrame.GetLabel() == 'Notebook':
3967            try:
3968                data = [G2frame.dataDisplay.GetValue()]
3969                G2frame.dataDisplay.Clear() 
3970                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
3971                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3972            except:     #clumsy but avoids dead window problem when opening another project
3973                pass
3974        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
3975            if G2frame.dataDisplay: 
3976                oldPage = G2frame.dataDisplay.GetSelection()
3977        G2frame.dataFrame.Clear()
3978        G2frame.dataFrame.SetLabel('')
3979    else:
3980        #create the frame for the data item window
3981        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
3982        G2frame.dataFrame.PhaseUserSize = None
3983       
3984    G2frame.dataFrame.Raise()           
3985    G2frame.PickId = item
3986    G2frame.PickIdText = None
3987    parentID = G2frame.root
3988    #for i in G2frame.ExportPattern: i.Enable(False)
3989    defWid = [250,150]
3990    if item != G2frame.root:
3991        parentID = G2frame.PatternTree.GetItemParent(item)
3992    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
3993        G2frame.PatternId = item
3994        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
3995            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
3996            G2frame.PatternId = 0
3997            #for i in G2frame.ExportPattern: i.Enable(False)
3998            data = G2frame.PatternTree.GetItemPyData(item)
3999            UpdateNotebook(G2frame,data)
4000        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
4001            G2frame.PatternId = 0
4002            #for i in G2frame.ExportPattern: i.Enable(False)
4003            data = G2frame.PatternTree.GetItemPyData(item)
4004            if not data:           #fill in defaults
4005                data = copy.copy(G2obj.DefaultControls)    #least squares controls
4006                G2frame.PatternTree.SetItemPyData(item,data)                             
4007            for i in G2frame.Refine: i.Enable(True)
4008            G2frame.EnableSeqRefineMenu()
4009            UpdateControls(G2frame,data)
4010        elif G2frame.PatternTree.GetItemText(item) == 'Sequential results':
4011            data = G2frame.PatternTree.GetItemPyData(item)
4012            UpdateSeqResults(G2frame,data)
4013        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
4014            data = G2frame.PatternTree.GetItemPyData(item)
4015            G2frame.dataFrame.setSizePosLeft(defWid)
4016            text = ''
4017            if 'Rvals' in data:
4018                Nvars = len(data['varyList'])
4019                Rvals = data['Rvals']
4020                text = '\nFinal residuals: \nwR = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
4021                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
4022                if 'lamMax' in Rvals:
4023                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
4024            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
4025                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
4026            G2plt.PlotCovariance(G2frame,data)
4027        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
4028            data = G2frame.PatternTree.GetItemPyData(item)
4029            G2cnstG.UpdateConstraints(G2frame,data)
4030        elif G2frame.PatternTree.GetItemText(item) == 'Rigid bodies':
4031            data = G2frame.PatternTree.GetItemPyData(item)
4032            G2cnstG.UpdateRigidBodies(G2frame,data)
4033        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
4034            data = G2frame.PatternTree.GetItemPyData(item)
4035            Phases = G2frame.GetPhaseData()
4036            phase = ''
4037            phaseName = ''
4038            if Phases:
4039                phaseName = Phases.keys()[0]
4040            G2frame.dataFrame.setSizePosLeft(defWid)
4041            G2restG.UpdateRestraints(G2frame,data,Phases,phaseName)
4042        elif 'IMG' in G2frame.PatternTree.GetItemText(item):
4043            G2frame.Image = item
4044            G2frame.dataFrame.SetTitle('Image Data')
4045            data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(
4046                G2frame,item,'Image Controls'))
4047            G2imG.UpdateImageData(G2frame,data)
4048            G2plt.PlotImage(G2frame,newPlot=True)
4049        elif 'PKS' in G2frame.PatternTree.GetItemText(item):
4050            G2plt.PlotPowderLines(G2frame)
4051        elif 'PWDR' in G2frame.PatternTree.GetItemText(item):
4052            #for i in G2frame.ExportPattern: i.Enable(True)
4053            if G2frame.EnablePlot:
4054                UpdatePWHKPlot(G2frame,'PWDR',item)
4055        elif 'SASD' in G2frame.PatternTree.GetItemText(item):
4056            #for i in G2frame.ExportPattern: i.Enable(True)
4057            if G2frame.EnablePlot:
4058                UpdatePWHKPlot(G2frame,'SASD',item)
4059        elif 'HKLF' in G2frame.PatternTree.GetItemText(item):
4060            G2frame.Sngl = True
4061            UpdatePWHKPlot(G2frame,'HKLF',item)
4062        elif 'PDF' in G2frame.PatternTree.GetItemText(item):
4063            G2frame.PatternId = item
4064            for i in G2frame.ExportPDF: i.Enable(True)
4065            G2plt.PlotISFG(G2frame,type='S(Q)')
4066        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
4067            G2frame.dataFrame.setSizePosLeft(defWid)
4068            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
4069                value='Select one phase to see its parameters')           
4070    elif 'I(Q)' in G2frame.PatternTree.GetItemText(item):
4071        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4072        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4073        G2pdG.UpdatePDFGrid(G2frame,data)
4074        G2plt.PlotISFG(G2frame,type='I(Q)',newPlot=True)
4075    elif 'S(Q)' in G2frame.PatternTree.GetItemText(item):
4076        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4077        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4078        G2pdG.UpdatePDFGrid(G2frame,data)
4079        G2plt.PlotISFG(G2frame,type='S(Q)',newPlot=True)
4080    elif 'F(Q)' in G2frame.PatternTree.GetItemText(item):
4081        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4082        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4083        G2pdG.UpdatePDFGrid(G2frame,data)
4084        G2plt.PlotISFG(G2frame,type='F(Q)',newPlot=True)
4085    elif 'G(R)' in G2frame.PatternTree.GetItemText(item):
4086        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4087        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4088        G2pdG.UpdatePDFGrid(G2frame,data)
4089        G2plt.PlotISFG(G2frame,type='G(R)',newPlot=True)           
4090    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
4091        data = G2frame.PatternTree.GetItemPyData(item)
4092        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
4093    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
4094        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
4095        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4096        data = G2frame.PatternTree.GetItemPyData(item)
4097        UpdateComments(G2frame,data)
4098    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
4099        G2frame.dataFrame.SetTitle('Image Controls')
4100        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4101        masks = G2frame.PatternTree.GetItemPyData(
4102            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
4103        data = G2frame.PatternTree.GetItemPyData(item)
4104        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4105        G2imG.UpdateImageControls(G2frame,data,masks)
4106        G2plt.PlotImage(G2frame,newPlot=True)
4107    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
4108        G2frame.dataFrame.SetTitle('Masks')
4109        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4110        masks = G2frame.PatternTree.GetItemPyData(item)
4111        data = G2frame.PatternTree.GetItemPyData(
4112            GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4113        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4114        G2imG.UpdateMasks(G2frame,masks)
4115        G2plt.PlotImage(G2frame,newPlot=True)
4116    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
4117        G2frame.dataFrame.SetTitle('Stress/Strain')
4118        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4119        data = G2frame.PatternTree.GetItemPyData(
4120            GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4121        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4122        strsta = G2frame.PatternTree.GetItemPyData(item)
4123        G2plt.PlotImage(G2frame,newPlot=True)
4124        G2plt.PlotStrain(G2frame,strsta,newPlot=True)
4125        G2imG.UpdateStressStrain(G2frame,strsta)
4126    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
4127        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4128        for i in G2frame.ExportPDF: i.Enable(True)
4129        data = G2frame.PatternTree.GetItemPyData(item)
4130        G2pdG.UpdatePDFGrid(G2frame,data)
4131        G2plt.PlotISFG(G2frame,type='I(Q)')
4132        G2plt.PlotISFG(G2frame,type='S(Q)')
4133        G2plt.PlotISFG(G2frame,type='F(Q)')
4134        G2plt.PlotISFG(G2frame,type='G(R)')
4135    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
4136        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4137        for i in G2frame.ExportPeakList: i.Enable(True)
4138        data = G2frame.PatternTree.GetItemPyData(item)
4139#patch
4140        if 'list' in str(type(data)):
4141            data = {'peaks':data,'sigDict':{}}
4142            G2frame.PatternTree.SetItemPyData(item,data)
4143#end patch
4144        G2pdG.UpdatePeakGrid(G2frame,data)
4145        G2plt.PlotPatterns(G2frame)
4146    elif G2frame.PatternTree.GetItemText(item) == 'Background':
4147        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4148        data = G2frame.PatternTree.GetItemPyData(item)
4149        G2pdG.UpdateBackground(G2frame,data)
4150        G2plt.PlotPatterns(G2frame)
4151    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
4152        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4153        datatype = G2frame.PatternTree.GetItemText(G2frame.PatternId)[:4]
4154        data = G2frame.PatternTree.GetItemPyData(item)
4155        G2pdG.UpdateLimitsGrid(G2frame,data,datatype)
4156        G2plt.PlotPatterns(G2frame,plotType=datatype)
4157    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
4158        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4159        data = G2frame.PatternTree.GetItemPyData(item)[0]
4160        G2pdG.UpdateInstrumentGrid(G2frame,data)
4161        if 'P' in data['Type'][0]:          #powder data only
4162            G2plt.PlotPeakWidths(G2frame)
4163    elif G2frame.PatternTree.GetItemText(item) == 'Models':
4164        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4165        data = G2frame.PatternTree.GetItemPyData(item)
4166        G2pdG.UpdateModelsGrid(G2frame,data)
4167        G2plt.PlotPatterns(G2frame,plotType='SASD')
4168        if len(data['Size']['Distribution']):
4169            G2plt.PlotSASDSizeDist(G2frame)
4170    elif G2frame.PatternTree.GetItemText(item) == 'Substances':
4171        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4172        data = G2frame.PatternTree.GetItemPyData(item)
4173        G2pdG.UpdateSubstanceGrid(G2frame,data)
4174    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
4175        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4176        data = G2frame.PatternTree.GetItemPyData(item)
4177        datatype = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[2][:4]
4178
4179        if 'Temperature' not in data:           #temp fix for old gpx files
4180            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
4181                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,
4182                    'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
4183                    'Gonio. radius':200.0}
4184            G2frame.PatternTree.SetItemPyData(item,data)
4185   
4186        G2pdG.UpdateSampleGrid(G2frame,data)
4187        G2plt.PlotPatterns(G2frame,plotType=datatype)
4188    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
4189        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4190        for i in G2frame.ExportPeakList: i.Enable(True)
4191        data = G2frame.PatternTree.GetItemPyData(item)
4192#patch
4193        if len(data) != 2:
4194            data = [data,[]]
4195            G2frame.PatternTree.SetItemPyData(item,data)
4196#end patch
4197        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
4198        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4199            G2plt.PlotPowderLines(G2frame)
4200        else:
4201            G2plt.PlotPatterns(G2frame)
4202    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
4203        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4204        data = G2frame.PatternTree.GetItemPyData(item)
4205        if not data:
4206            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
4207            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
4208            data.append([])                                 #empty cell list
4209            data.append([])                                 #empty dmin
4210            data.append({})                                 #empty superlattice stuff
4211            G2frame.PatternTree.SetItemPyData(item,data)                             
4212#patch
4213        if len(data) < 5:
4214            data.append({'Use':False,'ModVec':[0,0,0.1],'maxH':1,'ssSymb':''})                                 #empty superlattice stuff
4215            G2frame.PatternTree.SetItemPyData(item,data) 
4216#end patch
4217        G2pdG.UpdateUnitCellsGrid(G2frame,data)
4218        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4219            G2plt.PlotPowderLines(G2frame)
4220        else:
4221