source: trunk/GSASIIgrid.py @ 1878

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

refactor DDataGUI - mostly move event routines to be inside respective sizer routines
Enable Flack parameter - function OK; derivatives need work
Allow inversion of noncentrosymmetric structures in SymOpDialog? - to test enantiomers
some work to make pdf stuff neutron TOF friendly - not complete
fix Debye background function - now works; refactor result printing for it

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