source: trunk/GSASIIgrid.py @ 1998

Last change on this file since 1998 was 1998, checked in by toby, 7 years ago

rebuild docs

  • 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-11 02:59:34 +0000 (Sun, 11 Oct 2015) $
5# $Author: toby $
6# $Revision: 1998 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 1998 2015-10-11 02:59: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: 1998 $")
30import GSASIImath as G2mth
31import GSASIIIO as G2IO
32import GSASIIstrIO as G2stIO
33import GSASIIlattice as G2lat
34import GSASIIplot as G2plt
35import GSASIIpwdGUI as G2pdG
36import GSASIIimgGUI as G2imG
37import GSASIIphsGUI as G2phG
38import GSASIIspc as G2spc
39import GSASIImapvars as G2mv
40import GSASIIconstrGUI as G2cnstG
41import GSASIIrestrGUI as G2restG
42import GSASIIpy3 as G2py3
43import GSASIIobj as G2obj
44import GSASIIexprGUI as G2exG
45import GSASIIlog as log
46import GSASIIctrls as G2G
47
48# trig functions in degrees
49sind = lambda x: np.sin(x*np.pi/180.)
50tand = lambda x: np.tan(x*np.pi/180.)
51cosd = lambda x: np.cos(x*np.pi/180.)
52
53# Define a short name for convenience
54WACV = wx.ALIGN_CENTER_VERTICAL
55
56[ wxID_FOURCALC, wxID_FOURSEARCH, wxID_FOURCLEAR, wxID_PEAKSMOVE, wxID_PEAKSCLEAR, 
57    wxID_CHARGEFLIP, wxID_PEAKSUNIQUE, wxID_PEAKSDELETE, wxID_PEAKSDA,
58    wxID_PEAKSDISTVP, wxID_PEAKSVIEWPT, wxID_FINDEQVPEAKS,wxID_SHOWBONDS,wxID_MULTIMCSA,
59    wxID_SINGLEMCSA, wxID_4DMAPCOMPUTE,wxID_4DCHARGEFLIP,
60] = [wx.NewId() for item in range(17)]
61
62[ wxID_PWDRADD, wxID_HKLFADD, wxID_PWDANALYSIS, wxID_PWDCOPY, wxID_PLOTCTRLCOPY, 
63    wxID_DATADELETE,wxID_DATACOPY,wxID_DATACOPYFLAGS,wxID_DATASELCOPY,
64] = [wx.NewId() for item in range(9)]
65
66[ wxID_ATOMSEDITADD, wxID_ATOMSEDITINSERT, wxID_ATOMSEDITDELETE, wxID_ATOMSREFINE, 
67    wxID_ATOMSMODIFY, wxID_ATOMSTRANSFORM, wxID_ATOMSVIEWADD, wxID_ATOMVIEWINSERT,
68    wxID_RELOADDRAWATOMS,wxID_ATOMSDISAGL,wxID_ATOMMOVE,wxID_MAKEMOLECULE,
69    wxID_ASSIGNATMS2RB,wxID_ATOMSPDISAGL, wxID_ISODISP,wxID_ADDHATOM,wxID_UPDATEHATOM,
70] = [wx.NewId() for item in range(17)]
71
72[ wxID_DRAWATOMSTYLE, wxID_DRAWATOMLABEL, wxID_DRAWATOMCOLOR, wxID_DRAWATOMRESETCOLOR, 
73    wxID_DRAWVIEWPOINT, wxID_DRAWTRANSFORM, wxID_DRAWDELETE, wxID_DRAWFILLCELL, 
74    wxID_DRAWADDEQUIV, wxID_DRAWFILLCOORD, wxID_DRAWDISAGLTOR,  wxID_DRAWPLANE,
75    wxID_DRAWDISTVP,
76] = [wx.NewId() for item in range(13)]
77
78[ wxID_DRAWRESTRBOND, wxID_DRAWRESTRANGLE, wxID_DRAWRESTRPLANE, wxID_DRAWRESTRCHIRAL,
79] = [wx.NewId() for item in range(4)]
80
81[ wxID_ADDMCSAATOM,wxID_ADDMCSARB,wxID_CLEARMCSARB,wxID_MOVEMCSA,wxID_MCSACLEARRESULTS,
82] = [wx.NewId() for item in range(5)]
83
84[ wxID_CLEARTEXTURE,wxID_REFINETEXTURE,
85] = [wx.NewId() for item in range(2)]
86
87[ wxID_PAWLEYLOAD, wxID_PAWLEYESTIMATE, wxID_PAWLEYUPDATE,
88] = [wx.NewId() for item in range(3)]
89
90[ wxID_IMCALIBRATE,wxID_IMRECALIBRATE,wxID_IMINTEGRATE, wxID_IMCLEARCALIB, 
91    wxID_IMCOPYCONTROLS, wxID_INTEGRATEALL, wxID_IMSAVECONTROLS, wxID_IMLOADCONTROLS, 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        try: # remove after AutoInt is completed
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            print "development code: AutoInt found"
1117        except ImportError:
1118            pass
1119        self.PostfillDataMenu()
1120           
1121        # IMG / Masks
1122        self.MaskMenu = wx.MenuBar()
1123        self.PrefillDataMenu(self.MaskMenu,helpType='Image Masks')
1124        self.MaskEdit = wx.Menu(title='')
1125        self.MaskMenu.Append(menu=self.MaskEdit, title='Operations')
1126        submenu = wx.Menu()
1127        self.MaskEdit.AppendMenu(
1128            wx.ID_ANY,'Create new', submenu,
1129            help=''
1130            )
1131        self.MaskEdit.Append(help='Copy mask to other images', 
1132            id=wxID_MASKCOPY, kind=wx.ITEM_NORMAL,text='Copy mask')
1133        self.MaskEdit.Append(help='Save mask to file', 
1134            id=wxID_MASKSAVE, kind=wx.ITEM_NORMAL,text='Save mask')
1135        self.MaskEdit.Append(help='Load mask from file', 
1136            id=wxID_MASKLOAD, kind=wx.ITEM_NORMAL,text='Load mask')
1137        self.MaskEdit.Append(help='Load mask from file; ignore threshold', 
1138            id=wxID_MASKLOADNOT, kind=wx.ITEM_NORMAL,text='Load mask w/o threshold')
1139        submenu.Append(help='Create an arc mask with mouse input', 
1140            id=wxID_NEWMASKARC, kind=wx.ITEM_NORMAL,text='Arc mask')
1141        submenu.Append(help='Create a frame mask with mouse input', 
1142            id=wxID_NEWMASKFRAME, kind=wx.ITEM_NORMAL,text='Frame mask')
1143        submenu.Append(help='Create a polygon mask with mouse input', 
1144            id=wxID_NEWMASKPOLY, kind=wx.ITEM_NORMAL,text='Polygon mask')
1145        submenu.Append(help='Create a ring mask with mouse input', 
1146            id=wxID_NEWMASKRING, kind=wx.ITEM_NORMAL,text='Ring mask')
1147        submenu.Append(help='Create a spot mask with mouse input', 
1148            id=wxID_NEWMASKSPOT, kind=wx.ITEM_NORMAL,text='Spot mask')
1149        self.PostfillDataMenu()
1150           
1151        # IMG / Stress/Strain
1152        self.StrStaMenu = wx.MenuBar()
1153        self.PrefillDataMenu(self.StrStaMenu,helpType='Stress/Strain')
1154        self.StrStaEdit = wx.Menu(title='')
1155        self.StrStaMenu.Append(menu=self.StrStaEdit, title='Operations')
1156        self.StrStaEdit.Append(help='Append d-zero for one ring', 
1157            id=wxID_APPENDDZERO, kind=wx.ITEM_NORMAL,text='Append d-zero')
1158        self.StrStaEdit.Append(help='Fit stress/strain data', 
1159            id=wxID_STRSTAFIT, kind=wx.ITEM_NORMAL,text='Fit stress/strain')
1160        self.StrStaEdit.Append(help='Update d-zero from ave d-zero',
1161            id=wxID_UPDATEDZERO, kind=wx.ITEM_NORMAL,text='Update d-zero')       
1162        self.StrStaEdit.Append(help='Fit stress/strain data for all images', 
1163            id=wxID_STRSTAALLFIT, kind=wx.ITEM_NORMAL,text='All image fit')
1164        self.StrStaEdit.Append(help='Copy stress/strain data to other images', 
1165            id=wxID_STRSTACOPY, kind=wx.ITEM_NORMAL,text='Copy stress/strain')
1166        self.StrStaEdit.Append(help='Save stress/strain data to file', 
1167            id=wxID_STRSTASAVE, kind=wx.ITEM_NORMAL,text='Save stress/strain')
1168        self.StrStaEdit.Append(help='Load stress/strain data from file', 
1169            id=wxID_STRSTALOAD, kind=wx.ITEM_NORMAL,text='Load stress/strain')
1170        self.StrStaEdit.Append(help='Load sample data from file', 
1171            id=wxID_STRSTSAMPLE, kind=wx.ITEM_NORMAL,text='Load sample data')
1172        self.PostfillDataMenu()
1173           
1174        # PDF / PDF Controls
1175        self.PDFMenu = wx.MenuBar()
1176        self.PrefillDataMenu(self.PDFMenu,helpType='PDF Controls')
1177        self.PDFEdit = wx.Menu(title='')
1178        self.PDFMenu.Append(menu=self.PDFEdit, title='PDF Controls')
1179        self.PDFEdit.Append(help='Add element to sample composition',id=wxID_PDFADDELEMENT, kind=wx.ITEM_NORMAL,
1180            text='Add element')
1181        self.PDFEdit.Append(help='Delete element from sample composition',id=wxID_PDFDELELEMENT, kind=wx.ITEM_NORMAL,
1182            text='Delete element')
1183        self.PDFEdit.Append(help='Copy PDF controls', id=wxID_PDFCOPYCONTROLS, kind=wx.ITEM_NORMAL,
1184            text='Copy controls')
1185        self.PDFEdit.Append(help='Load PDF controls from file',id=wxID_PDFLOADCONTROLS, kind=wx.ITEM_NORMAL,
1186            text='Load Controls')
1187        self.PDFEdit.Append(help='Save PDF controls to file', id=wxID_PDFSAVECONTROLS, kind=wx.ITEM_NORMAL,
1188            text='Save controls')
1189        self.PDFEdit.Append(help='Compute PDF', id=wxID_PDFCOMPUTE, kind=wx.ITEM_NORMAL,
1190            text='Compute PDF')
1191        self.PDFEdit.Append(help='Compute all PDFs', id=wxID_PDFCOMPUTEALL, kind=wx.ITEM_NORMAL,
1192            text='Compute all PDFs')
1193        self.PostfillDataMenu()
1194       
1195        # Phase / General tab
1196        self.DataGeneral = wx.MenuBar()
1197        self.PrefillDataMenu(self.DataGeneral,helpType='General', helpLbl='Phase/General')
1198        self.DataGeneral.Append(menu=wx.Menu(title=''),title='Select tab')
1199        self.GeneralCalc = wx.Menu(title='')
1200        self.DataGeneral.Append(menu=self.GeneralCalc,title='Compute')
1201        self.GeneralCalc.Append(help='Compute Fourier map',id=wxID_FOURCALC, kind=wx.ITEM_NORMAL,
1202            text='Fourier map')
1203        self.GeneralCalc.Append(help='Search Fourier map',id=wxID_FOURSEARCH, kind=wx.ITEM_NORMAL,
1204            text='Search map')
1205        self.GeneralCalc.Append(help='Run charge flipping',id=wxID_CHARGEFLIP, kind=wx.ITEM_NORMAL,
1206            text='Charge flipping')
1207        self.GeneralCalc.Append(help='Run 4D charge flipping',id=wxID_4DCHARGEFLIP, kind=wx.ITEM_NORMAL,
1208            text='4D Charge flipping')
1209        self.GeneralCalc.Enable(wxID_4DCHARGEFLIP,False)   
1210        self.GeneralCalc.Append(help='Clear map',id=wxID_FOURCLEAR, kind=wx.ITEM_NORMAL,
1211            text='Clear map')
1212        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing',id=wxID_SINGLEMCSA, kind=wx.ITEM_NORMAL,
1213            text='MC/SA')
1214        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing on multiprocessors',id=wxID_MULTIMCSA, kind=wx.ITEM_NORMAL,
1215            text='Multi MC/SA')            #currently not useful
1216        self.PostfillDataMenu()
1217       
1218        # Phase / Data tab
1219        self.DataMenu = wx.MenuBar()
1220        self.PrefillDataMenu(self.DataMenu,helpType='Data', helpLbl='Phase/Data')
1221        self.DataMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1222        self.DataEdit = wx.Menu(title='')
1223        self.DataMenu.Append(menu=self.DataEdit, title='Edit')
1224        self.DataEdit.Append(id=wxID_DATACOPY, kind=wx.ITEM_NORMAL,text='Copy data',
1225            help='Copy phase data to other histograms')
1226        self.DataEdit.Append(id=wxID_DATACOPYFLAGS, kind=wx.ITEM_NORMAL,text='Copy flags',
1227            help='Copy phase data flags to other histograms')
1228        self.DataEdit.Append(id=wxID_DATASELCOPY, kind=wx.ITEM_NORMAL,text='Copy selected data',
1229            help='Copy selected phase data to other histograms')
1230        self.DataEdit.Append(id=wxID_PWDRADD, kind=wx.ITEM_NORMAL,text='Add powder histograms',
1231            help='Select new powder histograms to be used for this phase')
1232        self.DataEdit.Append(id=wxID_HKLFADD, kind=wx.ITEM_NORMAL,text='Add single crystal histograms',
1233            help='Select new single crystal histograms to be used for this phase')
1234        self.DataEdit.Append(id=wxID_DATADELETE, kind=wx.ITEM_NORMAL,text='Remove histograms',
1235            help='Remove histograms from use for this phase')
1236        self.PostfillDataMenu()
1237           
1238        # Phase / Atoms tab
1239        self.AtomsMenu = wx.MenuBar()
1240        self.PrefillDataMenu(self.AtomsMenu,helpType='Atoms')
1241        self.AtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1242        self.AtomEdit = wx.Menu(title='')
1243        self.AtomCompute = wx.Menu(title='')
1244        self.AtomsMenu.Append(menu=self.AtomEdit, title='Edit')
1245        self.AtomsMenu.Append(menu=self.AtomCompute, title='Compute')
1246        self.AtomEdit.Append(id=wxID_ATOMSEDITADD, kind=wx.ITEM_NORMAL,text='Append atom',
1247            help='Appended as an H atom')
1248        self.AtomEdit.Append(id=wxID_ATOMSVIEWADD, kind=wx.ITEM_NORMAL,text='Append view point',
1249            help='Appended as an H atom')
1250        self.AtomEdit.Append(id=wxID_ATOMSEDITINSERT, kind=wx.ITEM_NORMAL,text='Insert atom',
1251            help='Select atom row to insert before; inserted as an H atom')
1252        self.AtomEdit.Append(id=wxID_ATOMVIEWINSERT, kind=wx.ITEM_NORMAL,text='Insert view point',
1253            help='Select atom row to insert before; inserted as an H atom')
1254        self.AtomEdit.Append(id=wxID_ADDHATOM, kind=wx.ITEM_NORMAL,text='Insert H atoms',
1255            help='Insert H atoms in standard positions bonded to selected atoms')
1256        self.AtomEdit.Append(id=wxID_UPDATEHATOM, kind=wx.ITEM_NORMAL,text='Update H atoms',
1257            help='Update H atoms in standard positions')
1258        self.AtomEdit.Append(id=wxID_ATOMMOVE, kind=wx.ITEM_NORMAL,text='Move atom to view point',
1259            help='Select single atom to move')
1260        self.AtomEdit.Append(id=wxID_ATOMSEDITDELETE, kind=wx.ITEM_NORMAL,text='Delete atom',
1261            help='Select atoms to delete first')
1262        self.AtomEdit.Append(id=wxID_ATOMSREFINE, kind=wx.ITEM_NORMAL,text='Set atom refinement flags',
1263            help='Select atoms to refine first')
1264        self.AtomEdit.Append(id=wxID_ATOMSMODIFY, kind=wx.ITEM_NORMAL,text='Modify atom parameters',
1265            help='Select atoms to modify first')
1266        self.AtomEdit.Append(id=wxID_ATOMSTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform atoms',
1267            help='Select atoms to transform first')
1268        self.AtomEdit.Append(id=wxID_MAKEMOLECULE, kind=wx.ITEM_NORMAL,text='Assemble molecule',
1269            help='Assemble molecule from scatterd atom positions')
1270        self.AtomEdit.Append(id=wxID_RELOADDRAWATOMS, kind=wx.ITEM_NORMAL,text='Reload draw atoms',
1271            help='Reload atom drawing list')
1272        submenu = wx.Menu()
1273        self.AtomEdit.AppendMenu(wx.ID_ANY, 'Reimport atoms', submenu, 
1274            help='Reimport atoms from file; sequence must match')
1275        # setup a cascade menu for the formats that have been defined
1276        self.ReImportMenuId = {}  # points to readers for each menu entry
1277        for reader in self.G2frame.ImportPhaseReaderlist:
1278            item = submenu.Append(
1279                wx.ID_ANY,help=reader.longFormatName,
1280                kind=wx.ITEM_NORMAL,text='reimport coordinates from '+reader.formatName+' file')
1281            self.ReImportMenuId[item.GetId()] = reader
1282        item = submenu.Append(
1283            wx.ID_ANY,
1284            help='Reimport coordinates, try to determine format from file',
1285            kind=wx.ITEM_NORMAL,
1286            text='guess format from file')
1287        self.ReImportMenuId[item.GetId()] = None # try all readers
1288
1289        self.AtomCompute.Append(id=wxID_ATOMSDISAGL, kind=wx.ITEM_NORMAL,text='Show Distances && Angles',
1290            help='Compute distances & angles for selected atoms')
1291        self.AtomCompute.Append(id=wxID_ATOMSPDISAGL, kind=wx.ITEM_NORMAL,text='Save Distances && Angles',
1292            help='Compute distances & angles for selected atoms')
1293        self.AtomCompute.ISOcalc = self.AtomCompute.Append(
1294            id=wxID_ISODISP, kind=wx.ITEM_NORMAL,
1295            text='Compute ISODISTORT mode values',
1296            help='Compute values of ISODISTORT modes from atom parameters')
1297        self.PostfillDataMenu()
1298       
1299        # Phase / Imcommensurate "waves" tab
1300        self.WavesData = wx.MenuBar()
1301        self.PrefillDataMenu(self.WavesData,helpType='Wave Data', helpLbl='Imcommensurate wave data')
1302        self.WavesData.Append(menu=wx.Menu(title=''),title='Select tab')
1303        self.WavesDataCompute = wx.Menu(title='')
1304        self.WavesData.Append(menu=self.WavesDataCompute,title='Compute')
1305        self.WavesDataCompute.Append(id=wxID_4DMAPCOMPUTE, kind=wx.ITEM_NORMAL,text='Compute 4D map',
1306            help='Compute 4-dimensional map')
1307        self.PostfillDataMenu()
1308                 
1309        # Phase / Draw Options tab
1310        self.DataDrawOptions = wx.MenuBar()
1311        self.PrefillDataMenu(self.DataDrawOptions,helpType='Draw Options', helpLbl='Phase/Draw Options')
1312        self.DataDrawOptions.Append(menu=wx.Menu(title=''),title='Select tab')
1313        self.PostfillDataMenu()
1314       
1315        # Phase / Draw Atoms tab
1316        self.DrawAtomsMenu = wx.MenuBar()
1317        self.PrefillDataMenu(self.DrawAtomsMenu,helpType='Draw Atoms')
1318        self.DrawAtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1319        self.DrawAtomEdit = wx.Menu(title='')
1320        self.DrawAtomCompute = wx.Menu(title='')
1321        self.DrawAtomRestraint = wx.Menu(title='')
1322        self.DrawAtomRigidBody = wx.Menu(title='')
1323        self.DrawAtomsMenu.Append(menu=self.DrawAtomEdit, title='Edit')
1324        self.DrawAtomsMenu.Append(menu=self.DrawAtomCompute,title='Compute')
1325        self.DrawAtomsMenu.Append(menu=self.DrawAtomRestraint, title='Restraints')
1326        self.DrawAtomsMenu.Append(menu=self.DrawAtomRigidBody, title='Rigid body')
1327        self.DrawAtomEdit.Append(id=wxID_DRAWATOMSTYLE, kind=wx.ITEM_NORMAL,text='Atom style',
1328            help='Select atoms first')
1329        self.DrawAtomEdit.Append(id=wxID_DRAWATOMLABEL, kind=wx.ITEM_NORMAL,text='Atom label',
1330            help='Select atoms first')
1331        self.DrawAtomEdit.Append(id=wxID_DRAWATOMCOLOR, kind=wx.ITEM_NORMAL,text='Atom color',
1332            help='Select atoms first')
1333        self.DrawAtomEdit.Append(id=wxID_DRAWATOMRESETCOLOR, kind=wx.ITEM_NORMAL,text='Reset atom colors',
1334            help='Resets all atom colors to defaults')
1335        self.DrawAtomEdit.Append(id=wxID_DRAWVIEWPOINT, kind=wx.ITEM_NORMAL,text='View point',
1336            help='View point is 1st atom selected')
1337        self.DrawAtomEdit.Append(id=wxID_DRAWADDEQUIV, kind=wx.ITEM_NORMAL,text='Add atoms',
1338            help='Add symmetry & cell equivalents to drawing set from selected atoms')
1339        self.DrawAtomEdit.Append(id=wxID_DRAWTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform draw atoms',
1340            help='Transform selected atoms by symmetry & cell translations')
1341        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCOORD, kind=wx.ITEM_NORMAL,text='Fill CN-sphere',
1342            help='Fill coordination sphere for selected atoms')           
1343        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCELL, kind=wx.ITEM_NORMAL,text='Fill unit cell',
1344            help='Fill unit cell with selected atoms')
1345        self.DrawAtomEdit.Append(id=wxID_DRAWDELETE, kind=wx.ITEM_NORMAL,text='Delete atoms',
1346            help='Delete atoms from drawing set')
1347        self.DrawAtomCompute.Append(id=wxID_DRAWDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
1348            help='Compute distance of selected atoms from view point')   
1349        self.DrawAtomCompute.Append(id=wxID_DRAWDISAGLTOR, kind=wx.ITEM_NORMAL,text='Dist. Ang. Tors.',
1350            help='Compute distance, angle or torsion for 2-4 selected atoms')   
1351        self.DrawAtomCompute.Append(id=wxID_DRAWPLANE, kind=wx.ITEM_NORMAL,text='Best plane',
1352            help='Compute best plane for 4+ selected atoms')   
1353        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRBOND, kind=wx.ITEM_NORMAL,text='Add bond restraint',
1354            help='Add bond restraint for selected atoms (2)')
1355        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRANGLE, kind=wx.ITEM_NORMAL,text='Add angle restraint',
1356            help='Add angle restraint for selected atoms (3: one end 1st)')
1357        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRPLANE, kind=wx.ITEM_NORMAL,text='Add plane restraint',
1358            help='Add plane restraint for selected atoms (4+)')
1359        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRCHIRAL, kind=wx.ITEM_NORMAL,text='Add chiral restraint',
1360            help='Add chiral restraint for selected atoms (4: center atom 1st)')
1361        self.DrawAtomRigidBody.Append(id=wxID_DRAWDEFINERB, kind=wx.ITEM_NORMAL,text='Define rigid body',
1362            help='Define rigid body with selected atoms')
1363        self.PostfillDataMenu()
1364
1365        # Phase / MCSA tab
1366        self.MCSAMenu = wx.MenuBar()
1367        self.PrefillDataMenu(self.MCSAMenu,helpType='MC/SA')
1368        self.MCSAMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1369        self.MCSAEdit = wx.Menu(title='')
1370        self.MCSAMenu.Append(menu=self.MCSAEdit, title='MC/SA')
1371        self.MCSAEdit.Append(id=wxID_ADDMCSAATOM, kind=wx.ITEM_NORMAL,text='Add atom', 
1372            help='Add single atom to MC/SA model')
1373        self.MCSAEdit.Append(id=wxID_ADDMCSARB, kind=wx.ITEM_NORMAL,text='Add rigid body', 
1374            help='Add rigid body to MC/SA model' )
1375        self.MCSAEdit.Append(id=wxID_CLEARMCSARB, kind=wx.ITEM_NORMAL,text='Clear rigid bodies', 
1376            help='Clear all atoms & rigid bodies from MC/SA model' )
1377        self.MCSAEdit.Append(id=wxID_MOVEMCSA, kind=wx.ITEM_NORMAL,text='Move MC/SA solution', 
1378            help='Move MC/SA solution to atom list' )
1379        self.MCSAEdit.Append(id=wxID_MCSACLEARRESULTS, kind=wx.ITEM_NORMAL,text='Clear results', 
1380            help='Clear table of MC/SA results' )
1381        self.PostfillDataMenu()
1382           
1383        # Phase / Texture tab
1384        self.TextureMenu = wx.MenuBar()
1385        self.PrefillDataMenu(self.TextureMenu,helpType='Texture')
1386        self.TextureMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1387        self.TextureEdit = wx.Menu(title='')
1388        self.TextureMenu.Append(menu=self.TextureEdit, title='Texture')
1389        self.TextureEdit.Append(id=wxID_REFINETEXTURE, kind=wx.ITEM_NORMAL,text='Refine texture', 
1390            help='Refine the texture coefficients from sequential results')
1391#        self.TextureEdit.Append(id=wxID_CLEARTEXTURE, kind=wx.ITEM_NORMAL,text='Clear texture',
1392#            help='Clear the texture coefficients' )
1393        self.PostfillDataMenu()
1394           
1395        # Phase / Pawley tab
1396        self.PawleyMenu = wx.MenuBar()
1397        self.PrefillDataMenu(self.PawleyMenu,helpType='Pawley')
1398        self.PawleyMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1399        self.PawleyEdit = wx.Menu(title='')
1400        self.PawleyMenu.Append(menu=self.PawleyEdit,title='Operations')
1401        self.PawleyEdit.Append(id=wxID_PAWLEYLOAD, kind=wx.ITEM_NORMAL,text='Pawley create',
1402            help='Initialize Pawley reflection list')
1403        self.PawleyEdit.Append(id=wxID_PAWLEYESTIMATE, kind=wx.ITEM_NORMAL,text='Pawley estimate',
1404            help='Estimate initial Pawley intensities')
1405        self.PawleyEdit.Append(id=wxID_PAWLEYUPDATE, kind=wx.ITEM_NORMAL,text='Pawley update',
1406            help='Update negative Pawley intensities with -0.5*Fobs and turn off refinemnt')
1407        self.PostfillDataMenu()
1408           
1409        # Phase / Map peaks tab
1410        self.MapPeaksMenu = wx.MenuBar()
1411        self.PrefillDataMenu(self.MapPeaksMenu,helpType='Map peaks')
1412        self.MapPeaksMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1413        self.MapPeaksEdit = wx.Menu(title='')
1414        self.MapPeaksMenu.Append(menu=self.MapPeaksEdit, title='Map peaks')
1415        self.MapPeaksEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks', 
1416            help='Move selected peaks to atom list')
1417        self.MapPeaksEdit.Append(id=wxID_PEAKSVIEWPT, kind=wx.ITEM_NORMAL,text='View point',
1418            help='View point is 1st peak selected')
1419        self.MapPeaksEdit.Append(id=wxID_PEAKSDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
1420            help='Compute distance of selected peaks from view point')   
1421        self.MapPeaksEdit.Append(id=wxID_SHOWBONDS, kind=wx.ITEM_NORMAL,text='Hide bonds',
1422            help='Hide or show bonds between peak positions')   
1423        self.MapPeaksEdit.Append(id=wxID_PEAKSDA, kind=wx.ITEM_NORMAL,text='Calc dist/ang', 
1424            help='Calculate distance or angle for selection')
1425        self.MapPeaksEdit.Append(id=wxID_FINDEQVPEAKS, kind=wx.ITEM_NORMAL,text='Equivalent peaks', 
1426            help='Find equivalent peaks')
1427        self.MapPeaksEdit.Append(id=wxID_PEAKSUNIQUE, kind=wx.ITEM_NORMAL,text='Unique peaks', 
1428            help='Select unique set')
1429        self.MapPeaksEdit.Append(id=wxID_PEAKSDELETE, kind=wx.ITEM_NORMAL,text='Delete peaks', 
1430            help='Delete selected peaks')
1431        self.MapPeaksEdit.Append(id=wxID_PEAKSCLEAR, kind=wx.ITEM_NORMAL,text='Clear peaks', 
1432            help='Clear the map peak list')
1433        self.PostfillDataMenu()
1434
1435        # Phase / Rigid bodies tab
1436        self.RigidBodiesMenu = wx.MenuBar()
1437        self.PrefillDataMenu(self.RigidBodiesMenu,helpType='Rigid bodies')
1438        self.RigidBodiesMenu.Append(menu=wx.Menu(title=''),title='Select tab')
1439        self.RigidBodiesEdit = wx.Menu(title='')
1440        self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit')
1441        self.RigidBodiesEdit.Append(id=wxID_ASSIGNATMS2RB, kind=wx.ITEM_NORMAL,text='Assign atoms to rigid body',
1442            help='Select & position rigid body in structure of existing atoms')
1443        self.RigidBodiesEdit.Append(id=wxID_AUTOFINDRESRB, kind=wx.ITEM_NORMAL,text='Auto find residues',
1444            help='Auto find of residue RBs in macromolecule')
1445        self.RigidBodiesEdit.Append(id=wxID_COPYRBPARMS, kind=wx.ITEM_NORMAL,text='Copy rigid body parms',
1446            help='Copy rigid body location & TLS parameters')
1447        self.RigidBodiesEdit.Append(id=wxID_GLOBALTHERM, kind=wx.ITEM_NORMAL,text='Global thermal motion',
1448            help='Global setting of residue thermal motion models')
1449        self.RigidBodiesEdit.Append(id=wxID_GLOBALRESREFINE, kind=wx.ITEM_NORMAL,text='Global residue refine',
1450            help='Global setting of residue RB refinement flags')
1451        self.RigidBodiesEdit.Append(id=wxID_RBREMOVEALL, kind=wx.ITEM_NORMAL,text='Remove all rigid bodies',
1452            help='Remove all rigid body assignment for atoms')
1453        self.PostfillDataMenu()
1454    # end of GSAS-II menu definitions
1455       
1456    def _init_ctrls(self, parent,name=None,size=None,pos=None):
1457        wx.Frame.__init__(
1458            self,parent=parent,
1459            #style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT ,
1460            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX,
1461            size=size,pos=pos,title='GSAS-II data display')
1462        self._init_menus()
1463        if name:
1464            self.SetLabel(name)
1465        self.Show()
1466       
1467    def __init__(self,parent,frame,data=None,name=None, size=None,pos=None):
1468        self.G2frame = frame
1469        self._init_ctrls(parent,name,size,pos)
1470        self.data = data
1471        clientSize = wx.ClientDisplayRect()
1472        Size = self.GetSize()
1473        xPos = clientSize[2]-Size[0]
1474        self.SetPosition(wx.Point(xPos,clientSize[1]+250))
1475        self.AtomGrid = []
1476        self.selectedRow = 0
1477       
1478    def setSizePosLeft(self,Width):
1479        clientSize = wx.ClientDisplayRect()
1480        Width[1] = min(Width[1],clientSize[2]-300)
1481        Width[0] = max(Width[0],300)
1482        self.SetSize(Width)
1483#        self.SetPosition(wx.Point(clientSize[2]-Width[0],clientSize[1]+250))
1484       
1485    def Clear(self):
1486        self.ClearBackground()
1487        self.DestroyChildren()
1488                   
1489
1490################################################################################
1491#####  Notebook Tree Item editor
1492################################################################################                 
1493def UpdateNotebook(G2frame,data):
1494    '''Called when the data tree notebook entry is selected. Allows for
1495    editing of the text in that tree entry
1496    '''
1497    def OnNoteBook(event):
1498        data = G2frame.dataDisplay.GetValue().split('\n')
1499        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Notebook'),data)
1500        if 'nt' not in os.name:
1501            G2frame.dataDisplay.AppendText('\n')
1502                   
1503    if G2frame.dataDisplay:
1504        G2frame.dataDisplay.Destroy()
1505    G2frame.dataFrame.SetLabel('Notebook')
1506    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
1507        style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
1508    G2frame.dataDisplay.Bind(wx.EVT_TEXT_ENTER,OnNoteBook)
1509    G2frame.dataDisplay.Bind(wx.EVT_KILL_FOCUS,OnNoteBook)
1510    for line in data:
1511        G2frame.dataDisplay.AppendText(line+"\n")
1512    G2frame.dataDisplay.AppendText('Notebook entry @ '+time.ctime()+"\n")
1513    G2frame.dataFrame.setSizePosLeft([400,250])
1514           
1515################################################################################
1516#####  Controls Tree Item editor
1517################################################################################           
1518def UpdateControls(G2frame,data):
1519    '''Edit overall GSAS-II controls in main Controls data tree entry
1520    '''
1521    #patch
1522    if 'deriv type' not in data:
1523        data = {}
1524        data['deriv type'] = 'analytic Hessian'
1525        data['min dM/M'] = 0.0001
1526        data['shift factor'] = 1.
1527        data['max cyc'] = 3       
1528        data['F**2'] = False
1529    if 'shift factor' not in data:
1530        data['shift factor'] = 1.
1531    if 'max cyc' not in data:
1532        data['max cyc'] = 3
1533    if 'F**2' not in data:
1534        data['F**2'] = False
1535    if 'Author' not in data:
1536        data['Author'] = 'no name'
1537    if 'FreePrm1' not in data:
1538        data['FreePrm1'] = 'Sample humidity (%)'
1539    if 'FreePrm2' not in data:
1540        data['FreePrm2'] = 'Sample voltage (V)'
1541    if 'FreePrm3' not in data:
1542        data['FreePrm3'] = 'Applied load (MN)'
1543    if 'Copy2Next' not in data:
1544        data['Copy2Next'] = False
1545    if 'Reverse Seq' not in data:
1546        data['Reverse Seq'] = False
1547    if 'UsrReject' not in data:
1548        data['UsrReject'] = {'minF/sig':0,'MinExt':0.01,'MaxDF/F':20.,'MaxD':500.,'MinD':0.05}
1549    if 'HatomFix' not in data:
1550        data['HatomFix'] = False
1551   
1552    #end patch
1553
1554    def SeqSizer():
1555       
1556        def OnSelectData(event):
1557            choices = GetPatternTreeDataNames(G2frame,['PWDR','HKLF',])
1558            sel = []
1559            try:
1560                if 'Seq Data' in data:
1561                    for item in data['Seq Data']:
1562                        sel.append(choices.index(item))
1563                    sel = [choices.index(item) for item in data['Seq Data']]
1564            except ValueError:  #data changed somehow - start fresh
1565                sel = []
1566            dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential refinement',
1567                'Select dataset to include',choices)
1568            dlg.SetSelections(sel)
1569            names = []
1570            if dlg.ShowModal() == wx.ID_OK:
1571                for sel in dlg.GetSelections():
1572                    names.append(choices[sel])
1573                data['Seq Data'] = names               
1574                G2frame.EnableSeqRefineMenu()
1575            dlg.Destroy()
1576            wx.CallAfter(UpdateControls,G2frame,data)
1577           
1578        def OnReverse(event):
1579            data['Reverse Seq'] = reverseSel.GetValue()
1580           
1581        def OnCopySel(event):
1582            data['Copy2Next'] = copySel.GetValue() 
1583                   
1584        seqSizer = wx.BoxSizer(wx.VERTICAL)
1585        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
1586        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Sequential Refinement: '),0,WACV)
1587        selSeqData = wx.Button(G2frame.dataDisplay,-1,label=' Select data')
1588        selSeqData.Bind(wx.EVT_BUTTON,OnSelectData)
1589        dataSizer.Add(selSeqData,0,WACV)
1590        SeqData = data.get('Seq Data',[])
1591        if not SeqData:
1592            lbl = ' (no data selected)'
1593        else:
1594            lbl = ' ('+str(len(SeqData))+' dataset(s) selected)'
1595
1596        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=lbl),0,WACV)
1597        seqSizer.Add(dataSizer,0)
1598        if SeqData:
1599            selSizer = wx.BoxSizer(wx.HORIZONTAL)
1600            reverseSel = wx.CheckBox(G2frame.dataDisplay,-1,label=' Reverse order?')
1601            reverseSel.Bind(wx.EVT_CHECKBOX,OnReverse)
1602            reverseSel.SetValue(data['Reverse Seq'])
1603            selSizer.Add(reverseSel,0,WACV)
1604            copySel =  wx.CheckBox(G2frame.dataDisplay,-1,label=' Copy results to next histogram?')
1605            copySel.Bind(wx.EVT_CHECKBOX,OnCopySel)
1606            copySel.SetValue(data['Copy2Next'])
1607            selSizer.Add(copySel,0,WACV)
1608            seqSizer.Add(selSizer,0)
1609        return seqSizer
1610       
1611    def LSSizer():       
1612       
1613        def OnDerivType(event):
1614            data['deriv type'] = derivSel.GetValue()
1615            derivSel.SetValue(data['deriv type'])
1616            wx.CallAfter(UpdateControls,G2frame,data)
1617           
1618        def OnConvergence(event):
1619            try:
1620                value = max(1.e-9,min(1.0,float(Cnvrg.GetValue())))
1621            except ValueError:
1622                value = 0.0001
1623            data['min dM/M'] = value
1624            Cnvrg.SetValue('%.2g'%(value))
1625           
1626        def OnMaxCycles(event):
1627            data['max cyc'] = int(maxCyc.GetValue())
1628            maxCyc.SetValue(str(data['max cyc']))
1629                       
1630        def OnFactor(event):
1631            try:
1632                value = min(max(float(Factr.GetValue()),0.00001),100.)
1633            except ValueError:
1634                value = 1.0
1635            data['shift factor'] = value
1636            Factr.SetValue('%.5f'%(value))
1637           
1638        def OnFsqRef(event):
1639            data['F**2'] = fsqRef.GetValue()
1640           
1641        def OnHatomFix(event):
1642            data['HatomFix'] = Hfix.GetValue()
1643       
1644        def OnUsrRej(event):
1645            Obj = event.GetEventObject()
1646            item,limits = Indx[Obj]
1647            try:
1648                value = min(max(float(Obj.GetValue()),limits[0]),limits[1])
1649            except ValueError:
1650                value = data['UsrReject'][item]
1651            data['UsrReject'][item] = value
1652            Obj.SetValue('%.2f'%(value))
1653
1654        LSSizer = wx.FlexGridSizer(cols=4,vgap=5,hgap=5)
1655        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement derivatives: '),0,WACV)
1656        Choice=['analytic Jacobian','numeric','analytic Hessian']
1657        derivSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['deriv type'],choices=Choice,
1658            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1659        derivSel.SetValue(data['deriv type'])
1660        derivSel.Bind(wx.EVT_COMBOBOX, OnDerivType)
1661           
1662        LSSizer.Add(derivSel,0,WACV)
1663        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min delta-M/M: '),0,WACV)
1664        Cnvrg = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2g'%(data['min dM/M']),style=wx.TE_PROCESS_ENTER)
1665        Cnvrg.Bind(wx.EVT_TEXT_ENTER,OnConvergence)
1666        Cnvrg.Bind(wx.EVT_KILL_FOCUS,OnConvergence)
1667        LSSizer.Add(Cnvrg,0,WACV)
1668        Indx = {}
1669        if 'Hessian' in data['deriv type']:
1670            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max cycles: '),0,WACV)
1671            Choice = ['0','1','2','3','5','10','15','20']
1672            maxCyc = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['max cyc']),choices=Choice,
1673                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1674            maxCyc.SetValue(str(data['max cyc']))
1675            maxCyc.Bind(wx.EVT_COMBOBOX, OnMaxCycles)
1676            LSSizer.Add(maxCyc,0,WACV)
1677        else:
1678            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial shift factor: '),0,WACV)
1679            Factr = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.5f'%(data['shift factor']),style=wx.TE_PROCESS_ENTER)
1680            Factr.Bind(wx.EVT_TEXT_ENTER,OnFactor)
1681            Factr.Bind(wx.EVT_KILL_FOCUS,OnFactor)
1682            LSSizer.Add(Factr,0,WACV)
1683        if G2frame.Sngl:
1684            userReject = data['UsrReject']
1685            usrRej = {'minF/sig':[' Min obs/sig (0-5): ',[0,5], ],'MinExt':[' Min extinct. (0-.9): ',[0,.9],],
1686                'MaxDF/F':[' Max delt-F/sig (3-1000): ',[3.,1000.],],'MaxD':[' Max d-spacing (3-500): ',[3,500],],
1687                'MinD':[' Min d-spacing (0.1-1.0): ',[0.1,1.0],]}
1688
1689            fsqRef = wx.CheckBox(G2frame.dataDisplay,-1,label='Refine HKLF as F^2? ')
1690            fsqRef.SetValue(data['F**2'])
1691            fsqRef.Bind(wx.EVT_CHECKBOX,OnFsqRef)
1692            LSSizer.Add(fsqRef,0,WACV)
1693            LSSizer.Add((1,0),)
1694            for item in usrRej:
1695                LSSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=usrRej[item][0]),0,WACV)
1696                usrrej = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(userReject[item]),style=wx.TE_PROCESS_ENTER)
1697                Indx[usrrej] = [item,usrRej[item][1]]
1698                usrrej.Bind(wx.EVT_TEXT_ENTER,OnUsrRej)
1699                usrrej.Bind(wx.EVT_KILL_FOCUS,OnUsrRej)
1700                LSSizer.Add(usrrej,0,WACV)
1701#        Hfix = wx.CheckBox(G2frame.dataDisplay,-1,label='Regularize H atoms? ')
1702#        Hfix.SetValue(data['HatomFix'])
1703#        Hfix.Bind(wx.EVT_CHECKBOX,OnHatomFix)
1704#        LSSizer.Add(Hfix,0,WACV)   #for now
1705        return LSSizer
1706       
1707    def AuthSizer():
1708
1709        def OnAuthor(event):
1710            data['Author'] = auth.GetValue()
1711
1712        Author = data['Author']
1713        authSizer = wx.BoxSizer(wx.HORIZONTAL)
1714        authSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' CIF Author (last, first):'),0,WACV)
1715        auth = wx.TextCtrl(G2frame.dataDisplay,-1,value=Author,style=wx.TE_PROCESS_ENTER)
1716        auth.Bind(wx.EVT_TEXT_ENTER,OnAuthor)
1717        auth.Bind(wx.EVT_KILL_FOCUS,OnAuthor)
1718        authSizer.Add(auth,0,WACV)
1719        return authSizer
1720       
1721       
1722    if G2frame.dataDisplay:
1723        G2frame.dataDisplay.Destroy()
1724    if not G2frame.dataFrame.GetStatusBar():
1725        Status = G2frame.dataFrame.CreateStatusBar()
1726        Status.SetStatusText('')
1727    G2frame.dataFrame.SetLabel('Controls')
1728    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1729    SetDataMenuBar(G2frame,G2frame.dataFrame.ControlsMenu)
1730    mainSizer = wx.BoxSizer(wx.VERTICAL)
1731    mainSizer.Add((5,5),0)
1732    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement Controls:'),0,WACV)   
1733    mainSizer.Add(LSSizer())
1734    mainSizer.Add((5,5),0)
1735    mainSizer.Add(SeqSizer())
1736    mainSizer.Add((5,5),0)
1737    mainSizer.Add(AuthSizer())
1738    mainSizer.Add((5,5),0)
1739       
1740    mainSizer.Layout()   
1741    G2frame.dataDisplay.SetSizer(mainSizer)
1742    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
1743    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1744     
1745################################################################################
1746#####  Comments
1747################################################################################           
1748       
1749def UpdateComments(G2frame,data):                   
1750
1751    if G2frame.dataDisplay:
1752        G2frame.dataDisplay.Destroy()
1753    G2frame.dataFrame.SetLabel('Comments')
1754    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
1755        style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP)
1756    for line in data:
1757        G2frame.dataDisplay.AppendText(line+'\n')
1758    G2frame.dataFrame.setSizePosLeft([400,250])
1759           
1760################################################################################
1761#####  Display of Sequential Results
1762################################################################################           
1763       
1764def UpdateSeqResults(G2frame,data,prevSize=None):
1765    """
1766    Called when the Sequential Results data tree entry is selected
1767    to show results from a sequential refinement.
1768   
1769    :param wx.Frame G2frame: main GSAS-II data tree windows
1770
1771    :param dict data: a dictionary containing the following items: 
1772
1773            * 'histNames' - list of histogram names in order as processed by Sequential Refinement
1774            * 'varyList' - list of variables - identical over all refinements in sequence
1775              note that this is the original list of variables, prior to processing
1776              constraints.
1777            * 'variableLabels' -- a dict of labels to be applied to each parameter
1778              (this is created as an empty dict if not present in data).
1779            * keyed by histName - dictionaries for all data sets processed, which contains:
1780
1781              * 'variables'- result[0] from leastsq call
1782              * 'varyList' - list of variables passed to leastsq call (not same as above)
1783              * 'sig' - esds for variables
1784              * 'covMatrix' - covariance matrix from individual refinement
1785              * 'title' - histogram name; same as dict item name
1786              * 'newAtomDict' - new atom parameters after shifts applied
1787              * 'newCellDict' - refined cell parameters after shifts to A0-A5 from Dij terms applied'
1788    """
1789
1790    def GetSampleParms():
1791        '''Make a dictionary of the sample parameters are not the same over the
1792        refinement series.
1793        '''
1794        if 'IMG' in histNames[0]:
1795            sampleParmDict = {'Sample load':[],}
1796        else:
1797            sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[],
1798                'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[],
1799                'Chi':[],'Phi':[],'Azimuth':[],}
1800        Controls = G2frame.PatternTree.GetItemPyData(
1801            GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
1802        sampleParm = {}
1803        for name in histNames:
1804            if 'IMG' in name:
1805                for item in sampleParmDict:
1806                    sampleParmDict[item].append(data[name]['parmDict'].get(item,0))
1807            else:
1808                Id = GetPatternTreeItemId(G2frame,G2frame.root,name)
1809                sampleData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1810                for item in sampleParmDict:
1811                    sampleParmDict[item].append(sampleData.get(item,0))
1812        for item in sampleParmDict:
1813            frstValue = sampleParmDict[item][0]
1814            if np.any(np.array(sampleParmDict[item])-frstValue):
1815                if item.startswith('FreePrm'):
1816                    sampleParm[Controls[item]] = sampleParmDict[item]
1817                else:
1818                    sampleParm[item] = sampleParmDict[item]
1819        return sampleParm
1820
1821    def GetColumnInfo(col):
1822        '''returns column label, lists of values and errors (or None) for each column in the table
1823        for plotting. The column label is reformatted from Unicode to MatPlotLib encoding
1824        '''
1825        colName = G2frame.SeqTable.GetColLabelValue(col)
1826        plotName = variableLabels.get(colName,colName)
1827        plotName = plotSpCharFix(plotName)
1828        return plotName,colList[col],colSigs[col]
1829           
1830    def PlotSelect(event):
1831        'Plots a row (covariance) or column on double-click'
1832        cols = G2frame.dataDisplay.GetSelectedCols()
1833        rows = G2frame.dataDisplay.GetSelectedRows()
1834        if cols:
1835            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
1836        elif rows:
1837            name = histNames[rows[0]]       #only does 1st one selected
1838            G2plt.PlotCovariance(G2frame,data[name])
1839        else:
1840            G2frame.ErrorDialog(
1841                'Select row or columns',
1842                'Nothing selected in table. Click on column or row label(s) to plot. N.B. Grid selection can be a bit funky.'
1843                )
1844           
1845    def OnPlotSelSeq(event):
1846        'plot the selected columns or row from menu command'
1847        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
1848        rows = G2frame.dataDisplay.GetSelectedRows()
1849        if cols:
1850            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
1851        elif rows:
1852            name = histNames[rows[0]]       #only does 1st one selected
1853            G2plt.PlotCovariance(G2frame,data[name])
1854        else:
1855            G2frame.ErrorDialog(
1856                'Select columns',
1857                'No columns or rows selected in table. Click on row or column labels to select fields for plotting.'
1858                )
1859               
1860    def OnAveSelSeq(event):
1861        'average the selected columns from menu command'
1862        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
1863        if cols:
1864            for col in cols:
1865                ave = np.mean(GetColumnInfo(col)[1])
1866                sig = np.std(GetColumnInfo(col)[1])
1867                print ' Average for '+G2frame.SeqTable.GetColLabelValue(col)+': '+'%.6g'%(ave)+' +/- '+'%.6g'%(sig)
1868        else:
1869            G2frame.ErrorDialog(
1870                'Select columns',
1871                'No columns selected in table. Click on column labels to select fields for averaging.'
1872                )
1873               
1874    def OnRenameSelSeq(event):
1875        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
1876        colNames = [G2frame.SeqTable.GetColLabelValue(c) for c in cols]
1877        newNames = colNames[:]
1878        for i,name in enumerate(colNames):
1879            if name in variableLabels:
1880                newNames[i] = variableLabels[name]
1881        if not cols:
1882            G2frame.ErrorDialog('Select columns',
1883                'No columns selected in table. Click on column labels to select fields for rename.')
1884            return
1885        dlg = G2G.MultiStringDialog(G2frame.dataDisplay,'Set column names',colNames,newNames)
1886        if dlg.Show():
1887            newNames = dlg.GetValues()           
1888            variableLabels.update(dict(zip(colNames,newNames)))
1889        data['variableLabels'] = variableLabels
1890        dlg.Destroy()
1891        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
1892        G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
1893           
1894    def OnReOrgSelSeq(event):
1895        'Reorder the columns'
1896        G2G.GetItemOrder(G2frame,VaryListChanges,vallookup,posdict)   
1897        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
1898
1899    def OnSaveSelSeqCSV(event):
1900        'export the selected columns to a .csv file from menu command'
1901        OnSaveSelSeq(event,csv=True)
1902       
1903    def OnSaveSeqCSV(event):
1904        'export all columns to a .csv file from menu command'
1905        OnSaveSelSeq(event,csv=True,allcols=True)
1906       
1907    def OnSaveSelSeq(event,csv=False,allcols=False):
1908        'export the selected columns to a .txt or .csv file from menu command'
1909        def WriteCSV():
1910            def WriteList(headerItems):
1911                line = ''
1912                for lbl in headerItems:
1913                    if line: line += ','
1914                    line += '"'+lbl+'"'
1915                return line
1916            head = ['name']
1917            for col in cols:
1918                item = G2frame.SeqTable.GetColLabelValue(col)
1919                # get rid of labels that have Unicode characters
1920                if not all([ord(c) < 128 and ord(c) != 0 for c in item]): item = '?'
1921                if col in havesig:
1922                    head += [item,'esd-'+item]
1923                else:
1924                    head += [item]
1925            SeqFile.write(WriteList(head)+'\n')
1926            for row,name in enumerate(saveNames):
1927                line = '"'+saveNames[row]+'"'
1928                for col in cols:
1929                    if col in havesig:
1930                        line += ','+str(saveData[col][row])+','+str(saveSigs[col][row])
1931                    else:
1932                        line += ','+str(saveData[col][row])
1933                SeqFile.write(line+'\n')
1934        def WriteSeq():
1935            lenName = len(saveNames[0])
1936            line = %s  '%('name'.center(lenName))
1937            for col in cols:
1938                item = G2frame.SeqTable.GetColLabelValue(col)
1939                if col in havesig:
1940                    line += ' %12s %12s '%(item.center(12),'esd'.center(12))
1941                else:
1942                    line += ' %12s '%(item.center(12))
1943            SeqFile.write(line+'\n')
1944            for row,name in enumerate(saveNames):
1945                line = " '%s' "%(saveNames[row])
1946                for col in cols:
1947                    if col in havesig:
1948                        line += ' %12.6f %12.6f '%(saveData[col][row],saveSigs[col][row])
1949                    else:
1950                        line += ' %12.6f '%saveData[col][row]
1951                SeqFile.write(line+'\n')
1952
1953        # start of OnSaveSelSeq code
1954        if allcols:
1955            cols = range(G2frame.SeqTable.GetNumberCols())
1956        else:
1957            cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
1958        nrows = G2frame.SeqTable.GetNumberRows()
1959        if not cols:
1960            G2frame.ErrorDialog('Select columns',
1961                             'No columns selected in table. Click on column labels to select fields for output.')
1962            return
1963        saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(nrows)]
1964        saveData = {}
1965        saveSigs = {}
1966        havesig = []
1967        for col in cols:
1968            name,vals,sigs = GetColumnInfo(col)
1969            saveData[col] = vals
1970            if sigs:
1971                havesig.append(col)
1972                saveSigs[col] = sigs
1973        if csv:
1974            wild = 'CSV output file (*.csv)|*.csv'
1975        else:
1976            wild = 'Text output file (*.txt)|*.txt'
1977        dlg = wx.FileDialog(
1978            G2frame,
1979            'Choose text output file for your selection', '.', '', 
1980            wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1981        try:
1982            if dlg.ShowModal() == wx.ID_OK:
1983                SeqTextFile = dlg.GetPath()
1984                SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) 
1985                SeqFile = open(SeqTextFile,'w')
1986                if csv:
1987                    WriteCSV()
1988                else:
1989                    WriteSeq()
1990                SeqFile.close()
1991        finally:
1992            dlg.Destroy()
1993               
1994    def striphist(var,insChar=''):
1995        'strip a histogram number from a var name'
1996        sv = var.split(':')
1997        if len(sv) <= 1: return var
1998        if sv[1]:
1999            sv[1] = insChar
2000        return ':'.join(sv)
2001       
2002    def plotSpCharFix(lbl):
2003        'Change selected unicode characters to their matplotlib equivalent'
2004        for u,p in [
2005            (u'\u03B1',r'$\alpha$'),
2006            (u'\u03B2',r'$\beta$'),
2007            (u'\u03B3',r'$\gamma$'),
2008            (u'\u0394\u03C7',r'$\Delta\chi$'),
2009            ]:
2010            lbl = lbl.replace(u,p)
2011        return lbl
2012   
2013    def SelectXaxis():
2014        'returns a selected column number (or None) as the X-axis selection'
2015        ncols = G2frame.SeqTable.GetNumberCols()
2016        colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)]
2017        dlg = G2G.G2SingleChoiceDialog(
2018            G2frame.dataDisplay,
2019            'Select x-axis parameter for plot or Cancel for sequence number',
2020            'Select X-axis',
2021            colNames)
2022        try:
2023            if dlg.ShowModal() == wx.ID_OK:
2024                col = dlg.GetSelection()
2025            else:
2026                col = None
2027        finally:
2028            dlg.Destroy()
2029        return col
2030   
2031    def EnablePseudoVarMenus():
2032        'Enables or disables the PseudoVar menu items that require existing defs'
2033        if Controls['SeqPseudoVars']:
2034            val = True
2035        else:
2036            val = False
2037        G2frame.dataFrame.SequentialPvars.Enable(wxDELSEQVAR,val)
2038        G2frame.dataFrame.SequentialPvars.Enable(wxEDITSEQVAR,val)
2039
2040    def DelPseudoVar(event):
2041        'Ask the user to select a pseudo var expression to delete'
2042        choices = Controls['SeqPseudoVars'].keys()
2043        selected = G2G.ItemSelector(
2044            choices,G2frame.dataFrame,
2045            multiple=True,
2046            title='Select expressions to remove',
2047            header='Delete expression')
2048        if selected is None: return
2049        for item in selected:
2050            del Controls['SeqPseudoVars'][choices[item]]
2051        if selected:
2052            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2053
2054    def EditPseudoVar(event):
2055        'Edit an existing pseudo var expression'
2056        choices = Controls['SeqPseudoVars'].keys()
2057        if len(choices) == 1:
2058            selected = 0
2059        else:
2060            selected = G2G.ItemSelector(
2061                choices,G2frame.dataFrame,
2062                multiple=False,
2063                title='Select an expression to edit',
2064                header='Edit expression')
2065        if selected is not None:
2066            dlg = G2exG.ExpressionDialog(
2067                G2frame.dataDisplay,PSvarDict,
2068                Controls['SeqPseudoVars'][choices[selected]],
2069                header="Edit the PseudoVar expression",
2070                VarLabel="PseudoVar #"+str(selected+1),
2071                fit=False)
2072            newobj = dlg.Show(True)
2073            if newobj:
2074                calcobj = G2obj.ExpressionCalcObj(newobj)
2075                del Controls['SeqPseudoVars'][choices[selected]]
2076                Controls['SeqPseudoVars'][calcobj.eObj.expression] = newobj
2077                UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2078       
2079    def AddNewPseudoVar(event):
2080        'Create a new pseudo var expression'
2081        dlg = G2exG.ExpressionDialog(
2082            G2frame.dataDisplay,PSvarDict,
2083            header='Enter an expression for a PseudoVar here',
2084            VarLabel = "New PseudoVar",
2085            fit=False)
2086        obj = dlg.Show(True)
2087        dlg.Destroy()
2088        if obj:
2089            calcobj = G2obj.ExpressionCalcObj(obj)
2090            Controls['SeqPseudoVars'][calcobj.eObj.expression] = obj
2091            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
2092
2093    def UpdateParmDict(parmDict):
2094        '''generate the atom positions and the direct & reciprocal cell values,
2095        because they might be needed to evaluate the pseudovar
2096        '''
2097        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2098                         ['A'+str(i) for i in range(6)])
2099                     )
2100        delList = []
2101        phaselist = []
2102        for item in parmDict: 
2103            if ':' not in item: continue
2104            key = item.split(':')
2105            if len(key) < 3: continue
2106            # remove the dA[xyz] terms, they would only bring confusion
2107            if key[2].startswith('dA'):
2108                delList.append(item)
2109            # compute and update the corrected reciprocal cell terms using the Dij values
2110            elif key[2] in Ddict:
2111                if key[0] not in phaselist: phaselist.append(key[0])
2112                akey = key[0]+'::'+Ddict[key[2]]
2113                parmDict[akey] -= parmDict[item]
2114                delList.append(item)
2115        for item in delList:
2116            del parmDict[item]               
2117        for i in phaselist:
2118            pId = int(i)
2119            # apply cell symmetry
2120            A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId])
2121            # convert to direct cell & add the unique terms to the dictionary
2122            for i,val in enumerate(G2lat.A2cell(A)):
2123                if i in uniqCellIndx[pId]:
2124                    lbl = str(pId)+'::'+cellUlbl[i]
2125                    parmDict[lbl] = val
2126            lbl = str(pId)+'::'+'vol'
2127            parmDict[lbl] = G2lat.calc_V(A)
2128        return parmDict
2129
2130    def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD):
2131        '''Evaluate an expression derivative with respect to a
2132        GSAS-II variable name.
2133
2134        Note this likely could be faster if the loop over calcobjs were done
2135        inside after the Dict was created.
2136        '''
2137        step = ESD/10
2138        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
2139                         ['A'+str(i) for i in range(6)])
2140                     )
2141        results = []
2142        phaselist = []
2143        VparmDict = sampleDict.copy()
2144        for incr in step,-step:
2145            VparmDict.update(parmDict.copy())           
2146            # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]'
2147            # values are not zeroed: fix that!
2148            VparmDict.update({item:0.0 for item in parmDict if 'dA' in item})
2149            VparmDict[var] += incr
2150            G2mv.Dict2Map(VparmDict,[]) # apply constraints
2151            # generate the atom positions and the direct & reciprocal cell values now, because they might
2152            # needed to evaluate the pseudovar
2153            for item in VparmDict:
2154                if item in sampleDict:
2155                    continue 
2156                if ':' not in item: continue
2157                key = item.split(':')
2158                if len(key) < 3: continue
2159                # apply any new shifts to atom positions
2160                if key[2].startswith('dA'):
2161                    VparmDict[''.join(item.split('d'))] += VparmDict[item]
2162                    VparmDict[item] = 0.0
2163                # compute and update the corrected reciprocal cell terms using the Dij values
2164                if key[2] in Ddict:
2165                    if key[0] not in phaselist: phaselist.append(key[0])
2166                    akey = key[0]+'::'+Ddict[key[2]]
2167                    VparmDict[akey] -= VparmDict[item]
2168            for i in phaselist:
2169                pId = int(i)
2170                # apply cell symmetry
2171                A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId])
2172                # convert to direct cell & add the unique terms to the dictionary
2173                for i,val in enumerate(G2lat.A2cell(A)):
2174                    if i in uniqCellIndx[pId]:
2175                        lbl = str(pId)+'::'+cellUlbl[i]
2176                        VparmDict[lbl] = val
2177                lbl = str(pId)+'::'+'vol'
2178                VparmDict[lbl] = G2lat.calc_V(A)
2179            # dict should be fully updated, use it & calculate
2180            calcobj.SetupCalc(VparmDict)
2181            results.append(calcobj.EvalExpression())
2182        return (results[0] - results[1]) / (2.*step)
2183       
2184    def EnableParFitEqMenus():
2185        'Enables or disables the Parametric Fit menu items that require existing defs'
2186        if Controls['SeqParFitEqList']:
2187            val = True
2188        else:
2189            val = False
2190        G2frame.dataFrame.SequentialPfit.Enable(wxDELPARFIT,val)
2191        G2frame.dataFrame.SequentialPfit.Enable(wxEDITPARFIT,val)
2192        G2frame.dataFrame.SequentialPfit.Enable(wxDOPARFIT,val)
2193
2194    def ParEqEval(Values,calcObjList,varyList):
2195        '''Evaluate the parametric expression(s)
2196        :param list Values: a list of values for each variable parameter
2197        :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj`
2198          expression objects to evaluate
2199        :param list varyList: a list of variable names for each value in Values
2200        '''
2201        result = []
2202        for calcobj in calcObjList:
2203            calcobj.UpdateVars(varyList,Values)
2204            result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig)
2205        return result
2206
2207    def DoParEqFit(event,eqObj=None):
2208        'Parametric fit minimizer'
2209        varyValueDict = {} # dict of variables and their initial values
2210        calcObjList = [] # expression objects, ready to go for each data point
2211        if eqObj is not None:
2212            eqObjList = [eqObj,]
2213        else:
2214            eqObjList = Controls['SeqParFitEqList']
2215        UseFlags = G2frame.SeqTable.GetColValues(0)         
2216        for obj in eqObjList:
2217            expr = obj.expression
2218            # assemble refined vars for this equation
2219            varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()})
2220            # lookup dependent var position
2221            depVar = obj.GetDepVar()
2222            if depVar in colLabels:
2223                indx = colLabels.index(depVar)
2224            else:
2225                raise Exception('Dependent variable '+depVar+' not found')
2226            # assemble a list of the independent variables
2227            indepVars = obj.GetIndependentVars()
2228            # loop over each datapoint
2229            for j,row in enumerate(zip(*colList)):
2230                if not UseFlags[j]: continue
2231                # assemble equations to fit
2232                calcobj = G2obj.ExpressionCalcObj(obj)
2233                # prepare a dict of needed independent vars for this expression
2234                indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
2235                calcobj.SetupCalc(indepVarDict)               
2236                # values and sigs for current value of dependent var
2237                calcobj.depVal = row[indx]
2238                calcobj.depSig = colSigs[indx][j]
2239                calcObjList.append(calcobj)
2240        # varied parameters
2241        varyList = varyValueDict.keys()
2242        values = varyValues = [varyValueDict[key] for key in varyList]
2243        if not varyList:
2244            print 'no variables to refine!'
2245            return
2246        try:
2247            result = so.leastsq(ParEqEval,varyValues,full_output=True,   #ftol=Ftol,
2248                                args=(calcObjList,varyList)
2249                                )
2250            values = result[0]
2251            covar = result[1]
2252            if covar is None:
2253                raise Exception
2254            esdDict = {}
2255            for i,avar in enumerate(varyList):
2256                esdDict[avar] = np.sqrt(covar[i,i])
2257        except:
2258            print('====> Fit failed')
2259            return
2260        print('==== Fit Results ====')
2261        for obj in eqObjList:
2262            obj.UpdateVariedVars(varyList,values)
2263            ind = '      '
2264            print('  '+obj.GetDepVar()+' = '+obj.expression)
2265            for var in obj.assgnVars:
2266                print(ind+var+' = '+obj.assgnVars[var])
2267            for var in obj.freeVars:
2268                avar = "::"+obj.freeVars[var][0]
2269                val = obj.freeVars[var][1]
2270                if obj.freeVars[var][2]:
2271                    print(ind+var+' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar]))
2272                else:
2273                    print(ind+var+' = '+avar + " =" + G2mth.ValEsd(val,0))
2274        # create a plot for each parametric variable
2275        for fitnum,obj in enumerate(eqObjList):
2276            calcobj = G2obj.ExpressionCalcObj(obj)
2277            # lookup dependent var position
2278            indx = colLabels.index(obj.GetDepVar())
2279            # assemble a list of the independent variables
2280            indepVars = obj.GetIndependentVars()           
2281            # loop over each datapoint
2282            fitvals = []
2283            for j,row in enumerate(zip(*colList)):
2284                calcobj.SetupCalc(
2285                    {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
2286                    )
2287                fitvals.append(calcobj.EvalExpression())
2288            G2plt.PlotSelectedSequence(
2289                G2frame,[indx],GetColumnInfo,SelectXaxis,
2290                fitnum,fitvals)
2291
2292    def SingleParEqFit(eqObj):
2293        DoParEqFit(None,eqObj)
2294
2295    def DelParFitEq(event):
2296        'Ask the user to select function to delete'
2297        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2298        selected = G2G.ItemSelector(
2299            txtlst,G2frame.dataFrame,
2300            multiple=True,
2301            title='Select a parametric equation(s) to remove',
2302            header='Delete equation')
2303        if selected is None: return
2304        Controls['SeqParFitEqList'] = [obj for i,obj in enumerate(Controls['SeqParFitEqList']) if i not in selected]
2305        EnableParFitEqMenus()
2306        if Controls['SeqParFitEqList']: DoParEqFit(event)
2307       
2308    def EditParFitEq(event):
2309        'Edit an existing parametric equation'
2310        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2311        if len(txtlst) == 1:
2312            selected = 0
2313        else:
2314            selected = G2G.ItemSelector(
2315                txtlst,G2frame.dataFrame,
2316                multiple=False,
2317                title='Select a parametric equation to edit',
2318                header='Edit equation')
2319        if selected is not None:
2320            dlg = G2exG.ExpressionDialog(
2321                G2frame.dataDisplay,indepVarDict,
2322                Controls['SeqParFitEqList'][selected],
2323                depVarDict=depVarDict,
2324                header="Edit the formula for this minimization function",
2325                ExtraButton=['Fit',SingleParEqFit])
2326            newobj = dlg.Show(True)
2327            if newobj:
2328                calcobj = G2obj.ExpressionCalcObj(newobj)
2329                Controls['SeqParFitEqList'][selected] = newobj
2330                EnableParFitEqMenus()
2331            if Controls['SeqParFitEqList']: DoParEqFit(event)
2332
2333    def AddNewParFitEq(event):
2334        'Create a new parametric equation to be fit to sequential results'
2335
2336        # compile the variable names used in previous freevars to avoid accidental name collisions
2337        usedvarlist = []
2338        for obj in Controls['SeqParFitEqList']:
2339            for var in obj.freeVars:
2340                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
2341
2342        dlg = G2exG.ExpressionDialog(
2343            G2frame.dataDisplay,indepVarDict,
2344            depVarDict=depVarDict,
2345            header='Define an equation to minimize in the parametric fit',
2346            ExtraButton=['Fit',SingleParEqFit],
2347            usedVars=usedvarlist)
2348        obj = dlg.Show(True)
2349        dlg.Destroy()
2350        if obj:
2351            Controls['SeqParFitEqList'].append(obj)
2352            EnableParFitEqMenus()
2353            if Controls['SeqParFitEqList']: DoParEqFit(event)
2354               
2355    def CopyParFitEq(event):
2356        'Copy an existing parametric equation to be fit to sequential results'
2357        # compile the variable names used in previous freevars to avoid accidental name collisions
2358        usedvarlist = []
2359        for obj in Controls['SeqParFitEqList']:
2360            for var in obj.freeVars:
2361                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
2362        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in Controls['SeqParFitEqList']]
2363        if len(txtlst) == 1:
2364            selected = 0
2365        else:
2366            selected = G2G.ItemSelector(
2367                txtlst,G2frame.dataFrame,
2368                multiple=False,
2369                title='Select a parametric equation to copy',
2370                header='Copy equation')
2371        if selected is not None:
2372            newEqn = copy.deepcopy(Controls['SeqParFitEqList'][selected])
2373            for var in newEqn.freeVars:
2374                newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist)
2375            dlg = G2exG.ExpressionDialog(
2376                G2frame.dataDisplay,indepVarDict,
2377                newEqn,
2378                depVarDict=depVarDict,
2379                header="Edit the formula for this minimization function",
2380                ExtraButton=['Fit',SingleParEqFit])
2381            newobj = dlg.Show(True)
2382            if newobj:
2383                calcobj = G2obj.ExpressionCalcObj(newobj)
2384                Controls['SeqParFitEqList'].append(newobj)
2385                EnableParFitEqMenus()
2386            if Controls['SeqParFitEqList']: DoParEqFit(event)
2387                                           
2388    def GridSetToolTip(row,col):
2389        '''Routine to show standard uncertainties for each element in table
2390        as a tooltip
2391        '''
2392        if colSigs[col]:
2393            return u'\u03c3 = '+str(colSigs[col][row])
2394        return ''
2395       
2396    def GridColLblToolTip(col):
2397        '''Define a tooltip for a column. This will be the user-entered value
2398        (from data['variableLabels']) or the default name
2399        '''
2400        if col < 0 or col > len(colLabels):
2401            print 'Illegal column #',col
2402            return
2403        var = colLabels[col]
2404        return variableLabels.get(var,G2obj.fmtVarDescr(var))
2405       
2406    def SetLabelString(event):
2407        '''Define or edit the label for a column in the table, to be used
2408        as a tooltip and for plotting
2409        '''
2410        col = event.GetCol()
2411        if col < 0 or col > len(colLabels):
2412            return
2413        var = colLabels[col]
2414        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
2415        dlg = G2G.SingleStringDialog(G2frame.dataFrame,'Set variable label',
2416                                 'Set a new name for variable '+var,lbl,size=(400,-1))
2417        if dlg.Show():
2418            variableLabels[var] = dlg.GetValue()
2419        dlg.Destroy()
2420       
2421    #def GridRowLblToolTip(row): return 'Row ='+str(row)
2422   
2423    # lookup table for unique cell parameters by symmetry
2424    cellGUIlist = [
2425        [['m3','m3m'],(0,)],
2426        [['3R','3mR'],(0,3)],
2427        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
2428        [['mmm'],(0,1,2)],
2429        [['2/m'+'a'],(0,1,2,3)],
2430        [['2/m'+'b'],(0,1,2,4)],
2431        [['2/m'+'c'],(0,1,2,5)],
2432        [['-1'],(0,1,2,3,4,5)],
2433        ]
2434    # cell labels
2435    cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
2436
2437    #======================================================================
2438    # start processing sequential results here (UpdateSeqResults)
2439    #======================================================================
2440    if not data:
2441        print 'No sequential refinement results'
2442        return
2443    variableLabels = data.get('variableLabels',{})
2444    data['variableLabels'] = variableLabels
2445    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
2446    Controls = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
2447    # create a place to store Pseudo Vars & Parametric Fit functions, if not present
2448    if 'SeqPseudoVars' not in Controls: Controls['SeqPseudoVars'] = {}
2449    if 'SeqParFitEqList' not in Controls: Controls['SeqParFitEqList'] = []
2450    histNames = data['histNames']
2451    if G2frame.dataDisplay:
2452        G2frame.dataDisplay.Destroy()
2453    if not G2frame.dataFrame.GetStatusBar():
2454        Status = G2frame.dataFrame.CreateStatusBar()
2455        Status.SetStatusText("Select column to export; Double click on column to plot data; on row for Covariance")
2456    sampleParms = GetSampleParms()
2457
2458    # make dict of varied atom coords keyed by absolute position
2459    newAtomDict = data[histNames[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
2460    # Possible error: the next might need to be data[histNames[0]]['varyList']
2461    # error will arise if there constraints on coordinates?
2462    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in data['varyList']}
2463   
2464    # make dict of varied cell parameters equivalents
2465    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
2466    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
2467    # N.B. These Dij vars are missing a histogram #
2468    newCellDict = data[histNames[0]].get('newCellDict',{})
2469    for item in newCellDict:
2470        if item in data['varyList']:
2471            ESDlookup[newCellDict[item][0]] = item
2472            Dlookup[item] = newCellDict[item][0]
2473    # add coordinate equivalents to lookup table
2474    for parm in atomLookup:
2475        Dlookup[atomLookup[parm]] = parm
2476        ESDlookup[parm] = atomLookup[parm]
2477
2478    # get unit cell & symmetry for all phases & initial stuff for later use
2479    RecpCellTerms = {}
2480    SGdata = {}
2481    uniqCellIndx = {}
2482    initialCell = {}
2483    RcellLbls = {}
2484    zeroDict = {}
2485    Rcelldict = {}
2486    for phase in Phases:
2487        phasedict = Phases[phase]
2488        pId = phasedict['pId']
2489        pfx = str(pId)+'::' # prefix for A values from phase
2490        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
2491        RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7])
2492        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
2493        SGdata[pId] = phasedict['General']['SGData']
2494        Rcelldict.update({lbl:val for lbl,val in zip(RcellLbls[pId],RecpCellTerms[pId])})
2495        laue = SGdata[pId]['SGLaue']
2496        if laue == '2/m':
2497            laue += SGdata[pId]['SGUniq']
2498        for symlist,celllist in cellGUIlist:
2499            if laue in symlist:
2500                uniqCellIndx[pId] = celllist
2501                break
2502        else: # should not happen
2503            uniqCellIndx[pId] = range(6)
2504        for i in uniqCellIndx[pId]:
2505            initialCell[str(pId)+'::A'+str(i)] =  RecpCellTerms[pId][i]
2506
2507    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
2508    G2frame.dataFrame.SetLabel('Sequential refinement results')
2509    if not G2frame.dataFrame.GetStatusBar():
2510        Status = G2frame.dataFrame.CreateStatusBar()
2511        Status.SetStatusText('')
2512    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=wxID_RENAMESEQSEL)
2513    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
2514    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=wxID_SAVESEQSELCSV)
2515    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=wxID_SAVESEQCSV)
2516    G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=wxID_PLOTSEQSEL)
2517    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAveSelSeq, id=wxID_AVESEQSEL)
2518    G2frame.dataFrame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=wxID_ORGSEQSEL)
2519    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=wxADDSEQVAR)
2520    G2frame.dataFrame.Bind(wx.EVT_MENU, DelPseudoVar, id=wxDELSEQVAR)
2521    G2frame.dataFrame.Bind(wx.EVT_MENU, EditPseudoVar, id=wxEDITSEQVAR)
2522    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewParFitEq, id=wxADDPARFIT)
2523    G2frame.dataFrame.Bind(wx.EVT_MENU, CopyParFitEq, id=wxCOPYPARFIT)
2524    G2frame.dataFrame.Bind(wx.EVT_MENU, DelParFitEq, id=wxDELPARFIT)
2525    G2frame.dataFrame.Bind(wx.EVT_MENU, EditParFitEq, id=wxEDITPARFIT)
2526    G2frame.dataFrame.Bind(wx.EVT_MENU, DoParEqFit, id=wxDOPARFIT)
2527    EnablePseudoVarMenus()
2528    EnableParFitEqMenus()
2529
2530    # scan for locations where the variables change
2531    VaryListChanges = [] # histograms where there is a change
2532    combinedVaryList = []
2533    firstValueDict = {}
2534    vallookup = {}
2535    posdict = {}
2536    prevVaryList = []
2537    for i,name in enumerate(histNames):
2538        for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']):
2539            svar = striphist(var,'*') # wild-carded
2540            if svar not in combinedVaryList:
2541                # add variables to list as they appear
2542                combinedVaryList.append(svar)
2543                firstValueDict[svar] = (val,sig)
2544        if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous
2545            prevVaryList = data[name]['varyList']
2546            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
2547            posdict[name] = {}
2548            for var in data[name]['varyList']:
2549                svar = striphist(var,'*')
2550                posdict[name][combinedVaryList.index(svar)] = svar
2551            VaryListChanges.append(name)
2552    if len(VaryListChanges) > 1:
2553        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,True)
2554    else:
2555        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,False)
2556    #-----------------------------------------------------------------------------------
2557    # build up the data table by columns -----------------------------------------------
2558    nRows = len(histNames)
2559    colList = [nRows*[True]]
2560    colSigs = [None]
2561    colLabels = ['Use']
2562    Types = [wg.GRID_VALUE_BOOL]
2563    # start with Rwp values
2564    if 'IMG ' not in histNames[0][:4]:
2565        colList += [[data[name]['Rvals']['Rwp'] for name in histNames]]
2566        colSigs += [None]
2567        colLabels += ['Rwp']
2568        Types += [wg.GRID_VALUE_FLOAT+':10,3',]
2569    # add % change in Chi^2 in last cycle
2570    if histNames[0][:4] not in ['SASD','IMG '] and Controls.get('ShowCell'):
2571        colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]]
2572        colSigs += [None]
2573        colLabels += [u'\u0394\u03C7\u00B2 (%)']
2574        Types += [wg.GRID_VALUE_FLOAT,]
2575    deltaChiCol = len(colLabels)-1
2576    # add changing sample parameters to table
2577    for key in sampleParms:
2578        colList += [sampleParms[key]]
2579        colSigs += [None]
2580        colLabels += [key]
2581        Types += [wg.GRID_VALUE_FLOAT,]
2582    sampleDict = {}
2583    for i,name in enumerate(histNames):
2584        sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) 
2585    # add unique cell parameters TODO: review this where the cell symmetry changes (when possible)
2586    if Controls.get('ShowCell',False):
2587        for pId in sorted(RecpCellTerms):
2588            pfx = str(pId)+'::' # prefix for A values from phase
2589            cells = []
2590            cellESDs = []
2591            colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
2592            colLabels += [pfx+'Vol']
2593            Types += (1+len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT,]
2594            for name in histNames:
2595                covData = {
2596                    'varyList': [Dlookup.get(striphist(v),v) for v in data[name]['varyList']],
2597                    'covMatrix': data[name]['covMatrix']
2598                    }
2599                A = RecpCellTerms[pId][:] # make copy of starting A values
2600                # update with refined values
2601                for i in range(6):
2602                    var = str(pId)+'::A'+str(i)
2603                    if var in ESDlookup:
2604                        val = data[name]['newCellDict'][ESDlookup[var]][1] # get refined value
2605                        A[i] = val # override with updated value
2606                # apply symmetry
2607                Albls = [pfx+'A'+str(i) for i in range(6)]
2608                cellDict = dict(zip(Albls,A))
2609                A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
2610                # convert to direct cell & add only unique values to table
2611                c = G2lat.A2cell(A)
2612                vol = G2lat.calc_V(A)
2613                cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
2614                cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
2615                cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
2616            colList += zip(*cells)
2617            colSigs += zip(*cellESDs)
2618    # sort out the variables in their selected order
2619    varcols = 0
2620    for d in posdict.itervalues():
2621        varcols = max(varcols,max(d.keys())+1)
2622    # get labels for each column
2623    for i in range(varcols):
2624        lbl = ''
2625        for h in VaryListChanges:
2626            if posdict[h].get(i):
2627                if posdict[h].get(i) in lbl: continue
2628                if lbl != "": lbl += '/'
2629                lbl += posdict[h].get(i)
2630        colLabels.append(lbl)
2631    Types += varcols*[wg.GRID_VALUE_FLOAT]
2632    vals = []
2633    esds = []
2634    varsellist = None        # will be a list of variable names in the order they are selected to appear
2635    # tabulate values for each hist, leaving None for blank columns
2636    for name in histNames:
2637        if name in posdict:
2638            varsellist = [posdict[name].get(i) for i in range(varcols)]
2639            # translate variable names to how they will be used in the headings
2640            vs = [striphist(v,'*') for v in data[name]['varyList']]
2641            # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists
2642            sellist = [vs.index(v) if v is not None else None for v in varsellist]
2643            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])]
2644        if not varsellist: raise Exception()
2645        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
2646        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
2647        #GSASIIpath.IPyBreak()
2648    colList += zip(*vals)
2649    colSigs += zip(*esds)
2650               
2651    # tabulate constrained variables, removing histogram numbers if needed
2652    # from parameter label
2653    depValDict = {}
2654    depSigDict = {}
2655    for name in histNames:
2656        for var in data[name].get('depParmDict',{}):
2657            val,sig = data[name]['depParmDict'][var]
2658            svar = striphist(var,'*')
2659            if svar not in depValDict:
2660               depValDict[svar] = [val]
2661               depSigDict[svar] = [sig]
2662            else:
2663               depValDict[svar].append(val)
2664               depSigDict[svar].append(sig)
2665    # add the dependent constrained variables to the table
2666    for var in sorted(depValDict):
2667        if len(depValDict[var]) != len(histNames): continue
2668        colLabels.append(var)
2669        Types += [wg.GRID_VALUE_FLOAT,]
2670        colSigs += [depSigDict[var]]
2671        colList += [depValDict[var]]
2672
2673    # add atom parameters to table
2674    colLabels += atomLookup.keys()
2675    Types += len(atomLookup)*[wg.GRID_VALUE_FLOAT]
2676    for parm in sorted(atomLookup):
2677        colList += [[data[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
2678        if atomLookup[parm] in data[histNames[0]]['varyList']:
2679            col = data[histNames[0]]['varyList'].index(atomLookup[parm])
2680            colSigs += [[data[name]['sig'][col] for name in histNames]]
2681        else:
2682            colSigs += [None] # should not happen
2683    # evaluate Pseudovars, their ESDs and add them to grid
2684    for expr in Controls['SeqPseudoVars']:
2685        obj = Controls['SeqPseudoVars'][expr]
2686        calcobj = G2obj.ExpressionCalcObj(obj)
2687        valList = []
2688        esdList = []
2689        for seqnum,name in enumerate(histNames):
2690            sigs = data[name]['sig']
2691            G2mv.InitVars()
2692            parmDict = data[name].get('parmDict')
2693            badVary = data[name].get('badVary',[])
2694            constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum])
2695            groups,parmlist,constrDict,fixedList,ihst = constraintInfo
2696            varyList = data[name]['varyList']
2697            parmDict = data[name]['parmDict']
2698            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmDict,SeqHist=ihst)
2699            derivs = np.array(
2700                [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD)
2701                 for var,ESD in zip(varyList,sigs)]
2702                )
2703            esdList.append(np.sqrt(
2704                np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T))
2705                ))
2706            PSvarDict = parmDict.copy()
2707            PSvarDict.update(sampleDict[name])
2708            UpdateParmDict(PSvarDict)
2709            calcobj.UpdateDict(PSvarDict)
2710            valList.append(calcobj.EvalExpression())
2711        if not esdList:
2712            esdList = None
2713        colList += [valList]
2714        colSigs += [esdList]
2715        colLabels += [expr]
2716        Types += [wg.GRID_VALUE_FLOAT,]
2717    #---- table build done -------------------------------------------------------------
2718
2719    # Make dict needed for creating & editing pseudovars (PSvarDict).
2720    name = histNames[0]
2721    parmDict = data[name].get('parmDict')
2722    PSvarDict = parmDict.copy()
2723    PSvarDict.update(sampleParms)
2724    UpdateParmDict(PSvarDict)
2725    # Also dicts of dependent (depVarDict) & independent vars (indepVarDict)
2726    # for Parametric fitting from the data table
2727    parmDict = dict(zip(colLabels,zip(*colList)[0])) # scratch dict w/all values in table
2728    parmDict.update(
2729        {var:val for var,val in data[name].get('newCellDict',{}).values()} #  add varied reciprocal cell terms
2730    )
2731    name = histNames[0]
2732
2733    #******************************************************************************
2734    # create a set of values for example evaluation of pseudovars and
2735    # this does not work for refinements that have differing numbers of variables.
2736    #raise Exception
2737    indepVarDict = {}     #  values in table w/o ESDs
2738    depVarDict = {}
2739    for i,var in enumerate(colLabels):
2740        if var == 'Use': continue
2741        if colList[i][0] is None:
2742            val,sig = firstValueDict.get(var,[None,None])
2743        elif colSigs[i]:
2744            val,sig = colList[i][0],colSigs[i][0]
2745        else:
2746            val,sig = colList[i][0],None
2747        if val is None:
2748            continue
2749        elif sig is None:
2750            indepVarDict[var] = val
2751        elif striphist(var) not in Dlookup:
2752            depVarDict[var] = val
2753    # add recip cell coeff. values
2754    depVarDict.update({var:val for var,val in data[name].get('newCellDict',{}).values()})
2755
2756    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
2757    G2frame.SeqTable = G2G.Table(
2758        [list(c) for c in zip(*colList)],     # convert from columns to rows
2759        colLabels=colLabels,rowLabels=histNames,types=Types)
2760    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
2761    #G2frame.dataDisplay.EnableEditing(False)
2762    # make all but first column read-only
2763    for c in range(1,len(colLabels)):
2764        for r in range(nRows):
2765            G2frame.dataDisplay.SetCellReadOnly(r,c)
2766    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, PlotSelect)
2767    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, SetLabelString)
2768    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
2769    G2frame.dataDisplay.SetMargins(0,0)
2770    G2frame.dataDisplay.AutoSizeColumns(True)
2771    if prevSize:
2772        G2frame.dataDisplay.SetSize(prevSize)
2773    else:
2774        G2frame.dataFrame.setSizePosLeft([700,350])
2775    # highlight unconverged shifts
2776    if histNames[0][:4] not in ['SASD','IMG ']:
2777        for row,name in enumerate(histNames):
2778            deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol)
2779            if deltaChi > 10.:
2780                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0))
2781            elif deltaChi > 1.0:
2782                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0))
2783    G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip)
2784    G2frame.dataDisplay.SendSizeEvent() # resize needed on mac
2785    G2frame.dataDisplay.Refresh() # shows colored text on mac
2786   
2787################################################################################
2788#####  Main PWDR panel
2789################################################################################           
2790       
2791def UpdatePWHKPlot(G2frame,kind,item):
2792    '''Called when the histogram main tree entry is called. Displays the
2793    histogram weight factor, refinement statistics for the histogram
2794    and the range of data for a simulation.
2795
2796    Also invokes a plot of the histogram.
2797    '''
2798    def onEditSimRange(event):
2799        'Edit simulation range'
2800        inp = [
2801            min(data[1][0]),
2802            max(data[1][0]),
2803            None
2804            ]
2805        inp[2] = (inp[1] - inp[0])/(len(data[1][0])-1.)
2806        names = ('start angle', 'end angle', 'step size')
2807        dictlst = [inp] * len(inp)
2808        elemlst = range(len(inp))
2809        dlg = G2G.ScrolledMultiEditor(
2810            G2frame,[inp] * len(inp), range(len(inp)), names,
2811            header='Edit simulation range',
2812            minvals=(0.001,0.001,0.0001),
2813            maxvals=(180.,180.,.1),
2814            )
2815        dlg.CenterOnParent()
2816        val = dlg.ShowModal()
2817        dlg.Destroy()
2818        if val != wx.ID_OK: return
2819        if inp[0] > inp[1]:
2820            end,start,step = inp
2821        else:               
2822            start,end,step = inp
2823        step = abs(step)
2824        N = int((end-start)/step)+1
2825        newdata = np.linspace(start,end,N,True)
2826        if len(newdata) < 2: return # too small a range - reject
2827        data[1] = [newdata,np.zeros_like(newdata),np.ones_like(newdata),
2828            np.zeros_like(newdata),np.zeros_like(newdata),np.zeros_like(newdata)]
2829        Tmin = newdata[0]
2830        Tmax = newdata[-1]
2831        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,item,'Limits'),
2832            [(Tmin,Tmax),[Tmin,Tmax]])
2833        UpdatePWHKPlot(G2frame,kind,item) # redisplay data screen
2834
2835    def OnPlot3DHKL(event):
2836        refList = data[1]['RefList']
2837        FoMax = np.max(refList.T[8+Super])
2838        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2839        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2840        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
2841        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
2842            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
2843            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
2844            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
2845        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2846       
2847    def OnPlotAll3DHKL(event):
2848        choices = GetPatternTreeDataNames(G2frame,['HKLF',])
2849        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select reflection sets to plot',
2850            'Use data',choices)
2851        try:
2852            if dlg.ShowModal() == wx.ID_OK:
2853                refNames = [choices[i] for i in dlg.GetSelections()]
2854            else:
2855                return
2856        finally:
2857            dlg.Destroy()
2858        refList = np.zeros(0)
2859        for name in refNames:
2860            Id = GetPatternTreeItemId(G2frame,G2frame.root, name)
2861            reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
2862            if len(refList):
2863                refList = np.concatenate((refList,reflData['RefList']))
2864            else:
2865                refList = reflData['RefList']
2866           
2867        FoMax = np.max(refList.T[8+Super])
2868        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2869        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2870        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
2871        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
2872            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
2873            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
2874            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
2875        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2876       
2877       
2878    def OnErrorAnalysis(event):
2879        G2plt.PlotDeltSig(G2frame,kind)
2880       
2881    def OnWtFactor(event):
2882        try:
2883            val = float(wtval.GetValue())
2884        except ValueError:
2885            val = data[0]['wtFactor']
2886        data[0]['wtFactor'] = val
2887        wtval.SetValue('%.3f'%(val))
2888       
2889    def OnCompression(event):
2890        data[0] = int(comp.GetValue())
2891       
2892    def onCopyPlotCtrls(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.CopyPlotCtrls(G2frame)
2897
2898    def onCopySelectedItems(event):
2899        '''Respond to menu item to copy multiple sections from a histogram.
2900        Need this here to pass on the G2frame object.
2901        '''
2902        G2pdG.CopySelectedHistItems(G2frame)
2903           
2904    data = G2frame.PatternTree.GetItemPyData(item)
2905#patches
2906    if 'wtFactor' not in data[0]:
2907        data[0] = {'wtFactor':1.0}
2908#    if kind == 'PWDR' and 'Compression' not in data[0]:
2909#        data[0]['Compression'] = 1
2910    #if isinstance(data[1],list) and kind == 'HKLF':
2911    if 'list' in str(type(data[1])) and kind == 'HKLF':
2912        RefData = {'RefList':[],'FF':[]}
2913        for ref in data[1]:
2914            RefData['RefList'].append(ref[:11]+[ref[13],])
2915            RefData['FF'].append(ref[14])
2916        data[1] = RefData
2917        G2frame.PatternTree.SetItemPyData(item,data)
2918#end patches
2919    if G2frame.dataDisplay:
2920        G2frame.dataDisplay.Destroy()
2921    if kind in ['PWDR','SASD']:
2922        SetDataMenuBar(G2frame,G2frame.dataFrame.PWDRMenu)
2923        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
2924        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
2925        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopyPlotCtrls, id=wxID_PLOTCTRLCOPY)
2926    elif kind in ['HKLF',]:
2927        SetDataMenuBar(G2frame,G2frame.dataFrame.HKLFMenu)
2928        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
2929        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=wxID_PWD3DHKLPLOT)
2930        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotAll3DHKL, id=wxID_3DALLHKLPLOT)
2931#        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
2932    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2933   
2934    mainSizer = wx.BoxSizer(wx.VERTICAL)
2935    mainSizer.Add((5,5),)
2936    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
2937    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,WACV)
2938    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
2939    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
2940    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
2941    wtSizer.Add(wtval,0,WACV)
2942#    if kind == 'PWDR':         #possible future compression feature; NB above patch as well
2943#        wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Compression factor: '),0,WACV)
2944#        choice = ['1','2','3','4','5','6']
2945#        comp = wx.ComboBox(parent=G2frame.dataDisplay,choices=choice,
2946#            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2947#        comp.SetValue(str(data[0]['Compression']))
2948#        comp.Bind(wx.EVT_COMBOBOX, OnCompression)
2949#        wtSizer.Add(comp,0,WACV)
2950    mainSizer.Add(wtSizer)
2951    if data[0].get('Dummy'):
2952        simSizer = wx.BoxSizer(wx.HORIZONTAL)
2953        Tmin = min(data[1][0])
2954        Tmax = max(data[1][0])
2955        num = len(data[1][0])
2956        step = (Tmax - Tmin)/(num-1)
2957        t = u'2\u03b8' # 2theta
2958        lbl =  u'Simulation range: {:.2f} to {:.2f} {:s}\nwith {:.4f} steps ({:d} points)'
2959        lbl += u'\n(Edit range resets observed intensities).'
2960        lbl = lbl.format(Tmin,Tmax,t,step,num)
2961        simSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,lbl),
2962                    0,WACV)
2963        but = wx.Button(G2frame.dataDisplay,wx.ID_ANY,"Edit range")
2964        but.Bind(wx.EVT_BUTTON,onEditSimRange)
2965        simSizer.Add(but,0,WACV)
2966        mainSizer.Add(simSizer)
2967    if 'Nobs' in data[0]:
2968        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
2969            ' Data residual wR: %.3f%% on %d observations'%(data[0]['wR'],data[0]['Nobs'])))
2970        for value in data[0]:
2971            if 'Nref' in value:
2972                pfx = value.split('Nref')[0]
2973                name = data[0].get(pfx.split(':')[0]+'::Name','?')
2974                if 'SS' in value:
2975                    mainSizer.Add((5,5),)
2976                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For incommensurate phase '+name+':'))
2977                    for m,(Rf2,Rf,Nobs) in enumerate(zip(data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])):
2978                        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
2979                            u' m = +/- %d: RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
2980                            (m,Rf2,Rf,Nobs)))
2981                else:
2982                    mainSizer.Add((5,5),)
2983                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For phase '+name+':'))
2984                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
2985                        u' Unweighted phase residuals RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
2986                        (data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])))
2987                   
2988    mainSizer.Add((5,5),)
2989    mainSizer.Layout()   
2990    G2frame.dataDisplay.SetSizer(mainSizer)
2991    Size = mainSizer.Fit(G2frame.dataFrame)
2992    Size[1] += 10
2993    G2frame.dataFrame.setSizePosLeft(Size)
2994    G2frame.PatternTree.SetItemPyData(item,data)
2995    if kind in ['PWDR','SASD']:
2996        if 'xylim' in dir(G2frame):
2997            NewPlot = False
2998        else:
2999
3000            NewPlot = True
3001        G2plt.PlotPatterns(G2frame,plotType=kind,newPlot=NewPlot)
3002    elif kind == 'HKLF':
3003        Name = G2frame.PatternTree.GetItemText(item)
3004        phaseName = G2pdG.IsHistogramInAnyPhase(G2frame,Name)
3005        if phaseName:
3006            pId = GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3007            phaseId =  GetPatternTreeItemId(G2frame,pId,phaseName)
3008            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3009            Super = General.get('Super',0)
3010            SuperVec = General.get('SuperVec',[])
3011        else:
3012            Super = 0
3013            SuperVec = []       
3014        refList = data[1]['RefList']
3015        FoMax = np.max(refList.T[5+data[1].get('Super',0)])
3016        page = G2frame.G2plotNB.nb.GetSelection()
3017        tab = ''
3018        if page >= 0:
3019            tab = G2frame.G2plotNB.nb.GetPageText(page)
3020        if '3D' in tab:
3021            Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3022            Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3023            Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3024            Page = G2frame.G2plotNB.nb.GetPage(page)
3025            controls = Page.controls
3026            G2plt.Plot3DSngl(G2frame,newPlot=False,Data=controls,hklRef=refList,Title=phaseName)
3027        else:
3028            controls = {'Type' : 'Fo','ifFc' : True,     
3029                'HKLmax' : [int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))],
3030                'HKLmin' : [int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))],
3031                'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3032            G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList)
3033                 
3034################################################################################
3035#####  Pattern tree routines
3036################################################################################           
3037       
3038def GetPatternTreeDataNames(G2frame,dataTypes):
3039    '''Needs a doc string
3040    '''
3041    names = []
3042    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
3043    while item:
3044        name = G2frame.PatternTree.GetItemText(item)
3045        if name[:4] in dataTypes:
3046            names.append(name)
3047        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3048    return names
3049                         
3050def GetPatternTreeItemId(G2frame, parentId, itemText):
3051    '''Needs a doc string
3052    '''
3053    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
3054    while item:
3055        if G2frame.PatternTree.GetItemText(item) == itemText:
3056            return item
3057        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
3058    return 0               
3059
3060def MovePatternTreeToGrid(G2frame,item):
3061    '''Called from GSASII.OnPatternTreeSelChanged when a item is selected on the tree
3062    '''
3063    pickName = G2frame.PatternTree.GetItemText(item)
3064    if G2frame.PickIdText == pickName:
3065        return
3066   
3067    oldPage = None # will be set later if already on a Phase item
3068    if G2frame.dataFrame:
3069        SetDataMenuBar(G2frame)
3070        if G2frame.dataFrame.GetLabel() == 'Comments':
3071            try:
3072                data = [G2frame.dataDisplay.GetValue()]
3073                G2frame.dataDisplay.Clear() 
3074                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
3075                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3076            except:     #clumsy but avoids dead window problem when opening another project
3077                pass
3078        elif G2frame.dataFrame.GetLabel() == 'Notebook':
3079            try:
3080                data = [G2frame.dataDisplay.GetValue()]
3081                G2frame.dataDisplay.Clear() 
3082                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
3083                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
3084            except:     #clumsy but avoids dead window problem when opening another project
3085                pass
3086        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
3087            if G2frame.dataDisplay: 
3088                oldPage = G2frame.dataDisplay.GetSelection()
3089        G2frame.dataFrame.Clear()
3090        G2frame.dataFrame.SetLabel('')
3091    else:
3092        #create the frame for the data item window
3093        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
3094        G2frame.dataFrame.PhaseUserSize = None
3095       
3096    G2frame.dataFrame.Raise()           
3097    G2frame.PickId = item
3098    G2frame.PickIdText = None
3099    parentID = G2frame.root
3100    #for i in G2frame.ExportPattern: i.Enable(False)
3101    defWid = [250,150]
3102    if item != G2frame.root:
3103        parentID = G2frame.PatternTree.GetItemParent(item)
3104    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
3105        G2frame.PatternId = item
3106        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
3107            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
3108            G2frame.PatternId = 0
3109            #for i in G2frame.ExportPattern: i.Enable(False)
3110            data = G2frame.PatternTree.GetItemPyData(item)
3111            UpdateNotebook(G2frame,data)
3112        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
3113            G2frame.PatternId = 0
3114            #for i in G2frame.ExportPattern: i.Enable(False)
3115            data = G2frame.PatternTree.GetItemPyData(item)
3116            if not data:           #fill in defaults
3117                data = copy.copy(G2obj.DefaultControls)    #least squares controls
3118                G2frame.PatternTree.SetItemPyData(item,data)                             
3119            for i in G2frame.Refine: i.Enable(True)
3120            G2frame.EnableSeqRefineMenu()
3121            UpdateControls(G2frame,data)
3122        elif G2frame.PatternTree.GetItemText(item) == 'Sequential results':
3123            data = G2frame.PatternTree.GetItemPyData(item)
3124            UpdateSeqResults(G2frame,data)
3125        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
3126            data = G2frame.PatternTree.GetItemPyData(item)
3127            G2frame.dataFrame.setSizePosLeft(defWid)
3128            text = ''
3129            if 'Rvals' in data:
3130                Nvars = len(data['varyList'])
3131                Rvals = data['Rvals']
3132                text = '\nFinal residuals: \nwR = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
3133                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
3134                if 'lamMax' in Rvals:
3135                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
3136            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
3137                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
3138            G2plt.PlotCovariance(G2frame,data)
3139        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
3140            data = G2frame.PatternTree.GetItemPyData(item)
3141            G2cnstG.UpdateConstraints(G2frame,data)
3142        elif G2frame.PatternTree.GetItemText(item) == 'Rigid bodies':
3143            data = G2frame.PatternTree.GetItemPyData(item)
3144            G2cnstG.UpdateRigidBodies(G2frame,data)
3145        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
3146            data = G2frame.PatternTree.GetItemPyData(item)
3147            Phases = G2frame.GetPhaseData()
3148            phase = ''
3149            phaseName = ''
3150            if Phases:
3151                phaseName = Phases.keys()[0]
3152            G2frame.dataFrame.setSizePosLeft(defWid)
3153            G2restG.UpdateRestraints(G2frame,data,Phases,phaseName)
3154        elif 'IMG' in G2frame.PatternTree.GetItemText(item):
3155            G2frame.Image = item
3156            G2frame.dataFrame.SetTitle('Image Data')
3157            data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId( \
3158                G2frame,item,'Image Controls'))
3159            G2imG.UpdateImageData(G2frame,data)
3160            G2plt.PlotImage(G2frame,newPlot=True)
3161        elif 'PKS' in G2frame.PatternTree.GetItemText(item):
3162            G2plt.PlotPowderLines(G2frame)
3163        elif 'PWDR' in G2frame.PatternTree.GetItemText(item):
3164            #for i in G2frame.ExportPattern: i.Enable(True)
3165            if G2frame.EnablePlot:
3166                UpdatePWHKPlot(G2frame,'PWDR',item)
3167        elif 'SASD' in G2frame.PatternTree.GetItemText(item):
3168            #for i in G2frame.ExportPattern: i.Enable(True)
3169            if G2frame.EnablePlot:
3170                UpdatePWHKPlot(G2frame,'SASD',item)
3171        elif 'HKLF' in G2frame.PatternTree.GetItemText(item):
3172            G2frame.Sngl = True
3173            UpdatePWHKPlot(G2frame,'HKLF',item)
3174        elif 'PDF' in G2frame.PatternTree.GetItemText(item):
3175            G2frame.PatternId = item
3176            for i in G2frame.ExportPDF: i.Enable(True)
3177            G2plt.PlotISFG(G2frame,type='S(Q)')
3178        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
3179            G2frame.dataFrame.setSizePosLeft(defWid)
3180            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
3181                value='Select one phase to see its parameters')           
3182    elif 'I(Q)' in G2frame.PatternTree.GetItemText(item):
3183        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3184        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3185        G2pdG.UpdatePDFGrid(G2frame,data)
3186        G2plt.PlotISFG(G2frame,type='I(Q)',newPlot=True)
3187    elif 'S(Q)' in G2frame.PatternTree.GetItemText(item):
3188        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3189        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3190        G2pdG.UpdatePDFGrid(G2frame,data)
3191        G2plt.PlotISFG(G2frame,type='S(Q)',newPlot=True)
3192    elif 'F(Q)' in G2frame.PatternTree.GetItemText(item):
3193        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3194        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3195        G2pdG.UpdatePDFGrid(G2frame,data)
3196        G2plt.PlotISFG(G2frame,type='F(Q)',newPlot=True)
3197    elif 'G(R)' in G2frame.PatternTree.GetItemText(item):
3198        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3199        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
3200        G2pdG.UpdatePDFGrid(G2frame,data)
3201        G2plt.PlotISFG(G2frame,type='G(R)',newPlot=True)           
3202    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
3203        data = G2frame.PatternTree.GetItemPyData(item)
3204        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
3205    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
3206        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
3207        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3208        data = G2frame.PatternTree.GetItemPyData(item)
3209        UpdateComments(G2frame,data)
3210    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
3211        G2frame.dataFrame.SetTitle('Image Controls')
3212        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3213        masks = G2frame.PatternTree.GetItemPyData(
3214            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
3215        data = G2frame.PatternTree.GetItemPyData(item)
3216        G2imG.UpdateImageControls(G2frame,data,masks)
3217        G2plt.PlotImage(G2frame)
3218    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
3219        G2frame.dataFrame.SetTitle('Masks')
3220        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3221        data = G2frame.PatternTree.GetItemPyData(item)
3222        G2imG.UpdateMasks(G2frame,data)
3223        G2plt.PlotImage(G2frame)
3224    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
3225        G2frame.dataFrame.SetTitle('Stress/Strain')
3226        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
3227        data = G2frame.PatternTree.GetItemPyData(item)
3228        G2plt.PlotImage(G2frame)
3229        G2plt.PlotStrain(G2frame,data,newPlot=True)
3230        G2imG.UpdateStressStrain(G2frame,data)
3231    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
3232        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3233        for i in G2frame.ExportPDF: i.Enable(True)
3234        data = G2frame.PatternTree.GetItemPyData(item)
3235        G2pdG.UpdatePDFGrid(G2frame,data)
3236        G2plt.PlotISFG(G2frame,type='I(Q)')
3237        G2plt.PlotISFG(G2frame,type='S(Q)')
3238        G2plt.PlotISFG(G2frame,type='F(Q)')
3239        G2plt.PlotISFG(G2frame,type='G(R)')
3240    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
3241        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3242        for i in G2frame.ExportPeakList: i.Enable(True)
3243        data = G2frame.PatternTree.GetItemPyData(item)
3244#patch
3245        if 'list' in str(type(data)):
3246            data = {'peaks':data,'sigDict':{}}
3247            G2frame.PatternTree.SetItemPyData(item,data)
3248#end patch
3249        G2pdG.UpdatePeakGrid(G2frame,data)
3250        G2plt.PlotPatterns(G2frame)
3251    elif G2frame.PatternTree.GetItemText(item) == 'Background':
3252        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3253        data = G2frame.PatternTree.GetItemPyData(item)
3254        G2pdG.UpdateBackground(G2frame,data)
3255        G2plt.PlotPatterns(G2frame)
3256    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
3257        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3258        datatype = G2frame.PatternTree.GetItemText(G2frame.PatternId)[:4]
3259        data = G2frame.PatternTree.GetItemPyData(item)
3260        G2pdG.UpdateLimitsGrid(G2frame,data,datatype)
3261        G2plt.PlotPatterns(G2frame,plotType=datatype)
3262    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
3263        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3264        data = G2frame.PatternTree.GetItemPyData(item)[0]
3265        G2pdG.UpdateInstrumentGrid(G2frame,data)
3266        if 'P' in data['Type'][0]:          #powder data only
3267            G2plt.PlotPeakWidths(G2frame)
3268    elif G2frame.PatternTree.GetItemText(item) == 'Models':
3269        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3270        data = G2frame.PatternTree.GetItemPyData(item)
3271        G2pdG.UpdateModelsGrid(G2frame,data)
3272        G2plt.PlotPatterns(G2frame,plotType='SASD')
3273        if len(data['Size']['Distribution']):
3274            G2plt.PlotSASDSizeDist(G2frame)
3275    elif G2frame.PatternTree.GetItemText(item) == 'Substances':
3276        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3277        data = G2frame.PatternTree.GetItemPyData(item)
3278        G2pdG.UpdateSubstanceGrid(G2frame,data)
3279    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
3280        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3281        data = G2frame.PatternTree.GetItemPyData(item)
3282        datatype = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[2][:4]
3283
3284        if 'Temperature' not in data:           #temp fix for old gpx files
3285            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
3286                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,
3287                    'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
3288                    'Gonio. radius':200.0}
3289            G2frame.PatternTree.SetItemPyData(item,data)
3290   
3291        G2pdG.UpdateSampleGrid(G2frame,data)
3292        G2plt.PlotPatterns(G2frame,plotType=datatype)
3293    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
3294        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3295        for i in G2frame.ExportPeakList: i.Enable(True)
3296        data = G2frame.PatternTree.GetItemPyData(item)
3297#patch
3298        if len(data) != 2:
3299            data = [data,[]]
3300            G2frame.PatternTree.SetItemPyData(item,data)
3301#end patch
3302        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
3303        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
3304            G2plt.PlotPowderLines(G2frame)
3305        else:
3306            G2plt.PlotPatterns(G2frame)
3307    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
3308        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3309        data = G2frame.PatternTree.GetItemPyData(item)
3310        if not data:
3311            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
3312            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
3313            data.append([])                                 #empty cell list
3314            data.append([])                                 #empty dmin
3315            data.append({})                                 #empty superlattice stuff
3316            G2frame.PatternTree.SetItemPyData(item,data)                             
3317#patch
3318        if len(data) < 5:
3319            data.append({'Use':False,'ModVec':[0,0,0.1],'maxH':1,'ssSymb':''})                                 #empty superlattice stuff
3320            G2frame.PatternTree.SetItemPyData(item,data) 
3321#end patch
3322        G2pdG.UpdateUnitCellsGrid(G2frame,data)
3323        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
3324            G2plt.PlotPowderLines(G2frame)
3325        else:
3326            G2plt.PlotPatterns(G2frame)
3327    elif G2frame.PatternTree.GetItemText(item) == 'Reflection Lists':   #powder reflections
3328        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3329        data = G2frame.PatternTree.GetItemPyData(item)
3330        G2frame.RefList = ''
3331        if len(data):
3332            G2frame.RefList = data.keys()[0]
3333        G2pdG.UpdateReflectionGrid(G2frame,data)
3334        G2plt.PlotPatterns(G2frame)
3335    elif G2frame.PatternTree.GetItemText(item) == 'Reflection List':    #HKLF reflections
3336        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
3337        name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3338        data = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
3339        G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
3340
3341    if G2frame.PickId:
3342        G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
3343    G2frame.dataFrame.Raise()
3344
3345def SetDataMenuBar(G2frame,menu=None):
3346    '''Set the menu for the data frame. On the Mac put this
3347    menu for the data tree window instead.
3348
3349    Note that data frame items do not have menus, for these (menu=None)
3350    display a blank menu or on the Mac display the standard menu for
3351    the data tree window.
3352    '''
3353    if sys.platform == "darwin":
3354        if menu is None:
3355            G2frame.SetMenuBar(G2frame.GSASIIMenu)
3356        else:
3357            G2frame.SetMenuBar(menu)
3358    else:
3359        if menu is None:
3360            G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
3361        else:
3362            G2frame.dataFrame.SetMenuBar(menu)
3363
3364def HowDidIgetHere():
3365    '''Show a traceback with calls that brought us to the current location.
3366    Used for debugging.
3367    '''
3368    import traceback
3369    print 70*'*'   
3370    for i in traceback.format_list(traceback.extract_stack()[:-1]): print(i.strip.rstrip())
3371    print 70*'*'   
3372       
Note: See TracBrowser for help on using the repository browser.