source: trunk/GSASIIgrid.py @ 2195

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

remove selected area image multiplier - not necessary
fix image scaling issues for selected area simulations
fix issues with absent pydiffaxlib & DIFFaX.exe on some platforms

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