source: trunk/GSASIIgrid.py @ 2272

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

add Stacking Faults II tutorial
add a Copy Phase command to Layers menu
bring up new phase after Transform
change default dir/file name for saved structure drawings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 195.3 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIgrid - data display routines
3########### SVN repository information ###################
4# $Date: 2016-05-14 14:45:23 +0000 (Sat, 14 May 2016) $
5# $Author: vondreele $
6# $Revision: 2272 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 2272 2016-05-14 14:45:23Z 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: 2272 $")
31import GSASIImath as G2mth
32import GSASIIIO as G2IO
33import GSASIIstrIO as G2stIO
34import GSASIIlattice as G2lat
35import GSASIIplot as G2plt
36import GSASIIpwdGUI as G2pdG
37import GSASIIimgGUI as G2imG
38import GSASIIphsGUI as G2phG
39import GSASIIspc as G2spc
40import GSASIImapvars as G2mv
41import GSASIIconstrGUI as G2cnstG
42import GSASIIrestrGUI as G2restG
43import GSASIIpy3 as G2py3
44import GSASIIobj as G2obj
45import GSASIIexprGUI as G2exG
46import GSASIIlog as log
47import GSASIIctrls as G2G
48
49# trig functions in degrees
50sind = lambda x: np.sin(x*np.pi/180.)
51tand = lambda x: np.tan(x*np.pi/180.)
52cosd = lambda x: np.cos(x*np.pi/180.)
53
54# Define a short name for convenience
55WACV = wx.ALIGN_CENTER_VERTICAL
56
57[ wxID_FOURCALC, wxID_FOURSEARCH, wxID_FOURCLEAR, wxID_PEAKSMOVE, wxID_PEAKSCLEAR, 
58    wxID_CHARGEFLIP, wxID_PEAKSUNIQUE, wxID_PEAKSDELETE, wxID_PEAKSDA,
59    wxID_PEAKSDISTVP, wxID_PEAKSVIEWPT, wxID_FINDEQVPEAKS,wxID_SHOWBONDS,wxID_MULTIMCSA,
60    wxID_SINGLEMCSA,wxID_4DCHARGEFLIP,wxID_TRANSFORMSTRUCTURE,
61] = [wx.NewId() for item in range(17)]
62
63[ wxID_PWDRADD, wxID_HKLFADD, wxID_PWDANALYSIS, wxID_PWDCOPY, wxID_PLOTCTRLCOPY, 
64    wxID_DATADELETE,wxID_DATACOPY,wxID_DATACOPYFLAGS,wxID_DATASELCOPY,wxID_DATAUSE,
65] = [wx.NewId() for item in range(10)]
66
67[ wxID_ATOMSEDITADD, wxID_ATOMSEDITINSERT, wxID_ATOMSEDITDELETE, wxID_ATOMSREFINE, 
68    wxID_ATOMSMODIFY, wxID_ATOMSTRANSFORM, wxID_ATOMSVIEWADD, wxID_ATOMVIEWINSERT,
69    wxID_RELOADDRAWATOMS,wxID_ATOMSDISAGL,wxID_ATOMMOVE,wxID_MAKEMOLECULE,
70    wxID_ASSIGNATMS2RB,wxID_ATOMSPDISAGL, wxID_ISODISP,wxID_ADDHATOM,wxID_UPDATEHATOM,
71    wxID_WAVEVARY,wxID_ATOMSROTATE,
72] = [wx.NewId() for item in range(19)]
73
74[ wxID_DRAWATOMSTYLE, wxID_DRAWATOMLABEL, wxID_DRAWATOMCOLOR, wxID_DRAWATOMRESETCOLOR, 
75    wxID_DRAWVIEWPOINT, wxID_DRAWTRANSFORM, wxID_DRAWDELETE, wxID_DRAWFILLCELL, 
76    wxID_DRAWADDEQUIV, wxID_DRAWFILLCOORD, wxID_DRAWDISAGLTOR,  wxID_DRAWPLANE,
77    wxID_DRAWDISTVP,
78] = [wx.NewId() for item in range(13)]
79
80[ wxID_DRAWRESTRBOND, wxID_DRAWRESTRANGLE, wxID_DRAWRESTRPLANE, wxID_DRAWRESTRCHIRAL,
81] = [wx.NewId() for item in range(4)]
82
83[ wxID_ADDMCSAATOM,wxID_ADDMCSARB,wxID_CLEARMCSARB,wxID_MOVEMCSA,wxID_MCSACLEARRESULTS,
84] = [wx.NewId() for item in range(5)]
85
86[ wxID_CLEARTEXTURE,wxID_REFINETEXTURE,
87] = [wx.NewId() for item in range(2)]
88
89[ wxID_LOADDIFFAX,wxID_LAYERSIMULATE,wxID_SEQUENCESIMULATE, wxID_COPYPHASE,
90] = [wx.NewId() for item in range(4)]
91
92[ wxID_PAWLEYLOAD, wxID_PAWLEYESTIMATE, wxID_PAWLEYUPDATE,
93] = [wx.NewId() for item in range(3)]
94
95[ wxID_IMCALIBRATE,wxID_IMRECALIBRATE,wxID_IMINTEGRATE, wxID_IMCLEARCALIB, 
96    wxID_IMCOPYCONTROLS, wxID_INTEGRATEALL, wxID_IMSAVECONTROLS, wxID_IMLOADCONTROLS, wxID_IMAUTOINTEG,
97] = [wx.NewId() for item in range(9)]
98
99[ wxID_MASKCOPY, wxID_MASKSAVE, wxID_MASKLOAD, wxID_NEWMASKSPOT,wxID_NEWMASKARC,wxID_NEWMASKRING,
100    wxID_NEWMASKFRAME, wxID_NEWMASKPOLY,  wxID_MASKLOADNOT,
101] = [wx.NewId() for item in range(9)]
102
103[ wxID_STRSTACOPY, wxID_STRSTAFIT, wxID_STRSTASAVE, wxID_STRSTALOAD,wxID_STRSTSAMPLE,
104    wxID_APPENDDZERO,wxID_STRSTAALLFIT,wxID_UPDATEDZERO,
105] = [wx.NewId() for item in range(8)]
106
107[ wxID_BACKCOPY,wxID_LIMITCOPY, wxID_SAMPLECOPY, wxID_SAMPLECOPYSOME, wxID_BACKFLAGCOPY, wxID_SAMPLEFLAGCOPY,
108    wxID_SAMPLESAVE, wxID_SAMPLELOAD,wxID_ADDEXCLREGION,wxID_SETSCALE,wxID_SAMPLE1VAL,wxID_ALLSAMPLELOAD,
109] = [wx.NewId() for item in range(12)]
110
111[ wxID_INSTPRMRESET,wxID_CHANGEWAVETYPE,wxID_INSTCOPY, wxID_INSTFLAGCOPY, wxID_INSTLOAD,
112    wxID_INSTSAVE, wxID_INST1VAL, wxID_INSTCALIB,wxID_INSTSAVEALL,
113] = [wx.NewId() for item in range(9)]
114
115[ wxID_UNDO,wxID_LSQPEAKFIT,wxID_LSQONECYCLE,wxID_RESETSIGGAM,wxID_CLEARPEAKS,wxID_AUTOSEARCH,
116    wxID_PEAKSCOPY, wxID_SEQPEAKFIT,
117] = [wx.NewId() for item in range(8)]
118
119[  wxID_INDXRELOAD, wxID_INDEXPEAKS, wxID_REFINECELL, wxID_COPYCELL, wxID_MAKENEWPHASE,
120    wxID_EXPORTCELLS,
121] = [wx.NewId() for item in range(6)]
122
123[ wxID_CONSTRAINTADD,wxID_EQUIVADD,wxID_HOLDADD,wxID_FUNCTADD,wxID_ADDRIDING,
124  wxID_CONSPHASE, wxID_CONSHIST, wxID_CONSHAP, wxID_CONSGLOBAL,wxID_EQUIVALANCEATOMS,
125] = [wx.NewId() for item in range(10)]
126
127[ wxID_RESTRAINTADD, wxID_RESTSELPHASE,wxID_RESTDELETE, wxID_RESRCHANGEVAL, 
128    wxID_RESTCHANGEESD,wxID_AARESTRAINTADD,wxID_AARESTRAINTPLOT,
129] = [wx.NewId() for item in range(7)]
130
131[ wxID_RIGIDBODYADD,wxID_DRAWDEFINERB,wxID_RIGIDBODYIMPORT,wxID_RESIDUETORSSEQ,
132    wxID_AUTOFINDRESRB,wxID_GLOBALRESREFINE,wxID_RBREMOVEALL,wxID_COPYRBPARMS,
133    wxID_GLOBALTHERM,wxID_VECTORBODYADD
134] = [wx.NewId() for item in range(10)]
135
136[ wxID_RENAMESEQSEL,wxID_SAVESEQSEL,wxID_SAVESEQSELCSV,wxID_SAVESEQCSV,wxID_PLOTSEQSEL,
137  wxID_ORGSEQSEL,wxADDSEQVAR,wxDELSEQVAR,wxEDITSEQVAR,wxCOPYPARFIT,wxID_AVESEQSEL,
138  wxADDPARFIT,wxDELPARFIT,wxEDITPARFIT,wxDOPARFIT,
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_COPYPHASE, kind=wx.ITEM_NORMAL,text='Copy phase cell',
1964            help='Copy phase cell from another project')
1965        self.LayerDataEdit.Append(id=wxID_LAYERSIMULATE, kind=wx.ITEM_NORMAL,text='Simulate pattern',
1966            help='Simulate diffraction pattern from layer stacking')
1967        self.LayerDataEdit.Append(id=wxID_SEQUENCESIMULATE, kind=wx.ITEM_NORMAL,text='Sequence simulations',
1968            help='Sequence simulation changing one parameter')
1969        self.PostfillDataMenu()
1970                 
1971        # Phase / Draw Options tab
1972        self.DataDrawOptions = wx.MenuBar()
1973        self.PrefillDataMenu(self.DataDrawOptions,helpType='Draw Options', helpLbl='Phase/Draw Options')
1974        self.DataDrawOptions.Append(menu=wx.Menu(title=''),title='Select tab')
1975        self.PostfillDataMenu()
1976       
1977        # Phase / Draw Atoms tab
1978        self.DrawAtomsMenu = wx.MenuBar()
1979        self.PrefillDataMenu(self.DrawAtomsMenu,helpType='Draw Atoms')
1980        self.DrawAtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1981        self.DrawAtomEdit = wx.Menu(title='')
1982        self.DrawAtomCompute = wx.Menu(title='')
1983        self.DrawAtomRestraint = wx.Menu(title='')
1984        self.DrawAtomRigidBody = wx.Menu(title='')
1985        self.DrawAtomsMenu.Append(menu=self.DrawAtomEdit, title='Edit')
1986        self.DrawAtomsMenu.Append(menu=self.DrawAtomCompute,title='Compute')
1987        self.DrawAtomsMenu.Append(menu=self.DrawAtomRestraint, title='Restraints')
1988        self.DrawAtomsMenu.Append(menu=self.DrawAtomRigidBody, title='Rigid body')
1989        self.DrawAtomEdit.Append(id=wxID_DRAWATOMSTYLE, kind=wx.ITEM_NORMAL,text='Atom style',
1990            help='Select atoms first')
1991        self.DrawAtomEdit.Append(id=wxID_DRAWATOMLABEL, kind=wx.ITEM_NORMAL,text='Atom label',
1992            help='Select atoms first')
1993        self.DrawAtomEdit.Append(id=wxID_DRAWATOMCOLOR, kind=wx.ITEM_NORMAL,text='Atom color',
1994            help='Select atoms first')
1995        self.DrawAtomEdit.Append(id=wxID_DRAWATOMRESETCOLOR, kind=wx.ITEM_NORMAL,text='Reset atom colors',
1996            help='Resets all atom colors to defaults')
1997        self.DrawAtomEdit.Append(id=wxID_DRAWVIEWPOINT, kind=wx.ITEM_NORMAL,text='View point',
1998            help='View point is 1st atom selected')
1999        self.DrawAtomEdit.Append(id=wxID_DRAWADDEQUIV, kind=wx.ITEM_NORMAL,text='Add atoms',
2000            help='Add symmetry & cell equivalents to drawing set from selected atoms')
2001        self.DrawAtomEdit.Append(id=wxID_DRAWTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform draw atoms',
2002            help='Transform selected atoms by symmetry & cell translations')
2003        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCOORD, kind=wx.ITEM_NORMAL,text='Fill CN-sphere',
2004            help='Fill coordination sphere for selected atoms')           
2005        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCELL, kind=wx.ITEM_NORMAL,text='Fill unit cell',
2006            help='Fill unit cell with selected atoms')
2007        self.DrawAtomEdit.Append(id=wxID_DRAWDELETE, kind=wx.ITEM_NORMAL,text='Delete atoms',
2008            help='Delete atoms from drawing set')
2009        self.DrawAtomCompute.Append(id=wxID_DRAWDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2010            help='Compute distance of selected atoms from view point')   
2011        self.DrawAtomCompute.Append(id=wxID_DRAWDISAGLTOR, kind=wx.ITEM_NORMAL,text='Dist. Ang. Tors.',
2012            help='Compute distance, angle or torsion for 2-4 selected atoms')   
2013        self.DrawAtomCompute.Append(id=wxID_DRAWPLANE, kind=wx.ITEM_NORMAL,text='Best plane',
2014            help='Compute best plane for 4+ selected atoms')   
2015        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRBOND, kind=wx.ITEM_NORMAL,text='Add bond restraint',
2016            help='Add bond restraint for selected atoms (2)')
2017        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRANGLE, kind=wx.ITEM_NORMAL,text='Add angle restraint',
2018            help='Add angle restraint for selected atoms (3: one end 1st)')
2019        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRPLANE, kind=wx.ITEM_NORMAL,text='Add plane restraint',
2020            help='Add plane restraint for selected atoms (4+)')
2021        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRCHIRAL, kind=wx.ITEM_NORMAL,text='Add chiral restraint',
2022            help='Add chiral restraint for selected atoms (4: center atom 1st)')
2023        self.DrawAtomRigidBody.Append(id=wxID_DRAWDEFINERB, kind=wx.ITEM_NORMAL,text='Define rigid body',
2024            help='Define rigid body with selected atoms')
2025        self.PostfillDataMenu()
2026
2027        # Phase / MCSA tab
2028        self.MCSAMenu = wx.MenuBar()
2029        self.PrefillDataMenu(self.MCSAMenu,helpType='MC/SA')
2030        self.MCSAMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2031        self.MCSAEdit = wx.Menu(title='')
2032        self.MCSAMenu.Append(menu=self.MCSAEdit, title='MC/SA')
2033        self.MCSAEdit.Append(id=wxID_ADDMCSAATOM, kind=wx.ITEM_NORMAL,text='Add atom', 
2034            help='Add single atom to MC/SA model')
2035        self.MCSAEdit.Append(id=wxID_ADDMCSARB, kind=wx.ITEM_NORMAL,text='Add rigid body', 
2036            help='Add rigid body to MC/SA model' )
2037        self.MCSAEdit.Append(id=wxID_CLEARMCSARB, kind=wx.ITEM_NORMAL,text='Clear rigid bodies', 
2038            help='Clear all atoms & rigid bodies from MC/SA model' )
2039        self.MCSAEdit.Append(id=wxID_MOVEMCSA, kind=wx.ITEM_NORMAL,text='Move MC/SA solution', 
2040            help='Move MC/SA solution to atom list' )
2041        self.MCSAEdit.Append(id=wxID_MCSACLEARRESULTS, kind=wx.ITEM_NORMAL,text='Clear results', 
2042            help='Clear table of MC/SA results' )
2043        self.PostfillDataMenu()
2044           
2045        # Phase / Texture tab
2046        self.TextureMenu = wx.MenuBar()
2047        self.PrefillDataMenu(self.TextureMenu,helpType='Texture')
2048        self.TextureMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2049        self.TextureEdit = wx.Menu(title='')
2050        self.TextureMenu.Append(menu=self.TextureEdit, title='Texture')
2051        self.TextureEdit.Append(id=wxID_REFINETEXTURE, kind=wx.ITEM_NORMAL,text='Refine texture', 
2052            help='Refine the texture coefficients from sequential results')
2053#        self.TextureEdit.Append(id=wxID_CLEARTEXTURE, kind=wx.ITEM_NORMAL,text='Clear texture',
2054#            help='Clear the texture coefficients' )
2055        self.PostfillDataMenu()
2056           
2057        # Phase / Pawley tab
2058        self.PawleyMenu = wx.MenuBar()
2059        self.PrefillDataMenu(self.PawleyMenu,helpType='Pawley')
2060        self.PawleyMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2061        self.PawleyEdit = wx.Menu(title='')
2062        self.PawleyMenu.Append(menu=self.PawleyEdit,title='Operations')
2063        self.PawleyEdit.Append(id=wxID_PAWLEYLOAD, kind=wx.ITEM_NORMAL,text='Pawley create',
2064            help='Initialize Pawley reflection list')
2065        self.PawleyEdit.Append(id=wxID_PAWLEYESTIMATE, kind=wx.ITEM_NORMAL,text='Pawley estimate',
2066            help='Estimate initial Pawley intensities')
2067        self.PawleyEdit.Append(id=wxID_PAWLEYUPDATE, kind=wx.ITEM_NORMAL,text='Pawley update',
2068            help='Update negative Pawley intensities with -0.5*Fobs and turn off refinemnt')
2069        self.PostfillDataMenu()
2070           
2071        # Phase / Map peaks tab
2072        self.MapPeaksMenu = wx.MenuBar()
2073        self.PrefillDataMenu(self.MapPeaksMenu,helpType='Map peaks')
2074        self.MapPeaksMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2075        self.MapPeaksEdit = wx.Menu(title='')
2076        self.MapPeaksMenu.Append(menu=self.MapPeaksEdit, title='Map peaks')
2077        self.MapPeaksEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks', 
2078            help='Move selected peaks to atom list')
2079        self.MapPeaksEdit.Append(id=wxID_PEAKSVIEWPT, kind=wx.ITEM_NORMAL,text='View point',
2080            help='View point is 1st peak selected')
2081        self.MapPeaksEdit.Append(id=wxID_PEAKSDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2082            help='Compute distance of selected peaks from view point')   
2083        self.MapPeaksEdit.Append(id=wxID_SHOWBONDS, kind=wx.ITEM_NORMAL,text='Hide bonds',
2084            help='Hide or show bonds between peak positions')   
2085        self.MapPeaksEdit.Append(id=wxID_PEAKSDA, kind=wx.ITEM_NORMAL,text='Calc dist/ang', 
2086            help='Calculate distance or angle for selection')
2087        self.MapPeaksEdit.Append(id=wxID_FINDEQVPEAKS, kind=wx.ITEM_NORMAL,text='Equivalent peaks', 
2088            help='Find equivalent peaks')
2089        self.MapPeaksEdit.Append(id=wxID_PEAKSUNIQUE, kind=wx.ITEM_NORMAL,text='Unique peaks', 
2090            help='Select unique set')
2091        self.MapPeaksEdit.Append(id=wxID_PEAKSDELETE, kind=wx.ITEM_NORMAL,text='Delete peaks', 
2092            help='Delete selected peaks')
2093        self.MapPeaksEdit.Append(id=wxID_PEAKSCLEAR, kind=wx.ITEM_NORMAL,text='Clear peaks', 
2094            help='Clear the map peak list')
2095        self.PostfillDataMenu()
2096
2097        # Phase / Rigid bodies tab
2098        self.RigidBodiesMenu = wx.MenuBar()
2099        self.PrefillDataMenu(self.RigidBodiesMenu,helpType='Rigid bodies')
2100        self.RigidBodiesMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2101        self.RigidBodiesEdit = wx.Menu(title='')
2102        self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit')
2103        self.RigidBodiesEdit.Append(id=wxID_ASSIGNATMS2RB, kind=wx.ITEM_NORMAL,text='Assign atoms to rigid body',
2104            help='Select & position rigid body in structure of existing atoms')
2105        self.RigidBodiesEdit.Append(id=wxID_AUTOFINDRESRB, kind=wx.ITEM_NORMAL,text='Auto find residues',
2106            help='Auto find of residue RBs in macromolecule')
2107        self.RigidBodiesEdit.Append(id=wxID_COPYRBPARMS, kind=wx.ITEM_NORMAL,text='Copy rigid body parms',
2108            help='Copy rigid body location & TLS parameters')
2109        self.RigidBodiesEdit.Append(id=wxID_GLOBALTHERM, kind=wx.ITEM_NORMAL,text='Global thermal motion',
2110            help='Global setting of residue thermal motion models')
2111        self.RigidBodiesEdit.Append(id=wxID_GLOBALRESREFINE, kind=wx.ITEM_NORMAL,text='Global residue refine',
2112            help='Global setting of residue RB refinement flags')
2113        self.RigidBodiesEdit.Append(id=wxID_RBREMOVEALL, kind=wx.ITEM_NORMAL,text='Remove all rigid bodies',
2114            help='Remove all rigid body assignment for atoms')
2115        self.PostfillDataMenu()
2116    # end of GSAS-II menu definitions
2117       
2118    def _init_ctrls(self, parent,name=None,size=None,pos=None):
2119        wx.Frame.__init__(
2120            self,parent=parent,
2121            #style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT ,
2122            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX,
2123            size=size,pos=pos,title='GSAS-II data display')
2124        self._init_menus()
2125        if name:
2126            self.SetLabel(name)
2127        self.Show()
2128       
2129    def __init__(self,parent,frame,data=None,name=None, size=None,pos=None):
2130        self.G2frame = frame
2131        self._init_ctrls(parent,name,size,pos)
2132        self.data = data
2133        clientSize = wx.ClientDisplayRect()
2134        Size = self.GetSize()
2135        xPos = clientSize[2]-Size[0]
2136        self.SetPosition(wx.Point(xPos,clientSize[1]+250))
2137        self.AtomGrid = []
2138        self.selectedRow = 0
2139       
2140    def setSizePosLeft(self,Width):
2141        clientSize = wx.ClientDisplayRect()
2142        Width[1] = min(Width[1],clientSize[2]-300)
2143        Width[0] = max(Width[0],300)
2144        self.SetSize(Width)
2145#        self.SetPosition(wx.Point(clientSize[2]-Width[0],clientSize[1]+250))
2146       
2147    def Clear(self):
2148        self.ClearBackground()
2149        self.DestroyChildren()
2150                   
2151
2152################################################################################
2153#####  Notebook Tree Item editor
2154################################################################################                 
2155def UpdateNotebook(G2frame,data):
2156    '''Called when the data tree notebook entry is selected. Allows for
2157    editing of the text in that tree entry
2158    '''
2159    def OnNoteBook(event):
2160        data = G2frame.dataDisplay.GetValue().split('\n')
2161        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Notebook'),data)
2162        if 'nt' not in os.name:
2163            G2frame.dataDisplay.AppendText('\n')
2164                   
2165    if G2frame.dataDisplay:
2166        G2frame.dataDisplay.Destroy()
2167    G2frame.dataFrame.SetLabel('Notebook')
2168    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2169        style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
2170    G2frame.dataDisplay.Bind(wx.EVT_TEXT_ENTER,OnNoteBook)
2171    G2frame.dataDisplay.Bind(wx.EVT_KILL_FOCUS,OnNoteBook)
2172    for line in data:
2173        G2frame.dataDisplay.AppendText(line+"\n")
2174    G2frame.dataDisplay.AppendText('Notebook entry @ '+time.ctime()+"\n")
2175    G2frame.dataFrame.setSizePosLeft([400,250])
2176           
2177################################################################################
2178#####  Controls Tree Item editor
2179################################################################################           
2180def UpdateControls(G2frame,data):
2181    '''Edit overall GSAS-II controls in main Controls data tree entry
2182    '''
2183    #patch
2184    if 'deriv type' not in data:
2185        data = {}
2186        data['deriv type'] = 'analytic Hessian'
2187        data['min dM/M'] = 0.0001
2188        data['shift factor'] = 1.
2189        data['max cyc'] = 3       
2190        data['F**2'] = False
2191    if 'shift factor' not in data:
2192        data['shift factor'] = 1.
2193    if 'max cyc' not in data:
2194        data['max cyc'] = 3
2195    if 'F**2' not in data:
2196        data['F**2'] = False
2197    if 'Author' not in data:
2198        data['Author'] = 'no name'
2199    if 'FreePrm1' not in data:
2200        data['FreePrm1'] = 'Sample humidity (%)'
2201    if 'FreePrm2' not in data:
2202        data['FreePrm2'] = 'Sample voltage (V)'
2203    if 'FreePrm3' not in data:
2204        data['FreePrm3'] = 'Applied load (MN)'
2205    if 'Copy2Next' not in data:
2206        data['Copy2Next'] = False
2207    if 'Reverse Seq' not in data:
2208        data['Reverse Seq'] = False
2209    if 'UsrReject' not in data:
2210        data['UsrReject'] = {'minF/sig':0,'MinExt':0.01,'MaxDF/F':20.,'MaxD':500.,'MinD':0.05}
2211    if 'HatomFix' not in data:
2212        data['HatomFix'] = False
2213   
2214    #end patch
2215
2216    def SeqSizer():
2217       
2218        def OnSelectData(event):
2219            choices = GetPatternTreeDataNames(G2frame,['PWDR','HKLF',])
2220            sel = []
2221            try:
2222                if 'Seq Data' in data:
2223                    for item in data['Seq Data']:
2224                        sel.append(choices.index(item))
2225                    sel = [choices.index(item) for item in data['Seq Data']]
2226            except ValueError:  #data changed somehow - start fresh
2227                sel = []
2228            dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential refinement',
2229                'Select dataset to include',choices)
2230            dlg.SetSelections(sel)
2231            names = []
2232            if dlg.ShowModal() == wx.ID_OK:
2233                for sel in dlg.GetSelections():
2234                    names.append(choices[sel])
2235                data['Seq Data'] = names               
2236                G2frame.EnableSeqRefineMenu()
2237            dlg.Destroy()
2238            wx.CallAfter(UpdateControls,G2frame,data)
2239           
2240        def OnReverse(event):
2241            data['Reverse Seq'] = reverseSel.GetValue()
2242           
2243        def OnCopySel(event):
2244            data['Copy2Next'] = copySel.GetValue() 
2245                   
2246        seqSizer = wx.BoxSizer(wx.VERTICAL)
2247        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
2248        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Sequential Refinement: '),0,WACV)
2249        selSeqData = wx.Button(G2frame.dataDisplay,-1,label=' Select data')
2250        selSeqData.Bind(wx.EVT_BUTTON,OnSelectData)
2251        dataSizer.Add(selSeqData,0,WACV)
2252        SeqData = data.get('Seq Data',[])
2253        if not SeqData:
2254            lbl = ' (no data selected)'
2255        else:
2256            lbl = ' ('+str(len(SeqData))+' dataset(s) selected)'
2257
2258        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=lbl),0,WACV)
2259        seqSizer.Add(dataSizer,0)
2260        if SeqData:
2261            selSizer = wx.BoxSizer(wx.HORIZONTAL)
2262            reverseSel = wx.CheckBox(G2frame.dataDisplay,-1,label=' Reverse order?')
2263            reverseSel.Bind(wx.EVT_CHECKBOX,OnReverse)
2264            reverseSel.SetValue(data['Reverse Seq'])
2265            selSizer.Add(reverseSel,0,WACV)
2266            copySel =  wx.CheckBox(G2frame.dataDisplay,-1,label=' Copy results to next histogram?')
2267            copySel.Bind(wx.EVT_CHECKBOX,OnCopySel)
2268            copySel.SetValue(data['Copy2Next'])
2269            selSizer.Add(copySel,0,WACV)
2270            seqSizer.Add(selSizer,0)
2271        return seqSizer
2272       
2273    def LSSizer():       
2274       
2275        def OnDerivType(event):
2276            data['deriv type'] = derivSel.GetValue()
2277            derivSel.SetValue(data['deriv type'])
2278            wx.CallAfter(UpdateControls,G2frame,data)
2279           
2280        def OnConvergence(event):
2281            try:
2282                value = max(1.e-9,min(1.0,float(Cnvrg.GetValue())))
2283            except ValueError:
2284                value = 0.0001
2285            data['min dM/M'] = value
2286            Cnvrg.SetValue('%.2g'%(value))
2287           
2288        def OnMaxCycles(event):
2289            data['max cyc'] = int(maxCyc.GetValue())
2290            maxCyc.SetValue(str(data['max cyc']))
2291                       
2292        def OnFactor(event):
2293            try:
2294                value = min(max(float(Factr.GetValue()),0.00001),100.)
2295            except ValueError:
2296                value = 1.0
2297            data['shift factor'] = value
2298            Factr.SetValue('%.5f'%(value))
2299           
2300        def OnFsqRef(event):
2301            data['F**2'] = fsqRef.GetValue()
2302           
2303        def OnHatomFix(event):
2304            data['HatomFix'] = Hfix.GetValue()
2305       
2306        def OnUsrRej(event):
2307            Obj = event.GetEventObject()
2308            item,limits = Indx[Obj]
2309            try:
2310                value = min(max(float(Obj.GetValue()),limits[0]),limits[1])
2311            except ValueError:
2312                value = data['UsrReject'][item]
2313            data['UsrReject'][item] = value
2314            Obj.SetValue('%.2f'%(value))
2315
2316        LSSizer = wx.FlexGridSizer(cols=4,vgap=5,hgap=5)
2317        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement derivatives: '),0,WACV)
2318        Choice=['analytic Jacobian','numeric','analytic Hessian']
2319        derivSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['deriv type'],choices=Choice,
2320            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2321        derivSel.SetValue(data['deriv type'])
2322        derivSel.Bind(wx.EVT_COMBOBOX, OnDerivType)
2323           
2324        LSSizer.Add(derivSel,0,WACV)
2325        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min delta-M/M: '),0,WACV)
2326        Cnvrg = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2g'%(data['min dM/M']),style=wx.TE_PROCESS_ENTER)
2327        Cnvrg.Bind(wx.EVT_TEXT_ENTER,OnConvergence)
2328        Cnvrg.Bind(wx.EVT_KILL_FOCUS,OnConvergence)
2329        LSSizer.Add(Cnvrg,0,WACV)
2330        Indx = {}
2331        if 'Hessian' in data['deriv type']:
2332            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max cycles: '),0,WACV)
2333            Choice = ['0','1','2','3','5','10','15','20']
2334            maxCyc = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['max cyc']),choices=Choice,
2335                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2336            maxCyc.SetValue(str(data['max cyc']))
2337            maxCyc.Bind(wx.EVT_COMBOBOX, OnMaxCycles)
2338            LSSizer.Add(maxCyc,0,WACV)
2339        else:
2340            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial shift factor: '),0,WACV)
2341            Factr = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.5f'%(data['shift factor']),style=wx.TE_PROCESS_ENTER)
2342            Factr.Bind(wx.EVT_TEXT_ENTER,OnFactor)
2343            Factr.Bind(wx.EVT_KILL_FOCUS,OnFactor)
2344            LSSizer.Add(Factr,0,WACV)
2345        if G2frame.Sngl:
2346            userReject = data['UsrReject']
2347            usrRej = {'minF/sig':[' Min obs/sig (0-5): ',[0,5], ],'MinExt':[' Min extinct. (0-.9): ',[0,.9],],
2348                'MaxDF/F':[' Max delt-F/sig (3-1000): ',[3.,1000.],],'MaxD':[' Max d-spacing (3-500): ',[3,500],],
2349                'MinD':[' Min d-spacing (0.1-2.0): ',[0.1,2.0],]}
2350
2351            fsqRef = wx.CheckBox(G2frame.dataDisplay,-1,label='Refine HKLF as F^2? ')
2352            fsqRef.SetValue(data['F**2'])
2353            fsqRef.Bind(wx.EVT_CHECKBOX,OnFsqRef)
2354            LSSizer.Add(fsqRef,0,WACV)
2355            LSSizer.Add((1,0),)
2356            for item in usrRej:
2357                LSSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=usrRej[item][0]),0,WACV)
2358                usrrej = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(userReject[item]),style=wx.TE_PROCESS_ENTER)
2359                Indx[usrrej] = [item,usrRej[item][1]]
2360                usrrej.Bind(wx.EVT_TEXT_ENTER,OnUsrRej)
2361                usrrej.Bind(wx.EVT_KILL_FOCUS,OnUsrRej)
2362                LSSizer.Add(usrrej,0,WACV)
2363#        Hfix = wx.CheckBox(G2frame.dataDisplay,-1,label='Regularize H atoms? ')
2364#        Hfix.SetValue(data['HatomFix'])
2365#        Hfix.Bind(wx.EVT_CHECKBOX,OnHatomFix)
2366#        LSSizer.Add(Hfix,0,WACV)   #for now
2367        return LSSizer
2368       
2369    def AuthSizer():
2370
2371        def OnAuthor(event):
2372            data['Author'] = auth.GetValue()
2373
2374        Author = data['Author']
2375        authSizer = wx.BoxSizer(wx.HORIZONTAL)
2376        authSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' CIF Author (last, first):'),0,WACV)
2377        auth = wx.TextCtrl(G2frame.dataDisplay,-1,value=Author,style=wx.TE_PROCESS_ENTER)
2378        auth.Bind(wx.EVT_TEXT_ENTER,OnAuthor)
2379        auth.Bind(wx.EVT_KILL_FOCUS,OnAuthor)
2380        authSizer.Add(auth,0,WACV)
2381        return authSizer
2382       
2383       
2384    if G2frame.dataDisplay:
2385        G2frame.dataDisplay.Destroy()
2386    if not G2frame.dataFrame.GetStatusBar():
2387        Status = G2frame.dataFrame.CreateStatusBar()
2388        Status.SetStatusText('')
2389    G2frame.dataFrame.SetLabel('Controls')
2390    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2391    SetDataMenuBar(G2frame,G2frame.dataFrame.ControlsMenu)
2392    mainSizer = wx.BoxSizer(wx.VERTICAL)
2393    mainSizer.Add((5,5),0)
2394    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement Controls:'),0,WACV)   
2395    mainSizer.Add(LSSizer())
2396    mainSizer.Add((5,5),0)
2397    mainSizer.Add(SeqSizer())
2398    mainSizer.Add((5,5),0)
2399    mainSizer.Add(AuthSizer())
2400    mainSizer.Add((5,5),0)
2401       
2402    mainSizer.Layout()   
2403    G2frame.dataDisplay.SetSizer(mainSizer)
2404    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
2405    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
2406     
2407################################################################################
2408#####  Comments
2409################################################################################           
2410       
2411def UpdateComments(G2frame,data):                   
2412
2413    if G2frame.dataDisplay:
2414        G2frame.dataDisplay.Destroy()
2415    G2frame.dataFrame.SetLabel('Comments')
2416    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2417        style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP)
2418    for line in data:
2419        G2frame.dataDisplay.AppendText(line+'\n')
2420    G2frame.dataFrame.setSizePosLeft([400,250])
2421           
2422################################################################################
2423#####  Display of Sequential Results
2424################################################################################           
2425       
2426def UpdateSeqResults(G2frame,data,prevSize=None):
2427    """
2428    Called when the Sequential Results data tree entry is selected
2429    to show results from a sequential refinement.
2430   
2431    :param wx.Frame G2frame: main GSAS-II data tree windows
2432
2433    :param dict data: a dictionary containing the following items: 
2434
2435            * 'histNames' - list of histogram names in order as processed by Sequential Refinement
2436            * 'varyList' - list of variables - identical over all refinements in sequence
2437              note that this is the original list of variables, prior to processing
2438              constraints.
2439            * 'variableLabels' -- a dict of labels to be applied to each parameter
2440              (this is created as an empty dict if not present in data).
2441            * keyed by histName - dictionaries for all data sets processed, which contains:
2442
2443              * 'variables'- result[0] from leastsq call
2444              * 'varyList' - list of variables passed to leastsq call (not same as above)
2445              * 'sig' - esds for variables
2446              * 'covMatrix' - covariance matrix from individual refinement
2447              * 'title' - histogram name; same as dict item name
2448              * 'newAtomDict' - new atom parameters after shifts applied
2449              * 'newCellDict' - refined cell parameters after shifts to A0-A5 from Dij terms applied'
2450    """
2451
2452    def GetSampleParms():
2453        '''Make a dictionary of the sample parameters are not the same over the
2454        refinement series.
2455        '''
2456        if 'IMG' in histNames[0]:
2457            sampleParmDict = {'Sample load':[],}
2458        else:
2459            sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[],
2460                'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[],
2461                'Chi':[],'Phi':[],'Azimuth':[],}
2462        Controls = G2frame.PatternTree.GetItemPyData(
2463            GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2464        sampleParm = {}
2465        for name in histNames:
2466            if 'IMG' in name:
2467                for item in sampleParmDict:
2468                    sampleParmDict[item].append(data[name]['parmDict'].get(item,0))
2469            else:
2470                Id = GetPatternTreeItemId(G2frame,G2frame.root,name)
2471                sampleData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2472                for item in sampleParmDict:
2473                    sampleParmDict[item].append(sampleData.get(item,0))
2474        for item in sampleParmDict:
2475            frstValue = sampleParmDict[item][0]
2476            if np.any(np.array(sampleParmDict[item])-frstValue):
2477                if item.startswith('FreePrm'):
2478                    sampleParm[Controls[item]] = sampleParmDict[item]
2479                else:
2480                    sampleParm[item] = sampleParmDict[item]
2481        return sampleParm
2482
2483    def GetColumnInfo(col):
2484        '''returns column label, lists of values and errors (or None) for each column in the table
2485        for plotting. The column label is reformatted from Unicode to MatPlotLib encoding
2486        '''
2487        colName = G2frame.SeqTable.GetColLabelValue(col)
2488        plotName = variableLabels.get(colName,colName)
2489        plotName = plotSpCharFix(plotName)
2490        return plotName,colList[col],colSigs[col]
2491           
2492    def PlotSelect(event):
2493        'Plots a row (covariance) or column on double-click'
2494        cols = G2frame.dataDisplay.GetSelectedCols()
2495        rows = G2frame.dataDisplay.GetSelectedRows()
2496        if cols:
2497            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2498        elif rows:
2499            name = histNames[rows[0]]       #only does 1st one selected
2500            G2plt.PlotCovariance(G2frame,data[name])
2501        else:
2502            G2frame.ErrorDialog(
2503                'Select row or columns',
2504                'Nothing selected in table. Click on column or row label(s) to plot. N.B. Grid selection can be a bit funky.'
2505                )
2506           
2507    def OnPlotSelSeq(event):
2508        'plot the selected columns or row from menu command'
2509        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2510        rows = G2frame.dataDisplay.GetSelectedRows()
2511        if cols:
2512            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2513        elif rows:
2514            name = histNames[rows[0]]       #only does 1st one selected
2515            G2plt.PlotCovariance(G2frame,data[name])
2516        else:
2517            G2frame.ErrorDialog(
2518                'Select columns',
2519                'No columns or rows selected in table. Click on row or column labels to select fields for plotting.'
2520                )
2521               
2522    def OnAveSelSeq(event):
2523        'average the selected columns from menu command'
2524        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2525        if cols:
2526            for col in cols:
2527                ave = np.mean(GetColumnInfo(col)[1])
2528                sig = np.std(GetColumnInfo(col)[1])
2529                print ' Average for '+G2frame.SeqTable.GetColLabelValue(col)+': '+'%.6g'%(ave)+' +/- '+'%.6g'%(sig)
2530        else:
2531            G2frame.ErrorDialog(
2532                'Select columns',
2533                'No columns selected in table. Click on column labels to select fields for averaging.'
2534                )
2535               
2536    def OnRenameSelSeq(event):
2537        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2538        colNames = [G2frame.SeqTable.GetColLabelValue(c) for c in cols]
2539        newNames = colNames[:]
2540        for i,name in enumerate(colNames):
2541            if name in variableLabels:
2542                newNames[i] = variableLabels[name]
2543        if not cols:
2544            G2frame.ErrorDialog('Select columns',
2545                'No columns selected in table. Click on column labels to select fields for rename.')
2546            return
2547        dlg = G2G.MultiStringDialog(G2frame.dataDisplay,'Set column names',colNames,newNames)
2548        if dlg.Show():
2549            newNames = dlg.GetValues()           
2550            variableLabels.update(dict(zip(colNames,newNames)))
2551        data['variableLabels'] = variableLabels
2552        dlg.Destroy()
2553        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2554        G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
2555           
2556    def OnReOrgSelSeq(event):
2557        'Reorder the columns'
2558        G2G.GetItemOrder(G2frame,VaryListChanges,vallookup,posdict)   
2559        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2560
2561    def OnSaveSelSeqCSV(event):
2562        'export the selected columns to a .csv file from menu command'
2563        OnSaveSelSeq(event,csv=True)
2564       
2565    def OnSaveSeqCSV(event):
2566        'export all columns to a .csv file from menu command'
2567        OnSaveSelSeq(event,csv=True,allcols=True)
2568       
2569    def OnSaveSelSeq(event,csv=False,allcols=False):
2570        'export the selected columns to a .txt or .csv file from menu command'
2571        def WriteCSV():
2572            def WriteList(headerItems):
2573                line = ''
2574                for lbl in headerItems:
2575                    if line: line += ','
2576                    line += '"'+lbl+'"'
2577                return line
2578            head = ['name']
2579            for col in cols:
2580                item = G2frame.SeqTable.GetColLabelValue(col)
2581                # get rid of labels that have Unicode characters
2582                if not all([ord(c) < 128 and ord(c) != 0 for c in item]): item = '?'
2583                if col in havesig:
2584                    head += [item,'esd-'+item]
2585                else:
2586                    head += [item]
2587            SeqFile.write(WriteList(head)+'\n')
2588            for row,name in enumerate(saveNames):
2589                line = '"'+saveNames[row]+'"'
2590                for col in cols:
2591                    if col in havesig:
2592                        line += ','+str(saveData[col][row])+','+str(saveSigs[col][row])
2593                    else:
2594                        line += ','+str(saveData[col][row])
2595                SeqFile.write(line+'\n')
2596        def WriteSeq():
2597            lenName = len(saveNames[0])
2598            line = %s  '%('name'.center(lenName))
2599            for col in cols:
2600                item = G2frame.SeqTable.GetColLabelValue(col)
2601                if col in havesig:
2602                    line += ' %12s %12s '%(item.center(12),'esd'.center(12))
2603                else:
2604                    line += ' %12s '%(item.center(12))
2605            SeqFile.write(line+'\n')
2606            for row,name in enumerate(saveNames):
2607                line = " '%s' "%(saveNames[row])
2608                for col in cols:
2609                    if col in havesig:
2610                        line += ' %12.6f %12.6f '%(saveData[col][row],saveSigs[col][row])
2611                    else:
2612                        line += ' %12.6f '%saveData[col][row]
2613                SeqFile.write(line+'\n')
2614
2615        # start of OnSaveSelSeq code
2616        if allcols:
2617            cols = range(G2frame.SeqTable.GetNumberCols())
2618        else:
2619            cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
2620        nrows = G2frame.SeqTable.GetNumberRows()
2621        if not cols:
2622            G2frame.ErrorDialog('Select columns',
2623                             'No columns selected in table. Click on column labels to select fields for output.')
2624            return
2625        saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(nrows)]
2626        saveData = {}
2627        saveSigs = {}
2628        havesig = []
2629        for col in cols:
2630            name,vals,sigs = GetColumnInfo(col)
2631            saveData[col] = vals
2632            if sigs:
2633                havesig.append(col)
2634                saveSigs[col] = sigs
2635        if csv:
2636            wild = 'CSV output file (*.csv)|*.csv'
2637        else:
2638            wild = 'Text output file (*.txt)|*.txt'
2639        pth = G2G.GetExportPath(G2frame)
2640        dlg = wx.FileDialog(
2641            G2frame,
2642            'Choose text output file for your selection', pth, '', 
2643            wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
2644        try:
2645            if dlg.ShowModal() == wx.ID_OK:
2646                SeqTextFile = dlg.GetPath()
2647                SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) 
2648                SeqFile = open(SeqTextFile,'w')
2649                if csv:
2650                    WriteCSV()
2651                else:
2652                    WriteSeq()
2653                SeqFile.close()
2654        finally:
2655            dlg.Destroy()
2656               
2657    def striphist(var,insChar=''):
2658        'strip a histogram number from a var name'
2659        sv = var.split(':')
2660        if len(sv) <= 1: return var
2661        if sv[1]:
2662            sv[1] = insChar
2663        return ':'.join(sv)
2664       
2665    def plotSpCharFix(lbl):
2666        'Change selected unicode characters to their matplotlib equivalent'
2667        for u,p in [
2668            (u'\u03B1',r'$\alpha$'),
2669            (u'\u03B2',r'$\beta$'),
2670            (u'\u03B3',r'$\gamma$'),
2671            (u'\u0394\u03C7',r'$\Delta\chi$'),
2672            ]:
2673            lbl = lbl.replace(u,p)
2674        return lbl
2675   
2676    def SelectXaxis():
2677        'returns a selected column number (or None) as the X-axis selection'
2678        ncols = G2frame.SeqTable.GetNumberCols()
2679        colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)]
2680        dlg = G2G.G2SingleChoiceDialog(
2681            G2frame.dataDisplay,
2682            'Select x-axis parameter for plot or Cancel for sequence number',
2683            'Select X-axis',
2684            colNames)
2685        try:
2686            if dlg.ShowModal() == wx.ID_OK:
2687                col = dlg.GetSelection()
2688            else:
2689                col = None
2690        finally:
2691            dlg.Destroy()
2692        return col
2693   
2694    def EnablePseudoVarMenus():
2695        'Enables or disables the PseudoVar menu items that require existing defs'
2696        if Controls['SeqPseudoVars']:
2697            val = True
2698        else:
2699            val = False
2700        G2frame.dataFrame.SequentialPvars.Enable(wxDELSEQVAR,val)
2701        G2frame.dataFrame.SequentialPvars.Enable(wxEDITSEQVAR,val)
2702
2703    def DelPseudoVar(event):
2704        'Ask the user to select a pseudo var expression to delete'
2705        choices = Controls['SeqPseudoVars'].keys()
2706        selected = G2G.ItemSelector(
2707            choices,G2frame.dataFrame,
2708            multiple=True,
2709            title='Select expressions to remove',
2710            header='Delete expression')
2711        if selected is None: return
2712        for item in selected:
2713            del Controls['SeqPseudoVars'][choices[item]]
2714        if selected:
2715            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2716
2717    def EditPseudoVar(event):
2718        'Edit an existing pseudo var expression'
2719        choices = Controls['SeqPseudoVars'].keys()
2720        if len(choices) == 1:
2721            selected = 0
2722        else:
2723            selected = G2G.ItemSelector(
2724                choices,G2frame.dataFrame,
2725                multiple=False,
2726                title='Select an expression to edit',
2727                header='Edit expression')
2728        if selected is not None:
2729            dlg = G2exG.ExpressionDialog(
2730                G2frame.dataDisplay,PSvarDict,
2731                Controls['SeqPseudoVars'][choices[selected]],
2732                header="Edit the PseudoVar expression",
2733                VarLabel="PseudoVar #"+str(selected+1),
2734                fit=False)
2735            newobj = dlg.Show(True)
2736            if newobj:
2737                calcobj = G2obj.ExpressionCalcObj(newobj)
2738                del Controls['SeqPseudoVars'][choices[selected]]
2739                Controls['SeqPseudoVars'][calcobj.eObj.expression] = newobj
2740                UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2741       
2742    def AddNewPseudoVar(event):
2743        'Create a new pseudo var expression'
2744        dlg = G2exG.ExpressionDialog(
2745            G2frame.dataDisplay,PSvarDict,
2746            header='Enter an expression for a PseudoVar here',
2747            VarLabel = "New PseudoVar",
2748            fit=False)
2749        obj = dlg.Show(True)
2750        dlg.Destroy()
2751        if obj:
2752            calcobj = G2obj.ExpressionCalcObj(obj)
2753            Controls['SeqPseudoVars'][calcobj.eObj.expression] = obj
2754            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2755
2756    def UpdateParmDict(parmDict):
2757        '''generate the atom positions and the direct & reciprocal cell values,
2758        because they might be needed to evaluate the pseudovar
2759        '''
2760        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2761                         ['A'+str(i) for i in range(6)])
2762                     )
2763        delList = []
2764        phaselist = []
2765        for item in parmDict: 
2766            if ':' not in item: continue
2767            key = item.split(':')
2768            if len(key) < 3: continue
2769            # remove the dA[xyz] terms, they would only bring confusion
2770            if key[2].startswith('dA'):
2771                delList.append(item)
2772            # compute and update the corrected reciprocal cell terms using the Dij values
2773            elif key[2] in Ddict:
2774                if key[0] not in phaselist: phaselist.append(key[0])
2775                akey = key[0]+'::'+Ddict[key[2]]
2776                parmDict[akey] -= parmDict[item]
2777                delList.append(item)
2778        for item in delList:
2779            del parmDict[item]               
2780        for i in phaselist:
2781            pId = int(i)
2782            # apply cell symmetry
2783            A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId])
2784            # convert to direct cell & add the unique terms to the dictionary
2785            for i,val in enumerate(G2lat.A2cell(A)):
2786                if i in uniqCellIndx[pId]:
2787                    lbl = str(pId)+'::'+cellUlbl[i]
2788                    parmDict[lbl] = val
2789            lbl = str(pId)+'::'+'vol'
2790            parmDict[lbl] = G2lat.calc_V(A)
2791        return parmDict
2792
2793    def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD):
2794        '''Evaluate an expression derivative with respect to a
2795        GSAS-II variable name.
2796
2797        Note this likely could be faster if the loop over calcobjs were done
2798        inside after the Dict was created.
2799        '''
2800        step = ESD/10
2801        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2802                         ['A'+str(i) for i in range(6)])
2803                     )
2804        results = []
2805        phaselist = []
2806        VparmDict = sampleDict.copy()
2807        for incr in step,-step:
2808            VparmDict.update(parmDict.copy())           
2809            # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]'
2810            # values are not zeroed: fix that!
2811            VparmDict.update({item:0.0 for item in parmDict if 'dA' in item})
2812            VparmDict[var] += incr
2813            G2mv.Dict2Map(VparmDict,[]) # apply constraints
2814            # generate the atom positions and the direct & reciprocal cell values now, because they might
2815            # needed to evaluate the pseudovar
2816            for item in VparmDict:
2817                if item in sampleDict:
2818                    continue 
2819                if ':' not in item: continue
2820                key = item.split(':')
2821                if len(key) < 3: continue
2822                # apply any new shifts to atom positions
2823                if key[2].startswith('dA'):
2824                    VparmDict[''.join(item.split('d'))] += VparmDict[item]
2825                    VparmDict[item] = 0.0
2826                # compute and update the corrected reciprocal cell terms using the Dij values
2827                if key[2] in Ddict:
2828                    if key[0] not in phaselist: phaselist.append(key[0])
2829                    akey = key[0]+'::'+Ddict[key[2]]
2830                    VparmDict[akey] -= VparmDict[item]
2831            for i in phaselist:
2832                pId = int(i)
2833                # apply cell symmetry
2834                A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId])
2835                # convert to direct cell & add the unique terms to the dictionary
2836                for i,val in enumerate(G2lat.A2cell(A)):
2837                    if i in uniqCellIndx[pId]:
2838                        lbl = str(pId)+'::'+cellUlbl[i]
2839                        VparmDict[lbl] = val
2840                lbl = str(pId)+'::'+'vol'
2841                VparmDict[lbl] = G2lat.calc_V(A)
2842            # dict should be fully updated, use it & calculate
2843            calcobj.SetupCalc(VparmDict)
2844            results.append(calcobj.EvalExpression())
2845        return (results[0] - results[1]) / (2.*step)
2846       
2847    def EnableParFitEqMenus():
2848        'Enables or disables the Parametric Fit menu items that require existing defs'
2849        if Controls['SeqParFitEqList']:
2850            val = True
2851        else:
2852            val = False
2853        G2frame.dataFrame.SequentialPfit.Enable(wxDELPARFIT,val)
2854        G2frame.dataFrame.SequentialPfit.Enable(wxEDITPARFIT,val)
2855        G2frame.dataFrame.SequentialPfit.Enable(wxDOPARFIT,val)
2856
2857    def ParEqEval(Values,calcObjList,varyList):
2858        '''Evaluate the parametric expression(s)
2859        :param list Values: a list of values for each variable parameter
2860        :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj`
2861          expression objects to evaluate
2862        :param list varyList: a list of variable names for each value in Values
2863        '''
2864        result = []
2865        for calcobj in calcObjList:
2866            calcobj.UpdateVars(varyList,Values)
2867            result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig)
2868        return result
2869
2870    def DoParEqFit(event,eqObj=None):
2871        'Parametric fit minimizer'
2872        varyValueDict = {} # dict of variables and their initial values
2873        calcObjList = [] # expression objects, ready to go for each data point
2874        if eqObj is not None:
2875            eqObjList = [eqObj,]
2876        else:
2877            eqObjList = Controls['SeqParFitEqList']
2878        UseFlags = G2frame.SeqTable.GetColValues(0)         
2879        for obj in eqObjList:
2880            expr = obj.expression
2881            # assemble refined vars for this equation
2882            varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()})
2883            # lookup dependent var position
2884            depVar = obj.GetDepVar()
2885            if depVar in colLabels:
2886                indx = colLabels.index(depVar)
2887            else:
2888                raise Exception('Dependent variable '+depVar+' not found')
2889            # assemble a list of the independent variables
2890            indepVars = obj.GetIndependentVars()
2891            # loop over each datapoint
2892            for j,row in enumerate(zip(*colList)):
2893                if not UseFlags[j]: continue
2894                # assemble equations to fit
2895                calcobj = G2obj.ExpressionCalcObj(obj)
2896                # prepare a dict of needed independent vars for this expression
2897                indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
2898                calcobj.SetupCalc(indepVarDict)               
2899                # values and sigs for current value of dependent var
2900                calcobj.depVal = row[indx]
2901                calcobj.depSig = colSigs[indx][j]
2902                calcObjList.append(calcobj)
2903        # varied parameters
2904        varyList = varyValueDict.keys()
2905        values = varyValues = [varyValueDict[key] for key in varyList]
2906        if not varyList:
2907            print 'no variables to refine!'
2908            return
2909        try:
2910            result = so.leastsq(ParEqEval,varyValues,full_output=True,   #ftol=Ftol,
2911                                args=(calcObjList,varyList)
2912                                )
2913            values = result[0]
2914            covar = result[1]
2915            if covar is None:
2916                raise Exception
2917            esdDict = {}
2918            for i,avar in enumerate(varyList):
2919                esdDict[avar] = np.sqrt(covar[i,i])
2920        except:
2921            print('====> Fit failed')
2922            return
2923        print('==== Fit Results ====')
2924        for obj in eqObjList:
2925            obj.UpdateVariedVars(varyList,values)
2926            ind = '      '
2927            print('  '+obj.GetDepVar()+' = '+obj.expression)
2928            for var in obj.assgnVars:
2929                print(ind+var+' = '+obj.assgnVars[var])
2930            for var in obj.freeVars:
2931                avar = "::"+obj.freeVars[var][0]
2932                val = obj.freeVars[var][1]
2933                if obj.freeVars[var][2]:
2934                    print(ind+var+' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar]))
2935                else:
2936                    print(ind+var+' = '+avar + " =" + G2mth.ValEsd(val,0))
2937        # create a plot for each parametric variable
2938        for fitnum,obj in enumerate(eqObjList):
2939            calcobj = G2obj.ExpressionCalcObj(obj)
2940            # lookup dependent var position
2941            indx = colLabels.index(obj.GetDepVar())
2942            # assemble a list of the independent variables
2943            indepVars = obj.GetIndependentVars()           
2944            # loop over each datapoint
2945            fitvals = []
2946            for j,row in enumerate(zip(*colList)):
2947                calcobj.SetupCalc(
2948                    {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
2949                    )
2950                fitvals.append(calcobj.EvalExpression())
2951            G2plt.PlotSelectedSequence(
2952                G2frame,[indx],GetColumnInfo,SelectXaxis,
2953                fitnum,fitvals)
2954
2955    def SingleParEqFit(eqObj):
2956        DoParEqFit(None,eqObj)
2957
2958    def DelParFitEq(event):
2959        'Ask the user to select function to delete'
2960        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2961        selected = G2G.ItemSelector(
2962            txtlst,G2frame.dataFrame,
2963            multiple=True,
2964            title='Select a parametric equation(s) to remove',
2965            header='Delete equation')
2966        if selected is None: return
2967        Controls['SeqParFitEqList'] = [obj for i,obj in enumerate(Controls['SeqParFitEqList']) if i not in selected]
2968        EnableParFitEqMenus()
2969        if Controls['SeqParFitEqList']: DoParEqFit(event)
2970       
2971    def EditParFitEq(event):
2972        'Edit an existing parametric equation'
2973        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2974        if len(txtlst) == 1:
2975            selected = 0
2976        else:
2977            selected = G2G.ItemSelector(
2978                txtlst,G2frame.dataFrame,
2979                multiple=False,
2980                title='Select a parametric equation to edit',
2981                header='Edit equation')
2982        if selected is not None:
2983            dlg = G2exG.ExpressionDialog(
2984                G2frame.dataDisplay,indepVarDict,
2985                Controls['SeqParFitEqList'][selected],
2986                depVarDict=depVarDict,
2987                header="Edit the formula for this minimization function",
2988                ExtraButton=['Fit',SingleParEqFit])
2989            newobj = dlg.Show(True)
2990            if newobj:
2991                calcobj = G2obj.ExpressionCalcObj(newobj)
2992                Controls['SeqParFitEqList'][selected] = newobj
2993                EnableParFitEqMenus()
2994            if Controls['SeqParFitEqList']: DoParEqFit(event)
2995
2996    def AddNewParFitEq(event):
2997        'Create a new parametric equation to be fit to sequential results'
2998
2999        # compile the variable names used in previous freevars to avoid accidental name collisions
3000        usedvarlist = []
3001        for obj in Controls['SeqParFitEqList']:
3002            for var in obj.freeVars:
3003                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3004
3005        dlg = G2exG.ExpressionDialog(
3006            G2frame.dataDisplay,indepVarDict,
3007            depVarDict=depVarDict,
3008            header='Define an equation to minimize in the parametric fit',
3009            ExtraButton=['Fit',SingleParEqFit],
3010            usedVars=usedvarlist)
3011        obj = dlg.Show(True)
3012        dlg.Destroy()
3013        if obj:
3014            Controls['SeqParFitEqList'].append(obj)
3015            EnableParFitEqMenus()
3016            if Controls['SeqParFitEqList']: DoParEqFit(event)
3017               
3018    def CopyParFitEq(event):
3019        'Copy an existing parametric equation to be fit to sequential results'
3020        # compile the variable names used in previous freevars to avoid accidental name collisions
3021        usedvarlist = []
3022        for obj in Controls['SeqParFitEqList']:
3023            for var in obj.freeVars:
3024                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3025        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
3026        if len(txtlst) == 1:
3027            selected = 0
3028        else:
3029            selected = G2G.ItemSelector(
3030                txtlst,G2frame.dataFrame,
3031                multiple=False,
3032                title='Select a parametric equation to copy',
3033                header='Copy equation')
3034        if selected is not None:
3035            newEqn = copy.deepcopy(Controls['SeqParFitEqList'][selected])
3036            for var in newEqn.freeVars:
3037                newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist)
3038            dlg = G2exG.ExpressionDialog(
3039                G2frame.dataDisplay,indepVarDict,
3040                newEqn,
3041                depVarDict=depVarDict,
3042                header="Edit the formula for this minimization function",
3043                ExtraButton=['Fit',SingleParEqFit])
3044            newobj = dlg.Show(True)
3045            if newobj:
3046                calcobj = G2obj.ExpressionCalcObj(newobj)
3047                Controls['SeqParFitEqList'].append(newobj)
3048                EnableParFitEqMenus()
3049            if Controls['SeqParFitEqList']: DoParEqFit(event)
3050                                           
3051    def GridSetToolTip(row,col):
3052        '''Routine to show standard uncertainties for each element in table
3053        as a tooltip
3054        '''
3055        if colSigs[col]:
3056            return u'\u03c3 = '+str(colSigs[col][row])
3057        return ''
3058       
3059    def GridColLblToolTip(col):
3060        '''Define a tooltip for a column. This will be the user-entered value
3061        (from data['variableLabels']) or the default name
3062        '''
3063        if col < 0 or col > len(colLabels):
3064            print 'Illegal column #',col
3065            return
3066        var = colLabels[col]
3067        return variableLabels.get(var,G2obj.fmtVarDescr(var))
3068       
3069    def SetLabelString(event):
3070        '''Define or edit the label for a column in the table, to be used
3071        as a tooltip and for plotting
3072        '''
3073        col = event.GetCol()
3074        if col < 0 or col > len(colLabels):
3075            return
3076        var = colLabels[col]
3077        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
3078        dlg = G2G.SingleStringDialog(G2frame.dataFrame,'Set variable label',
3079                                 'Set a new name for variable '+var,lbl,size=(400,-1))
3080        if dlg.Show():
3081            variableLabels[var] = dlg.GetValue()
3082        dlg.Destroy()
3083       
3084    #def GridRowLblToolTip(row): return 'Row ='+str(row)
3085   
3086    # lookup table for unique cell parameters by symmetry
3087    cellGUIlist = [
3088        [['m3','m3m'],(0,)],
3089        [['3R','3mR'],(0,3)],
3090        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
3091        [['mmm'],(0,1,2)],
3092        [['2/m'+'a'],(0,1,2,3)],
3093        [['2/m'+'b'],(0,1,2,4)],
3094        [['2/m'+'c'],(0,1,2,5)],
3095        [['-1'],(0,1,2,3,4,5)],
3096        ]
3097    # cell labels
3098    cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
3099
3100    #======================================================================
3101    # start processing sequential results here (UpdateSeqResults)
3102    #======================================================================
3103    if not data:
3104        print 'No sequential refinement results'
3105        return
3106    variableLabels = data.get('variableLabels',{})
3107    data['variableLabels'] = variableLabels
3108    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
3109    Controls = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
3110    # create a place to store Pseudo Vars & Parametric Fit functions, if not present
3111    if 'SeqPseudoVars' not in Controls: Controls['SeqPseudoVars'] = {}
3112    if 'SeqParFitEqList' not in Controls: Controls['SeqParFitEqList'] = []
3113    histNames = data['histNames']
3114    if G2frame.dataDisplay:
3115        G2frame.dataDisplay.Destroy()
3116    if not G2frame.dataFrame.GetStatusBar():
3117        Status = G2frame.dataFrame.CreateStatusBar()
3118        Status.SetStatusText("Select column to export; Double click on column to plot data; on row for Covariance")
3119    sampleParms = GetSampleParms()
3120
3121    # make dict of varied atom coords keyed by absolute position
3122    newAtomDict = data[histNames[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
3123    # Possible error: the next might need to be data[histNames[0]]['varyList']
3124    # error will arise if there constraints on coordinates?
3125    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in data['varyList']}
3126   
3127    # make dict of varied cell parameters equivalents
3128    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
3129    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
3130    # N.B. These Dij vars are missing a histogram #
3131    newCellDict = data[histNames[0]].get('newCellDict',{})
3132    for item in newCellDict:
3133        if item in data['varyList']:
3134            ESDlookup[newCellDict[item][0]] = item
3135            Dlookup[item] = newCellDict[item][0]
3136    # add coordinate equivalents to lookup table
3137    for parm in atomLookup:
3138        Dlookup[atomLookup[parm]] = parm
3139        ESDlookup[parm] = atomLookup[parm]
3140
3141    # get unit cell & symmetry for all phases & initial stuff for later use
3142    RecpCellTerms = {}
3143    SGdata = {}
3144    uniqCellIndx = {}
3145    initialCell = {}
3146    RcellLbls = {}
3147    zeroDict = {}
3148    Rcelldict = {}
3149    for phase in Phases:
3150        phasedict = Phases[phase]
3151        pId = phasedict['pId']
3152        pfx = str(pId)+'::' # prefix for A values from phase
3153        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
3154        RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7])
3155        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
3156        SGdata[pId] = phasedict['General']['SGData']
3157        Rcelldict.update({lbl:val for lbl,val in zip(RcellLbls[pId],RecpCellTerms[pId])})
3158        laue = SGdata[pId]['SGLaue']
3159        if laue == '2/m':
3160            laue += SGdata[pId]['SGUniq']
3161        for symlist,celllist in cellGUIlist:
3162            if laue in symlist:
3163                uniqCellIndx[pId] = celllist
3164                break
3165        else: # should not happen
3166            uniqCellIndx[pId] = range(6)
3167        for i in uniqCellIndx[pId]:
3168            initialCell[str(pId)+'::A'+str(i)] =  RecpCellTerms[pId][i]
3169
3170    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
3171    G2frame.dataFrame.SetLabel('Sequential refinement results')
3172    if not G2frame.dataFrame.GetStatusBar():
3173        Status = G2frame.dataFrame.CreateStatusBar()
3174        Status.SetStatusText('')
3175    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=wxID_RENAMESEQSEL)
3176    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
3177    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=wxID_SAVESEQSELCSV)
3178    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=wxID_SAVESEQCSV)
3179    G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=wxID_PLOTSEQSEL)
3180    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAveSelSeq, id=wxID_AVESEQSEL)
3181    G2frame.dataFrame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=wxID_ORGSEQSEL)
3182    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=wxADDSEQVAR)
3183    G2frame.dataFrame.Bind(wx.EVT_MENU, DelPseudoVar, id=wxDELSEQVAR)
3184    G2frame.dataFrame.Bind(wx.EVT_MENU, EditPseudoVar, id=wxEDITSEQVAR)
3185    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewParFitEq, id=wxADDPARFIT)
3186    G2frame.dataFrame.Bind(wx.EVT_MENU, CopyParFitEq, id=wxCOPYPARFIT)
3187    G2frame.dataFrame.Bind(wx.EVT_MENU, DelParFitEq, id=wxDELPARFIT)
3188    G2frame.dataFrame.Bind(wx.EVT_MENU, EditParFitEq, id=wxEDITPARFIT)
3189    G2frame.dataFrame.Bind(wx.EVT_MENU, DoParEqFit, id=wxDOPARFIT)
3190    EnablePseudoVarMenus()
3191    EnableParFitEqMenus()
3192
3193    # scan for locations where the variables change
3194    VaryListChanges = [] # histograms where there is a change
3195    combinedVaryList = []
3196    firstValueDict = {}
3197    vallookup = {}
3198    posdict = {}
3199    prevVaryList = []
3200    for i,name in enumerate(histNames):
3201        for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']):
3202            svar = striphist(var,'*') # wild-carded
3203            if svar not in combinedVaryList:
3204                # add variables to list as they appear
3205                combinedVaryList.append(svar)
3206                firstValueDict[svar] = (val,sig)
3207        if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous
3208            prevVaryList = data[name]['varyList']
3209            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
3210            posdict[name] = {}
3211            for var in data[name]['varyList']:
3212                svar = striphist(var,'*')
3213                posdict[name][combinedVaryList.index(svar)] = svar
3214            VaryListChanges.append(name)
3215    if len(VaryListChanges) > 1:
3216        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,True)
3217    else:
3218        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,False)
3219    #-----------------------------------------------------------------------------------
3220    # build up the data table by columns -----------------------------------------------
3221    nRows = len(histNames)
3222    colList = [nRows*[True]]
3223    colSigs = [None]
3224    colLabels = ['Use']
3225    Types = [wg.GRID_VALUE_BOOL]
3226    # start with Rwp values
3227    if 'IMG ' not in histNames[0][:4]:
3228        colList += [[data[name]['Rvals']['Rwp'] for name in histNames]]
3229        colSigs += [None]
3230        colLabels += ['Rwp']
3231        Types += [wg.GRID_VALUE_FLOAT+':10,3',]
3232    # add % change in Chi^2 in last cycle
3233    if histNames[0][:4] not in ['SASD','IMG '] and Controls.get('ShowCell'):
3234        colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]]
3235        colSigs += [None]
3236        colLabels += [u'\u0394\u03C7\u00B2 (%)']
3237        Types += [wg.GRID_VALUE_FLOAT,]
3238    deltaChiCol = len(colLabels)-1
3239    # add changing sample parameters to table
3240    for key in sampleParms:
3241        colList += [sampleParms[key]]
3242        colSigs += [None]
3243        colLabels += [key]
3244        Types += [wg.GRID_VALUE_FLOAT,]
3245    sampleDict = {}
3246    for i,name in enumerate(histNames):
3247        sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) 
3248    # add unique cell parameters TODO: review this where the cell symmetry changes (when possible)
3249    if Controls.get('ShowCell',False):
3250        for pId in sorted(RecpCellTerms):
3251            pfx = str(pId)+'::' # prefix for A values from phase
3252            cells = []
3253            cellESDs = []
3254            colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
3255            colLabels += [pfx+'Vol']
3256            Types += (1+len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT,]
3257            for name in histNames:
3258                covData = {
3259                    'varyList': [Dlookup.get(striphist(v),v) for v in data[name]['varyList']],
3260                    'covMatrix': data[name]['covMatrix']
3261                    }
3262                A = RecpCellTerms[pId][:] # make copy of starting A values
3263                # update with refined values
3264                for i in range(6):
3265                    var = str(pId)+'::A'+str(i)
3266                    if var in ESDlookup:
3267                        val = data[name]['newCellDict'][ESDlookup[var]][1] # get refined value
3268                        A[i] = val # override with updated value
3269                # apply symmetry
3270                Albls = [pfx+'A'+str(i) for i in range(6)]
3271                cellDict = dict(zip(Albls,A))
3272                A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
3273                # convert to direct cell & add only unique values to table
3274                c = G2lat.A2cell(A)
3275                vol = G2lat.calc_V(A)
3276                cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
3277                cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
3278                cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
3279            colList += zip(*cells)
3280            colSigs += zip(*cellESDs)
3281    # sort out the variables in their selected order
3282    varcols = 0
3283    for d in posdict.itervalues():
3284        varcols = max(varcols,max(d.keys())+1)
3285    # get labels for each column
3286    for i in range(varcols):
3287        lbl = ''
3288        for h in VaryListChanges:
3289            if posdict[h].get(i):
3290                if posdict[h].get(i) in lbl: continue
3291                if lbl != "": lbl += '/'
3292                lbl += posdict[h].get(i)
3293        colLabels.append(lbl)
3294    Types += varcols*[wg.GRID_VALUE_FLOAT]
3295    vals = []
3296    esds = []
3297    varsellist = None        # will be a list of variable names in the order they are selected to appear
3298    # tabulate values for each hist, leaving None for blank columns
3299    for name in histNames:
3300        if name in posdict:
3301            varsellist = [posdict[name].get(i) for i in range(varcols)]
3302            # translate variable names to how they will be used in the headings
3303            vs = [striphist(v,'*') for v in data[name]['varyList']]
3304            # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists
3305            sellist = [vs.index(v) if v is not None else None for v in varsellist]
3306            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])]
3307        if not varsellist: raise Exception()
3308        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
3309        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
3310        #GSASIIpath.IPyBreak()
3311    colList += zip(*vals)
3312    colSigs += zip(*esds)
3313               
3314    # tabulate constrained variables, removing histogram numbers if needed
3315    # from parameter label
3316    depValDict = {}
3317    depSigDict = {}
3318    for name in histNames:
3319        for var in data[name].get('depParmDict',{}):
3320            val,sig = data[name]['depParmDict'][var]
3321            svar = striphist(var,'*')
3322            if svar not in depValDict:
3323               depValDict[svar] = [val]
3324               depSigDict[svar] = [sig]
3325            else:
3326               depValDict[svar].append(val)
3327               depSigDict[svar].append(sig)
3328    # add the dependent constrained variables to the table
3329    for var in sorted(depValDict):
3330        if len(depValDict[var]) != len(histNames): continue
3331        colLabels.append(var)
3332        Types += [wg.GRID_VALUE_FLOAT,]
3333        colSigs += [depSigDict[var]]
3334        colList += [depValDict[var]]
3335
3336    # add atom parameters to table
3337    colLabels += atomLookup.keys()
3338    Types += len(atomLookup)*[wg.GRID_VALUE_FLOAT]
3339    for parm in sorted(atomLookup):
3340        colList += [[data[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
3341        if atomLookup[parm] in data[histNames[0]]['varyList']:
3342            col = data[histNames[0]]['varyList'].index(atomLookup[parm])
3343            colSigs += [[data[name]['sig'][col] for name in histNames]]
3344        else:
3345            colSigs += [None] # should not happen
3346    # evaluate Pseudovars, their ESDs and add them to grid
3347    for expr in Controls['SeqPseudoVars']:
3348        obj = Controls['SeqPseudoVars'][expr]
3349        calcobj = G2obj.ExpressionCalcObj(obj)
3350        valList = []
3351        esdList = []
3352        for seqnum,name in enumerate(histNames):
3353            sigs = data[name]['sig']
3354            G2mv.InitVars()
3355            parmDict = data[name].get('parmDict')
3356            badVary = data[name].get('badVary',[])
3357            constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum])
3358            groups,parmlist,constrDict,fixedList,ihst = constraintInfo
3359            varyList = data[name]['varyList']
3360            parmDict = data[name]['parmDict']
3361            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmDict,SeqHist=ihst)
3362            derivs = np.array(
3363                [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD)
3364                 for var,ESD in zip(varyList,sigs)]
3365                )
3366            esdList.append(np.sqrt(
3367                np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T))
3368                ))
3369            PSvarDict = parmDict.copy()
3370            PSvarDict.update(sampleDict[name])
3371            UpdateParmDict(PSvarDict)
3372            calcobj.UpdateDict(PSvarDict)
3373            valList.append(calcobj.EvalExpression())
3374        if not esdList:
3375            esdList = None
3376        colList += [valList]
3377        colSigs += [esdList]
3378        colLabels += [expr]
3379        Types += [wg.GRID_VALUE_FLOAT,]
3380    #---- table build done -------------------------------------------------------------
3381
3382    # Make dict needed for creating & editing pseudovars (PSvarDict).
3383    name = histNames[0]
3384    parmDict = data[name].get('parmDict')
3385    PSvarDict = parmDict.copy()
3386    PSvarDict.update(sampleParms)
3387    UpdateParmDict(PSvarDict)
3388    # Also dicts of dependent (depVarDict) & independent vars (indepVarDict)
3389    # for Parametric fitting from the data table
3390    parmDict = dict(zip(colLabels,zip(*colList)[0])) # scratch dict w/all values in table
3391    parmDict.update(
3392        {var:val for var,val in data[name].get('newCellDict',{}).values()} #  add varied reciprocal cell terms
3393    )
3394    name = histNames[0]
3395
3396    #******************************************************************************
3397    # create a set of values for example evaluation of pseudovars and
3398    # this does not work for refinements that have differing numbers of variables.
3399    #raise Exception
3400    indepVarDict = {}     #  values in table w/o ESDs
3401    depVarDict = {}
3402    for i,var in enumerate(colLabels):
3403        if var == 'Use': continue
3404        if colList[i][0] is None:
3405            val,sig = firstValueDict.get(var,[None,None])
3406        elif colSigs[i]:
3407            val,sig = colList[i][0],colSigs[i][0]
3408        else:
3409            val,sig = colList[i][0],None
3410        if val is None:
3411            continue
3412        elif sig is None:
3413            indepVarDict[var] = val
3414        elif striphist(var) not in Dlookup:
3415            depVarDict[var] = val
3416    # add recip cell coeff. values
3417    depVarDict.update({var:val for var,val in data[name].get('newCellDict',{}).values()})
3418
3419    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
3420    G2frame.SeqTable = G2G.Table(
3421        [list(c) for c in zip(*colList)],     # convert from columns to rows
3422        colLabels=colLabels,rowLabels=histNames,types=Types)
3423    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
3424    #G2frame.dataDisplay.EnableEditing(False)
3425    # make all but first column read-only
3426    for c in range(1,len(colLabels)):
3427        for r in range(nRows):
3428            G2frame.dataDisplay.SetCellReadOnly(r,c)
3429    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, PlotSelect)
3430    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, SetLabelString)
3431    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
3432    G2frame.dataDisplay.SetMargins(0,0)
3433    G2frame.dataDisplay.AutoSizeColumns(True)
3434    if prevSize:
3435        G2frame.dataDisplay.SetSize(prevSize)
3436    else:
3437        G2frame.dataFrame.setSizePosLeft([700,350])
3438    # highlight unconverged shifts
3439    if histNames[0][:4] not in ['SASD','IMG ']:
3440        for row,name in enumerate(histNames):
3441            deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol)
3442            if deltaChi > 10.:
3443                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0))
3444            elif deltaChi > 1.0:
3445                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0))
3446    G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip)
3447    G2frame.dataDisplay.SendSizeEvent() # resize needed on mac
3448    G2frame.dataDisplay.Refresh() # shows colored text on mac
3449   
3450################################################################################
3451#####  Main PWDR panel
3452################################################################################           
3453       
3454def UpdatePWHKPlot(G2frame,kind,item):
3455    '''Called when the histogram main tree entry is called. Displays the
3456    histogram weight factor, refinement statistics for the histogram
3457    and the range of data for a simulation.
3458
3459    Also invokes a plot of the histogram.
3460    '''
3461    def onEditSimRange(event):
3462        'Edit simulation range'
3463        inp = [
3464            min(data[1][0]),
3465            max(data[1][0]),
3466            None
3467            ]
3468        inp[2] = (inp[1] - inp[0])/(len(data[1][0])-1.)
3469        names = ('start angle', 'end angle', 'step size')
3470        dictlst = [inp] * len(inp)
3471        elemlst = range(len(inp))
3472        dlg = G2G.ScrolledMultiEditor(
3473            G2frame,[inp] * len(inp), range(len(inp)), names,
3474            header='Edit simulation range',
3475            minvals=(0.001,0.001,0.0001),
3476            maxvals=(180.,180.,.1),
3477            )
3478        dlg.CenterOnParent()
3479        val = dlg.ShowModal()
3480        dlg.Destroy()
3481        if val != wx.ID_OK: return
3482        if inp[0] > inp[1]:
3483            end,start,step = inp
3484        else:               
3485            start,end,step = inp
3486        step = abs(step)
3487        N = int((end-start)/step)+1
3488        newdata = np.linspace(start,end,N,True)
3489        if len(newdata) < 2: return # too small a range - reject
3490        data[1] = [newdata,np.zeros_like(newdata),np.ones_like(newdata),
3491            np.zeros_like(newdata),np.zeros_like(newdata),np.zeros_like(newdata)]
3492        Tmin = newdata[0]
3493        Tmax = newdata[-1]
3494        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,item,'Limits'),
3495            [(Tmin,Tmax),[Tmin,Tmax]])
3496        UpdatePWHKPlot(G2frame,kind,item) # redisplay data screen
3497
3498    def OnPlot3DHKL(event):
3499        refList = data[1]['RefList']
3500        FoMax = np.max(refList.T[8+Super])
3501        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3502        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3503        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3504        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
3505            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3506            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3507            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3508        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3509       
3510    def OnPlotAll3DHKL(event):
3511        choices = GetPatternTreeDataNames(G2frame,['HKLF',])
3512        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select reflection sets to plot',
3513            'Use data',choices)
3514        try:
3515            if dlg.ShowModal() == wx.ID_OK:
3516                refNames = [choices[i] for i in dlg.GetSelections()]
3517            else:
3518                return
3519        finally:
3520            dlg.Destroy()
3521        refList = np.zeros(0)
3522        for name in refNames:
3523            Id = GetPatternTreeItemId(G2frame,G2frame.root, name)
3524            reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
3525            if len(refList):
3526                refList = np.concatenate((refList,reflData['RefList']))
3527            else:
3528                refList = reflData['RefList']
3529           
3530        FoMax = np.max(refList.T[8+Super])
3531        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3532        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3533        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3534        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
3535            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3536            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3537            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
3538        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3539                 
3540    def OnMergeHKL(event):
3541        Name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3542        Inst = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,
3543            G2frame.PatternId,'Instrument Parameters'))
3544        CId = GetPatternTreeItemId(G2frame,G2frame.PatternId,'Comments')
3545        if CId:
3546            Comments = G2frame.PatternTree.GetItemPyData(CId)
3547        else:
3548            Comments = []
3549        refList = np.copy(data[1]['RefList'])
3550        Comments.append(' Merging %d reflections from %s'%(len(refList),Name))
3551        dlg = MergeDialog(G2frame,data)
3552        try:
3553            if dlg.ShowModal() == wx.ID_OK:
3554                Trans,Cent,Laue = dlg.GetSelection()
3555            else:
3556                return
3557        finally:
3558            dlg.Destroy()
3559        Super = data[1]['Super']
3560        refList,badRefs = G2lat.transposeHKLF(Trans,Super,refList)
3561        if len(badRefs):    #do I want to list badRefs?
3562            G2frame.ErrorDialog('Failed transformation','Matrix yields fractional hkl indices')
3563            return
3564        Comments.append(" Transformation M*H = H' applied; M=")
3565        Comments.append(str(Trans))
3566        SG = 'P '+Laue
3567        SGData = G2spc.SpcGroup(SG)[1]
3568        refList = G2lat.LaueUnique(Laue,refList)
3569        dlg = wx.ProgressDialog('Build HKL dictonary','',len(refList)+1, 
3570            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
3571        HKLdict = {}
3572        for ih,hkl in enumerate(refList):
3573            if str(hkl[:3+Super]) not in HKLdict:
3574                HKLdict[str(hkl[:3+Super])] = [hkl[:3+Super],[hkl[3+Super:],]]
3575            else:
3576                HKLdict[str(hkl[:3+Super])][1].append(hkl[3+Super:])
3577            dlg.Update(ih)
3578        dlg.Destroy()
3579        mergeRef = []
3580        dlg = wx.ProgressDialog('Processing merge','',len(HKLdict)+1, 
3581            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
3582        sumDf = 0.
3583        sumFo = 0.
3584        for ih,hkl in enumerate(HKLdict):
3585            HKL = HKLdict[hkl]
3586            newHKL = list(HKL[0])+list(HKL[1][0])
3587            if len(HKL[1]) > 1:
3588                fos = np.array(HKL[1])
3589                wFo = 1/fos[:,3]**2
3590                Fo = np.average(fos[:,2],weights=wFo)
3591                std = np.std(fos[:,2])
3592                sig = np.sqrt(np.mean(fos[:,3])**2+std**2)
3593                sumFo += np.sum(fos[:,2])
3594                sumDf += np.sum(np.abs(fos[:,2]-Fo))
3595                dlg.Update(ih)
3596                newHKL[5+Super] = Fo
3597                newHKL[6+Super] = sig
3598                newHKL[8+Super] = Fo
3599            if newHKL[5+Super] > 0.:
3600                mergeRef.append(list(newHKL)) 
3601        dlg.Destroy()
3602        if Super:
3603            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,3),2),1),0)
3604        else:
3605            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,2),1),0)
3606        mergeRef = np.array(mergeRef)
3607        if sumFo:
3608            mtext = ' merge R = %6.2f%s for %d reflections in %s'%(100.*sumDf/sumFo,'%',mergeRef.shape[0],Laue)
3609            print mtext
3610            Comments.append(mtext)
3611        else:
3612            print 'nothing to merge for %s reflections'%(mergeRef.shape[0])
3613        HKLFlist = []
3614        newName = Name+' '+Laue
3615        if G2frame.PatternTree.GetCount():
3616            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3617            while item:
3618                name = G2frame.PatternTree.GetItemText(item)
3619                if name.startswith('HKLF ') and name not in HKLFlist:
3620                    HKLFlist.append(name)
3621                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3622        newName = G2obj.MakeUniqueLabel(newName,HKLFlist)
3623        newData = copy.deepcopy(data)
3624        newData[0]['ranId'] = ran.randint(0,sys.maxint)
3625        newData[1]['RefList'] = mergeRef
3626        Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=newName)
3627        G2frame.PatternTree.SetItemPyData(
3628            G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)
3629        G2frame.PatternTree.SetItemPyData(Id,newData)
3630        G2frame.PatternTree.SetItemPyData(
3631            G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
3632        G2frame.PatternTree.SetItemPyData(
3633            G2frame.PatternTree.AppendItem(Id,text='Reflection List'),{})  #dummy entry for GUI use
3634                   
3635    def OnErrorAnalysis(event):
3636        G2plt.PlotDeltSig(G2frame,kind)
3637       
3638    def OnWtFactor(event):
3639        try:
3640            val = float(wtval.GetValue())
3641        except ValueError:
3642            val = data[0]['wtFactor']
3643        data[0]['wtFactor'] = val
3644        wtval.SetValue('%.3f'%(val))
3645       
3646    def OnCompression(event):
3647        data[0] = int(comp.GetValue())
3648       
3649    def onCopyPlotCtrls(event):
3650        '''Respond to menu item to copy multiple sections from a histogram.
3651        Need this here to pass on the G2frame object.
3652        '''
3653        G2pdG.CopyPlotCtrls(G2frame)
3654
3655    def onCopySelectedItems(event):
3656        '''Respond to menu item to copy multiple sections from a histogram.
3657        Need this here to pass on the G2frame object.
3658        '''
3659        G2pdG.CopySelectedHistItems(G2frame)
3660           
3661    data = G2frame.PatternTree.GetItemPyData(item)
3662#patches
3663    if 'wtFactor' not in data[0]:
3664        data[0] = {'wtFactor':1.0}
3665#    if kind == 'PWDR' and 'Compression' not in data[0]:
3666#        data[0]['Compression'] = 1
3667    #if isinstance(data[1],list) and kind == 'HKLF':
3668    if 'list' in str(type(data[1])) and kind == 'HKLF':
3669        RefData = {'RefList':[],'FF':[]}
3670        for ref in data[1]:
3671            RefData['RefList'].append(ref[:11]+[ref[13],])
3672            RefData['FF'].append(ref[14])
3673        data[1] = RefData
3674        G2frame.PatternTree.SetItemPyData(item,data)
3675#end patches
3676    if G2frame.dataDisplay:
3677        G2frame.dataDisplay.Destroy()
3678    if kind in ['PWDR','SASD']:
3679        SetDataMenuBar(G2frame,G2frame.dataFrame.PWDRMenu)
3680        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
3681        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
3682        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopyPlotCtrls, id=wxID_PLOTCTRLCOPY)
3683    elif kind in ['HKLF',]:
3684        SetDataMenuBar(G2frame,G2frame.dataFrame.HKLFMenu)
3685        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
3686        G2frame.dataFrame.Bind(wx.EVT_MENU, OnMergeHKL, id=wxID_MERGEHKL)
3687        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=wxID_PWD3DHKLPLOT)
3688        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotAll3DHKL, id=wxID_3DALLHKLPLOT)
3689#        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
3690    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
3691   
3692    mainSizer = wx.BoxSizer(wx.VERTICAL)
3693    mainSizer.Add((5,5),)
3694    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
3695    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,WACV)
3696    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
3697    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
3698    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
3699    wtSizer.Add(wtval,0,WACV)
3700#    if kind == 'PWDR':         #possible future compression feature; NB above patch as well
3701#        wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Compression factor: '),0,WACV)
3702#        choice = ['1','2','3','4','5','6']
3703#        comp = wx.ComboBox(parent=G2frame.dataDisplay,choices=choice,
3704#            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3705#        comp.SetValue(str(data[0]['Compression']))
3706#        comp.Bind(wx.EVT_COMBOBOX, OnCompression)
3707#        wtSizer.Add(comp,0,WACV)
3708    mainSizer.Add(wtSizer)
3709    if data[0].get('Dummy'):
3710        simSizer = wx.BoxSizer(wx.HORIZONTAL)
3711        Tmin = min(data[1][0])
3712        Tmax = max(data[1][0])
3713        num = len(data[1][0])
3714        step = (Tmax - Tmin)/(num-1)
3715        t = u'2\u03b8' # 2theta
3716        lbl =  u'Simulation range: {:.2f} to {:.2f} {:s}\nwith {:.4f} steps ({:d} points)'
3717        lbl += u'\n(Edit range resets observed intensities).'
3718        lbl = lbl.format(Tmin,Tmax,t,step,num)
3719        simSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,lbl),
3720                    0,WACV)
3721        but = wx.Button(G2frame.dataDisplay,wx.ID_ANY,"Edit range")
3722        but.Bind(wx.EVT_BUTTON,onEditSimRange)
3723        simSizer.Add(but,0,WACV)
3724        mainSizer.Add(simSizer)
3725    if 'Nobs' in data[0]:
3726        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3727            ' Data residual wR: %.3f%% on %d observations'%(data[0]['wR'],data[0]['Nobs'])))
3728        for value in data[0]:
3729            if 'Nref' in value:
3730                pfx = value.split('Nref')[0]
3731                name = data[0].get(pfx.split(':')[0]+'::Name','?')
3732                if 'SS' in value:
3733                    mainSizer.Add((5,5),)
3734                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For incommensurate phase '+name+':'))
3735                    for m,(Rf2,Rf,Nobs) in enumerate(zip(data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])):
3736                        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3737                            u' m = +/- %d: RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
3738                            (m,Rf2,Rf,Nobs)))
3739                else:
3740                    mainSizer.Add((5,5),)
3741                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For phase '+name+':'))
3742                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
3743                        u' Unweighted phase residuals RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
3744                        (data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])))
3745                   
3746    mainSizer.Add((5,5),)
3747    mainSizer.Layout()   
3748    G2frame.dataDisplay.SetSizer(mainSizer)
3749    Size = mainSizer.Fit(G2frame.dataFrame)
3750    Size[1] += 10
3751    G2frame.dataFrame.setSizePosLeft(Size)
3752    G2frame.PatternTree.SetItemPyData(item,data)
3753    if kind in ['PWDR','SASD']:
3754        NewPlot = True
3755        if 'xylim' in dir(G2frame):
3756            NewPlot = False
3757        G2plt.PlotPatterns(G2frame,plotType=kind,newPlot=NewPlot)
3758    elif kind == 'HKLF':
3759        Name = G2frame.PatternTree.GetItemText(item)
3760        phaseName = G2pdG.IsHistogramInAnyPhase(G2frame,Name)
3761        if phaseName:
3762            pId = GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3763            phaseId =  GetPatternTreeItemId(G2frame,pId,phaseName)
3764            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3765            Super = General.get('Super',0)
3766            SuperVec = General.get('SuperVec',[])
3767        else:
3768            Super = 0
3769            SuperVec = []       
3770        refList = data[1]['RefList']
3771#        GSASIIpath.IPyBreak()
3772        FoMax = np.max(refList.T[5+data[1].get('Super',0)])
3773        page = G2frame.G2plotNB.nb.GetSelection()
3774        tab = ''
3775        if page >= 0:
3776            tab = G2frame.G2plotNB.nb.GetPageText(page)
3777        if '3D' in tab:
3778            Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3779            Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3780            Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3781            Page = G2frame.G2plotNB.nb.GetPage(page)
3782            controls = Page.controls
3783            G2plt.Plot3DSngl(G2frame,newPlot=False,Data=controls,hklRef=refList,Title=phaseName)
3784        else:
3785            controls = {'Type' : 'Fo','ifFc' : True,     
3786                'HKLmax' : [int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))],
3787                'HKLmin' : [int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))],
3788                'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3789            G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList)
3790                 
3791################################################################################
3792#####  Pattern tree routines
3793################################################################################           
3794       
3795def GetPatternTreeDataNames(G2frame,dataTypes):
3796    '''Finds all items in tree that match a 4 character prefix
3797   
3798    :param wx.Frame G2frame: Data tree frame object
3799    :param list dataTypes: Contains one or more data tree item types to be matched
3800      such as ['IMG '] or ['PWDR','HKLF']
3801    :returns: a list of tree item names for the matching items 
3802    '''
3803    names = []
3804    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
3805    while item:
3806        name = G2frame.PatternTree.GetItemText(item)
3807        if name[:4] in dataTypes:
3808            names.append(name)
3809        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3810    return names
3811                         
3812def GetPatternTreeItemId(G2frame, parentId, itemText):
3813    '''Find the tree item that matches the text in itemText starting with parentId
3814
3815    :param wx.Frame G2frame: Data tree frame object
3816    :param wx.TreeItemId parentId: tree item to start search with
3817    :param str itemText: text for tree item
3818    '''
3819    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
3820    while item:
3821        if G2frame.PatternTree.GetItemText(item) == itemText:
3822            return item
3823        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
3824    return 0               
3825
3826def MovePatternTreeToGrid(G2frame,item):
3827    '''Called from GSASII.OnPatternTreeSelChanged when a item is selected on the tree
3828    '''
3829    pickName = G2frame.PatternTree.GetItemText(item)
3830    if G2frame.PickIdText == pickName:
3831        return
3832   
3833    oldPage = None # will be set later if already on a Phase item
3834    if G2frame.dataFrame:
3835        SetDataMenuBar(G2frame)
3836        if G2frame.dataFrame.GetLabel() == 'Comments':
3837            try:
3838                data = [G2frame.dataDisplay.GetValue()]
3839                G2frame.dataDisplay.Clear() 
3840                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
3841                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3842            except:     #clumsy but avoids dead window problem when opening another project
3843                pass
3844        elif G2frame.dataFrame.GetLabel() == 'Notebook':
3845            try:
3846                data = [G2frame.dataDisplay.GetValue()]
3847                G2frame.dataDisplay.Clear() 
3848                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
3849                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3850            except:     #clumsy but avoids dead window problem when opening another project
3851                pass
3852        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
3853            if G2frame.dataDisplay: 
3854                oldPage = G2frame.dataDisplay.GetSelection()
3855        G2frame.dataFrame.Clear()
3856        G2frame.dataFrame.SetLabel('')
3857    else:
3858        #create the frame for the data item window
3859        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
3860        G2frame.dataFrame.PhaseUserSize = None
3861       
3862    G2frame.dataFrame.Raise()           
3863    G2frame.PickId = item
3864    G2frame.PickIdText = None
3865    parentID = G2frame.root
3866    #for i in G2frame.ExportPattern: i.Enable(False)
3867    defWid = [250,150]
3868    if item != G2frame.root:
3869        parentID = G2frame.PatternTree.GetItemParent(item)
3870    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
3871        G2frame.PatternId = item
3872        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
3873            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
3874            G2frame.PatternId = 0
3875            #for i in G2frame.ExportPattern: i.Enable(False)
3876            data = G2frame.PatternTree.GetItemPyData(item)
3877            UpdateNotebook(G2frame,data)
3878        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
3879            G2frame.PatternId = 0
3880            #for i in G2frame.ExportPattern: i.Enable(False)
3881            data = G2frame.PatternTree.GetItemPyData(item)
3882            if not data:           #fill in defaults
3883                data = copy.copy(G2obj.DefaultControls)    #least squares controls
3884                G2frame.PatternTree.SetItemPyData(item,data)                             
3885            for i in G2frame.Refine: i.Enable(True)
3886            G2frame.EnableSeqRefineMenu()
3887            UpdateControls(G2frame,data)
3888        elif G2frame.PatternTree.GetItemText(item) == 'Sequential results':
3889            data = G2frame.PatternTree.GetItemPyData(item)
3890            UpdateSeqResults(G2frame,data)
3891        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
3892            data = G2frame.PatternTree.GetItemPyData(item)
3893            G2frame.dataFrame.setSizePosLeft(defWid)
3894            text = ''
3895            if 'Rvals' in data:
3896                Nvars = len(data['varyList'])
3897                Rvals = data['Rvals']
3898                text = '\nFinal residuals: \nwR = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
3899                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
3900                if 'lamMax' in Rvals:
3901                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
3902            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
3903                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
3904            G2plt.PlotCovariance(G2frame,data)
3905        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
3906            data = G2frame.PatternTree.GetItemPyData(item)
3907            G2cnstG.UpdateConstraints(G2frame,data)
3908        elif G2frame.PatternTree.GetItemText(item) == 'Rigid bodies':
3909            data = G2frame.PatternTree.GetItemPyData(item)
3910            G2cnstG.UpdateRigidBodies(G2frame,data)
3911        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
3912            data = G2frame.PatternTree.GetItemPyData(item)
3913            Phases = G2frame.GetPhaseData()
3914            phase = ''
3915            phaseName = ''
3916            if Phases:
3917                phaseName = Phases.keys()[0]
3918            G2frame.dataFrame.setSizePosLeft(defWid)
3919            G2restG.UpdateRestraints(G2frame,data,Phases,phaseName)
3920        elif 'IMG' in G2frame.PatternTree.GetItemText(item):
3921            G2frame.Image = item
3922            G2frame.dataFrame.SetTitle('Image Data')
3923            data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(
3924                G2frame,item,'Image Controls'))
3925            G2imG.UpdateImageData(G2frame,data)
3926            G2plt.PlotImage(G2frame,newPlot=True)
3927        elif 'PKS' in G2frame.PatternTree.GetItemText(item):
3928            G2plt.PlotPowderLines(G2frame)
3929        elif 'PWDR' in G2frame.PatternTree.GetItemText(item):
3930            #for i in G2frame.ExportPattern: i.Enable(True)
3931            if G2frame.EnablePlot:
3932                UpdatePWHKPlot(G2frame,'PWDR',item)
3933        elif 'SASD' in G2frame.PatternTree.GetItemText(item):
3934            #for i in G2frame.ExportPattern: i.Enable(True)
3935            if G2frame.EnablePlot:
3936                UpdatePWHKPlot(G2frame,'SASD',item)
3937        elif 'HKLF' in G2frame.PatternTree.GetItemText(item):
3938            G2frame.Sngl = True
3939            UpdatePWHKPlot(G2frame,'HKLF',item)
3940        elif 'PDF' in G2frame.PatternTree.GetItemText(item):
3941            G2frame.PatternId = item
3942            for i in G2frame.ExportPDF: i.Enable(True)
3943            G2plt.PlotISFG(G2frame,type='S(Q)')
3944        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
3945            G2frame.dataFrame.setSizePosLeft(defWid)
3946            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
3947                value='Select one phase to see its parameters')           
3948    elif 'I(Q)' in G2frame.PatternTree.GetItemText(item):
3949        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3950        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3951        G2pdG.UpdatePDFGrid(G2frame,data)
3952        G2plt.PlotISFG(G2frame,type='I(Q)',newPlot=True)
3953    elif 'S(Q)' in G2frame.PatternTree.GetItemText(item):
3954        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3955        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3956        G2pdG.UpdatePDFGrid(G2frame,data)
3957        G2plt.PlotISFG(G2frame,type='S(Q)',newPlot=True)
3958    elif 'F(Q)' in G2frame.PatternTree.GetItemText(item):
3959        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3960        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3961        G2pdG.UpdatePDFGrid(G2frame,data)
3962        G2plt.PlotISFG(G2frame,type='F(Q)',newPlot=True)
3963    elif 'G(R)' in G2frame.PatternTree.GetItemText(item):
3964        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3965        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3966        G2pdG.UpdatePDFGrid(G2frame,data)
3967        G2plt.PlotISFG(G2frame,type='G(R)',newPlot=True)           
3968    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
3969        data = G2frame.PatternTree.GetItemPyData(item)
3970        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
3971    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
3972        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
3973        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3974        data = G2frame.PatternTree.GetItemPyData(item)
3975        UpdateComments(G2frame,data)
3976    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
3977        G2frame.dataFrame.SetTitle('Image Controls')
3978        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3979        masks = G2frame.PatternTree.GetItemPyData(
3980            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
3981        data = G2frame.PatternTree.GetItemPyData(item)
3982        G2imG.UpdateImageControls(G2frame,data,masks)
3983        G2plt.PlotImage(G2frame,newPlot=True)
3984    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
3985        G2frame.dataFrame.SetTitle('Masks')
3986        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3987        data = G2frame.PatternTree.GetItemPyData(item)
3988        G2imG.UpdateMasks(G2frame,data)
3989        G2plt.PlotImage(G2frame,newPlot=True)
3990    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
3991        G2frame.dataFrame.SetTitle('Stress/Strain')
3992        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3993        data = G2frame.PatternTree.GetItemPyData(item)
3994        G2plt.PlotImage(G2frame,newPlot=True)
3995        G2plt.PlotStrain(G2frame,data,newPlot=True)
3996        G2imG.UpdateStressStrain(G2frame,data)
3997    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
3998        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3999        for i in G2frame.ExportPDF: i.Enable(True)
4000        data = G2frame.PatternTree.GetItemPyData(item)
4001        G2pdG.UpdatePDFGrid(G2frame,data)
4002        G2plt.PlotISFG(G2frame,type='I(Q)')
4003        G2plt.PlotISFG(G2frame,type='S(Q)')
4004        G2plt.PlotISFG(G2frame,type='F(Q)')
4005        G2plt.PlotISFG(G2frame,type='G(R)')
4006    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
4007        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4008        for i in G2frame.ExportPeakList: i.Enable(True)
4009        data = G2frame.PatternTree.GetItemPyData(item)
4010#patch
4011        if 'list' in str(type(data)):
4012            data = {'peaks':data,'sigDict':{}}
4013            G2frame.PatternTree.SetItemPyData(item,data)
4014#end patch
4015        G2pdG.UpdatePeakGrid(G2frame,data)
4016        G2plt.PlotPatterns(G2frame)
4017    elif G2frame.PatternTree.GetItemText(item) == 'Background':
4018        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4019        data = G2frame.PatternTree.GetItemPyData(item)
4020        G2pdG.UpdateBackground(G2frame,data)
4021        G2plt.PlotPatterns(G2frame)
4022    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
4023        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4024        datatype = G2frame.PatternTree.GetItemText(G2frame.PatternId)[:4]
4025        data = G2frame.PatternTree.GetItemPyData(item)
4026        G2pdG.UpdateLimitsGrid(G2frame,data,datatype)
4027        G2plt.PlotPatterns(G2frame,plotType=datatype)
4028    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
4029        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4030        data = G2frame.PatternTree.GetItemPyData(item)[0]
4031        G2pdG.UpdateInstrumentGrid(G2frame,data)
4032        if 'P' in data['Type'][0]:          #powder data only
4033            G2plt.PlotPeakWidths(G2frame)
4034    elif G2frame.PatternTree.GetItemText(item) == 'Models':
4035        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4036        data = G2frame.PatternTree.GetItemPyData(item)
4037        G2pdG.UpdateModelsGrid(G2frame,data)
4038        G2plt.PlotPatterns(G2frame,plotType='SASD')
4039        if len(data['Size']['Distribution']):
4040            G2plt.PlotSASDSizeDist(G2frame)
4041    elif G2frame.PatternTree.GetItemText(item) == 'Substances':
4042        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4043        data = G2frame.PatternTree.GetItemPyData(item)
4044        G2pdG.UpdateSubstanceGrid(G2frame,data)
4045    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
4046        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4047        data = G2frame.PatternTree.GetItemPyData(item)
4048        datatype = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[2][:4]
4049
4050        if 'Temperature' not in data:           #temp fix for old gpx files
4051            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
4052                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,
4053                    'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
4054                    'Gonio. radius':200.0}
4055            G2frame.PatternTree.SetItemPyData(item,data)
4056   
4057        G2pdG.UpdateSampleGrid(G2frame,data)
4058        G2plt.PlotPatterns(G2frame,plotType=datatype)
4059    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
4060        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4061        for i in G2frame.ExportPeakList: i.Enable(True)
4062        data = G2frame.PatternTree.GetItemPyData(item)
4063#patch
4064        if len(data) != 2:
4065            data = [data,[]]
4066            G2frame.PatternTree.SetItemPyData(item,data)
4067#end patch
4068        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
4069        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4070            G2plt.PlotPowderLines(G2frame)
4071        else:
4072            G2plt.PlotPatterns(G2frame)
4073    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
4074        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4075        data = G2frame.PatternTree.GetItemPyData(item)
4076        if not data:
4077            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
4078            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
4079            data.append([])                                 #empty cell list
4080            data.append([])                                 #empty dmin
4081            data.append({})                                 #empty superlattice stuff
4082            G2frame.PatternTree.SetItemPyData(item,data)                             
4083#patch
4084        if len(data) < 5:
4085            data.append({'Use':False,'ModVec':[0,0,0.1],'maxH':1,'ssSymb':''})                                 #empty superlattice stuff
4086            G2frame.PatternTree.SetItemPyData(item,data) 
4087#end patch
4088        G2pdG.UpdateUnitCellsGrid(G2frame,data)
4089        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4090            G2plt.PlotPowderLines(G2frame)
4091        else:
4092            G2plt.PlotPatterns(G2frame)
4093    elif G2frame.PatternTree.GetItemText(item) == 'Reflection Lists':   #powder reflections
4094        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4095        data = G2frame.PatternTree.GetItemPyData(item)
4096        G2frame.RefList = ''
4097        if len(data):
4098            G2frame.RefList = data.keys()[0]
4099        G2pdG.UpdateReflectionGrid(G2frame,data)
4100        G2plt.PlotPatterns(G2frame)
4101    elif G2frame.PatternTree.GetItemText(item) == 'Reflection List':    #HKLF reflections
4102        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4103        name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
4104        data = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
4105        G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
4106
4107    if G2frame.PickId:
4108        G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
4109    G2frame.dataFrame.Raise()
4110
4111def SetDataMenuBar(G2frame,menu=None):
4112    '''Set the menu for the data frame. On the Mac put this
4113    menu for the data tree window instead.
4114
4115    Note that data frame items do not have menus, for these (menu=None)
4116    display a blank menu or on the Mac display the standard menu for
4117    the data tree window.
4118    '''
4119    if sys.platform == "darwin":
4120        if menu is None:
4121            G2frame.SetMenuBar(G2frame.GSASIIMenu)
4122        else:
4123            G2frame.SetMenuBar(menu)
4124    else:
4125        if menu is None:
4126            G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
4127        else:
4128            G2frame.dataFrame.SetMenuBar(menu)
4129
4130def HowDidIgetHere():
4131    '''Show a traceback with calls that brought us to the current location.
4132    Used for debugging.
4133    '''
4134    import traceback
4135    print 70*'*'   
4136    for i in traceback.format_list(traceback.extract_stack()[:-1]): print(i.strip.rstrip())
4137    print 70*'*'   
4138       
Note: See TracBrowser for help on using the repository browser.