source: trunk/GSASIIgrid.py @ 1958

Last change on this file since 1958 was 1958, checked in by vondreele, 7 years ago

add r-values by SS index
add a fade for frac modulation of atoms in drawing
work on modulation structure factor

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