source: trunk/GSASIIgrid.py @ 1894

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

Twins & Flack parameter can't exist together - make each exclusive
rename TwinFr?;n as TwinFr:n so constraint will work
Add a "Clear" option for fixed background points
Prevent Add, Move, Del ops. for fixed points when toolbar active

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