source: trunk/GSASIIgrid.py @ 2187

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

Modify the Cite please banners to add small angle & DIFFaX references
remov
e 'axial' from DIFFaX choices (for now) as it leads to a streak calculation not supported in GSAS-II
replace pylab stuff with use of PlotXYZ which has been improved
fix character Greek 'mu' in Layers GUI
new GSAS-II function for calculating selected area diffraction (still testing)

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