source: trunk/GSASIIgrid.py @ 2109

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

Andrey's enhancement: keep track of last GPX, import & export directories; optionally save the 1st two

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 161.5 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIgrid - data display routines
3########### SVN repository information ###################
4# $Date: 2015-12-27 04:22:09 +0000 (Sun, 27 Dec 2015) $
5# $Author: toby $
6# $Revision: 2109 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 2109 2015-12-27 04:22:09Z 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: 2109 $")
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        pth = G2G.GetExportPath(G2frame)
1970        dlg = wx.FileDialog(
1971            G2frame,
1972            'Choose text output file for your selection', pth, '', 
1973            wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1974        try:
1975            if dlg.ShowModal() == wx.ID_OK:
1976                SeqTextFile = dlg.GetPath()
1977                SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) 
1978                SeqFile = open(SeqTextFile,'w')
1979                if csv:
1980                    WriteCSV()
1981                else:
1982                    WriteSeq()
1983                SeqFile.close()
1984        finally:
1985            dlg.Destroy()
1986               
1987    def striphist(var,insChar=''):
1988        'strip a histogram number from a var name'
1989        sv = var.split(':')
1990        if len(sv) <= 1: return var
1991        if sv[1]:
1992            sv[1] = insChar
1993        return ':'.join(sv)
1994       
1995    def plotSpCharFix(lbl):
1996        'Change selected unicode characters to their matplotlib equivalent'
1997        for u,p in [
1998            (u'\u03B1',r'$\alpha$'),
1999            (u'\u03B2',r'$\beta$'),
2000            (u'\u03B3',r'$\gamma$'),
2001            (u'\u0394\u03C7',r'$\Delta\chi$'),
2002            ]:
2003            lbl = lbl.replace(u,p)
2004        return lbl
2005   
2006    def SelectXaxis():
2007        'returns a selected column number (or None) as the X-axis selection'
2008        ncols = G2frame.SeqTable.GetNumberCols()
2009        colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)]
2010        dlg = G2G.G2SingleChoiceDialog(
2011            G2frame.dataDisplay,
2012            'Select x-axis parameter for plot or Cancel for sequence number',
2013            'Select X-axis',
2014            colNames)
2015        try:
2016            if dlg.ShowModal() == wx.ID_OK:
2017                col = dlg.GetSelection()
2018            else:
2019                col = None
2020        finally:
2021            dlg.Destroy()
2022        return col
2023   
2024    def EnablePseudoVarMenus():
2025        'Enables or disables the PseudoVar menu items that require existing defs'
2026        if Controls['SeqPseudoVars']:
2027            val = True
2028        else:
2029            val = False
2030        G2frame.dataFrame.SequentialPvars.Enable(wxDELSEQVAR,val)
2031        G2frame.dataFrame.SequentialPvars.Enable(wxEDITSEQVAR,val)
2032
2033    def DelPseudoVar(event):
2034        'Ask the user to select a pseudo var expression to delete'
2035        choices = Controls['SeqPseudoVars'].keys()
2036        selected = G2G.ItemSelector(
2037            choices,G2frame.dataFrame,
2038            multiple=True,
2039            title='Select expressions to remove',
2040            header='Delete expression')
2041        if selected is None: return
2042        for item in selected:
2043            del Controls['SeqPseudoVars'][choices[item]]
2044        if selected:
2045            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2046
2047    def EditPseudoVar(event):
2048        'Edit an existing pseudo var expression'
2049        choices = Controls['SeqPseudoVars'].keys()
2050        if len(choices) == 1:
2051            selected = 0
2052        else:
2053            selected = G2G.ItemSelector(
2054                choices,G2frame.dataFrame,
2055                multiple=False,
2056                title='Select an expression to edit',
2057                header='Edit expression')
2058        if selected is not None:
2059            dlg = G2exG.ExpressionDialog(
2060                G2frame.dataDisplay,PSvarDict,
2061                Controls['SeqPseudoVars'][choices[selected]],
2062                header="Edit the PseudoVar expression",
2063                VarLabel="PseudoVar #"+str(selected+1),
2064                fit=False)
2065            newobj = dlg.Show(True)
2066            if newobj:
2067                calcobj = G2obj.ExpressionCalcObj(newobj)
2068                del Controls['SeqPseudoVars'][choices[selected]]
2069                Controls['SeqPseudoVars'][calcobj.eObj.expression] = newobj
2070                UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2071       
2072    def AddNewPseudoVar(event):
2073        'Create a new pseudo var expression'
2074        dlg = G2exG.ExpressionDialog(
2075            G2frame.dataDisplay,PSvarDict,
2076            header='Enter an expression for a PseudoVar here',
2077            VarLabel = "New PseudoVar",
2078            fit=False)
2079        obj = dlg.Show(True)
2080        dlg.Destroy()
2081        if obj:
2082            calcobj = G2obj.ExpressionCalcObj(obj)
2083            Controls['SeqPseudoVars'][calcobj.eObj.expression] = obj
2084            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2085
2086    def UpdateParmDict(parmDict):
2087        '''generate the atom positions and the direct & reciprocal cell values,
2088        because they might be needed to evaluate the pseudovar
2089        '''
2090        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2091                         ['A'+str(i) for i in range(6)])
2092                     )
2093        delList = []
2094        phaselist = []
2095        for item in parmDict: 
2096            if ':' not in item: continue
2097            key = item.split(':')
2098            if len(key) < 3: continue
2099            # remove the dA[xyz] terms, they would only bring confusion
2100            if key[2].startswith('dA'):
2101                delList.append(item)
2102            # compute and update the corrected reciprocal cell terms using the Dij values
2103            elif key[2] in Ddict:
2104                if key[0] not in phaselist: phaselist.append(key[0])
2105                akey = key[0]+'::'+Ddict[key[2]]
2106                parmDict[akey] -= parmDict[item]
2107                delList.append(item)
2108        for item in delList:
2109            del parmDict[item]               
2110        for i in phaselist:
2111            pId = int(i)
2112            # apply cell symmetry
2113            A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId])
2114            # convert to direct cell & add the unique terms to the dictionary
2115            for i,val in enumerate(G2lat.A2cell(A)):
2116                if i in uniqCellIndx[pId]:
2117                    lbl = str(pId)+'::'+cellUlbl[i]
2118                    parmDict[lbl] = val
2119            lbl = str(pId)+'::'+'vol'
2120            parmDict[lbl] = G2lat.calc_V(A)
2121        return parmDict
2122
2123    def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD):
2124        '''Evaluate an expression derivative with respect to a
2125        GSAS-II variable name.
2126
2127        Note this likely could be faster if the loop over calcobjs were done
2128        inside after the Dict was created.
2129        '''
2130        step = ESD/10
2131        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2132                         ['A'+str(i) for i in range(6)])
2133                     )
2134        results = []
2135        phaselist = []
2136        VparmDict = sampleDict.copy()
2137        for incr in step,-step:
2138            VparmDict.update(parmDict.copy())           
2139            # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]'
2140            # values are not zeroed: fix that!
2141            VparmDict.update({item:0.0 for item in parmDict if 'dA' in item})
2142            VparmDict[var] += incr
2143            G2mv.Dict2Map(VparmDict,[]) # apply constraints
2144            # generate the atom positions and the direct & reciprocal cell values now, because they might
2145            # needed to evaluate the pseudovar
2146            for item in VparmDict:
2147                if item in sampleDict:
2148                    continue 
2149                if ':' not in item: continue
2150                key = item.split(':')
2151                if len(key) < 3: continue
2152                # apply any new shifts to atom positions
2153                if key[2].startswith('dA'):
2154                    VparmDict[''.join(item.split('d'))] += VparmDict[item]
2155                    VparmDict[item] = 0.0
2156                # compute and update the corrected reciprocal cell terms using the Dij values
2157                if key[2] in Ddict:
2158                    if key[0] not in phaselist: phaselist.append(key[0])
2159                    akey = key[0]+'::'+Ddict[key[2]]
2160                    VparmDict[akey] -= VparmDict[item]
2161            for i in phaselist:
2162                pId = int(i)
2163                # apply cell symmetry
2164                A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId])
2165                # convert to direct cell & add the unique terms to the dictionary
2166                for i,val in enumerate(G2lat.A2cell(A)):
2167                    if i in uniqCellIndx[pId]:
2168                        lbl = str(pId)+'::'+cellUlbl[i]
2169                        VparmDict[lbl] = val
2170                lbl = str(pId)+'::'+'vol'
2171                VparmDict[lbl] = G2lat.calc_V(A)
2172            # dict should be fully updated, use it & calculate
2173            calcobj.SetupCalc(VparmDict)
2174            results.append(calcobj.EvalExpression())
2175        return (results[0] - results[1]) / (2.*step)
2176       
2177    def EnableParFitEqMenus():
2178        'Enables or disables the Parametric Fit menu items that require existing defs'
2179        if Controls['SeqParFitEqList']:
2180            val = True
2181        else:
2182            val = False
2183        G2frame.dataFrame.SequentialPfit.Enable(wxDELPARFIT,val)
2184        G2frame.dataFrame.SequentialPfit.Enable(wxEDITPARFIT,val)
2185        G2frame.dataFrame.SequentialPfit.Enable(wxDOPARFIT,val)
2186
2187    def ParEqEval(Values,calcObjList,varyList):
2188        '''Evaluate the parametric expression(s)
2189        :param list Values: a list of values for each variable parameter
2190        :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj`
2191          expression objects to evaluate
2192        :param list varyList: a list of variable names for each value in Values
2193        '''
2194        result = []
2195        for calcobj in calcObjList:
2196            calcobj.UpdateVars(varyList,Values)
2197            result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig)
2198        return result
2199
2200    def DoParEqFit(event,eqObj=None):
2201        'Parametric fit minimizer'
2202        varyValueDict = {} # dict of variables and their initial values
2203        calcObjList = [] # expression objects, ready to go for each data point
2204        if eqObj is not None:
2205            eqObjList = [eqObj,]
2206        else:
2207            eqObjList = Controls['SeqParFitEqList']
2208        UseFlags = G2frame.SeqTable.GetColValues(0)         
2209        for obj in eqObjList:
2210            expr = obj.expression
2211            # assemble refined vars for this equation
2212            varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()})
2213            # lookup dependent var position
2214            depVar = obj.GetDepVar()
2215            if depVar in colLabels:
2216                indx = colLabels.index(depVar)
2217            else:
2218                raise Exception('Dependent variable '+depVar+' not found')
2219            # assemble a list of the independent variables
2220            indepVars = obj.GetIndependentVars()
2221            # loop over each datapoint
2222            for j,row in enumerate(zip(*colList)):
2223                if not UseFlags[j]: continue
2224                # assemble equations to fit
2225                calcobj = G2obj.ExpressionCalcObj(obj)
2226                # prepare a dict of needed independent vars for this expression
2227                indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
2228                calcobj.SetupCalc(indepVarDict)               
2229                # values and sigs for current value of dependent var
2230                calcobj.depVal = row[indx]
2231                calcobj.depSig = colSigs[indx][j]
2232                calcObjList.append(calcobj)
2233        # varied parameters
2234        varyList = varyValueDict.keys()
2235        values = varyValues = [varyValueDict[key] for key in varyList]
2236        if not varyList:
2237            print 'no variables to refine!'
2238            return
2239        try:
2240            result = so.leastsq(ParEqEval,varyValues,full_output=True,   #ftol=Ftol,
2241                                args=(calcObjList,varyList)
2242                                )
2243            values = result[0]
2244            covar = result[1]
2245            if covar is None:
2246                raise Exception
2247            esdDict = {}
2248            for i,avar in enumerate(varyList):
2249                esdDict[avar] = np.sqrt(covar[i,i])
2250        except:
2251            print('====> Fit failed')
2252            return
2253        print('==== Fit Results ====')
2254        for obj in eqObjList:
2255            obj.UpdateVariedVars(varyList,values)
2256            ind = '      '
2257            print('  '+obj.GetDepVar()+' = '+obj.expression)
2258            for var in obj.assgnVars:
2259                print(ind+var+' = '+obj.assgnVars[var])
2260            for var in obj.freeVars:
2261                avar = "::"+obj.freeVars[var][0]
2262                val = obj.freeVars[var][1]
2263                if obj.freeVars[var][2]:
2264                    print(ind+var+' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar]))
2265                else:
2266                    print(ind+var+' = '+avar + " =" + G2mth.ValEsd(val,0))
2267        # create a plot for each parametric variable
2268        for fitnum,obj in enumerate(eqObjList):
2269            calcobj = G2obj.ExpressionCalcObj(obj)
2270            # lookup dependent var position
2271            indx = colLabels.index(obj.GetDepVar())
2272            # assemble a list of the independent variables
2273            indepVars = obj.GetIndependentVars()           
2274            # loop over each datapoint
2275            fitvals = []
2276            for j,row in enumerate(zip(*colList)):
2277                calcobj.SetupCalc(
2278                    {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
2279                    )
2280                fitvals.append(calcobj.EvalExpression())
2281            G2plt.PlotSelectedSequence(
2282                G2frame,[indx],GetColumnInfo,SelectXaxis,
2283                fitnum,fitvals)
2284
2285    def SingleParEqFit(eqObj):
2286        DoParEqFit(None,eqObj)
2287
2288    def DelParFitEq(event):
2289        'Ask the user to select function to delete'
2290        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2291        selected = G2G.ItemSelector(
2292            txtlst,G2frame.dataFrame,
2293            multiple=True,
2294            title='Select a parametric equation(s) to remove',
2295            header='Delete equation')
2296        if selected is None: return
2297        Controls['SeqParFitEqList'] = [obj for i,obj in enumerate(Controls['SeqParFitEqList']) if i not in selected]
2298        EnableParFitEqMenus()
2299        if Controls['SeqParFitEqList']: DoParEqFit(event)
2300       
2301    def EditParFitEq(event):
2302        'Edit an existing parametric equation'
2303        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2304        if len(txtlst) == 1:
2305            selected = 0
2306        else:
2307            selected = G2G.ItemSelector(
2308                txtlst,G2frame.dataFrame,
2309                multiple=False,
2310                title='Select a parametric equation to edit',
2311                header='Edit equation')
2312        if selected is not None:
2313            dlg = G2exG.ExpressionDialog(
2314                G2frame.dataDisplay,indepVarDict,
2315                Controls['SeqParFitEqList'][selected],
2316                depVarDict=depVarDict,
2317                header="Edit the formula for this minimization function",
2318                ExtraButton=['Fit',SingleParEqFit])
2319            newobj = dlg.Show(True)
2320            if newobj:
2321                calcobj = G2obj.ExpressionCalcObj(newobj)
2322                Controls['SeqParFitEqList'][selected] = newobj
2323                EnableParFitEqMenus()
2324            if Controls['SeqParFitEqList']: DoParEqFit(event)
2325
2326    def AddNewParFitEq(event):
2327        'Create a new parametric equation to be fit to sequential results'
2328
2329        # compile the variable names used in previous freevars to avoid accidental name collisions
2330        usedvarlist = []
2331        for obj in Controls['SeqParFitEqList']:
2332            for var in obj.freeVars:
2333                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
2334
2335        dlg = G2exG.ExpressionDialog(
2336            G2frame.dataDisplay,indepVarDict,
2337            depVarDict=depVarDict,
2338            header='Define an equation to minimize in the parametric fit',
2339            ExtraButton=['Fit',SingleParEqFit],
2340            usedVars=usedvarlist)
2341        obj = dlg.Show(True)
2342        dlg.Destroy()
2343        if obj:
2344            Controls['SeqParFitEqList'].append(obj)
2345            EnableParFitEqMenus()
2346            if Controls['SeqParFitEqList']: DoParEqFit(event)
2347               
2348    def CopyParFitEq(event):
2349        'Copy an existing parametric equation to be fit to sequential results'
2350        # compile the variable names used in previous freevars to avoid accidental name collisions
2351        usedvarlist = []
2352        for obj in Controls['SeqParFitEqList']:
2353            for var in obj.freeVars:
2354                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
2355        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2356        if len(txtlst) == 1:
2357            selected = 0
2358        else:
2359            selected = G2G.ItemSelector(
2360                txtlst,G2frame.dataFrame,
2361                multiple=False,
2362                title='Select a parametric equation to copy',
2363                header='Copy equation')
2364        if selected is not None:
2365            newEqn = copy.deepcopy(Controls['SeqParFitEqList'][selected])
2366            for var in newEqn.freeVars:
2367                newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist)
2368            dlg = G2exG.ExpressionDialog(
2369                G2frame.dataDisplay,indepVarDict,
2370                newEqn,
2371                depVarDict=depVarDict,
2372                header="Edit the formula for this minimization function",
2373                ExtraButton=['Fit',SingleParEqFit])
2374            newobj = dlg.Show(True)
2375            if newobj:
2376                calcobj = G2obj.ExpressionCalcObj(newobj)
2377                Controls['SeqParFitEqList'].append(newobj)
2378                EnableParFitEqMenus()
2379            if Controls['SeqParFitEqList']: DoParEqFit(event)
2380                                           
2381    def GridSetToolTip(row,col):
2382        '''Routine to show standard uncertainties for each element in table
2383        as a tooltip
2384        '''
2385        if colSigs[col]:
2386            return u'\u03c3 = '+str(colSigs[col][row])
2387        return ''
2388       
2389    def GridColLblToolTip(col):
2390        '''Define a tooltip for a column. This will be the user-entered value
2391        (from data['variableLabels']) or the default name
2392        '''
2393        if col < 0 or col > len(colLabels):
2394            print 'Illegal column #',col
2395            return
2396        var = colLabels[col]
2397        return variableLabels.get(var,G2obj.fmtVarDescr(var))
2398       
2399    def SetLabelString(event):
2400        '''Define or edit the label for a column in the table, to be used
2401        as a tooltip and for plotting
2402        '''
2403        col = event.GetCol()
2404        if col < 0 or col > len(colLabels):
2405            return
2406        var = colLabels[col]
2407        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
2408        dlg = G2G.SingleStringDialog(G2frame.dataFrame,'Set variable label',
2409                                 'Set a new name for variable '+var,lbl,size=(400,-1))
2410        if dlg.Show():
2411            variableLabels[var] = dlg.GetValue()
2412        dlg.Destroy()
2413       
2414    #def GridRowLblToolTip(row): return 'Row ='+str(row)
2415   
2416    # lookup table for unique cell parameters by symmetry
2417    cellGUIlist = [
2418        [['m3','m3m'],(0,)],
2419        [['3R','3mR'],(0,3)],
2420        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
2421        [['mmm'],(0,1,2)],
2422        [['2/m'+'a'],(0,1,2,3)],
2423        [['2/m'+'b'],(0,1,2,4)],
2424        [['2/m'+'c'],(0,1,2,5)],
2425        [['-1'],(0,1,2,3,4,5)],
2426        ]
2427    # cell labels
2428    cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
2429
2430    #======================================================================
2431    # start processing sequential results here (UpdateSeqResults)
2432    #======================================================================
2433    if not data:
2434        print 'No sequential refinement results'
2435        return
2436    variableLabels = data.get('variableLabels',{})
2437    data['variableLabels'] = variableLabels
2438    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
2439    Controls = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
2440    # create a place to store Pseudo Vars & Parametric Fit functions, if not present
2441    if 'SeqPseudoVars' not in Controls: Controls['SeqPseudoVars'] = {}
2442    if 'SeqParFitEqList' not in Controls: Controls['SeqParFitEqList'] = []
2443    histNames = data['histNames']
2444    if G2frame.dataDisplay:
2445        G2frame.dataDisplay.Destroy()
2446    if not G2frame.dataFrame.GetStatusBar():
2447        Status = G2frame.dataFrame.CreateStatusBar()
2448        Status.SetStatusText("Select column to export; Double click on column to plot data; on row for Covariance")
2449    sampleParms = GetSampleParms()
2450
2451    # make dict of varied atom coords keyed by absolute position
2452    newAtomDict = data[histNames[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
2453    # Possible error: the next might need to be data[histNames[0]]['varyList']
2454    # error will arise if there constraints on coordinates?
2455    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in data['varyList']}
2456   
2457    # make dict of varied cell parameters equivalents
2458    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
2459    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
2460    # N.B. These Dij vars are missing a histogram #
2461    newCellDict = data[histNames[0]].get('newCellDict',{})
2462    for item in newCellDict:
2463        if item in data['varyList']:
2464            ESDlookup[newCellDict[item][0]] = item
2465            Dlookup[item] = newCellDict[item][0]
2466    # add coordinate equivalents to lookup table
2467    for parm in atomLookup:
2468        Dlookup[atomLookup[parm]] = parm
2469        ESDlookup[parm] = atomLookup[parm]
2470
2471    # get unit cell & symmetry for all phases & initial stuff for later use
2472    RecpCellTerms = {}
2473    SGdata = {}
2474    uniqCellIndx = {}
2475    initialCell = {}
2476    RcellLbls = {}
2477    zeroDict = {}
2478    Rcelldict = {}
2479    for phase in Phases:
2480        phasedict = Phases[phase]
2481        pId = phasedict['pId']
2482        pfx = str(pId)+'::' # prefix for A values from phase
2483        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
2484        RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7])
2485        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
2486        SGdata[pId] = phasedict['General']['SGData']
2487        Rcelldict.update({lbl:val for lbl,val in zip(RcellLbls[pId],RecpCellTerms[pId])})
2488        laue = SGdata[pId]['SGLaue']
2489        if laue == '2/m':
2490            laue += SGdata[pId]['SGUniq']
2491        for symlist,celllist in cellGUIlist:
2492            if laue in symlist:
2493                uniqCellIndx[pId] = celllist
2494                break
2495        else: # should not happen
2496            uniqCellIndx[pId] = range(6)
2497        for i in uniqCellIndx[pId]:
2498            initialCell[str(pId)+'::A'+str(i)] =  RecpCellTerms[pId][i]
2499
2500    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
2501    G2frame.dataFrame.SetLabel('Sequential refinement results')
2502    if not G2frame.dataFrame.GetStatusBar():
2503        Status = G2frame.dataFrame.CreateStatusBar()
2504        Status.SetStatusText('')
2505    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=wxID_RENAMESEQSEL)
2506    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
2507    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=wxID_SAVESEQSELCSV)
2508    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=wxID_SAVESEQCSV)
2509    G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=wxID_PLOTSEQSEL)
2510    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAveSelSeq, id=wxID_AVESEQSEL)
2511    G2frame.dataFrame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=wxID_ORGSEQSEL)
2512    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=wxADDSEQVAR)
2513    G2frame.dataFrame.Bind(wx.EVT_MENU, DelPseudoVar, id=wxDELSEQVAR)
2514    G2frame.dataFrame.Bind(wx.EVT_MENU, EditPseudoVar, id=wxEDITSEQVAR)
2515    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewParFitEq, id=wxADDPARFIT)
2516    G2frame.dataFrame.Bind(wx.EVT_MENU, CopyParFitEq, id=wxCOPYPARFIT)
2517    G2frame.dataFrame.Bind(wx.EVT_MENU, DelParFitEq, id=wxDELPARFIT)
2518    G2frame.dataFrame.Bind(wx.EVT_MENU, EditParFitEq, id=wxEDITPARFIT)
2519    G2frame.dataFrame.Bind(wx.EVT_MENU, DoParEqFit, id=wxDOPARFIT)
2520    EnablePseudoVarMenus()
2521    EnableParFitEqMenus()
2522
2523    # scan for locations where the variables change
2524    VaryListChanges = [] # histograms where there is a change
2525    combinedVaryList = []
2526    firstValueDict = {}
2527    vallookup = {}
2528    posdict = {}
2529    prevVaryList = []
2530    for i,name in enumerate(histNames):
2531        for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']):
2532            svar = striphist(var,'*') # wild-carded
2533            if svar not in combinedVaryList:
2534                # add variables to list as they appear
2535                combinedVaryList.append(svar)
2536                firstValueDict[svar] = (val,sig)
2537        if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous
2538            prevVaryList = data[name]['varyList']
2539            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
2540            posdict[name] = {}
2541            for var in data[name]['varyList']:
2542                svar = striphist(var,'*')
2543                posdict[name][combinedVaryList.index(svar)] = svar
2544            VaryListChanges.append(name)
2545    if len(VaryListChanges) > 1:
2546        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,True)
2547    else:
2548        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,False)
2549    #-----------------------------------------------------------------------------------
2550    # build up the data table by columns -----------------------------------------------
2551    nRows = len(histNames)
2552    colList = [nRows*[True]]
2553    colSigs = [None]
2554    colLabels = ['Use']
2555    Types = [wg.GRID_VALUE_BOOL]
2556    # start with Rwp values
2557    if 'IMG ' not in histNames[0][:4]:
2558        colList += [[data[name]['Rvals']['Rwp'] for name in histNames]]
2559        colSigs += [None]
2560        colLabels += ['Rwp']
2561        Types += [wg.GRID_VALUE_FLOAT+':10,3',]
2562    # add % change in Chi^2 in last cycle
2563    if histNames[0][:4] not in ['SASD','IMG '] and Controls.get('ShowCell'):
2564        colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]]
2565        colSigs += [None]
2566        colLabels += [u'\u0394\u03C7\u00B2 (%)']
2567        Types += [wg.GRID_VALUE_FLOAT,]
2568    deltaChiCol = len(colLabels)-1
2569    # add changing sample parameters to table
2570    for key in sampleParms:
2571        colList += [sampleParms[key]]
2572        colSigs += [None]
2573        colLabels += [key]
2574        Types += [wg.GRID_VALUE_FLOAT,]
2575    sampleDict = {}
2576    for i,name in enumerate(histNames):
2577        sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) 
2578    # add unique cell parameters TODO: review this where the cell symmetry changes (when possible)
2579    if Controls.get('ShowCell',False):
2580        for pId in sorted(RecpCellTerms):
2581            pfx = str(pId)+'::' # prefix for A values from phase
2582            cells = []
2583            cellESDs = []
2584            colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
2585            colLabels += [pfx+'Vol']
2586            Types += (1+len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT,]
2587            for name in histNames:
2588                covData = {
2589                    'varyList': [Dlookup.get(striphist(v),v) for v in data[name]['varyList']],
2590                    'covMatrix': data[name]['covMatrix']
2591                    }
2592                A = RecpCellTerms[pId][:] # make copy of starting A values
2593                # update with refined values
2594                for i in range(6):
2595                    var = str(pId)+'::A'+str(i)
2596                    if var in ESDlookup:
2597                        val = data[name]['newCellDict'][ESDlookup[var]][1] # get refined value
2598                        A[i] = val # override with updated value
2599                # apply symmetry
2600                Albls = [pfx+'A'+str(i) for i in range(6)]
2601                cellDict = dict(zip(Albls,A))
2602                A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
2603                # convert to direct cell & add only unique values to table
2604                c = G2lat.A2cell(A)
2605                vol = G2lat.calc_V(A)
2606                cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
2607                cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
2608                cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
2609            colList += zip(*cells)
2610            colSigs += zip(*cellESDs)
2611    # sort out the variables in their selected order
2612    varcols = 0
2613    for d in posdict.itervalues():
2614        varcols = max(varcols,max(d.keys())+1)
2615    # get labels for each column
2616    for i in range(varcols):
2617        lbl = ''
2618        for h in VaryListChanges:
2619            if posdict[h].get(i):
2620                if posdict[h].get(i) in lbl: continue
2621                if lbl != "": lbl += '/'
2622                lbl += posdict[h].get(i)
2623        colLabels.append(lbl)
2624    Types += varcols*[wg.GRID_VALUE_FLOAT]
2625    vals = []
2626    esds = []
2627    varsellist = None        # will be a list of variable names in the order they are selected to appear
2628    # tabulate values for each hist, leaving None for blank columns
2629    for name in histNames:
2630        if name in posdict:
2631            varsellist = [posdict[name].get(i) for i in range(varcols)]
2632            # translate variable names to how they will be used in the headings
2633            vs = [striphist(v,'*') for v in data[name]['varyList']]
2634            # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists
2635            sellist = [vs.index(v) if v is not None else None for v in varsellist]
2636            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])]
2637        if not varsellist: raise Exception()
2638        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
2639        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
2640        #GSASIIpath.IPyBreak()
2641    colList += zip(*vals)
2642    colSigs += zip(*esds)
2643               
2644    # tabulate constrained variables, removing histogram numbers if needed
2645    # from parameter label
2646    depValDict = {}
2647    depSigDict = {}
2648    for name in histNames:
2649        for var in data[name].get('depParmDict',{}):
2650            val,sig = data[name]['depParmDict'][var]
2651            svar = striphist(var,'*')
2652            if svar not in depValDict:
2653               depValDict[svar] = [val]
2654               depSigDict[svar] = [sig]
2655            else:
2656               depValDict[svar].append(val)
2657               depSigDict[svar].append(sig)
2658    # add the dependent constrained variables to the table
2659    for var in sorted(depValDict):
2660        if len(depValDict[var]) != len(histNames): continue
2661        colLabels.append(var)
2662        Types += [wg.GRID_VALUE_FLOAT,]
2663        colSigs += [depSigDict[var]]
2664        colList += [depValDict[var]]
2665
2666    # add atom parameters to table
2667    colLabels += atomLookup.keys()
2668    Types += len(atomLookup)*[wg.GRID_VALUE_FLOAT]
2669    for parm in sorted(atomLookup):
2670        colList += [[data[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
2671        if atomLookup[parm] in data[histNames[0]]['varyList']:
2672            col = data[histNames[0]]['varyList'].index(atomLookup[parm])
2673            colSigs += [[data[name]['sig'][col] for name in histNames]]
2674        else:
2675            colSigs += [None] # should not happen
2676    # evaluate Pseudovars, their ESDs and add them to grid
2677    for expr in Controls['SeqPseudoVars']:
2678        obj = Controls['SeqPseudoVars'][expr]
2679        calcobj = G2obj.ExpressionCalcObj(obj)
2680        valList = []
2681        esdList = []
2682        for seqnum,name in enumerate(histNames):
2683            sigs = data[name]['sig']
2684            G2mv.InitVars()
2685            parmDict = data[name].get('parmDict')
2686            badVary = data[name].get('badVary',[])
2687            constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum])
2688            groups,parmlist,constrDict,fixedList,ihst = constraintInfo
2689            varyList = data[name]['varyList']
2690            parmDict = data[name]['parmDict']
2691            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmDict,SeqHist=ihst)
2692            derivs = np.array(
2693                [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD)
2694                 for var,ESD in zip(varyList,sigs)]
2695                )
2696            esdList.append(np.sqrt(
2697                np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T))
2698                ))
2699            PSvarDict = parmDict.copy()
2700            PSvarDict.update(sampleDict[name])
2701            UpdateParmDict(PSvarDict)
2702            calcobj.UpdateDict(PSvarDict)
2703            valList.append(calcobj.EvalExpression())
2704        if not esdList:
2705            esdList = None
2706        colList += [valList]
2707        colSigs += [esdList]
2708        colLabels += [expr]
2709        Types += [wg.GRID_VALUE_FLOAT,]
2710    #---- table build done -------------------------------------------------------------
2711
2712    # Make dict needed for creating & editing pseudovars (PSvarDict).
2713    name = histNames[0]
2714    parmDict = data[name].get('parmDict')
2715    PSvarDict = parmDict.copy()
2716    PSvarDict.update(sampleParms)
2717    UpdateParmDict(PSvarDict)
2718    # Also dicts of dependent (depVarDict) & independent vars (indepVarDict)
2719    # for Parametric fitting from the data table
2720    parmDict = dict(zip(colLabels,zip(*colList)[0])) # scratch dict w/all values in table
2721    parmDict.update(
2722        {var:val for var,val in data[name].get('newCellDict',{}).values()} #  add varied reciprocal cell terms
2723    )
2724    name = histNames[0]
2725
2726    #******************************************************************************
2727    # create a set of values for example evaluation of pseudovars and
2728    # this does not work for refinements that have differing numbers of variables.
2729    #raise Exception
2730    indepVarDict = {}     #  values in table w/o ESDs
2731    depVarDict = {}
2732    for i,var in enumerate(colLabels):
2733        if var == 'Use': continue
2734        if colList[i][0] is None:
2735            val,sig = firstValueDict.get(var,[None,None])
2736        elif colSigs[i]:
2737            val,sig = colList[i][0],colSigs[i][0]
2738        else:
2739            val,sig = colList[i][0],None
2740        if val is None:
2741            continue
2742        elif sig is None:
2743            indepVarDict[var] = val
2744        elif striphist(var) not in Dlookup:
2745            depVarDict[var] = val
2746    # add recip cell coeff. values
2747    depVarDict.update({var:val for var,val in data[name].get('newCellDict',{}).values()})
2748
2749    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
2750    G2frame.SeqTable = G2G.Table(
2751        [list(c) for c in zip(*colList)],     # convert from columns to rows
2752        colLabels=colLabels,rowLabels=histNames,types=Types)
2753    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
2754    #G2frame.dataDisplay.EnableEditing(False)
2755    # make all but first column read-only
2756    for c in range(1,len(colLabels)):
2757        for r in range(nRows):
2758            G2frame.dataDisplay.SetCellReadOnly(r,c)
2759    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, PlotSelect)
2760    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, SetLabelString)
2761    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
2762    G2frame.dataDisplay.SetMargins(0,0)
2763    G2frame.dataDisplay.AutoSizeColumns(True)
2764    if prevSize:
2765        G2frame.dataDisplay.SetSize(prevSize)
2766    else:
2767        G2frame.dataFrame.setSizePosLeft([700,350])
2768    # highlight unconverged shifts
2769    if histNames[0][:4] not in ['SASD','IMG ']:
2770        for row,name in enumerate(histNames):
2771            deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol)
2772            if deltaChi > 10.:
2773                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0))
2774            elif deltaChi > 1.0:
2775                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0))
2776    G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip)
2777    G2frame.dataDisplay.SendSizeEvent() # resize needed on mac
2778    G2frame.dataDisplay.Refresh() # shows colored text on mac
2779   
2780################################################################################
2781#####  Main PWDR panel
2782################################################################################           
2783       
2784def UpdatePWHKPlot(G2frame,kind,item):
2785    '''Called when the histogram main tree entry is called. Displays the
2786    histogram weight factor, refinement statistics for the histogram
2787    and the range of data for a simulation.
2788
2789    Also invokes a plot of the histogram.
2790    '''
2791    def onEditSimRange(event):
2792        'Edit simulation range'
2793        inp = [
2794            min(data[1][0]),
2795            max(data[1][0]),
2796            None
2797            ]
2798        inp[2] = (inp[1] - inp[0])/(len(data[1][0])-1.)
2799        names = ('start angle', 'end angle', 'step size')
2800        dictlst = [inp] * len(inp)
2801        elemlst = range(len(inp))
2802        dlg = G2G.ScrolledMultiEditor(
2803            G2frame,[inp] * len(inp), range(len(inp)), names,
2804            header='Edit simulation range',
2805            minvals=(0.001,0.001,0.0001),
2806            maxvals=(180.,180.,.1),
2807            )
2808        dlg.CenterOnParent()
2809        val = dlg.ShowModal()
2810        dlg.Destroy()
2811        if val != wx.ID_OK: return
2812        if inp[0] > inp[1]:
2813            end,start,step = inp
2814        else:               
2815            start,end,step = inp
2816        step = abs(step)
2817        N = int((end-start)/step)+1
2818        newdata = np.linspace(start,end,N,True)
2819        if len(newdata) < 2: return # too small a range - reject
2820        data[1] = [newdata,np.zeros_like(newdata),np.ones_like(newdata),
2821            np.zeros_like(newdata),np.zeros_like(newdata),np.zeros_like(newdata)]
2822        Tmin = newdata[0]
2823        Tmax = newdata[-1]
2824        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,item,'Limits'),
2825            [(Tmin,Tmax),[Tmin,Tmax]])
2826        UpdatePWHKPlot(G2frame,kind,item) # redisplay data screen
2827
2828    def OnPlot3DHKL(event):
2829        refList = data[1]['RefList']
2830        FoMax = np.max(refList.T[8+Super])
2831        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2832        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2833        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
2834        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
2835            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
2836            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
2837            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
2838        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2839       
2840    def OnPlotAll3DHKL(event):
2841        choices = GetPatternTreeDataNames(G2frame,['HKLF',])
2842        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select reflection sets to plot',
2843            'Use data',choices)
2844        try:
2845            if dlg.ShowModal() == wx.ID_OK:
2846                refNames = [choices[i] for i in dlg.GetSelections()]
2847            else:
2848                return
2849        finally:
2850            dlg.Destroy()
2851        refList = np.zeros(0)
2852        for name in refNames:
2853            Id = GetPatternTreeItemId(G2frame,G2frame.root, name)
2854            reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
2855            if len(refList):
2856                refList = np.concatenate((refList,reflData['RefList']))
2857            else:
2858                refList = reflData['RefList']
2859           
2860        FoMax = np.max(refList.T[8+Super])
2861        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2862        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2863        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
2864        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
2865            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
2866            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
2867            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
2868        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2869       
2870       
2871    def OnErrorAnalysis(event):
2872        G2plt.PlotDeltSig(G2frame,kind)
2873       
2874    def OnWtFactor(event):
2875        try:
2876            val = float(wtval.GetValue())
2877        except ValueError:
2878            val = data[0]['wtFactor']
2879        data[0]['wtFactor'] = val
2880        wtval.SetValue('%.3f'%(val))
2881       
2882    def OnCompression(event):
2883        data[0] = int(comp.GetValue())
2884       
2885    def onCopyPlotCtrls(event):
2886        '''Respond to menu item to copy multiple sections from a histogram.
2887        Need this here to pass on the G2frame object.
2888        '''
2889        G2pdG.CopyPlotCtrls(G2frame)
2890
2891    def onCopySelectedItems(event):
2892        '''Respond to menu item to copy multiple sections from a histogram.
2893        Need this here to pass on the G2frame object.
2894        '''
2895        G2pdG.CopySelectedHistItems(G2frame)
2896           
2897    data = G2frame.PatternTree.GetItemPyData(item)
2898#patches
2899    if 'wtFactor' not in data[0]:
2900        data[0] = {'wtFactor':1.0}
2901#    if kind == 'PWDR' and 'Compression' not in data[0]:
2902#        data[0]['Compression'] = 1
2903    #if isinstance(data[1],list) and kind == 'HKLF':
2904    if 'list' in str(type(data[1])) and kind == 'HKLF':
2905        RefData = {'RefList':[],'FF':[]}
2906        for ref in data[1]:
2907            RefData['RefList'].append(ref[:11]+[ref[13],])
2908            RefData['FF'].append(ref[14])
2909        data[1] = RefData
2910        G2frame.PatternTree.SetItemPyData(item,data)
2911#end patches
2912    if G2frame.dataDisplay:
2913        G2frame.dataDisplay.Destroy()
2914    if kind in ['PWDR','SASD']:
2915        SetDataMenuBar(G2frame,G2frame.dataFrame.PWDRMenu)
2916        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
2917        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
2918        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopyPlotCtrls, id=wxID_PLOTCTRLCOPY)
2919    elif kind in ['HKLF',]:
2920        SetDataMenuBar(G2frame,G2frame.dataFrame.HKLFMenu)
2921        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
2922        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=wxID_PWD3DHKLPLOT)
2923        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotAll3DHKL, id=wxID_3DALLHKLPLOT)
2924#        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
2925    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2926   
2927    mainSizer = wx.BoxSizer(wx.VERTICAL)
2928    mainSizer.Add((5,5),)
2929    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
2930    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,WACV)
2931    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
2932    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
2933    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
2934    wtSizer.Add(wtval,0,WACV)
2935#    if kind == 'PWDR':         #possible future compression feature; NB above patch as well
2936#        wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Compression factor: '),0,WACV)
2937#        choice = ['1','2','3','4','5','6']
2938#        comp = wx.ComboBox(parent=G2frame.dataDisplay,choices=choice,
2939#            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2940#        comp.SetValue(str(data[0]['Compression']))
2941#        comp.Bind(wx.EVT_COMBOBOX, OnCompression)
2942#        wtSizer.Add(comp,0,WACV)
2943    mainSizer.Add(wtSizer)
2944    if data[0].get('Dummy'):
2945        simSizer = wx.BoxSizer(wx.HORIZONTAL)
2946        Tmin = min(data[1][0])
2947        Tmax = max(data[1][0])
2948        num = len(data[1][0])
2949        step = (Tmax - Tmin)/(num-1)
2950        t = u'2\u03b8' # 2theta
2951        lbl =  u'Simulation range: {:.2f} to {:.2f} {:s}\nwith {:.4f} steps ({:d} points)'
2952        lbl += u'\n(Edit range resets observed intensities).'
2953        lbl = lbl.format(Tmin,Tmax,t,step,num)
2954        simSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,lbl),
2955                    0,WACV)
2956        but = wx.Button(G2frame.dataDisplay,wx.ID_ANY,"Edit range")
2957        but.Bind(wx.EVT_BUTTON,onEditSimRange)
2958        simSizer.Add(but,0,WACV)
2959        mainSizer.Add(simSizer)
2960    if 'Nobs' in data[0]:
2961        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
2962            ' Data residual wR: %.3f%% on %d observations'%(data[0]['wR'],data[0]['Nobs'])))
2963        for value in data[0]:
2964            if 'Nref' in value:
2965                pfx = value.split('Nref')[0]
2966                name = data[0].get(pfx.split(':')[0]+'::Name','?')
2967                if 'SS' in value:
2968                    mainSizer.Add((5,5),)
2969                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For incommensurate phase '+name+':'))
2970                    for m,(Rf2,Rf,Nobs) in enumerate(zip(data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])):
2971                        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
2972                            u' m = +/- %d: RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
2973                            (m,Rf2,Rf,Nobs)))
2974                else:
2975                    mainSizer.Add((5,5),)
2976                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For phase '+name+':'))
2977                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
2978                        u' Unweighted phase residuals RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
2979                        (data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])))
2980                   
2981    mainSizer.Add((5,5),)
2982    mainSizer.Layout()   
2983    G2frame.dataDisplay.SetSizer(mainSizer)
2984    Size = mainSizer.Fit(G2frame.dataFrame)
2985    Size[1] += 10
2986    G2frame.dataFrame.setSizePosLeft(Size)
2987    G2frame.PatternTree.SetItemPyData(item,data)
2988    if kind in ['PWDR','SASD']:
2989        if 'xylim' in dir(G2frame):
2990            NewPlot = False
2991        else:
2992
2993            NewPlot = True
2994        G2plt.PlotPatterns(G2frame,plotType=kind,newPlot=NewPlot)
2995    elif kind == 'HKLF':
2996        Name = G2frame.PatternTree.GetItemText(item)
2997        phaseName = G2pdG.IsHistogramInAnyPhase(G2frame,Name)
2998        if phaseName:
2999            pId = GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3000            phaseId =  GetPatternTreeItemId(G2frame,pId,phaseName)
3001            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3002            Super = General.get('Super',0)
3003            SuperVec = General.get('SuperVec',[])
3004        else:
3005            Super = 0
3006            SuperVec = []       
3007        refList = data[1]['RefList']
3008        FoMax = np.max(refList.T[5+data[1].get('Super',0)])
3009        page = G2frame.G2plotNB.nb.GetSelection()
3010        tab = ''
3011        if page >= 0:
3012            tab = G2frame.G2plotNB.nb.GetPageText(page)
3013        if '3D' in tab:
3014            Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3015            Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3016            Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3017            Page = G2frame.G2plotNB.nb.GetPage(page)
3018            controls = Page.controls
3019            G2plt.Plot3DSngl(G2frame,newPlot=False,Data=controls,hklRef=refList,Title=phaseName)
3020        else:
3021            controls = {'Type' : 'Fo','ifFc' : True,     
3022                'HKLmax' : [int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))],
3023                'HKLmin' : [int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))],
3024                'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3025            G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList)
3026                 
3027################################################################################
3028#####  Pattern tree routines
3029################################################################################           
3030       
3031def GetPatternTreeDataNames(G2frame,dataTypes):
3032    '''Finds all items in tree that match a 4 character prefix
3033   
3034    :param wx.Frame G2frame: Data tree frame object
3035    :param list dataTypes: Contains one or more data tree item types to be matched
3036      such as ['IMG '] or ['PWDR','HKLF']
3037    :returns: a list of tree item names for the matching items 
3038    '''
3039    names = []
3040    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
3041    while item:
3042        name = G2frame.PatternTree.GetItemText(item)
3043        if name[:4] in dataTypes:
3044            names.append(name)
3045        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3046    return names
3047                         
3048def GetPatternTreeItemId(G2frame, parentId, itemText):
3049    '''Needs a doc string
3050    '''
3051    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
3052    while item:
3053        if G2frame.PatternTree.GetItemText(item) == itemText:
3054            return item
3055        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
3056    return 0               
3057
3058def MovePatternTreeToGrid(G2frame,item):
3059    '''Called from GSASII.OnPatternTreeSelChanged when a item is selected on the tree
3060    '''
3061    pickName = G2frame.PatternTree.GetItemText(item)
3062    if G2frame.PickIdText == pickName:
3063        return
3064   
3065    oldPage = None # will be set later if already on a Phase item
3066    if G2frame.dataFrame:
3067        SetDataMenuBar(G2frame)
3068        if G2frame.dataFrame.GetLabel() == 'Comments':
3069            try:
3070                data = [G2frame.dataDisplay.GetValue()]
3071                G2frame.dataDisplay.Clear() 
3072                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
3073                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3074            except:     #clumsy but avoids dead window problem when opening another project
3075                pass
3076        elif G2frame.dataFrame.GetLabel() == 'Notebook':
3077            try:
3078                data = [G2frame.dataDisplay.GetValue()]
3079                G2frame.dataDisplay.Clear() 
3080                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
3081                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3082            except:     #clumsy but avoids dead window problem when opening another project
3083                pass
3084        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
3085            if G2frame.dataDisplay: 
3086                oldPage = G2frame.dataDisplay.GetSelection()
3087        G2frame.dataFrame.Clear()
3088        G2frame.dataFrame.SetLabel('')
3089    else:
3090        #create the frame for the data item window
3091        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
3092        G2frame.dataFrame.PhaseUserSize = None
3093       
3094    G2frame.dataFrame.Raise()           
3095    G2frame.PickId = item
3096    G2frame.PickIdText = None
3097    parentID = G2frame.root
3098    #for i in G2frame.ExportPattern: i.Enable(False)
3099    defWid = [250,150]
3100    if item != G2frame.root:
3101        parentID = G2frame.PatternTree.GetItemParent(item)
3102    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
3103        G2frame.PatternId = item
3104        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
3105            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
3106            G2frame.PatternId = 0
3107            #for i in G2frame.ExportPattern: i.Enable(False)
3108            data = G2frame.PatternTree.GetItemPyData(item)
3109            UpdateNotebook(G2frame,data)
3110        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
3111            G2frame.PatternId = 0
3112            #for i in G2frame.ExportPattern: i.Enable(False)
3113            data = G2frame.PatternTree.GetItemPyData(item)
3114            if not data:           #fill in defaults
3115                data = copy.copy(G2obj.DefaultControls)    #least squares controls
3116                G2frame.PatternTree.SetItemPyData(item,data)                             
3117            for i in G2frame.Refine: i.Enable(True)
3118            G2frame.EnableSeqRefineMenu()
3119            UpdateControls(G2frame,data)
3120        elif G2frame.PatternTree.GetItemText(item) == 'Sequential results':
3121            data = G2frame.PatternTree.GetItemPyData(item)
3122            UpdateSeqResults(G2frame,data)
3123        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
3124            data = G2frame.PatternTree.GetItemPyData(item)
3125            G2frame.dataFrame.setSizePosLeft(defWid)
3126            text = ''
3127            if 'Rvals' in data:
3128                Nvars = len(data['varyList'])
3129                Rvals = data['Rvals']
3130                text = '\nFinal residuals: \nwR = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
3131                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
3132                if 'lamMax' in Rvals:
3133                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
3134            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
3135                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
3136            G2plt.PlotCovariance(G2frame,data)
3137        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
3138            data = G2frame.PatternTree.GetItemPyData(item)
3139            G2cnstG.UpdateConstraints(G2frame,data)
3140        elif G2frame.PatternTree.GetItemText(item) == 'Rigid bodies':
3141            data = G2frame.PatternTree.GetItemPyData(item)
3142            G2cnstG.UpdateRigidBodies(G2frame,data)
3143        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
3144            data = G2frame.PatternTree.GetItemPyData(item)
3145            Phases = G2frame.GetPhaseData()
3146            phase = ''
3147            phaseName = ''
3148            if Phases:
3149                phaseName = Phases.keys()[0]
3150            G2frame.dataFrame.setSizePosLeft(defWid)
3151            G2restG.UpdateRestraints(G2frame,data,Phases,phaseName)
3152        elif 'IMG' in G2frame.PatternTree.GetItemText(item):
3153            G2frame.Image = item
3154            G2frame.dataFrame.SetTitle('Image Data')
3155            data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(
3156                G2frame,item,'Image Controls'))
3157            G2imG.UpdateImageData(G2frame,data)
3158            G2plt.PlotImage(G2frame,newPlot=True)
3159        elif 'PKS' in G2frame.PatternTree.GetItemText(item):
3160            G2plt.PlotPowderLines(G2frame)
3161        elif 'PWDR' in G2frame.PatternTree.GetItemText(item):
3162            #for i in G2frame.ExportPattern: i.Enable(True)
3163            if G2frame.EnablePlot:
3164                UpdatePWHKPlot(G2frame,'PWDR',item)
3165        elif 'SASD' in G2frame.PatternTree.GetItemText(item):
3166            #for i in G2frame.ExportPattern: i.Enable(True)
3167            if G2frame.EnablePlot:
3168                UpdatePWHKPlot(G2frame,'SASD',item)
3169        elif 'HKLF' in G2frame.PatternTree.GetItemText(item):
3170            G2frame.Sngl = True
3171            UpdatePWHKPlot(G2frame,'HKLF',item)
3172        elif 'PDF' in G2frame.PatternTree.GetItemText(item):
3173            G2frame.PatternId = item
3174            for i in G2frame.ExportPDF: i.Enable(True)
3175            G2plt.PlotISFG(G2frame,type='S(Q)')
3176        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
3177            G2frame.dataFrame.setSizePosLeft(defWid)
3178            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
3179                value='Select one phase to see its parameters')           
3180    elif 'I(Q)' in G2frame.PatternTree.GetItemText(item):
3181        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3182        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3183        G2pdG.UpdatePDFGrid(G2frame,data)
3184        G2plt.PlotISFG(G2frame,type='I(Q)',newPlot=True)
3185    elif 'S(Q)' in G2frame.PatternTree.GetItemText(item):
3186        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3187        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3188        G2pdG.UpdatePDFGrid(G2frame,data)
3189        G2plt.PlotISFG(G2frame,type='S(Q)',newPlot=True)
3190    elif 'F(Q)' in G2frame.PatternTree.GetItemText(item):
3191        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3192        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3193        G2pdG.UpdatePDFGrid(G2frame,data)
3194        G2plt.PlotISFG(G2frame,type='F(Q)',newPlot=True)
3195    elif 'G(R)' in G2frame.PatternTree.GetItemText(item):
3196        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3197        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3198        G2pdG.UpdatePDFGrid(G2frame,data)
3199        G2plt.PlotISFG(G2frame,type='G(R)',newPlot=True)           
3200    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
3201        data = G2frame.PatternTree.GetItemPyData(item)
3202        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
3203    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
3204        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
3205        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3206        data = G2frame.PatternTree.GetItemPyData(item)
3207        UpdateComments(G2frame,data)
3208    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
3209        G2frame.dataFrame.SetTitle('Image Controls')
3210        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3211        masks = G2frame.PatternTree.GetItemPyData(
3212            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
3213        data = G2frame.PatternTree.GetItemPyData(item)
3214        G2imG.UpdateImageControls(G2frame,data,masks)
3215        G2plt.PlotImage(G2frame,newPlot=True)
3216    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
3217        G2frame.dataFrame.SetTitle('Masks')
3218        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3219        data = G2frame.PatternTree.GetItemPyData(item)
3220        G2imG.UpdateMasks(G2frame,data)
3221        G2plt.PlotImage(G2frame,newPlot=True)
3222    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
3223        G2frame.dataFrame.SetTitle('Stress/Strain')
3224        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3225        data = G2frame.PatternTree.GetItemPyData(item)
3226        G2plt.PlotImage(G2frame,newPlot=True)
3227        G2plt.PlotStrain(G2frame,data,newPlot=True)
3228        G2imG.UpdateStressStrain(G2frame,data)
3229    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
3230        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3231        for i in G2frame.ExportPDF: i.Enable(True)
3232        data = G2frame.PatternTree.GetItemPyData(item)
3233        G2pdG.UpdatePDFGrid(G2frame,data)
3234        G2plt.PlotISFG(G2frame,type='I(Q)')
3235        G2plt.PlotISFG(G2frame,type='S(Q)')
3236        G2plt.PlotISFG(G2frame,type='F(Q)')
3237        G2plt.PlotISFG(G2frame,type='G(R)')
3238    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
3239        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3240        for i in G2frame.ExportPeakList: i.Enable(True)
3241        data = G2frame.PatternTree.GetItemPyData(item)
3242#patch
3243        if 'list' in str(type(data)):
3244            data = {'peaks':data,'sigDict':{}}
3245            G2frame.PatternTree.SetItemPyData(item,data)
3246#end patch
3247        G2pdG.UpdatePeakGrid(G2frame,data)
3248        G2plt.PlotPatterns(G2frame)
3249    elif G2frame.PatternTree.GetItemText(item) == 'Background':
3250        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3251        data = G2frame.PatternTree.GetItemPyData(item)
3252        G2pdG.UpdateBackground(G2frame,data)
3253        G2plt.PlotPatterns(G2frame)
3254    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
3255        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3256        datatype = G2frame.PatternTree.GetItemText(G2frame.PatternId)[:4]
3257        data = G2frame.PatternTree.GetItemPyData(item)
3258        G2pdG.UpdateLimitsGrid(G2frame,data,datatype)
3259        G2plt.PlotPatterns(G2frame,plotType=datatype)
3260    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
3261        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3262        data = G2frame.PatternTree.GetItemPyData(item)[0]
3263        G2pdG.UpdateInstrumentGrid(G2frame,data)
3264        if 'P' in data['Type'][0]:          #powder data only
3265            G2plt.PlotPeakWidths(G2frame)
3266    elif G2frame.PatternTree.GetItemText(item) == 'Models':
3267        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3268        data = G2frame.PatternTree.GetItemPyData(item)
3269        G2pdG.UpdateModelsGrid(G2frame,data)
3270        G2plt.PlotPatterns(G2frame,plotType='SASD')
3271        if len(data['Size']['Distribution']):
3272            G2plt.PlotSASDSizeDist(G2frame)
3273    elif G2frame.PatternTree.GetItemText(item) == 'Substances':
3274        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3275        data = G2frame.PatternTree.GetItemPyData(item)
3276        G2pdG.UpdateSubstanceGrid(G2frame,data)
3277    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
3278        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3279        data = G2frame.PatternTree.GetItemPyData(item)
3280        datatype = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[2][:4]
3281
3282        if 'Temperature' not in data:           #temp fix for old gpx files
3283            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
3284                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,
3285                    'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
3286                    'Gonio. radius':200.0}
3287            G2frame.PatternTree.SetItemPyData(item,data)
3288   
3289        G2pdG.UpdateSampleGrid(G2frame,data)
3290        G2plt.PlotPatterns(G2frame,plotType=datatype)
3291    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
3292        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3293        for i in G2frame.ExportPeakList: i.Enable(True)
3294        data = G2frame.PatternTree.GetItemPyData(item)
3295#patch
3296        if len(data) != 2:
3297            data = [data,[]]
3298            G2frame.PatternTree.SetItemPyData(item,data)
3299#end patch
3300        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
3301        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
3302            G2plt.PlotPowderLines(G2frame)
3303        else:
3304            G2plt.PlotPatterns(G2frame)
3305    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
3306        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3307        data = G2frame.PatternTree.GetItemPyData(item)
3308        if not data:
3309            data.append([0,0.0,4,25.0,0,'P1',1,1,1,90,90,90]) #zero error flag, zero value, max Nc/No, start volume
3310            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
3311            data.append([])                                 #empty cell list
3312            data.append([])                                 #empty dmin
3313            data.append({})                                 #empty superlattice stuff
3314            G2frame.PatternTree.SetItemPyData(item,data)                             
3315#patch
3316        if len(data) < 5:
3317            data.append({'Use':False,'ModVec':[0,0,0.1],'maxH':1,'ssSymb':''})                                 #empty superlattice stuff
3318            G2frame.PatternTree.SetItemPyData(item,data) 
3319#end patch
3320        G2pdG.UpdateUnitCellsGrid(G2frame,data)
3321        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
3322            G2plt.PlotPowderLines(G2frame)
3323        else:
3324            G2plt.PlotPatterns(G2frame)
3325    elif G2frame.PatternTree.GetItemText(item) == 'Reflection Lists':   #powder reflections
3326        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3327        data = G2frame.PatternTree.GetItemPyData(item)
3328        G2frame.RefList = ''
3329        if len(data):
3330            G2frame.RefList = data.keys()[0]
3331        G2pdG.UpdateReflectionGrid(G2frame,data)
3332        G2plt.PlotPatterns(G2frame)
3333    elif G2frame.PatternTree.GetItemText(item) == 'Reflection List':    #HKLF reflections
3334        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3335        name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3336        data = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
3337        G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
3338
3339    if G2frame.PickId:
3340        G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
3341    G2frame.dataFrame.Raise()
3342
3343def SetDataMenuBar(G2frame,menu=None):
3344    '''Set the menu for the data frame. On the Mac put this
3345    menu for the data tree window instead.
3346
3347    Note that data frame items do not have menus, for these (menu=None)
3348    display a blank menu or on the Mac display the standard menu for
3349    the data tree window.
3350    '''
3351    if sys.platform == "darwin":
3352        if menu is None:
3353            G2frame.SetMenuBar(G2frame.GSASIIMenu)
3354        else:
3355            G2frame.SetMenuBar(menu)
3356    else:
3357        if menu is None:
3358            G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
3359        else:
3360            G2frame.dataFrame.SetMenuBar(menu)
3361
3362def HowDidIgetHere():
3363    '''Show a traceback with calls that brought us to the current location.
3364    Used for debugging.
3365    '''
3366    import traceback
3367    print 70*'*'   
3368    for i in traceback.format_list(traceback.extract_stack()[:-1]): print(i.strip.rstrip())
3369    print 70*'*'   
3370       
Note: See TracBrowser for help on using the repository browser.