source: trunk/GSASIIgrid.py @ 2082

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

provide autoint interpolation table; merge into std GSAS-II version

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