source: trunk/GSASIIgrid.py @ 1907

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

comment out the G2plotNB.clear in OnRefine? so that the new plot will have the same limits as the old one before refinement

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