source: trunk/GSASIIgrid.py @ 2242

Last change on this file since 2242 was 2242, checked in by vondreele, 7 years ago

change default stack inst to Gaussian
provide labels for plots of sequential stacking fault calcs.

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