source: trunk/GSASIIgrid.py @ 2211

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

some work on Transform Phase menu item.
uncomment the if Page.context lines in OGL plots to make multistructure plots behave.
Trap trying to plot reflections when none available.

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