source: trunk/GSASIIgrid.py @ 2036

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

roll back 2033

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