source: trunk/GSASIIgrid.py @ 1889

Last change on this file since 1889 was 1889, checked in by toby, 7 years ago

Add fixed background points; animate dragging points and lines; add fixed bkg fit routine (bkg peaks buggy\!)

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