source: trunk/GSASIIgrid.py @ 2219

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

allow fractions in transformation matrix/vector elements
fix cell doubling transformations

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