source: trunk/GSASIIgrid.py @ 2166

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

add GetMeanWave? to G2math to return Ka-bar

more work on Stacking faults - now runs DIFFaX with data from GSAS-II

result as a powder pattern returned to ycalc.

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