source: trunk/GSASIIgrid.py @ 2212

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

Implement 'abc*' as one of the 'Common' cell transformations.
Transformations now transforms atom positions & Uijs
Fix problem in ImageGUI where load controls didn't update the image plot correctly.

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