source: trunk/GSASIIgrid.py @ 1926

Last change on this file since 1926 was 1926, checked in by vondreele, 8 years ago

Work on add Hydrogens

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