source: trunk/GSASIIgrid.py @ 2154

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

remove range restriction on LGmix - inhibited doing refinements
do wx.CallAfter? for size/strain plots in G2ddataGUI
Add TransformDialog?, prodMGMT, TransformCell?, TransformU6, TransformXYZ to G2lattice
A start on TransformAtoms? in G2math
fill in OnTransform?

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