source: trunk/GSASIIgrid.py @ 1840

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

Add an export routine (NB: not in exports!) for Unit Cell results as csv file (request by Angus Lawson)

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