source: trunk/GSASIIgrid.py @ 2298

Last change on this file since 2298 was 2298, checked in by vondreele, 6 years ago

Add stubs for BondDialog? & AngleDialog? for adding these to Seq results table
Add menu items for above
fix a bug in showing seq results
revert the occurrence counter for image integrations
capture bad pids in OnPageChanged?

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