source: trunk/GSASIIgrid.py @ 2161

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

Add GUI for layer stacking structures - almost complete; new phase type = 'faulted'
Add load from DIFFaX command files for stacking structures

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