source: trunk/GSASIIgrid.py @ 2033

Last change on this file since 2033 was 2033, checked in by toby, 6 years ago

change a few imports for RTFD

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