source: trunk/GSASIIgrid.py @ 2228

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

fixes to Transform of unit cell contents

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