source: trunk/GSASIIgrid.py @ 2836

Last change on this file since 2836 was 2825, checked in by vondreele, 8 years ago

remove two prints from GSASIIscriptable.py
fix seq results bug for unused image in strain ring fits

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 234.9 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIgrid - data display routines
3########### SVN repository information ###################
4# $Date: 2017-05-10 22:20:07 +0000 (Wed, 10 May 2017) $
5# $Author: vondreele $
6# $Revision: 2825 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 2825 2017-05-10 22:20:07Z vondreele $
9########### SVN repository information ###################
10'''
11*GSASIIgrid: Basic GUI routines*
12--------------------------------
13
14'''
15import wx
16import wx.grid as wg
17#import wx.wizard as wz
18#import wx.aui
19import wx.lib.scrolledpanel as wxscroll
20import time
21import copy
22import sys
23import os
24import random as ran
25import numpy as np
26import numpy.ma as ma
27import scipy.optimize as so
28import GSASIIpath
29GSASIIpath.SetVersionNumber("$Revision: 2825 $")
30import GSASIImath as G2mth
31import GSASIIIO as G2IO
32import GSASIIstrIO as G2stIO
33import GSASIIlattice as G2lat
34import GSASIIplot as G2plt
35import GSASIIpwdGUI as G2pdG
36import GSASIIimgGUI as G2imG
37import GSASIIphsGUI as G2phG
38import GSASIIspc as G2spc
39import GSASIImapvars as G2mv
40import GSASIIconstrGUI as G2cnstG
41import GSASIIrestrGUI as G2restG
42import GSASIIpy3 as G2py3
43import GSASIIobj as G2obj
44import GSASIIexprGUI as G2exG
45import GSASIIlog as log
46import GSASIIctrls as G2G
47
48# trig functions in degrees
49sind = lambda x: np.sin(x*np.pi/180.)
50tand = lambda x: np.tan(x*np.pi/180.)
51cosd = lambda x: np.cos(x*np.pi/180.)
52
53# Define a short name for convenience
54WACV = wx.ALIGN_CENTER_VERTICAL
55
56[ wxID_FOURCALC, wxID_FOURSEARCH, wxID_FOURCLEAR, wxID_PEAKSMOVE, wxID_PEAKSCLEAR, 
57    wxID_CHARGEFLIP, wxID_PEAKSUNIQUE, wxID_PEAKSDELETE, wxID_PEAKSDA,
58    wxID_PEAKSDISTVP, wxID_PEAKSVIEWPT, wxID_FINDEQVPEAKS,wxID_SHOWBONDS,wxID_MULTIMCSA,
59    wxID_SINGLEMCSA,wxID_4DCHARGEFLIP,wxID_TRANSFORMSTRUCTURE,
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,wxID_DATAUSE,
64] = [wx.NewId() for item in range(10)]
65
66[ wxID_ATOMSEDITADD, wxID_ATOMSEDITINSERT, wxID_ATOMSEDITDELETE, 
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    wxID_WAVEVARY,wxID_ATOMSROTATE, wxID_ATOMSDENSITY,
71    wxID_ATOMSSETALL, wxID_ATOMSSETSEL,
72] = [wx.NewId() for item in range(21)]
73
74[ wxID_DRAWATOMSTYLE, wxID_DRAWATOMLABEL, wxID_DRAWATOMCOLOR, wxID_DRAWATOMRESETCOLOR, 
75    wxID_DRAWVIEWPOINT, wxID_DRAWTRANSFORM, wxID_DRAWDELETE, wxID_DRAWFILLCELL, 
76    wxID_DRAWADDEQUIV, wxID_DRAWFILLCOORD, wxID_DRAWDISAGLTOR,  wxID_DRAWPLANE,
77    wxID_DRAWDISTVP, wxID_DRAWADDSPHERE,wxID_DRWAEDITRADII,
78] = [wx.NewId() for item in range(15)]
79
80[ wxID_DRAWRESTRBOND, wxID_DRAWRESTRANGLE, wxID_DRAWRESTRPLANE, wxID_DRAWRESTRCHIRAL,
81] = [wx.NewId() for item in range(4)]
82
83[ wxID_ADDMCSAATOM,wxID_ADDMCSARB,wxID_CLEARMCSARB,wxID_MOVEMCSA,wxID_MCSACLEARRESULTS,
84] = [wx.NewId() for item in range(5)]
85
86[ wxID_CLEARTEXTURE,wxID_REFINETEXTURE,
87] = [wx.NewId() for item in range(2)]
88
89[ wxID_LOADDIFFAX,wxID_LAYERSIMULATE,wxID_SEQUENCESIMULATE, wxID_LAYERSFIT, wxID_COPYPHASE,
90] = [wx.NewId() for item in range(5)]
91
92[ wxID_PAWLEYLOAD, wxID_PAWLEYESTIMATE, wxID_PAWLEYUPDATE, wxID_PAWLEYSELALL, wxID_PAWLEYSELNONE,
93  wxID_PAWLEYSELTOGGLE, wxID_PAWLEYSET, 
94] = [wx.NewId() for item in range(7)]
95
96[ wxID_IMCALIBRATE,wxID_IMRECALIBRATE,wxID_IMINTEGRATE, wxID_IMCLEARCALIB,wxID_IMRECALIBALL, 
97    wxID_IMCOPYCONTROLS, wxID_INTEGRATEALL, wxID_IMSAVECONTROLS, wxID_IMLOADCONTROLS, wxID_IMAUTOINTEG,
98    wxID_IMCOPYSELECTED, wxID_SAVESELECTEDCONTROLS, wxID_IMXFERCONTROLS,wxID_IMRESETDIST,
99] = [wx.NewId() for item in range(14)]
100
101[ wxID_MASKCOPY, wxID_MASKSAVE, wxID_MASKLOAD, wxID_NEWMASKSPOT,wxID_NEWMASKARC,wxID_NEWMASKRING,
102    wxID_NEWMASKFRAME, wxID_NEWMASKPOLY,wxID_MASKLOADNOT,wxID_FINDSPOTS,wxID_DELETESPOTS
103] = [wx.NewId() for item in range(11)]
104
105[ wxID_STRSTACOPY, wxID_STRSTAFIT, wxID_STRSTASAVE, wxID_STRSTALOAD,wxID_STRSTSAMPLE,
106    wxID_APPENDDZERO,wxID_STRSTAALLFIT,wxID_UPDATEDZERO,wxID_STRSTAPLOT,wxID_STRRINGSAVE,
107] = [wx.NewId() for item in range(10)]
108
109[ wxID_BACKCOPY,wxID_LIMITCOPY, wxID_SAMPLECOPY, wxID_SAMPLECOPYSOME, wxID_BACKFLAGCOPY, wxID_SAMPLEFLAGCOPY,
110    wxID_SAMPLESAVE, wxID_SAMPLELOAD,wxID_ADDEXCLREGION,wxID_SETSCALE,wxID_SAMPLE1VAL,wxID_ALLSAMPLELOAD,
111    wxID_MAKEBACKRDF,wxID_RESCALEALL,
112] = [wx.NewId() for item in range(14)]
113
114[ wxID_INSTPRMRESET,wxID_CHANGEWAVETYPE,wxID_INSTCOPY, wxID_INSTFLAGCOPY, wxID_INSTLOAD,
115    wxID_INSTSAVE, wxID_INST1VAL, wxID_INSTCALIB,wxID_INSTSAVEALL,
116] = [wx.NewId() for item in range(9)]
117
118[ wxID_UNDO,wxID_LSQPEAKFIT,wxID_LSQONECYCLE,wxID_RESETSIGGAM,wxID_CLEARPEAKS,wxID_AUTOSEARCH,
119    wxID_PEAKSCOPY, wxID_SEQPEAKFIT,
120] = [wx.NewId() for item in range(8)]
121
122[  wxID_INDXRELOAD, wxID_INDEXPEAKS, wxID_REFINECELL, wxID_COPYCELL, wxID_MAKENEWPHASE,
123    wxID_EXPORTCELLS,
124] = [wx.NewId() for item in range(6)]
125
126[ wxID_CONSTRAINTADD,wxID_EQUIVADD,wxID_HOLDADD,wxID_FUNCTADD,wxID_ADDRIDING,
127  wxID_CONSPHASE, wxID_CONSHIST, wxID_CONSHAP, wxID_CONSGLOBAL,wxID_EQUIVALANCEATOMS,
128] = [wx.NewId() for item in range(10)]
129
130[ wxID_RESTRAINTADD, wxID_RESTSELPHASE,wxID_RESTDELETE, wxID_RESRCHANGEVAL, 
131    wxID_RESTCHANGEESD,wxID_AARESTRAINTADD,wxID_AARESTRAINTPLOT,
132] = [wx.NewId() for item in range(7)]
133
134[ wxID_RIGIDBODYADD,wxID_DRAWDEFINERB,wxID_RIGIDBODYIMPORT,wxID_RESIDUETORSSEQ,
135    wxID_AUTOFINDRESRB,wxID_GLOBALRESREFINE,wxID_RBREMOVEALL,wxID_COPYRBPARMS,
136    wxID_GLOBALTHERM,wxID_VECTORBODYADD
137] = [wx.NewId() for item in range(10)]
138
139[ wxID_RENAMESEQSEL,wxID_SAVESEQSEL,wxID_SAVESEQSELCSV,wxID_SAVESEQCSV,wxID_PLOTSEQSEL,
140  wxID_ORGSEQSEL,wxADDSEQVAR,wxDELSEQVAR,wxEDITSEQVAR,wxCOPYPARFIT,wxID_AVESEQSEL,
141  wxADDPARFIT,wxDELPARFIT,wxEDITPARFIT,wxDOPARFIT,wxADDSEQDIST,wxADDSEQANGLE
142] = [wx.NewId() for item in range(17)]
143
144[ wxID_MODELCOPY,wxID_MODELFIT,wxID_MODELADD,wxID_ELEMENTADD,wxID_ELEMENTDELETE,
145    wxID_ADDSUBSTANCE,wxID_LOADSUBSTANCE,wxID_DELETESUBSTANCE,wxID_COPYSUBSTANCE,
146    wxID_MODELUNDO,wxID_MODELFITALL,wxID_MODELCOPYFLAGS,wxID_RELOADSUBSTANCES,
147    wxID_MODELPLOT,
148] = [wx.NewId() for item in range(14)]
149
150[ wxID_SELECTPHASE,wxID_PWDHKLPLOT,wxID_PWD3DHKLPLOT,wxID_3DALLHKLPLOT,wxID_MERGEHKL,
151] = [wx.NewId() for item in range(5)]
152
153[ wxID_PDFCOPYCONTROLS, wxID_PDFSAVECONTROLS, wxID_PDFLOADCONTROLS, wxID_PDFCOMPUTE, 
154    wxID_PDFCOMPUTEALL, wxID_PDFADDELEMENT, wxID_PDFDELELEMENT, wxID_PDFPKSFIT,
155    wxID_PDFPKSFITALL,wxID_PDFCOPYPEAKS,wxID_CLEARPDFPEAKS,
156] = [wx.NewId() for item in range(11)]
157
158[ wxID_MCRON,wxID_MCRLIST,wxID_MCRSAVE,wxID_MCRPLAY,
159] = [wx.NewId() for item in range(4)]
160
161VERY_LIGHT_GREY = wx.Colour(235,235,235)
162
163commonTrans = {'abc':np.eye(3),'a-cb':np.array([[1.,0.,0.],[0.,0.,-1.],[0.,1.,0.]]),
164    'ba-c':np.array([[0.,1.,0.],[1.,0.,0.],[0.,0.,-1.]]),'-cba':np.array([[0.,0.,-1.],[0.,1.,0.],[1.,0.,0.]]),
165    'bca':np.array([[0.,1.,0.],[0.,0.,1.],[1.,0.,0.]]),'cab':np.array([[0.,0.,1.],[1.,0.,0.],[0.,1.,0.]]),
166    'R->H':np.array([[1.,-1.,0.],[0.,1.,-1.],[1.,1.,1.]]),'H->R':np.array([[2./3,1./3,1./3],[-1./3,1./3,1./3],[-1./3,-2./3,1./3]]),
167    'P->A':np.array([[-1.,0.,0.],[0.,-1.,1.],[0.,1.,1.]]),'R->O':np.array([[-1.,0.,0.],[0.,-1.,0.],[0.,0.,1.]]),
168    'P->B':np.array([[-1.,0.,1.],[0.,-1.,0.],[1.,0.,1.]]),'B->P':np.array([[-.5,0.,.5],[0.,-1.,0.],[.5,0.,.5]]),
169    'P->C':np.array([[1.,1.,0.],[1.,-1.,0.],[0.,0.,-1.]]),'C->P':np.array([[.5,.5,0.],[.5,-.5,0.],[0.,0.,-1.]]),
170    'P->F':np.array([[-1.,1.,1.],[1.,-1.,1.],[1.,1.,-1.]]),'F->P':np.array([[0.,.5,.5],[.5,0.,.5],[.5,.5,0.]]),   
171    'P->I':np.array([[0.,1.,1.],[1.,0.,1.],[1.,1.,0.]]),'I->P':np.array([[-.5,.5,.5],[.5,-.5,.5],[.5,.5,-.5]]),   
172    'A->P':np.array([[-1.,0.,0.],[0.,-.5,.5],[0.,.5,.5]]),'O->R':np.array([[-1.,0.,0.],[0.,-1.,0.],[0.,0.,1.]]), 
173    'abc*':np.eye(3), }
174commonNames = ['abc','bca','cab','a-cb','ba-c','-cba','P->A','A->P','P->B','B->P','P->C','C->P',
175    'P->I','I->P','P->F','F->P','H->R','R->H','R->O','O->R','abc*','setting 1->2']          #don't put any new ones after the setting one!
176
177# Should SGMessageBox, SymOpDialog, DisAglDialog be moved?
178
179################################################################################
180#### GSAS-II class definitions
181################################################################################
182
183class SGMessageBox(wx.Dialog):
184    ''' Special version of MessageBox that displays space group & super space group text
185    in two blocks
186    '''
187    def __init__(self,parent,title,text,table,):
188        wx.Dialog.__init__(self,parent,wx.ID_ANY,title,pos=wx.DefaultPosition,
189            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
190        self.text = text
191        self.table = table
192        self.panel = wx.Panel(self)
193        mainSizer = wx.BoxSizer(wx.VERTICAL)
194        mainSizer.Add((0,10))
195        for line in text:
196            mainSizer.Add(wx.StaticText(self.panel,label='     %s     '%(line)),0,WACV)
197        ncol = self.table[0].count(',')+1
198        tableSizer = wx.FlexGridSizer(0,2*ncol+3,0,0)
199        for j,item in enumerate(self.table):
200            num,flds = item.split(')')
201            tableSizer.Add(wx.StaticText(self.panel,label='     %s  '%(num+')')),0,WACV|wx.ALIGN_LEFT)           
202            flds = flds.replace(' ','').split(',')
203            for i,fld in enumerate(flds):
204                if i < ncol-1:
205                    tableSizer.Add(wx.StaticText(self.panel,label='%s, '%(fld)),0,WACV|wx.ALIGN_RIGHT)
206                else:
207                    tableSizer.Add(wx.StaticText(self.panel,label='%s'%(fld)),0,WACV|wx.ALIGN_RIGHT)
208            if not j%2:
209                tableSizer.Add((20,0))
210        mainSizer.Add(tableSizer,0,wx.ALIGN_LEFT)
211        btnsizer = wx.StdDialogButtonSizer()
212        OKbtn = wx.Button(self.panel, wx.ID_OK)
213        OKbtn.Bind(wx.EVT_BUTTON, self.OnOk)
214        OKbtn.SetDefault()
215        btnsizer.AddButton(OKbtn)
216        btnsizer.Realize()
217        mainSizer.Add((0,10))
218        mainSizer.Add(btnsizer,0,wx.ALIGN_CENTER)
219        self.panel.SetSizer(mainSizer)
220        self.panel.Fit()
221        self.Fit()
222        size = self.GetSize()
223        self.SetSize([size[0]+20,size[1]])
224
225    def Show(self):
226        '''Use this method after creating the dialog to post it
227        '''
228        self.ShowModal()
229        return
230
231    def OnOk(self,event):
232        parent = self.GetParent()
233        parent.Raise()
234        self.EndModal(wx.ID_OK)
235
236class SGMagSpinBox(wx.Dialog):
237    ''' Special version of MessageBox that displays magnetic spin text
238    '''
239    def __init__(self,parent,title,text,table,names,spins,):
240        wx.Dialog.__init__(self,parent,wx.ID_ANY,title,pos=wx.DefaultPosition,
241            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,size=wx.Size(420,350))
242        self.text = text
243        self.table = table
244        self.names = names
245        self.spins = spins
246        self.panel = wxscroll.ScrolledPanel(self)
247        mainSizer = wx.BoxSizer(wx.VERTICAL)
248        mainSizer.Add((0,10))
249        first = text[0].split(':')[-1].strip()
250        cents = [0,]
251        if 'P' != first[0]:
252            cents = text[-1].split(';')
253        for line in text:
254            mainSizer.Add(wx.StaticText(self.panel,label='     %s     '%(line)),0,WACV)
255        ncol = self.table[0].count(',')+2
256        for ic,cent in enumerate(cents):
257            if cent:
258                cent = cent.strip(' (').strip(')+\n') 
259                mainSizer.Add(wx.StaticText(self.panel,label=' for (%s)+'%(cent)),0,WACV)
260            tableSizer = wx.FlexGridSizer(0,2*ncol+3,0,0)
261            for j,item in enumerate(self.table):
262                flds = item.split(')')[1]
263                tableSizer.Add(wx.StaticText(self.panel,label='  (%2d)  '%(j+1)),0,WACV|wx.ALIGN_LEFT)           
264                flds = flds.replace(' ','').split(',')
265                for i,fld in enumerate(flds):
266                    if i < ncol-1:
267                        text = wx.StaticText(self.panel,label='%s, '%(fld))
268                        tableSizer.Add(text,0,WACV|wx.ALIGN_RIGHT)
269                    else:
270                        text = wx.StaticText(self.panel,label='%s '%(fld))
271                        tableSizer.Add(text,0,WACV|wx.ALIGN_RIGHT)
272                text = wx.StaticText(self.panel,label=' (%s) '%(self.names[j]))
273                if self.spins[j+ic*len(self.table)] < 0:
274                    text.SetForegroundColour('Red')
275                tableSizer.Add(text,0,WACV|wx.ALIGN_RIGHT)
276                if not j%2:
277                    tableSizer.Add((20,0))
278            mainSizer.Add(tableSizer,0,wx.ALIGN_CENTER)
279           
280        btnsizer = wx.StdDialogButtonSizer()
281        OKbtn = wx.Button(self.panel, wx.ID_OK)
282        OKbtn.SetDefault()
283        btnsizer.AddButton(OKbtn)
284        btnsizer.Realize()
285        mainSizer.Add((0,10))
286        mainSizer.Add(btnsizer,0,wx.ALIGN_CENTER)
287        self.panel.SetSizer(mainSizer)
288        size = np.array(self.GetSize())
289        self.panel.SetupScrolling()
290        size = [size[0]-5,size[1]-20]       #this fiddling is needed for older wx!
291        self.panel.SetSize(size)
292        self.panel.SetAutoLayout(1)
293
294    def Show(self):
295        '''Use this method after creating the dialog to post it
296        '''
297        self.ShowModal()
298        return   
299
300################################################################################
301class SymOpDialog(wx.Dialog):
302    '''Class to select a symmetry operator
303    '''
304    def __init__(self,parent,SGData,New=True,ForceUnit=False):
305        wx.Dialog.__init__(self,parent,-1,'Select symmetry operator',
306            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
307        panel = wx.Panel(self)
308        self.SGData = SGData
309        self.New = New
310        self.Force = ForceUnit
311        self.OpSelected = [0,0,0,[0,0,0],False,False]
312        mainSizer = wx.BoxSizer(wx.VERTICAL)
313        if ForceUnit:
314            choice = ['No','Yes']
315            self.force = wx.RadioBox(panel,-1,'Force to unit cell?',choices=choice)
316            self.force.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
317            mainSizer.Add(self.force,0,WACV|wx.TOP,5)
318#        if SGData['SGInv']:
319        choice = ['No','Yes']
320        self.inv = wx.RadioBox(panel,-1,'Choose inversion?',choices=choice)
321        self.inv.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
322        mainSizer.Add(self.inv,0,WACV)
323        if SGData['SGLatt'] != 'P':
324            LattOp = G2spc.Latt2text(SGData['SGLatt']).split(';')
325            self.latt = wx.RadioBox(panel,-1,'Choose cell centering?',choices=LattOp)
326            self.latt.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
327            mainSizer.Add(self.latt,0,WACV)
328        if SGData['SGLaue'] in ['-1','2/m','mmm','4/m','4/mmm']:
329            Ncol = 2
330        else:
331            Ncol = 3
332        OpList = []
333        for Opr in SGData['SGOps']:
334            OpList.append(G2spc.MT2text(Opr))
335        self.oprs = wx.RadioBox(panel,-1,'Choose space group operator?',choices=OpList,
336            majorDimension=Ncol)
337        self.oprs.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
338        mainSizer.Add(self.oprs,0,WACV|wx.BOTTOM,5)
339        mainSizer.Add(wx.StaticText(panel,-1,"   Choose unit cell?"),0,WACV)
340        cellSizer = wx.BoxSizer(wx.HORIZONTAL)
341        cellName = ['X','Y','Z']
342        self.cell = []
343        for i in range(3):
344            self.cell.append(wx.SpinCtrl(panel,-1,cellName[i],size=wx.Size(50,20)))
345            self.cell[-1].SetRange(-3,3)
346            self.cell[-1].SetValue(0)
347            self.cell[-1].Bind(wx.EVT_SPINCTRL, self.OnOpSelect)
348            cellSizer.Add(self.cell[-1],0,WACV)
349        mainSizer.Add(cellSizer,0,WACV|wx.BOTTOM,5)
350        if self.New:
351            choice = ['No','Yes']
352            self.new = wx.RadioBox(panel,-1,'Generate new positions?',choices=choice)
353            self.new.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
354            mainSizer.Add(self.new,0,WACV)
355
356        OkBtn = wx.Button(panel,-1,"Ok")
357        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
358        cancelBtn = wx.Button(panel,-1,"Cancel")
359        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
360        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
361        btnSizer.Add((20,20),1)
362        btnSizer.Add(OkBtn)
363        btnSizer.Add((20,20),1)
364        btnSizer.Add(cancelBtn)
365        btnSizer.Add((20,20),1)
366
367        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
368        panel.SetSizer(mainSizer)
369        panel.Fit()
370        self.Fit()
371
372    def OnOpSelect(self,event):
373#        if self.SGData['SGInv']:
374        self.OpSelected[0] = self.inv.GetSelection()
375        if self.SGData['SGLatt'] != 'P':
376            self.OpSelected[1] = self.latt.GetSelection()
377        self.OpSelected[2] = self.oprs.GetSelection()
378        for i in range(3):
379            self.OpSelected[3][i] = float(self.cell[i].GetValue())
380        if self.New:
381            self.OpSelected[4] = self.new.GetSelection()
382        if self.Force:
383            self.OpSelected[5] = self.force.GetSelection()
384
385    def GetSelection(self):
386        return self.OpSelected
387
388    def OnOk(self,event):
389        parent = self.GetParent()
390        parent.Raise()
391        self.EndModal(wx.ID_OK)
392
393    def OnCancel(self,event):
394        parent = self.GetParent()
395        parent.Raise()
396        self.EndModal(wx.ID_CANCEL)
397       
398################################################################################
399class SphereEnclosure(wx.Dialog):
400    ''' Add atoms within sphere of enclosure to drawing
401   
402    :param wx.Frame parent: reference to parent frame (or None)
403    :param general: general data (includes drawing data)
404    :param atoms: drawing atoms data
405    :param indx: list of selected atoms (may be empty)
406   
407    '''
408    def __init__(self,parent,general,drawing,indx):
409        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Setup phase transformation', 
410            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
411        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
412        self.General = general
413        self.Drawing = drawing
414        self.indx = indx
415        self.Sphere = 1.0
416        self.centers = []
417        self.atomTypes = [[item,True] for item in self.General['AtomTypes']]
418       
419        self.Draw()
420       
421    def Draw(self):
422       
423#        def OnRadius(event):
424#            event.Skip()
425#            try:
426#                val = float(radius.GetValue())
427#                if val < 0.5:
428#                    raise ValueError
429#                self.Sphere = val
430#            except ValueError:
431#                pass
432#            radius.SetValue('%.3f'%(self.Sphere))
433#           
434        def OnAtomType(event):
435            Obj = event.GetEventObject()
436            id = Ind[Obj.GetId()]
437            self.atomTypes[id][1] = Obj.GetValue()
438       
439        self.panel.Destroy()
440        self.panel = wx.Panel(self)
441        mainSizer = wx.BoxSizer(wx.VERTICAL)
442        mainSizer.Add(wx.StaticText(self.panel,label=' Sphere of enclosure controls:'),0,WACV)
443        topSizer = wx.BoxSizer(wx.HORIZONTAL)
444        atoms = []
445        if len(self.indx):
446            topSizer.Add(wx.StaticText(self.panel,label=' Sphere centered at atoms: '),0,WACV)
447            cx,ct,cs = self.Drawing['atomPtrs'][:3]
448#            print self.Drawing.keys()
449            for id in self.indx:
450                atom = self.Drawing['Atoms'][id]
451                self.centers.append(atom[cx:cx+3])
452                atoms.append('%s(%s)'%(atom[ct-1],atom[cs-1]))
453            topSizer.Add(wx.ComboBox(self.panel,choices=atoms,value=atoms[0],
454                style=wx.CB_READONLY|wx.CB_DROPDOWN),0,WACV)
455        else:
456            topSizer.Add(wx.StaticText(self.panel,label=' Sphere centered at drawing view point'),0,WACV)
457            self.centers.append(self.Drawing['viewPoint'][0])
458        mainSizer.Add(topSizer,0,WACV)
459        sphereSizer = wx.BoxSizer(wx.HORIZONTAL)
460        sphereSizer.Add(wx.StaticText(self.panel,label=' Sphere radius: '),0,WACV)
461        radius = G2G.ValidatedTxtCtrl(self.panel,self.Sphere,nDig=(10,3),typeHint=float,size=(65,25))
462#        radius = wx.TextCtrl(self.panel,value='%.3f'%(self.Sphere),style=wx.TE_PROCESS_ENTER)
463#        radius.Bind(wx.EVT_TEXT_ENTER,OnRadius)
464#        radius.Bind(wx.EVT_KILL_FOCUS,OnRadius)
465        sphereSizer.Add(radius,0,WACV)
466        mainSizer.Add(sphereSizer,0,WACV)
467        mainSizer.Add(wx.StaticText(self.panel,label=' Target selected atoms:'),0,WACV)
468        atSizer = wx.BoxSizer(wx.HORIZONTAL)
469        Ind = {}
470        for i,item in enumerate(self.atomTypes):
471            atm = wx.CheckBox(self.panel,label=item[0])
472            atm.SetValue(item[1])
473            atm.Bind(wx.EVT_CHECKBOX, OnAtomType)
474            Ind[atm.GetId()] = i
475            atSizer.Add(atm,0,WACV)
476        mainSizer.Add(atSizer,0,WACV)
477       
478        OkBtn = wx.Button(self.panel,-1,"Ok")
479        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
480        cancelBtn = wx.Button(self.panel,-1,"Cancel")
481        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
482        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
483        btnSizer.Add((20,20),1)
484        btnSizer.Add(OkBtn)
485        btnSizer.Add((20,20),1)
486        btnSizer.Add(cancelBtn)
487        btnSizer.Add((20,20),1)
488       
489        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
490        self.panel.SetSizer(mainSizer)
491        self.panel.Fit()
492        self.Fit()
493       
494    def GetSelection(self):
495        used = []
496        for atm in self.atomTypes:
497            if atm[1]:
498                used.append(str(atm[0]))
499        return self.centers,self.Sphere,used
500
501    def OnOk(self,event):
502        parent = self.GetParent()
503        parent.Raise()
504        self.EndModal(wx.ID_OK)
505
506    def OnCancel(self,event):
507        parent = self.GetParent()
508        parent.Raise()
509        self.EndModal(wx.ID_CANCEL)
510       
511################################################################################
512class TransformDialog(wx.Dialog):
513    ''' Phase transformation
514   
515    :param wx.Frame parent: reference to parent frame (or None)
516    :param phase: phase data
517   
518    #NB: commonNames & commonTrans defined at top of this file
519    '''
520    def __init__(self,parent,phase):
521        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Setup phase transformation', 
522            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
523        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
524        self.Phase = copy.deepcopy(phase)   #will be a new phase!
525#        self.Super = phase['General']['Super']
526#        if self.Super:
527#            self.Trans = np.eye(4)
528#            self.Vec = np.zeros(4)
529#        else:
530        self.Trans = np.eye(3)
531        self.Vec = np.zeros(3)
532        self.oldSpGrp = phase['General']['SGData']['SpGrp']
533        self.oldSGdata = phase['General']['SGData']
534        self.newSpGrp = self.Phase['General']['SGData']['SpGrp']
535        self.oldCell = phase['General']['Cell'][1:8]
536        self.newCell = self.Phase['General']['Cell'][1:8]
537        self.Common = 'abc'
538        self.ifMag = False
539        self.ifConstr = True
540        self.Draw()
541
542    def Draw(self):
543               
544        def OnCommon(event):
545            Obj = event.GetEventObject()
546            self.Common = Obj.GetValue()
547            if '*' in self.Common:
548                A,B = G2lat.cell2AB(self.oldCell[:6])
549                self.newCell[2:5] = [A[2,2],90.,90.]
550                a,b = G2lat.cell2AB(self.newCell[:6])
551                self.Trans = np.inner(a.T,B)    #correct!
552                self.ifConstr = False
553                self.newSpGrp = 'P 1'
554                SGErr,SGData = G2spc.SpcGroup(self.newSpGrp)
555                self.Phase['General']['SGData'] = SGData
556            else:
557                if self.Common == commonNames[-1]:      #change setting
558                    self.Vec = G2spc.spg2origins[self.oldSpGrp]
559                    self.newSpGrp = self.oldSpGrp
560                else:
561                    self.Trans = commonTrans[self.Common]
562                    if 'R' == self.Common[-1]:
563                        self.newSpGrp += ' r'
564                        SGErr,SGData = G2spc.SpcGroup(self.newSpGrp)
565                        self.Phase['General']['SGData'] = SGData
566                        SGTxt.SetValue(self.newSpGrp)
567            OnTest(event)
568       
569        def OnSpaceGroup(event):
570            event.Skip()
571            Flds = SGTxt.GetValue().split()
572            Flds[0] = Flds[0].upper()
573            #get rid of extra spaces between fields first
574            for fld in Flds: fld = fld.strip()
575            SpcGp = ' '.join(Flds)
576            if SpcGp == self.newSpGrp: #didn't change it!
577                return
578            # try a lookup on the user-supplied name
579            SpGrpNorm = G2spc.StandardizeSpcName(SpcGp)
580            if SpGrpNorm:
581                SGErr,SGData = G2spc.SpcGroup(SpGrpNorm)
582            else:
583                SGErr,SGData = G2spc.SpcGroup(SpcGp)
584            if SGErr:
585                text = [G2spc.SGErrors(SGErr)+'\nSpace Group set to previous']
586                SGTxt.SetValue(self.newSpGrp)
587                msg = 'Space Group Error'
588                Style = wx.ICON_EXCLAMATION
589                Text = '\n'.join(text)
590                wx.MessageBox(Text,caption=msg,style=Style)
591            else:
592                text,table = G2spc.SGPrint(SGData)
593                self.Phase['General']['SGData'] = SGData
594                self.newSpGrp = SpcGp
595                SGTxt.SetValue(self.Phase['General']['SGData']['SpGrp'])
596                msg = 'Space Group Information'
597                SGMessageBox(self.panel,msg,text,table).Show()
598            if self.Phase['General']['Type'] == 'magnetic':
599                Nops = len(SGData['SGOps'])*len(SGData['SGCen'])
600                if SGData['SGInv']:
601                    Nops *= 2
602                SGData['SpnFlp'] = Nops*[1,]
603#            if self.Phase['General']['Type'] in ['modulated',]:
604#                self.Phase['General']['SuperSg'] = SetDefaultSSsymbol()
605#                self.Phase['General']['SSGData'] = G2spc.SSpcGroup(generalData['SGData'],generalData['SuperSg'])[1]
606
607        def OnTest(event):
608            self.newCell = G2lat.TransformCell(self.oldCell[:6],self.Trans)
609            wx.CallAfter(self.Draw)
610           
611        def OnMag(event):
612            self.ifMag = mag.GetValue()
613           
614        def OnConstr(event):
615            self.ifConstr = constr.GetValue()
616
617        self.panel.Destroy()
618        self.panel = wx.Panel(self)
619#        Ind = {}
620        mainSizer = wx.BoxSizer(wx.VERTICAL)
621        MatSizer = wx.BoxSizer(wx.HORIZONTAL)
622        transSizer = wx.BoxSizer(wx.VERTICAL)
623        transSizer.Add(wx.StaticText(self.panel,label=" XYZ Transformation matrix & vector: M*X+V = X'"))
624#        if self.Super:
625#            Trmat = wx.FlexGridSizer(4,4,0,0)
626#        else:
627        commonSizer = wx.BoxSizer(wx.HORIZONTAL)
628        commonSizer.Add(wx.StaticText(self.panel,label=' Common transformations: '),0,WACV)
629        if self.oldSpGrp not in G2spc.spg2origins:
630            common = wx.ComboBox(self.panel,value=self.Common,choices=commonNames[:-1],
631                style=wx.CB_READONLY|wx.CB_DROPDOWN)
632        else:
633            common = wx.ComboBox(self.panel,value=self.Common,choices=commonNames,
634                style=wx.CB_READONLY|wx.CB_DROPDOWN)
635        common.Bind(wx.EVT_COMBOBOX,OnCommon)
636        commonSizer.Add(common,0,WACV)
637        transSizer.Add(commonSizer)
638        Trmat = wx.FlexGridSizer(3,5,0,0)
639        for iy,line in enumerate(self.Trans):
640            for ix,val in enumerate(line):
641                item = G2G.ValidatedTxtCtrl(self.panel,self.Trans[iy],ix,nDig=(10,3),typeHint=float,size=(65,25))
642                Trmat.Add(item)
643            Trmat.Add((25,0),0)
644            vec = G2G.ValidatedTxtCtrl(self.panel,self.Vec,iy,nDig=(10,3),typeHint=float,size=(65,25))
645            Trmat.Add(vec)
646        transSizer.Add(Trmat)
647        MatSizer.Add((10,0),0)
648        MatSizer.Add(transSizer)
649        mainSizer.Add(MatSizer)
650        mainSizer.Add(wx.StaticText(self.panel,label=' Old lattice parameters:'),0,WACV)
651        mainSizer.Add(wx.StaticText(self.panel,label=
652            ' a = %.5f       b = %.5f      c = %.5f'%(self.oldCell[0],self.oldCell[1],self.oldCell[2])),0,WACV)
653        mainSizer.Add(wx.StaticText(self.panel,label=' alpha = %.3f beta = %.3f gamma = %.3f'%
654            (self.oldCell[3],self.oldCell[4],self.oldCell[5])),0,WACV)
655        mainSizer.Add(wx.StaticText(self.panel,label=' volume = %.3f'%(self.oldCell[6])),0,WACV)
656        mainSizer.Add(wx.StaticText(self.panel,label=' New lattice parameters:'),0,WACV)
657        mainSizer.Add(wx.StaticText(self.panel,label=
658            ' a = %.5f       b = %.5f      c = %.5f'%(self.newCell[0],self.newCell[1],self.newCell[2])),0,WACV)
659        mainSizer.Add(wx.StaticText(self.panel,label=' alpha = %.3f beta = %.3f gamma = %.3f'%
660            (self.newCell[3],self.newCell[4],self.newCell[5])),0,WACV)
661        mainSizer.Add(wx.StaticText(self.panel,label=' volume = %.3f'%(self.newCell[6])),0,WACV)
662        sgSizer = wx.BoxSizer(wx.HORIZONTAL)
663        sgSizer.Add(wx.StaticText(self.panel,label='  Space group: '),0,WACV)
664        SGTxt = wx.TextCtrl(self.panel,value=self.newSpGrp,style=wx.TE_PROCESS_ENTER)
665        SGTxt.Bind(wx.EVT_TEXT_ENTER,OnSpaceGroup)
666        SGTxt.Bind(wx.EVT_KILL_FOCUS,OnSpaceGroup)
667        sgSizer.Add(SGTxt,0,WACV)
668        mainSizer.Add(sgSizer,0,WACV)
669        if 'magnetic' not in self.Phase['General']['Type']:
670            mag = wx.CheckBox(self.panel,label=' Make new phase magnetic?')
671            mag.Bind(wx.EVT_CHECKBOX,OnMag)
672            mainSizer.Add(mag,0,WACV)
673            mainSizer.Add(wx.StaticText(self.panel, \
674                label=' NB: Nonmagnetic atoms will be deleted from new phase'),0,WACV)
675            constr = wx.CheckBox(self.panel,label=' Make constraints between phases?')
676            mainSizer.Add(wx.StaticText(self.panel, \
677                label=' Constraints not correct for non-diagonal transforms'),0,WACV)
678            constr.SetValue(self.ifConstr)
679            constr.Bind(wx.EVT_CHECKBOX,OnConstr)
680            mainSizer.Add(constr,0,WACV)
681
682        TestBtn = wx.Button(self.panel,-1,"Test")
683        TestBtn.Bind(wx.EVT_BUTTON, OnTest)
684        OkBtn = wx.Button(self.panel,-1,"Ok")
685        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
686        cancelBtn = wx.Button(self.panel,-1,"Cancel")
687        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
688        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
689        btnSizer.Add((20,20),1)
690        btnSizer.Add(TestBtn)
691        btnSizer.Add((20,20),1)
692        btnSizer.Add(OkBtn)
693        btnSizer.Add((20,20),1)
694        btnSizer.Add(cancelBtn)
695        btnSizer.Add((20,20),1)
696       
697        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
698        self.panel.SetSizer(mainSizer)
699        self.panel.Fit()
700        self.Fit()
701       
702    def GetSelection(self):
703        if self.ifMag:
704            self.Phase['General']['Name'] += ' mag'
705        else:
706            self.Phase['General']['Name'] += ' %s'%(self.Common)
707        self.Phase['General']['Cell'][1:] = G2lat.TransformCell(self.oldCell[:6],self.Trans)           
708        return self.Phase,self.Trans,self.Vec,self.ifMag,self.ifConstr,self.Common
709
710    def OnOk(self,event):
711        parent = self.GetParent()
712        parent.Raise()
713        self.EndModal(wx.ID_OK)
714
715    def OnCancel(self,event):
716        parent = self.GetParent()
717        parent.Raise()
718        self.EndModal(wx.ID_CANCEL)
719################################################################################
720class UseMagAtomDialog(wx.Dialog):
721    '''Get user selected magnetic atoms after cell transformation
722    '''
723    def __init__(self,parent,Atoms,atCodes):
724        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Magnetic atom selection', 
725            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
726        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
727        self.Atoms = Atoms
728        self.atCodes = atCodes
729        self.Use = len(self.Atoms)*[True,]
730        self.Draw()
731       
732    def Draw(self):
733       
734        def OnUseChk(event):
735            Obj = event.GetEventObject()
736            iuse = Indx[Obj.GetId()]
737            self.Use[iuse] = not self.Use[iuse]
738            Obj.SetValue(self.Use[iuse])
739       
740        self.panel.Destroy()
741        self.panel = wx.Panel(self)
742        Indx = {}
743        mainSizer = wx.BoxSizer(wx.VERTICAL)
744       
745        mainSizer.Add(wx.StaticText(self.panel,label=' Name, x, y, z:'),0,WACV)
746        atmSizer = wx.FlexGridSizer(0,2,5,5)
747        for iuse,[use,atom] in enumerate(zip(self.Use,self.Atoms)):
748            useChk = wx.CheckBox(self.panel,label='Use?')
749            Indx[useChk.GetId()] = iuse
750            useChk.SetValue(use)
751            useChk.Bind(wx.EVT_CHECKBOX, OnUseChk)
752            atmSizer.Add(useChk,0,WACV)
753            text = ' %s %10.5f %10.5f %10.5f'%(atom[0],atom[3],atom[4],atom[5])
754            atmSizer.Add(wx.StaticText(self.panel,label=text),0,WACV)
755        mainSizer.Add(atmSizer)
756       
757        OkBtn = wx.Button(self.panel,-1,"Ok")
758        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
759        cancelBtn = wx.Button(self.panel,-1,"Use All")
760        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
761        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
762        btnSizer.Add((20,20),1)
763        btnSizer.Add(OkBtn)
764        btnSizer.Add((20,20),1)
765        btnSizer.Add(cancelBtn)
766        btnSizer.Add((20,20),1)
767       
768        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
769        self.panel.SetSizer(mainSizer)
770        self.panel.Fit()
771        self.Fit()
772       
773    def GetSelection(self):
774        useAtoms = []
775        useatCodes = []
776        for use,atom,code in zip(self.Use,self.Atoms,self.atCodes):
777            if use:
778                useAtoms.append(atom)
779                useatCodes.append(code)
780        return useAtoms,useatCodes
781
782    def OnOk(self,event):
783        parent = self.GetParent()
784        parent.Raise()
785        self.EndModal(wx.ID_OK)
786
787    def OnCancel(self,event):
788        parent = self.GetParent()
789        parent.Raise()
790        self.EndModal(wx.ID_CANCEL)
791           
792               
793################################################################################
794class RotationDialog(wx.Dialog):
795    ''' Get Rotate & translate matrix & vector - currently not used
796    needs rethinking - possible use to rotate a group of atoms about some
797    vector/origin + translation
798   
799    '''
800    def __init__(self,parent):
801        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Atom group rotation/translation', 
802            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
803        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
804        self.Trans = np.eye(3)
805        self.Vec = np.zeros(3)
806        self.rotAngle = 0.
807        self.rotVec = np.array([0.,0.,1.])
808        self.Expand = ''
809        self.Draw()
810
811    def Draw(self):
812
813#        def OnMatValue(event):
814#            event.Skip()
815#            Obj = event.GetEventObject()
816#            ix,iy = Ind[Obj.GetId()]
817#            val = Obj.GetValue()
818#            if '/' in val:
819#                vals = val.split('/')
820#                self.Trans[iy,ix] = float(vals[0])/float(vals[1])
821#            else:   
822#                self.Trans[iy,ix] = float(Obj.GetValue())
823#            Obj.SetValue('%5.3f'%(self.Trans[iy,ix]))
824#           
825#           
826#        def OnVecValue(event):
827#            event.Skip()
828#            Obj = event.GetEventObject()
829#            iy = Ind[Obj.GetId()]
830#            val = Obj.GetValue()
831#            if '/' in val:
832#                vals = val.split('/')
833#                self.Vec[iy] = float(vals[0])/float(vals[1])
834#            else:   
835#                self.Vec[iy] = float(Obj.GetValue())
836#            Obj.SetValue('%5.3f'%(self.Vec[iy]))
837#           
838        def OnExpand(event):
839            self.Expand = expand.GetValue()
840           
841        def OnRotAngle(event):
842            event.Skip()
843            self.rotAngle = float(rotangle.GetValue())
844            rotangle.SetValue('%5.3f'%(self.rotAngle))
845            Q = G2mth.AVdeg2Q(self.rotAngle,self.rotVec)
846            self.Trans = G2mth.Q2Mat(Q)
847            self.Draw()
848           
849        def OnRotVec(event):
850            event.Skip()
851            vals = rotvec.GetValue()
852            vals = vals.split()
853            self.rotVec = np.array([float(val) for val in vals])
854            rotvec.SetValue('%5.3f %5.3f %5.3f'%(self.rotVec[0],self.rotVec[1],self.rotVec[2]))
855            Q = G2mth.AVdeg2Q(self.rotAngle,self.rotVec)
856            self.Trans = G2mth.Q2Mat(Q)
857            self.Draw()
858           
859        self.panel.Destroy()
860        self.panel = wx.Panel(self)
861#        Ind = {}
862        mainSizer = wx.BoxSizer(wx.VERTICAL)
863        MatSizer = wx.BoxSizer(wx.HORIZONTAL)
864        transSizer = wx.BoxSizer(wx.VERTICAL)
865        transSizer.Add(wx.StaticText(self.panel,label=" XYZ Transformation matrix && vector: "+ \
866            "\n B*M*A*(X-V)+V = X'\n A,B: Cartesian transformation matrices"))
867        Trmat = wx.FlexGridSizer(3,5,0,0)
868        for iy,line in enumerate(self.Trans):
869            for ix,val in enumerate(line):
870                item = G2G.ValidatedTxtCtrl(self.panel,self.Trans[iy],ix,nDig=(10,3),typeHint=float,size=(65,25))
871#                item = wx.TextCtrl(self.panel,value='%5.3f'%(val),
872#                    size=(50,25),style=wx.TE_PROCESS_ENTER)
873#                Ind[item.GetId()] = [ix,iy]
874#                item.Bind(wx.EVT_TEXT_ENTER,OnMatValue)
875#                item.Bind(wx.EVT_KILL_FOCUS,OnMatValue)
876                Trmat.Add(item)
877            Trmat.Add((25,0),0)
878            vec = G2G.ValidatedTxtCtrl(self.panel,self.Vec,iy,nDig=(10,3),typeHint=float,size=(65,25))
879#            vec = wx.TextCtrl(self.panel,value='%5.3f'%(self.Vec[iy]),
880#                    size=(50,25),style=wx.TE_PROCESS_ENTER)
881#            Ind[vec.GetId()] = [iy]       
882#            vec.Bind(wx.EVT_TEXT_ENTER,OnVecValue)
883#            vec.Bind(wx.EVT_KILL_FOCUS,OnVecValue)
884            Trmat.Add(vec)
885        transSizer.Add(Trmat)
886        MatSizer.Add((10,0),0)
887        MatSizer.Add(transSizer)
888        mainSizer.Add(MatSizer)
889        rotationBox = wx.BoxSizer(wx.HORIZONTAL)
890        rotationBox.Add(wx.StaticText(self.panel,label=' Rotation angle: '),0,WACV)
891        rotangle = wx.TextCtrl(self.panel,value='%5.3f'%(self.rotAngle),
892            size=(50,25),style=wx.TE_PROCESS_ENTER)
893        rotangle.Bind(wx.EVT_TEXT_ENTER,OnRotAngle)
894        rotangle.Bind(wx.EVT_KILL_FOCUS,OnRotAngle)
895        rotationBox.Add(rotangle,0,WACV)
896        rotationBox.Add(wx.StaticText(self.panel,label=' about vector: '),0,WACV)
897        rotvec = wx.TextCtrl(self.panel,value='%5.3f %5.3f %5.3f'%(self.rotVec[0],self.rotVec[1],self.rotVec[2]),
898            size=(100,25),style=wx.TE_PROCESS_ENTER)
899        rotvec.Bind(wx.EVT_TEXT_ENTER,OnRotVec)
900        rotvec.Bind(wx.EVT_KILL_FOCUS,OnRotVec)
901        rotationBox.Add(rotvec,0,WACV)
902        mainSizer.Add(rotationBox,0,WACV)
903        expandChoice = ['','xy','xz','yz','xyz']
904        expandBox = wx.BoxSizer(wx.HORIZONTAL)
905        expandBox.Add(wx.StaticText(self.panel,label=' Expand -1 to +1 on: '),0,WACV)
906        expand = wx.ComboBox(self.panel,value=self.Expand,choices=expandChoice,
907            style=wx.CB_READONLY|wx.CB_DROPDOWN)
908        expand.Bind(wx.EVT_COMBOBOX,OnExpand)
909        expandBox.Add(expand,0,WACV)
910        expandBox.Add(wx.StaticText(self.panel,label=' and find unique atoms '),0,WACV)       
911        mainSizer.Add(expandBox)
912               
913        OkBtn = wx.Button(self.panel,-1,"Ok")
914        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
915        cancelBtn = wx.Button(self.panel,-1,"Cancel")
916        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
917        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
918        btnSizer.Add((20,20),1)
919        btnSizer.Add(OkBtn)
920        btnSizer.Add((20,20),1)
921        btnSizer.Add(cancelBtn)
922        btnSizer.Add((20,20),1)
923       
924        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
925        self.panel.SetSizer(mainSizer)
926        self.panel.Fit()
927        self.Fit()
928
929    def GetSelection(self):
930        return self.Trans,self.Vec,self.Expand
931
932    def OnOk(self,event):
933        parent = self.GetParent()
934        parent.Raise()
935        self.EndModal(wx.ID_OK)
936
937    def OnCancel(self,event):
938        parent = self.GetParent()
939        parent.Raise()
940        self.EndModal(wx.ID_CANCEL)   
941       
942################################################################################
943class DIFFaXcontrols(wx.Dialog):
944    ''' Solicit items needed to prepare DIFFaX control.dif file
945    '''
946    def __init__(self,parent,ctrls,parms=None):
947        wx.Dialog.__init__(self,parent,wx.ID_ANY,'DIFFaX controls', 
948            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
949        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
950        self.ctrls = ctrls
951        self.calcType = 'powder pattern'
952        self.plane = 'h0l'
953        self.planeChoice = ['h0l','0kl','hhl','h-hl',]
954        self.lmax = '2'
955        self.lmaxChoice = [str(i+1) for i in range(6)]
956        self.Parms = parms
957        self.Parm = None
958        if self.Parms != None:
959            self.Parm = self.Parms[0]
960        self.parmRange = [0.,1.]
961        self.parmStep = 2
962        self.Inst = 'Gaussian'
963        self.Draw()
964       
965    def Draw(self):
966       
967        def OnCalcType(event):
968            self.calcType = calcType.GetValue()
969            wx.CallAfter(self.Draw)
970           
971        def OnPlane(event):
972            self.plane = plane.GetValue()
973           
974        def OnMaxL(event):
975            self.lmax = lmax.GetValue()
976           
977        def OnParmSel(event):
978            self.Parm = parmsel.GetValue()
979           
980        def OnNumStep(event):
981            self.parmStep = int(numStep.GetValue())
982           
983        def OnParmRange(event):
984            event.Skip()
985            vals = parmrange.GetValue().split()
986            try:
987                vals = [float(vals[0]),float(vals[1])]
988            except ValueError:
989                vals = self.parmRange
990            parmrange.SetValue('%.3f %.3f'%(vals[0],vals[1]))
991            self.parmRange = vals
992           
993        def OnInstSel(event):
994            self.Inst = instsel.GetValue()
995       
996        self.panel.Destroy()
997        self.panel = wx.Panel(self)
998        mainSizer = wx.BoxSizer(wx.VERTICAL)
999        mainSizer.Add(wx.StaticText(self.panel,label=' Controls for DIFFaX'),0,WACV)
1000        if self.Parms:
1001            mainSizer.Add(wx.StaticText(self.panel,label=' Sequential powder pattern simulation'),0,WACV)
1002        else:
1003            calcChoice = ['powder pattern','selected area']
1004            calcSizer = wx.BoxSizer(wx.HORIZONTAL)
1005            calcSizer.Add(wx.StaticText(self.panel,label=' Select calculation type: '),0,WACV)
1006            calcType = wx.ComboBox(self.panel,value=self.calcType,choices=calcChoice,
1007                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1008            calcType.Bind(wx.EVT_COMBOBOX,OnCalcType)
1009            calcSizer.Add(calcType,0,WACV)
1010            mainSizer.Add(calcSizer)
1011        if self.Parms:
1012            parmSel = wx.BoxSizer(wx.HORIZONTAL)
1013            parmSel.Add(wx.StaticText(self.panel,label=' Select parameter to vary: '),0,WACV)
1014            parmsel = wx.ComboBox(self.panel,value=self.Parm,choices=self.Parms,
1015                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1016            parmsel.Bind(wx.EVT_COMBOBOX,OnParmSel)
1017            parmSel.Add(parmsel,0,WACV)
1018            mainSizer.Add(parmSel)
1019            mainSizer.Add(wx.StaticText(self.panel,label=' Enter parameter range & no. steps: '),0,WACV)
1020            parmRange =  wx.BoxSizer(wx.HORIZONTAL)
1021            numChoice = [str(i+1) for i in range(10)]
1022            parmrange = wx.TextCtrl(self.panel,value='%.3f %.3f'%(self.parmRange[0],self.parmRange[1]),
1023                style=wx.TE_PROCESS_ENTER)
1024            parmrange.Bind(wx.EVT_TEXT_ENTER,OnParmRange)
1025            parmrange.Bind(wx.EVT_KILL_FOCUS,OnParmRange)
1026            parmRange.Add(parmrange,0,WACV)
1027            numStep = wx.ComboBox(self.panel,value=str(self.parmStep),choices=numChoice,
1028                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1029            numStep.Bind(wx.EVT_COMBOBOX,OnNumStep)
1030            parmRange.Add(numStep,0,WACV)
1031            mainSizer.Add(parmRange)           
1032        if 'selected' in self.calcType:
1033            planeSizer = wx.BoxSizer(wx.HORIZONTAL)
1034            planeSizer.Add(wx.StaticText(self.panel,label=' Select plane: '),0,WACV)
1035            plane = wx.ComboBox(self.panel,value=self.plane,choices=self.planeChoice,
1036                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1037            plane.Bind(wx.EVT_COMBOBOX,OnPlane)
1038            planeSizer.Add(plane,0,WACV)
1039            planeSizer.Add(wx.StaticText(self.panel,label=' Max. l index: '),0,WACV)
1040            lmax = wx.ComboBox(self.panel,value=self.lmax,choices=self.lmaxChoice,
1041                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1042            lmax.Bind(wx.EVT_COMBOBOX,OnMaxL)
1043            planeSizer.Add(lmax,0,WACV)           
1044            mainSizer.Add(planeSizer)
1045        else:
1046            instChoice = ['None','Mean Gaussian','Gaussian',]
1047            instSizer = wx.BoxSizer(wx.HORIZONTAL)
1048            instSizer.Add(wx.StaticText(self.panel,label=' Select instrument broadening: '),0,WACV)
1049            instsel = wx.ComboBox(self.panel,value=self.Inst,choices=instChoice,
1050                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1051            instsel.Bind(wx.EVT_COMBOBOX,OnInstSel)
1052            instSizer.Add(instsel,0,WACV)
1053            mainSizer.Add(instSizer)
1054        OkBtn = wx.Button(self.panel,-1,"Ok")
1055        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1056        cancelBtn = wx.Button(self.panel,-1,"Cancel")
1057        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1058        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1059        btnSizer.Add((20,20),1)
1060        btnSizer.Add(OkBtn)
1061        btnSizer.Add((20,20),1)
1062        btnSizer.Add(cancelBtn)
1063        btnSizer.Add((20,20),1)
1064       
1065        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1066        self.panel.SetSizer(mainSizer)
1067        self.panel.Fit()
1068        self.Fit()
1069       
1070    def GetSelection(self):
1071        if 'powder' in self.calcType:
1072            return 'PWDR',self.Inst,self.Parm,self.parmRange,self.parmStep
1073        elif 'selected' in self.calcType:
1074            return 'SADP',self.plane,self.lmax
1075
1076    def OnOk(self,event):
1077        parent = self.GetParent()
1078        parent.Raise()
1079        self.EndModal(wx.ID_OK)
1080
1081    def OnCancel(self,event):
1082        parent = self.GetParent()
1083        parent.Raise()
1084        self.EndModal(wx.ID_CANCEL)
1085           
1086       
1087################################################################################
1088class MergeDialog(wx.Dialog):
1089    ''' HKL transformation & merge dialog
1090   
1091    :param wx.Frame parent: reference to parent frame (or None)
1092    :param data: HKLF data
1093   
1094    #NB: commonNames & commonTrans defined at top of this file     
1095    '''       
1096    def __init__(self,parent,data):
1097        wx.Dialog.__init__(self,parent,wx.ID_ANY,'Setup HKLF merge', 
1098            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1099        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
1100        self.data = data
1101        self.Super = data[1]['Super']
1102        if self.Super:
1103            self.Trans = np.eye(4)
1104        else:
1105            self.Trans = np.eye(3)
1106        self.Cent = 'noncentrosymmetric'
1107        self.Laue = '1'
1108        self.Class = 'triclinic'
1109        self.Common = 'abc'
1110        self.Draw()
1111       
1112    def Draw(self):
1113               
1114#        def OnMatValue(event):
1115#            event.Skip()
1116#            Obj = event.GetEventObject()
1117#            ix,iy = Ind[Obj.GetId()]
1118#            self.Trans[ix,iy] = float(Obj.GetValue())
1119#               
1120        def OnCent(event):
1121            Obj = event.GetEventObject()
1122            self.Cent = Obj.GetValue()
1123            self.Laue = ''
1124            wx.CallAfter(self.Draw)
1125           
1126        def OnLaue(event):
1127            Obj = event.GetEventObject()
1128            self.Laue = Obj.GetValue()
1129            wx.CallAfter(self.Draw)
1130           
1131        def OnClass(event):
1132            Obj = event.GetEventObject()
1133            self.Class = Obj.GetValue()
1134            self.Laue = ''
1135            wx.CallAfter(self.Draw)
1136           
1137        def OnCommon(event):
1138            Obj = event.GetEventObject()
1139            self.Common = Obj.GetValue()
1140            self.Trans = commonTrans[self.Common]
1141            wx.CallAfter(self.Draw)
1142       
1143        self.panel.Destroy()
1144        self.panel = wx.Panel(self)
1145#        Ind = {}
1146        mainSizer = wx.BoxSizer(wx.VERTICAL)
1147        MatSizer = wx.BoxSizer(wx.HORIZONTAL)
1148        transSizer = wx.BoxSizer(wx.VERTICAL)
1149        transSizer.Add(wx.StaticText(self.panel,label=" HKL Transformation matrix: M*H = H'"))
1150        if self.Super:
1151            Trmat = wx.FlexGridSizer(4,4,0,0)
1152        else:
1153            commonSizer = wx.BoxSizer(wx.HORIZONTAL)
1154            commonSizer.Add(wx.StaticText(self.panel,label=' Common transformations: '),0,WACV)
1155            common = wx.ComboBox(self.panel,value=self.Common,choices=commonNames[:-2], #not the last two!
1156                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1157            common.Bind(wx.EVT_COMBOBOX,OnCommon)
1158            commonSizer.Add(common,0,WACV)
1159            transSizer.Add(commonSizer)
1160            Trmat = wx.FlexGridSizer(3,3,0,0)
1161        for iy,line in enumerate(self.Trans):
1162            for ix,val in enumerate(line):
1163                item = G2G.ValidatedTxtCtrl(self.panel,self.Trans[iy],ix,nDig=(10,3),typeHint=float,size=(65,25))
1164#                item = wx.TextCtrl(self.panel,value='%5.3f'%(val),
1165#                    size=(50,25),style=wx.TE_PROCESS_ENTER)
1166#                Ind[item.GetId()] = [ix,iy]
1167#                item.Bind(wx.EVT_TEXT_ENTER,OnMatValue)
1168#                item.Bind(wx.EVT_KILL_FOCUS,OnMatValue)
1169                Trmat.Add(item)
1170        transSizer.Add(Trmat)
1171        MatSizer.Add((10,0),0)
1172        MatSizer.Add(transSizer)
1173        mainSizer.Add(MatSizer)
1174        laueClass = ['triclinic','monoclinic','orthorhombic','trigonal(H)','tetragonal','hexagonal','cubic']
1175        centroLaue = {'triclinic':['-1',],'monoclinic':['2/m','1 1 2/m','2/m 1 1',],
1176            'orthorhombic':['m m m',],'trigonal(H)':['-3','-3 m 1','-3 1 m',],    \
1177            'tetragonal':['4/m','4/m m m',],'hexagonal':['6/m','6/m m m',],'cubic':['m 3','m 3 m']}
1178        noncentroLaue = {'triclinic':['1',],'monoclinic':['2','2 1 1','1 1 2','m','m 1 1','1 1 m',],
1179            'orthorhombic':['2 2 2','m m 2','m 2 m','2 m m',],
1180            'trigonal(H)':['3','3 1 2','3 2 1','3 m 1','3 1 m',],
1181            'tetragonal':['4','-4','4 2 2','4 m m','-4 2 m','-4 m 2',], \
1182            'hexagonal':['6','-6','6 2 2','6 m m','-6 m 2','-6 2 m',],'cubic':['2 3','4 3 2','-4 3 m']}
1183        centChoice = ['noncentrosymmetric','centrosymmetric']
1184        mainSizer.Add(wx.StaticText(self.panel,label=' Select Laue class for new lattice:'),0,WACV)
1185        Class = wx.ComboBox(self.panel,value=self.Class,choices=laueClass,
1186            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1187        Class.Bind(wx.EVT_COMBOBOX,OnClass)
1188        mainSizer.Add(Class,0,WACV)
1189        mainSizer.Add(wx.StaticText(self.panel,label=' Target Laue symmetry:'),0,WACV)
1190        Cent = wx.ComboBox(self.panel,value=self.Cent,choices=centChoice,
1191            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1192        Cent.Bind(wx.EVT_COMBOBOX,OnCent)
1193        mergeSizer = wx.BoxSizer(wx.HORIZONTAL)
1194        mergeSizer.Add(Cent,0,WACV)
1195        mergeSizer.Add((10,0),0)
1196        Choice = centroLaue[self.Class]
1197        if 'non' in self.Cent:
1198            Choice = noncentroLaue[self.Class]
1199        Laue = wx.ComboBox(self.panel,value=self.Laue,choices=Choice,
1200            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1201        Laue.Bind(wx.EVT_COMBOBOX,OnLaue)
1202        mergeSizer.Add(Laue,0,WACV)
1203        mainSizer.Add(mergeSizer)
1204
1205        OkBtn = wx.Button(self.panel,-1,"Ok")
1206        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1207        cancelBtn = wx.Button(self.panel,-1,"Cancel")
1208        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1209        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1210        btnSizer.Add((20,20),1)
1211        if self.Laue:
1212            btnSizer.Add(OkBtn)
1213            btnSizer.Add((20,20),1)
1214        btnSizer.Add(cancelBtn)
1215        btnSizer.Add((20,20),1)
1216       
1217        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1218        self.panel.SetSizer(mainSizer)
1219        self.panel.Fit()
1220        self.Fit()
1221       
1222    def GetSelection(self):
1223        return self.Trans,self.Cent,self.Laue
1224
1225    def OnOk(self,event):
1226        parent = self.GetParent()
1227        parent.Raise()
1228        self.EndModal(wx.ID_OK)
1229
1230    def OnCancel(self,event):
1231        parent = self.GetParent()
1232        parent.Raise()
1233        self.EndModal(wx.ID_CANCEL)
1234
1235       
1236################################################################################
1237class AddHatomDialog(wx.Dialog):
1238    '''H atom addition dialog. After :meth:`ShowModal` returns, the results
1239    are found in dict :attr:`self.data`, which is accessed using :meth:`GetData`.
1240   
1241    :param wx.Frame parent: reference to parent frame (or None)
1242    :param dict Neigh: a dict of atom names with list of atom name, dist pairs for neighboring atoms
1243    :param dict phase: a dict containing the phase as defined by
1244      :ref:`Phase Tree Item <Phase_table>`   
1245    '''
1246    def __init__(self,parent,Neigh,phase):
1247        wx.Dialog.__init__(self,parent,wx.ID_ANY,'H atom add', 
1248            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1249        self.panel = wxscroll.ScrolledPanel(self)         #just a dummy - gets destroyed in Draw!
1250        self.Neigh = Neigh
1251        self.phase = phase
1252        self.Hatoms = []
1253        self.Draw(self.Neigh,self.phase)
1254           
1255    def Draw(self,Neigh,phase):
1256        '''Creates the contents of the dialog. Normally called
1257        by :meth:`__init__`.
1258        '''
1259        def OnHSelect(event):
1260            Obj = event.GetEventObject()
1261            item,i = Indx[Obj.GetId()]
1262            for obj in Indx[item]:
1263                obj.SetValue(False)
1264            Obj.SetValue(True)
1265            self.Neigh[item][2] = i
1266           
1267        def OnBond(event):
1268            Obj = event.GetEventObject()
1269            inei,ibond = Indx[Obj.GetId()]
1270            self.Neigh[inei][1][0][ibond][2] = Obj.GetValue()
1271           
1272        self.panel.Destroy()
1273        self.panel = wxscroll.ScrolledPanel(self,style = wx.DEFAULT_DIALOG_STYLE)
1274        mainSizer = wx.BoxSizer(wx.VERTICAL)
1275        mainSizer.Add(wx.StaticText(self.panel,-1,'H atom add controls for phase %s:'%(phase['General']['Name'])),
1276            0,wx.LEFT|wx.TOP,10)
1277        mainSizer.Add(wx.StaticText(self.panel,-1,'NB: Check selections as they may not be correct'),0,WACV|wx.LEFT,10)
1278        mainSizer.Add(wx.StaticText(self.panel,-1," Atom:  Add # H's          Use: Neighbors, dist"),0,wx.TOP|wx.LEFT,5)
1279        nHatms = ['0','1','2','3']
1280        dataSizer = wx.FlexGridSizer(0,3,0,0)
1281        Indx = {}
1282        for inei,neigh in enumerate(Neigh):
1283            dataSizer.Add(wx.StaticText(self.panel,-1,' %s:  '%(neigh[0])),0,WACV)
1284            nH = 1      #for O atom
1285            if 'C' in neigh[0] or 'N' in neigh[0]:
1286                nH = 4-len(neigh[1][0])
1287            checks = wx.BoxSizer(wx.HORIZONTAL)
1288            Ids = []
1289            for i in range(nH+1):
1290                nHs = wx.CheckBox(self.panel,-1,label=nHatms[i])
1291                if i == neigh[2]:
1292                    nHs.SetValue(True)
1293                Indx[nHs.GetId()] = [inei,i]
1294                Ids.append(nHs)
1295                nHs.Bind(wx.EVT_CHECKBOX, OnHSelect)
1296                checks.Add(nHs,0,WACV)
1297            Indx[inei] = Ids
1298            dataSizer.Add(checks,0,WACV)
1299            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
1300            for ib,bond in enumerate(neigh[1][0]):
1301                Bond = wx.CheckBox(self.panel,-1,label=': %s, %.3f'%(bond[0],bond[1]))
1302                Bond.SetValue(bond[2])
1303                Indx[Bond.GetId()] = [inei,ib]
1304                Bond.Bind(wx.EVT_CHECKBOX,OnBond)               
1305                lineSizer.Add(Bond,0,WACV)               
1306            dataSizer.Add(lineSizer,0,WACV|wx.RIGHT,10)
1307        mainSizer.Add(dataSizer,0,wx.LEFT,5)
1308
1309        CancelBtn = wx.Button(self.panel,-1,'Cancel')
1310        CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1311        OkBtn = wx.Button(self.panel,-1,'Ok')
1312        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1313        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1314        btnSizer.Add((20,20),1)
1315        btnSizer.Add(OkBtn)
1316        btnSizer.Add((20,20),1)
1317        btnSizer.Add(CancelBtn)
1318        btnSizer.Add((20,20),1)
1319        mainSizer.Add(btnSizer,0,wx.BOTTOM|wx.TOP, 10)
1320        self.panel.SetSizer(mainSizer)
1321        size = np.array(self.GetSize())
1322        self.panel.SetupScrolling()
1323        self.panel.SetAutoLayout(1)
1324        size = [size[0]-5,size[1]-20]       #this fiddling is needed for older wx!
1325        self.panel.SetSize(size)
1326       
1327    def GetData(self):
1328        'Returns the values from the dialog'
1329        for neigh in self.Neigh:
1330            for ibond,bond in enumerate(neigh[1][0]):
1331                if not bond[2]:
1332                    neigh[1][1][1][ibond] = 0   #deselected bond
1333            neigh[1][1][1] = [a for a in  neigh[1][1][1] if a]
1334        return self.Neigh       #has #Hs to add for each entry
1335       
1336    def OnOk(self,event):
1337        'Called when the OK button is pressed'
1338        parent = self.GetParent()
1339        parent.Raise()
1340        self.EndModal(wx.ID_OK)             
1341
1342    def OnCancel(self,event):
1343        parent = self.GetParent()
1344        parent.Raise()
1345        self.EndModal(wx.ID_CANCEL)
1346
1347################################################################################
1348class DisAglDialog(wx.Dialog):
1349    '''Distance/Angle Controls input dialog. After
1350    :meth:`ShowModal` returns, the results are found in
1351    dict :attr:`self.data`, which is accessed using :meth:`GetData`.
1352
1353    :param wx.Frame parent: reference to parent frame (or None)
1354    :param dict data: a dict containing the current
1355      search ranges or an empty dict, which causes default values
1356      to be used.
1357      Will be used to set element `DisAglCtls` in
1358      :ref:`Phase Tree Item <Phase_table>`
1359    :param dict default:  A dict containing the default
1360      search ranges for each element.
1361    :param bool Reset: if True (default), show Reset button
1362    :param bool Angle: if True (default), show angle radii
1363    '''
1364    def __init__(self,parent,data,default,Reset=True,Angle=True):
1365        text = 'Distance Angle Controls'
1366        if not Angle:
1367            text = 'Distance Controls'
1368        wx.Dialog.__init__(self,parent,wx.ID_ANY,text, 
1369            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1370        self.default = default
1371        self.Reset = Reset
1372        self.Angle = Angle
1373        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
1374        self._default(data,self.default)
1375        self.Draw(self.data)
1376               
1377    def _default(self,data,default):
1378        '''Set starting values for the search values, either from
1379        the input array or from defaults, if input is null
1380        '''
1381        if data:
1382            self.data = copy.deepcopy(data) # don't mess with originals
1383        else:
1384            self.data = {}
1385            self.data['Name'] = default['Name']
1386            self.data['Factors'] = [0.85,0.85]
1387            self.data['AtomTypes'] = default['AtomTypes']
1388            self.data['BondRadii'] = default['BondRadii'][:]
1389            self.data['AngleRadii'] = default['AngleRadii'][:]
1390
1391    def Draw(self,data):
1392        '''Creates the contents of the dialog. Normally called
1393        by :meth:`__init__`.
1394        '''
1395        self.panel.Destroy()
1396        self.panel = wx.Panel(self)
1397        mainSizer = wx.BoxSizer(wx.VERTICAL)
1398        mainSizer.Add(wx.StaticText(self.panel,-1,'Controls for phase '+data['Name']),
1399            0,WACV|wx.LEFT,10)
1400        mainSizer.Add((10,10),1)
1401       
1402        ncol = 3
1403        if not self.Angle:
1404            ncol=2
1405        radiiSizer = wx.FlexGridSizer(0,ncol,5,5)
1406        radiiSizer.Add(wx.StaticText(self.panel,-1,' Type'),0,WACV)
1407        radiiSizer.Add(wx.StaticText(self.panel,-1,'Bond radii'),0,WACV)
1408        if self.Angle:
1409            radiiSizer.Add(wx.StaticText(self.panel,-1,'Angle radii'),0,WACV)
1410        self.objList = {}
1411        for id,item in enumerate(self.data['AtomTypes']):
1412            radiiSizer.Add(wx.StaticText(self.panel,-1,' '+item),0,WACV)
1413            bRadii = G2G.ValidatedTxtCtrl(self.panel,data['BondRadii'],id,nDig=(10,3),typeHint=float)
1414            radiiSizer.Add(bRadii,0,WACV)
1415            if self.Angle:
1416                aRadii = G2G.ValidatedTxtCtrl(self.panel,data['AngleRadii'],id,nDig=(10,3),typeHint=float)
1417                radiiSizer.Add(aRadii,0,WACV)
1418        mainSizer.Add(radiiSizer,0,wx.EXPAND)
1419        if self.Angle:
1420            factorSizer = wx.FlexGridSizer(0,2,5,5)
1421            Names = ['Bond','Angle']
1422            for i,name in enumerate(Names):
1423                factorSizer.Add(wx.StaticText(self.panel,-1,name+' search factor'),0,WACV)
1424                bondFact = G2G.ValidatedTxtCtrl(self.panel,data['Factors'],i,nDig=(10,3),typeHint=float)
1425                factorSizer.Add(bondFact)
1426            mainSizer.Add(factorSizer,0,wx.EXPAND)
1427       
1428        OkBtn = wx.Button(self.panel,-1,"Ok")
1429        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1430        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1431        btnSizer.Add((20,20),1)
1432        btnSizer.Add(OkBtn)
1433        if self.Reset:
1434            ResetBtn = wx.Button(self.panel,-1,'Reset')
1435            ResetBtn.Bind(wx.EVT_BUTTON, self.OnReset)
1436            btnSizer.Add(ResetBtn)
1437        btnSizer.Add((20,20),1)
1438        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1439        self.panel.SetSizer(mainSizer)
1440        self.panel.Fit()
1441        self.Fit()
1442   
1443    def GetData(self):
1444        'Returns the values from the dialog'
1445        return self.data
1446       
1447    def OnOk(self,event):
1448        'Called when the OK button is pressed'
1449        parent = self.GetParent()
1450        parent.Raise()
1451        self.EndModal(wx.ID_OK)             
1452       
1453    def OnReset(self,event):
1454        'Called when the Reset button is pressed'
1455        data = {}
1456        self._default(data,self.default)
1457        self.Draw(self.data)
1458               
1459################################################################################
1460class ShowLSParms(wx.Dialog):
1461    '''Create frame to show least-squares parameters
1462    '''
1463    def __init__(self,parent,title,parmDict,varyList,fullVaryList,
1464                 size=(300,430)):
1465       
1466        wx.Dialog.__init__(self,parent,wx.ID_ANY,title,size=size,
1467                           style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
1468        self.panel = wxscroll.ScrolledPanel(self)         #just a dummy - gets destroyed in DrawPanel!
1469        self.parmChoice = 'Phase'
1470        self.parmDict = parmDict
1471        self.varyList = varyList
1472        self.fullVaryList = fullVaryList
1473
1474        self.parmNames = parmDict.keys()
1475        self.parmNames.sort()
1476        splitNames = [item.split(':') for item in self.parmNames if len(item) > 3 and not isinstance(self.parmDict[item],basestring)]
1477        self.globNames = [':'.join(item) for item in splitNames if not item[0] and not item[1]]
1478        self.globVars = list(set([' ',]+[item[2] for item in splitNames if not item[0] and not item[1]]))
1479        self.globVars.sort()
1480        self.hisNames = [':'.join(item) for item in splitNames if not item[0] and item[1]]
1481        self.hisNums = list(set([int(item.split(':')[1]) for item in self.hisNames]))
1482        self.hisNums.sort()
1483        self.hisNums = [' ',]+[str(item) for item in self.hisNums]
1484        self.hisVars = list(set([' ',]+[item[2] for item in splitNames if not item[0]]))
1485        self.hisVars.sort()
1486        self.phasNames = [':'.join(item) for item in splitNames if not item[1] and 'is' not in item[2]]
1487        self.phasNums = [' ',]+list(set([item.split(':')[0] for item in self.phasNames]))
1488        if '' in self.phasNums: self.phasNums.remove('')
1489        self.phasVars = list(set([' ',]+[item[2] for item in splitNames if not item[1] and 'is' not in item[2]]))
1490        self.phasVars.sort()
1491        self.phasNums.sort()
1492        self.hapNames = [':'.join(item) for item in splitNames if item[0] and item[1]]
1493        self.hapVars = list(set([' ',]+[item[2] for item in splitNames if item[0] and item[1]]))
1494        self.hapVars.sort()
1495        self.hisNum = '0'
1496        self.phasNum = '0'
1497        self.varName = ' '
1498        self.listSel = 'Refined'
1499        self.DrawPanel()
1500       
1501           
1502    def DrawPanel(self):
1503           
1504        def _OnParmSel(event):
1505            self.parmChoice = parmSel.GetStringSelection()
1506            self.varName = ' '
1507            wx.CallAfter(self.DrawPanel)
1508           
1509        def OnPhasSel(event):
1510            event.Skip()
1511            self.phasNum = phasSel.GetValue()
1512            self.varName = ' '
1513            wx.CallAfter(self.DrawPanel)
1514
1515        def OnHistSel(event):
1516            event.Skip()
1517            self.hisNum = histSel.GetValue()
1518            self.varName = ' '
1519            wx.CallAfter(self.DrawPanel)
1520           
1521        def OnVarSel(event):
1522            self.varName = varSel.GetValue()
1523            self.phasNum = ' '
1524            self.hisNum = ' '
1525            wx.CallAfter(self.DrawPanel)
1526           
1527        def OnListSel(event):
1528            self.listSel = listSel.GetStringSelection()
1529            wx.CallAfter(self.DrawPanel)
1530
1531        if self.panel:
1532            self.panel.DestroyChildren()
1533        mainSizer = wx.BoxSizer(wx.VERTICAL)
1534        num = len(self.varyList)
1535        mainSizer.Add(wx.StaticText(self.panel,label=' Number of refined variables: '+str(num)),0)
1536        if len(self.varyList) != len(self.fullVaryList):
1537            num = len(self.fullVaryList) - len(self.varyList)
1538            mainSizer.Add(wx.StaticText(self.panel,label=' + '+str(num)+' parameters are varied via constraints'))
1539        choiceDict = {'Global':self.globNames,'Phase':self.phasNames,'Phase/Histo':self.hapNames,'Histogram':self.hisNames}
1540        choice = ['Phase','Phase/Histo','Histogram']
1541        if len(self.globNames):
1542            choice += ['Global',]
1543        parmSizer = wx.FlexGridSizer(0,3,5,5)
1544        parmSel = wx.RadioBox(self.panel,wx.ID_ANY,'Parameter type:',choices=choice,
1545            majorDimension=1,style=wx.RA_SPECIFY_COLS)
1546        parmSel.Bind(wx.EVT_RADIOBOX,_OnParmSel)
1547        parmSel.SetStringSelection(self.parmChoice)
1548        parmSizer.Add(parmSel,0)
1549        numSizer = wx.BoxSizer(wx.VERTICAL)
1550        numSizer.Add((5,25),0)
1551        if self.parmChoice in ['Phase','Phase/Histo'] and len(self.phasNums) > 1:
1552            numSizer.Add(wx.StaticText(self.panel,label='Phase'),0)
1553            phasSel = wx.ComboBox(self.panel,choices=self.phasNums,value=self.phasNum,
1554                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1555            phasSel.Bind(wx.EVT_COMBOBOX,OnPhasSel)
1556            numSizer.Add(phasSel,0)
1557        if self.parmChoice in ['Histogram','Phase/Histo'] and len(self.hisNums) > 1:
1558            numSizer.Add(wx.StaticText(self.panel,label='Histogram'),0)
1559            histSel = wx.ComboBox(self.panel,choices=self.hisNums,value=self.hisNum,
1560                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1561            histSel.Bind(wx.EVT_COMBOBOX,OnHistSel)
1562#            histSel = wx.TextCtrl(self.panel,size=(50,25),value='0',style=wx.TE_PROCESS_ENTER)
1563#            histSel.Bind(wx.EVT_TEXT_ENTER,OnHistSel)
1564#            histSel.Bind(wx.EVT_KILL_FOCUS,OnHistSel)
1565            numSizer.Add(histSel,0)
1566        parmSizer.Add(numSizer)
1567        varSizer = wx.BoxSizer(wx.VERTICAL)
1568        varSizer.Add(wx.StaticText(self.panel,label='Parameter'))
1569        if self.parmChoice in ['Phase',]:
1570            varSel = wx.ComboBox(self.panel,choices=self.phasVars,value=self.varName,
1571                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1572            varSel.Bind(wx.EVT_COMBOBOX,OnVarSel)
1573        elif self.parmChoice in ['Histogram',]:
1574            varSel = wx.ComboBox(self.panel,choices=self.hisVars,value=self.varName,
1575                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1576            varSel.Bind(wx.EVT_COMBOBOX,OnVarSel)
1577        elif self.parmChoice in ['Phase/Histo',]:
1578            varSel = wx.ComboBox(self.panel,choices=self.hapVars,value=self.varName,
1579                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1580            varSel.Bind(wx.EVT_COMBOBOX,OnVarSel)
1581        if self.parmChoice != 'Global': 
1582            varSizer.Add(varSel,0)
1583            parmSizer.Add(varSizer,0)
1584        mainSizer.Add(parmSizer,0)
1585        listChoice = ['All','Refined']
1586        listSel = wx.RadioBox(self.panel,wx.ID_ANY,'Parameter type:',choices=listChoice,
1587            majorDimension=0,style=wx.RA_SPECIFY_COLS)
1588        listSel.SetStringSelection(self.listSel)
1589        listSel.Bind(wx.EVT_RADIOBOX,OnListSel)
1590        mainSizer.Add(listSel,0)
1591        subSizer = wx.FlexGridSizer(cols=4,hgap=2,vgap=2)
1592        subSizer.Add((-1,-1))
1593        subSizer.Add(wx.StaticText(self.panel,wx.ID_ANY,'Parameter name  '))
1594        subSizer.Add(wx.StaticText(self.panel,wx.ID_ANY,'refine?'))
1595        subSizer.Add(wx.StaticText(self.panel,wx.ID_ANY,'value'),0,wx.ALIGN_RIGHT)
1596        explainRefine = False
1597        for name in choiceDict[self.parmChoice]:
1598            # skip entries without numerical values
1599            if isinstance(self.parmDict[name],basestring): continue
1600            if 'Refined' in self.listSel and (name not in self.fullVaryList): continue
1601            if 'Phase' in self.parmChoice:
1602                if self.phasNum != ' ' and name.split(':')[0] != self.phasNum: continue
1603            if 'Histo' in self.parmChoice:
1604                if self.hisNum != ' ' and name.split(':')[1] != self.hisNum: continue
1605            if (self.varName != ' ') and (self.varName not in name): continue
1606            try:
1607                value = G2py3.FormatSigFigs(self.parmDict[name])
1608            except TypeError:
1609                value = str(self.parmDict[name])+' -?' # unexpected
1610                #continue
1611            v = G2obj.getVarDescr(name)
1612            if v is None or v[-1] is None:
1613                subSizer.Add((-1,-1))
1614            else:               
1615                ch = G2G.HelpButton(self.panel,G2obj.fmtVarDescr(name))
1616                subSizer.Add(ch,0,wx.LEFT|wx.RIGHT|WACV|wx.ALIGN_CENTER,1)
1617            subSizer.Add(wx.StaticText(self.panel,wx.ID_ANY,str(name)))
1618            if name in self.varyList:
1619                subSizer.Add(wx.StaticText(self.panel,label='R'))   #TODO? maybe a checkbox for one stop refinemnt flag setting?
1620            elif name in self.fullVaryList:
1621                subSizer.Add(wx.StaticText(self.panel,label='C'))
1622                explainRefine = True
1623            else:
1624                subSizer.Add((-1,-1))
1625            subSizer.Add(wx.StaticText(self.panel,label=value),0,wx.ALIGN_RIGHT)
1626
1627        mainSizer.Add(subSizer,0)
1628        if explainRefine:
1629            mainSizer.Add(
1630                wx.StaticText(self.panel,label='"R" indicates a refined variable\n'+
1631                    '"C" indicates generated from a constraint'),0, wx.ALL,0)
1632        # make OK button
1633        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
1634        btn = wx.Button(self.panel, wx.ID_CLOSE,"Close") 
1635        btn.Bind(wx.EVT_BUTTON,self._onClose)
1636        btnsizer.Add(btn)
1637        mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)
1638        # Allow window to be enlarged but not made smaller
1639        self.panel.SetSizer(mainSizer)
1640        self.panel.SetAutoLayout(1)
1641        self.panel.SetupScrolling()
1642        self.panel.SetMinSize(self.GetSize())
1643
1644    def _onClose(self,event):
1645        self.EndModal(wx.ID_CANCEL)
1646 
1647################################################################################
1648class DataFrame(wx.Frame):
1649    '''Create the data item window and all the entries in menus used in
1650    that window. For Linux and windows, the menu entries are created for the
1651    current data item window, but in the Mac the menu is accessed from all
1652    windows. This means that a different menu is posted depending on which
1653    data item is posted. On the Mac, all the menus contain the data tree menu
1654    items, but additional menus are added specific to the data item.
1655
1656    Note that while the menus are created here,
1657    the binding for the menus is done later in various GSASII*GUI modules,
1658    where the functions to be called are defined.
1659    '''
1660    def Bind(self,eventtype,handler,*args,**kwargs):
1661        '''Override the Bind() function: on the Mac the binding is to
1662        the main window, so that menus operate with any window on top.
1663        For other platforms, either wrap calls that will be logged
1664        or call the default wx.Frame Bind() to bind to the menu item directly.
1665
1666        Note that bindings can be made to objects by Id or by direct reference to the
1667        object. As a convention, when bindings are to objects, they are not logged
1668        but when bindings are by Id, they are logged.
1669        '''
1670        if sys.platform == "darwin": # mac
1671            self.G2frame.Bind(eventtype,handler,*args,**kwargs)
1672            return
1673        if eventtype == wx.EVT_MENU and 'id' in kwargs:
1674            menulabels = log.SaveMenuCommand(kwargs['id'],self.G2frame,handler)
1675            if menulabels:
1676                #print 'intercepting bind for',handler,menulabels,kwargs['id']
1677                wx.Frame.Bind(self,eventtype,self.G2frame.MenuBinding,*args,**kwargs)
1678                return
1679            wx.Frame.Bind(self,eventtype,handler,*args,**kwargs)     
1680       
1681    def PrefillDataMenu(self,menu,empty=False):
1682        '''Create the "standard" part of data frame menus. Note that on Linux and
1683        Windows nothing happens here. On Mac, this menu duplicates the
1684        tree menu, but adds an extra help command for the data item and a separator.
1685        '''
1686        self.datamenu = menu
1687        self.G2frame.dataMenuBars.append(menu)
1688        if sys.platform == "darwin": # mac                         
1689            self.G2frame.FillMainMenu(menu,addhelp=False) # add the data tree menu items
1690            if not empty:
1691                menu.Append(wx.Menu(title=''),title='|') # add a separator
1692       
1693    def PostfillDataMenu(self,empty=False):
1694        '''Add the help menu to the data frame menus. Note that on Linux and
1695        Windows, this is the standard help Menu but without the update commands but adds an extra help
1696        command for the data item.
1697        On Mac, this is the entire help menu including the update commands, a separator and the
1698        extra help command for the data item.
1699        '''
1700        menu = self.datamenu
1701        if sys.platform == "darwin": # mac
1702            if not empty:
1703                menu.Append(wx.Menu(title=''),title='|') # add another separator
1704            HelpMenu=G2G.MyHelp(self,includeTree=True,
1705                morehelpitems=[('&Tutorials','Tutorials'),])
1706            menu.Append(menu=HelpMenu,title='&Help')
1707        else: # other
1708            menu.Append(menu=G2G.MyHelp(self),title='&Help')
1709
1710    def _init_menus(self):
1711        'define all GSAS-II data frame menus'
1712
1713        # for use where no menu or data frame help is provided
1714        self.BlankMenu = wx.MenuBar()
1715       
1716        # Controls
1717        self.ControlsMenu = wx.MenuBar()
1718        self.PrefillDataMenu(self.ControlsMenu,empty=True)
1719        self.PostfillDataMenu(empty=True)
1720       
1721        # Notebook
1722        self.DataNotebookMenu = wx.MenuBar() 
1723        self.PrefillDataMenu(self.DataNotebookMenu,empty=True)
1724        self.PostfillDataMenu(empty=True)
1725       
1726        # Comments
1727        self.DataCommentsMenu = wx.MenuBar()
1728        self.PrefillDataMenu(self.DataCommentsMenu,empty=True)
1729        self.PostfillDataMenu(empty=True)
1730       
1731        # Constraints
1732        self.ConstraintMenu = wx.MenuBar()
1733        self.PrefillDataMenu(self.ConstraintMenu)
1734        self.ConstraintTab = wx.Menu(title='')
1735        self.ConstraintMenu.Append(menu=self.ConstraintTab, title='Select tab')
1736        for id,txt in (
1737            (wxID_CONSPHASE,'Phase'),
1738            (wxID_CONSHAP,'Histogram/Phase'),
1739            (wxID_CONSHIST,'Histogram'),
1740            (wxID_CONSGLOBAL,'Global')):
1741            self.ConstraintTab.Append(
1742                id=id, kind=wx.ITEM_NORMAL,text=txt,
1743                help='Select '+txt+' constraint editing tab')
1744        self.ConstraintEdit = wx.Menu(title='')
1745        self.ConstraintMenu.Append(menu=self.ConstraintEdit, title='Edit Constr.') # renamed from Edit due to Mac adding extra items to menu
1746        self.ConstraintEdit.Append(id=wxID_HOLDADD, kind=wx.ITEM_NORMAL,text='Add hold',
1747            help='Prevent refinement of parameter values')
1748        self.ConstraintEdit.Append(id=wxID_EQUIVADD, kind=wx.ITEM_NORMAL,text='Add equivalence',
1749            help='Force parameter values to be equivalent')
1750        self.ConstraintEdit.Append(id=wxID_CONSTRAINTADD, kind=wx.ITEM_NORMAL,text='Add constraint equation',
1751            help='Add a constraint equation to apply to parameter values')
1752        self.ConstraintEdit.Append(id=wxID_FUNCTADD, kind=wx.ITEM_NORMAL,text='Add New Var',
1753            help='Create a variable composed of existing parameters')
1754        self.ConstraintEdit.Append(id=wxID_EQUIVALANCEATOMS, kind=wx.ITEM_NORMAL,text='Make atoms equivalent',
1755            help='Force atom parameter values to be equivalent')
1756        self.ConstraintEdit.Enable(wxID_EQUIVALANCEATOMS,False)
1757#        self.ConstraintEdit.Append(id=wxID_ADDRIDING, kind=wx.ITEM_NORMAL,text='Add H riding constraints',
1758#            help='Add H atom riding constraints between atom parameter values')
1759#        self.ConstraintEdit.Enable(wxID_ADDRIDING,False)
1760        self.PostfillDataMenu()
1761
1762        # item = self.ConstraintEdit.Append(id=wx.ID_ANY,kind=wx.ITEM_NORMAL,text='Update GUI')
1763        # def UpdateGSASIIconstrGUI(event):
1764        #     import GSASIIconstrGUI
1765        #     reload(GSASIIconstrGUI)
1766        #     import GSASIIobj
1767        #     reload(GSASIIobj)
1768        # self.Bind(wx.EVT_MENU,UpdateGSASIIconstrGUI,id=item.GetId())
1769
1770        # Rigid bodies
1771        self.RigidBodyMenu = wx.MenuBar()
1772        self.PrefillDataMenu(self.RigidBodyMenu)
1773        self.ResidueRBMenu = wx.Menu(title='')
1774        self.ResidueRBMenu.Append(id=wxID_RIGIDBODYIMPORT, kind=wx.ITEM_NORMAL,text='Import XYZ',
1775            help='Import rigid body XYZ from file')
1776        self.ResidueRBMenu.Append(id=wxID_RESIDUETORSSEQ, kind=wx.ITEM_NORMAL,text='Define sequence',
1777            help='Define torsion sequence')
1778        self.ResidueRBMenu.Append(id=wxID_RIGIDBODYADD, kind=wx.ITEM_NORMAL,text='Import residues',
1779            help='Import residue rigid bodies from macro file')
1780        self.RigidBodyMenu.Append(menu=self.ResidueRBMenu, title='Edit Body')
1781        self.PostfillDataMenu()
1782
1783        self.VectorBodyMenu = wx.MenuBar()
1784        self.PrefillDataMenu(self.VectorBodyMenu)
1785        self.VectorRBEdit = wx.Menu(title='')
1786        self.VectorRBEdit.Append(id=wxID_VECTORBODYADD, kind=wx.ITEM_NORMAL,text='Add rigid body',
1787            help='Add vector rigid body')
1788        self.VectorBodyMenu.Append(menu=self.VectorRBEdit, title='Edit Vector Body')
1789        self.PostfillDataMenu()
1790
1791                   
1792        # Restraints
1793        self.RestraintTab = wx.Menu(title='')
1794        self.RestraintEdit = wx.Menu(title='')
1795        self.RestraintEdit.Append(id=wxID_RESTSELPHASE, kind=wx.ITEM_NORMAL,text='Select phase',
1796            help='Select phase')
1797        self.RestraintEdit.Append(id=wxID_RESTRAINTADD, kind=wx.ITEM_NORMAL,text='Add restraints',
1798            help='Add restraints')
1799        self.RestraintEdit.Enable(wxID_RESTRAINTADD,True)    #gets disabled if macromolecule phase
1800        self.RestraintEdit.Append(id=wxID_AARESTRAINTADD, kind=wx.ITEM_NORMAL,text='Add residue restraints',
1801            help='Add residue based restraints for macromolecules from macro file')
1802        self.RestraintEdit.Enable(wxID_AARESTRAINTADD,False)    #gets enabled if macromolecule phase
1803        self.RestraintEdit.Append(id=wxID_AARESTRAINTPLOT, kind=wx.ITEM_NORMAL,text='Plot residue restraints',
1804            help='Plot selected residue based restraints for macromolecules from macro file')
1805        self.RestraintEdit.Enable(wxID_AARESTRAINTPLOT,False)    #gets enabled if macromolecule phase
1806        self.RestraintEdit.Append(id=wxID_RESRCHANGEVAL, kind=wx.ITEM_NORMAL,text='Change value',
1807            help='Change observed value')
1808        self.RestraintEdit.Append(id=wxID_RESTCHANGEESD, kind=wx.ITEM_NORMAL,text='Change esd',
1809            help='Change esd in observed value')
1810        self.RestraintEdit.Append(id=wxID_RESTDELETE, kind=wx.ITEM_NORMAL,text='Delete restraints',
1811            help='Delete selected restraints')
1812
1813        self.RestraintMenu = wx.MenuBar()
1814        self.PrefillDataMenu(self.RestraintMenu)
1815        self.RestraintMenu.Append(menu=self.RestraintTab, title='Select tab')
1816        self.RestraintMenu.Append(menu=self.RestraintEdit, title='Edit Restr.')
1817        self.PostfillDataMenu()
1818           
1819        # Sequential results
1820        self.SequentialMenu = wx.MenuBar()
1821        self.PrefillDataMenu(self.SequentialMenu)
1822        self.SequentialFile = wx.Menu(title='')
1823        self.SequentialMenu.Append(menu=self.SequentialFile, title='Columns')
1824        self.SequentialFile.Append(id=wxID_RENAMESEQSEL, kind=wx.ITEM_NORMAL,text='Rename selected',
1825            help='Rename selected sequential refinement columns')
1826        self.SequentialFile.Append(id=wxID_SAVESEQSEL, kind=wx.ITEM_NORMAL,text='Save selected as text',
1827            help='Save selected sequential refinement results as a text file')
1828        self.SequentialFile.Append(id=wxID_SAVESEQCSV, kind=wx.ITEM_NORMAL,text='Save all as CSV',
1829            help='Save all sequential refinement results as a CSV spreadsheet file')
1830        self.SequentialFile.Append(id=wxID_SAVESEQSELCSV, kind=wx.ITEM_NORMAL,text='Save selected as CSV',
1831            help='Save selected sequential refinement results as a CSV spreadsheet file')
1832        self.SequentialFile.Append(id=wxID_PLOTSEQSEL, kind=wx.ITEM_NORMAL,text='Plot selected',
1833            help='Plot selected sequential refinement results')
1834        self.SequentialFile.Append(id=wxID_AVESEQSEL, kind=wx.ITEM_NORMAL,text='Compute average',
1835            help='Compute average for selected parameter')           
1836        self.SequentialFile.Append(id=wxID_ORGSEQSEL, kind=wx.ITEM_NORMAL,text='Reorganize',
1837            help='Reorganize variables where variables change')
1838        self.SequentialPvars = wx.Menu(title='')
1839        self.SequentialMenu.Append(menu=self.SequentialPvars, title='Pseudo Vars')
1840        self.SequentialPvars.Append(
1841            id=wxADDSEQVAR, kind=wx.ITEM_NORMAL,text='Add Formula',
1842            help='Add a new custom pseudo-variable')
1843        self.SequentialPvars.Append(
1844            id=wxADDSEQDIST, kind=wx.ITEM_NORMAL,text='Add Distance',
1845            help='Add a new bond distance pseudo-variable')
1846        self.SequentialPvars.Append(
1847            id=wxADDSEQANGLE, kind=wx.ITEM_NORMAL,text='Add Angle',
1848            help='Add a new bond angle pseudo-variable')
1849        self.SequentialPvars.Append(
1850            id=wxDELSEQVAR, kind=wx.ITEM_NORMAL,text='Delete',
1851            help='Delete an existing pseudo-variable')
1852        self.SequentialPvars.Append(
1853            id=wxEDITSEQVAR, kind=wx.ITEM_NORMAL,text='Edit',
1854            help='Edit an existing pseudo-variable')
1855
1856        self.SequentialPfit = wx.Menu(title='')
1857        self.SequentialMenu.Append(menu=self.SequentialPfit, title='Parametric Fit')
1858        self.SequentialPfit.Append(
1859            id=wxADDPARFIT, kind=wx.ITEM_NORMAL,text='Add equation',
1860            help='Add a new equation to minimize')
1861        self.SequentialPfit.Append(
1862            id=wxCOPYPARFIT, kind=wx.ITEM_NORMAL,text='Copy equation',
1863            help='Copy an equation to minimize - edit it next')
1864        self.SequentialPfit.Append(
1865            id=wxDELPARFIT, kind=wx.ITEM_NORMAL,text='Delete equation',
1866            help='Delete an equation for parametric minimization')
1867        self.SequentialPfit.Append(
1868            id=wxEDITPARFIT, kind=wx.ITEM_NORMAL,text='Edit equation',
1869            help='Edit an existing parametric minimization equation')
1870        self.SequentialPfit.Append(
1871            id=wxDOPARFIT, kind=wx.ITEM_NORMAL,text='Fit to equation(s)',
1872            help='Perform a parametric minimization')
1873        # fill sequential Export menu
1874        self.SeqExportLookup = {}
1875        self.SequentialEx = wx.Menu(title='')
1876        self.SequentialMenu.Append(menu=self.SequentialEx, title='Seq Export')
1877        for lbl,txt in (('Phase','Export selected phase(s)'),
1878                        ('Project','Export entire sequential fit')):
1879            objlist = []
1880            for obj in self.G2frame.exporterlist:
1881                if lbl.lower() in obj.exporttype:
1882                    try:
1883                        obj.Writer
1884                    except AttributeError:
1885                        continue
1886                    objlist.append(obj)
1887            if objlist:
1888                submenu = wx.Menu()
1889                item = self.SequentialEx.AppendMenu(
1890                    wx.ID_ANY, lbl+' as',
1891                    submenu, help=txt)
1892                for obj in objlist:
1893                    item = submenu.Append(
1894                        wx.ID_ANY,
1895                        help=obj.longFormatName,
1896                        kind=wx.ITEM_NORMAL,
1897                        text=obj.formatName)
1898                    self.SeqExportLookup[item.GetId()] = (obj,lbl) # lookup table for submenu item
1899       
1900        self.PostfillDataMenu()
1901           
1902        # PWDR & SASD
1903        self.PWDRMenu = wx.MenuBar()
1904        self.PrefillDataMenu(self.PWDRMenu)
1905        self.ErrorAnal = wx.Menu(title='')
1906        self.PWDRMenu.Append(menu=self.ErrorAnal,title='Commands')
1907        self.ErrorAnal.Append(id=wxID_PWDANALYSIS,kind=wx.ITEM_NORMAL,text='Error Analysis',
1908            help='Error analysis on powder pattern')
1909        self.ErrorAnal.Append(id=wxID_PWDCOPY,kind=wx.ITEM_NORMAL,text='Copy params',
1910            help='Copy of PWDR parameters')
1911        self.ErrorAnal.Append(id=wxID_PLOTCTRLCOPY,kind=wx.ITEM_NORMAL,text='Copy plot controls',
1912            help='Copy of PWDR plot controls')
1913        self.moveDiffCurve = self.ErrorAnal.Append(id=wx.ID_ANY,kind=wx.ITEM_NORMAL,text='Move diff. curve',
1914            help='Click on position where difference curve is placed')
1915        self.moveTickLoc = self.ErrorAnal.Append(id=wx.ID_ANY,kind=wx.ITEM_NORMAL,text='Move ticks',
1916            help='Move mouse to where tick marks should be positioned')
1917        self.moveTickSpc = self.ErrorAnal.Append(id=wx.ID_ANY,kind=wx.ITEM_NORMAL,text='Set tick space',
1918            help='Click to set spacing between phase tick marks')
1919        self.PostfillDataMenu()
1920           
1921        # HKLF
1922        self.HKLFMenu = wx.MenuBar()
1923        self.PrefillDataMenu(self.HKLFMenu)
1924        self.ErrorAnal = wx.Menu(title='')
1925        self.HKLFMenu.Append(menu=self.ErrorAnal,title='Commands')
1926        self.ErrorAnal.Append(id=wxID_PWDANALYSIS,kind=wx.ITEM_NORMAL,text='Error Analysis',
1927            help='Error analysis on single crystal data')
1928        self.ErrorAnal.Append(id=wxID_MERGEHKL,kind=wx.ITEM_NORMAL,text='Merge HKLs',
1929            help='Transform & merge HKLF data to new histogram')
1930        self.ErrorAnal.Append(id=wxID_PWD3DHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot 3D HKLs',
1931            help='Plot HKLs from single crystal data in 3D')
1932        self.ErrorAnal.Append(id=wxID_3DALLHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot all 3D HKLs',
1933            help='Plot HKLs from all single crystal data in 3D')
1934        self.ErrorAnal.Append(id=wxID_PWDCOPY,kind=wx.ITEM_NORMAL,text='Copy params',
1935            help='Copy of HKLF parameters')
1936        self.PostfillDataMenu()
1937           
1938        # PWDR / Limits
1939        self.LimitMenu = wx.MenuBar()
1940        self.PrefillDataMenu(self.LimitMenu)
1941        self.LimitEdit = wx.Menu(title='')
1942        self.LimitMenu.Append(menu=self.LimitEdit, title='Edit Limits')
1943        self.LimitEdit.Append(id=wxID_LIMITCOPY, kind=wx.ITEM_NORMAL,text='Copy',
1944            help='Copy limits to other histograms')
1945        self.LimitEdit.Append(id=wxID_ADDEXCLREGION, kind=wx.ITEM_NORMAL,text='Add exclude',
1946            help='Add excluded region - select a point on plot; drag to adjust')           
1947        self.PostfillDataMenu()
1948           
1949        # PDR / Background
1950        self.BackMenu = wx.MenuBar()
1951        self.PrefillDataMenu(self.BackMenu)
1952        self.BackEdit = wx.Menu(title='')
1953        self.BackMenu.Append(menu=self.BackEdit, title='File')
1954        self.BackEdit.Append(id=wxID_BACKCOPY, kind=wx.ITEM_NORMAL,text='Copy',
1955            help='Copy background parameters to other histograms')
1956        self.BackEdit.Append(id=wxID_BACKFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
1957            help='Copy background refinement flags to other histograms')
1958        self.BackEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks',
1959            help='Move background peaks to Peak List')
1960        self.BackEdit.Append(id=wxID_MAKEBACKRDF, kind=wx.ITEM_NORMAL,text='Plot RDF',
1961            help='Plot radial distribution from differences')
1962        self.BackFixed = wx.Menu(title='') # fixed background point menu
1963        self.BackMenu.Append(menu=self.BackFixed, title='Fixed Points')
1964        self.wxID_BackPts = {}
1965        self.wxID_BackPts['Add'] = wx.NewId() # N.B. not using wxID_ global as for other menu items
1966        self.BackFixed.Append(id=self.wxID_BackPts['Add'], kind=wx.ITEM_RADIO,text='Add',
1967            help='Add fixed background points with mouse clicks')
1968        self.wxID_BackPts['Move'] = wx.NewId() 
1969        item = self.BackFixed.Append(id=self.wxID_BackPts['Move'], kind=wx.ITEM_RADIO,text='Move',
1970            help='Move selected fixed background points with mouse drags')
1971        item.Check(True)
1972        self.wxID_BackPts['Del'] = wx.NewId()
1973        self.BackFixed.Append(id=self.wxID_BackPts['Del'], kind=wx.ITEM_RADIO,text='Delete',
1974            help='Delete fixed background points with mouse clicks')
1975        self.wxID_BackPts['Clear'] = wx.NewId() 
1976        self.BackFixed.Append(id=self.wxID_BackPts['Clear'], kind=wx.ITEM_NORMAL,text='Clear',
1977            help='Clear fixed background points')
1978        self.wxID_BackPts['Fit'] = wx.NewId() 
1979        self.BackFixed.Append(id=self.wxID_BackPts['Fit'], kind=wx.ITEM_NORMAL,text='Fit background',
1980            help='Fit background function to fixed background points')
1981        self.PostfillDataMenu()
1982           
1983        # PDR / Instrument Parameters
1984        self.InstMenu = wx.MenuBar()
1985        self.PrefillDataMenu(self.InstMenu)
1986        self.InstEdit = wx.Menu(title='')
1987        self.InstMenu.Append(menu=self.InstEdit, title='Operations')
1988        self.InstEdit.Append(help='Calibrate from indexed peaks', 
1989            id=wxID_INSTCALIB, kind=wx.ITEM_NORMAL,text='Calibrate')           
1990        self.InstEdit.Append(help='Reset instrument profile parameters to default', 
1991            id=wxID_INSTPRMRESET, kind=wx.ITEM_NORMAL,text='Reset profile')           
1992        self.InstEdit.Append(help='Load instrument profile parameters from file', 
1993            id=wxID_INSTLOAD, kind=wx.ITEM_NORMAL,text='Load profile...')           
1994        self.InstEdit.Append(help='Save instrument profile parameters to file', 
1995            id=wxID_INSTSAVE, kind=wx.ITEM_NORMAL,text='Save profile...')
1996        self.InstEdit.Append(help='Save all instrument profile parameters to one file', 
1997            id=wxID_INSTSAVEALL, kind=wx.ITEM_NORMAL,text='Save all profile...')           
1998        self.InstEdit.Append(help='Copy instrument profile parameters to other histograms', 
1999            id=wxID_INSTCOPY, kind=wx.ITEM_NORMAL,text='Copy')
2000        self.InstEdit.Append(id=wxID_INSTFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
2001            help='Copy instrument parameter refinement flags to other histograms')
2002#        self.InstEdit.Append(help='Change radiation type (Ka12 - synch)',
2003#            id=wxID_CHANGEWAVETYPE, kind=wx.ITEM_NORMAL,text='Change radiation')
2004        self.InstEdit.Append(id=wxID_INST1VAL, kind=wx.ITEM_NORMAL,text='Set one value',
2005            help='Set one instrument parameter value across multiple histograms')
2006
2007        self.PostfillDataMenu()
2008       
2009        # PDR / Sample Parameters
2010        self.SampleMenu = wx.MenuBar()
2011        self.PrefillDataMenu(self.SampleMenu)
2012        self.SampleEdit = wx.Menu(title='')
2013        self.SampleMenu.Append(menu=self.SampleEdit, title='Command')
2014        self.SetScale = self.SampleEdit.Append(id=wxID_SETSCALE, kind=wx.ITEM_NORMAL,text='Set scale',
2015            help='Set scale by matching to another histogram')
2016        self.SampleEdit.Append(id=wxID_SAMPLELOAD, kind=wx.ITEM_NORMAL,text='Load',
2017            help='Load sample parameters from file')
2018        self.SampleEdit.Append(id=wxID_SAMPLESAVE, kind=wx.ITEM_NORMAL,text='Save',
2019            help='Save sample parameters to file')
2020        self.SampleEdit.Append(id=wxID_SAMPLECOPY, kind=wx.ITEM_NORMAL,text='Copy',
2021            help='Copy refinable and most other sample parameters to other histograms')
2022        self.SampleEdit.Append(id=wxID_SAMPLECOPYSOME, kind=wx.ITEM_NORMAL,text='Copy selected...',
2023            help='Copy selected sample parameters to other histograms')
2024        self.SampleEdit.Append(id=wxID_SAMPLEFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
2025            help='Copy sample parameter refinement flags to other histograms')
2026        self.SampleEdit.Append(id=wxID_SAMPLE1VAL, kind=wx.ITEM_NORMAL,text='Set one value',
2027            help='Set one sample parameter value across multiple histograms')
2028        self.SampleEdit.Append(id=wxID_ALLSAMPLELOAD, kind=wx.ITEM_NORMAL,text='Load all',
2029            help='Load sample parmameters over multiple histograms')
2030        self.SampleEdit.Append(id=wxID_RESCALEALL, kind=wx.ITEM_NORMAL,text='Rescale all',
2031            help='Rescale all data with selected range')
2032       
2033
2034        self.PostfillDataMenu()
2035        self.SetScale.Enable(False)
2036
2037        # PDR / Peak List
2038        self.PeakMenu = wx.MenuBar()
2039        self.PrefillDataMenu(self.PeakMenu)
2040        self.PeakEdit = wx.Menu(title='')
2041        self.PeakMenu.Append(menu=self.PeakEdit, title='Peak Fitting')
2042        self.peaksSel = self.PeakEdit.Append(wx.ID_ANY,
2043            help='Set refinement flags for selected peaks',
2044            kind=wx.ITEM_NORMAL,
2045            text='Set sel. ref flags...')
2046        self.peaksAll = self.PeakEdit.Append(wx.ID_ANY,
2047            help='Set refinement flags for all peaks',
2048            kind=wx.ITEM_NORMAL,
2049            text='Set all ref flags...')
2050        self.AutoSearch = self.PeakEdit.Append(help='Automatic peak search', 
2051            id=wxID_AUTOSEARCH, kind=wx.ITEM_NORMAL,text='Auto search')
2052        self.UnDo = self.PeakEdit.Append(help='Undo last least squares refinement', 
2053            id=wxID_UNDO, kind=wx.ITEM_NORMAL,text='UnDo')
2054        self.PeakFit = self.PeakEdit.Append(id=wxID_LSQPEAKFIT, kind=wx.ITEM_NORMAL,text='Peakfit', 
2055            help='Peak fitting' )
2056        self.PFOneCycle = self.PeakEdit.Append(id=wxID_LSQONECYCLE, kind=wx.ITEM_NORMAL,text='Peakfit one cycle', 
2057            help='One cycle of Peak fitting' )
2058        self.PeakEdit.Append(id=wxID_RESETSIGGAM, kind=wx.ITEM_NORMAL, 
2059            text='Reset sig and gam',help='Reset sigma and gamma to global fit' )
2060        self.PeakCopy = self.PeakEdit.Append(help='Copy peaks to other histograms', 
2061            id=wxID_PEAKSCOPY, kind=wx.ITEM_NORMAL,text='Peak copy')
2062        self.SeqPeakFit = self.PeakEdit.Append(id=wxID_SEQPEAKFIT, kind=wx.ITEM_NORMAL,text='Seq PeakFit', 
2063            help='Sequential Peak fitting for all histograms' )
2064        self.PeakEdit.Append(id=wxID_CLEARPEAKS, kind=wx.ITEM_NORMAL,text='Clear peaks', 
2065            help='Clear the peak list' )
2066        self.movePeak = self.PeakEdit.Append(id=wx.ID_ANY,kind=wx.ITEM_NORMAL,text='Move selected peak',
2067            help='Select a peak in the table, then use this to move it with the mouse.')
2068        self.PostfillDataMenu()
2069        self.UnDo.Enable(False)
2070        self.PeakFit.Enable(False)
2071        self.PFOneCycle.Enable(False)
2072        self.AutoSearch.Enable(True)
2073       
2074        # PDR / Index Peak List
2075        self.IndPeaksMenu = wx.MenuBar()
2076        self.PrefillDataMenu(self.IndPeaksMenu)
2077        self.IndPeaksEdit = wx.Menu(title='')
2078        self.IndPeaksMenu.Append(menu=self.IndPeaksEdit,title='Operations')
2079        self.IndPeaksEdit.Append(help='Load/Reload index peaks from peak list',id=wxID_INDXRELOAD, 
2080            kind=wx.ITEM_NORMAL,text='Load/Reload')
2081        self.PostfillDataMenu()
2082       
2083        # PDR / Unit Cells List
2084        self.IndexMenu = wx.MenuBar()
2085        self.PrefillDataMenu(self.IndexMenu)
2086        self.IndexEdit = wx.Menu(title='')
2087        self.IndexMenu.Append(menu=self.IndexEdit, title='Cell Index/Refine')
2088        self.IndexPeaks = self.IndexEdit.Append(help='', id=wxID_INDEXPEAKS, kind=wx.ITEM_NORMAL,
2089            text='Index Cell')
2090        self.CopyCell = self.IndexEdit.Append( id=wxID_COPYCELL, kind=wx.ITEM_NORMAL,text='Copy Cell', 
2091            help='Copy selected unit cell from indexing to cell refinement fields')
2092        self.RefineCell = self.IndexEdit.Append( id=wxID_REFINECELL, kind=wx.ITEM_NORMAL, 
2093            text='Refine Cell',help='Refine unit cell parameters from indexed peaks')
2094        self.MakeNewPhase = self.IndexEdit.Append( id=wxID_MAKENEWPHASE, kind=wx.ITEM_NORMAL,
2095            text='Make new phase',help='Make new phase from selected unit cell')
2096        self.ExportCells = self.IndexEdit.Append( id=wxID_EXPORTCELLS, kind=wx.ITEM_NORMAL,
2097            text='Export cell list',help='Export cell list to csv file')
2098        self.PostfillDataMenu()
2099        self.IndexPeaks.Enable(False)
2100        self.CopyCell.Enable(False)
2101        self.RefineCell.Enable(False)
2102        self.MakeNewPhase.Enable(False)
2103       
2104        # PDR / Reflection Lists
2105        self.ReflMenu = wx.MenuBar()
2106        self.PrefillDataMenu(self.ReflMenu)
2107        self.ReflEdit = wx.Menu(title='')
2108        self.ReflMenu.Append(menu=self.ReflEdit, title='Reflection List')
2109        self.SelectPhase = self.ReflEdit.Append(help='Select phase for reflection list',id=wxID_SELECTPHASE, 
2110            kind=wx.ITEM_NORMAL,text='Select phase')
2111        self.ReflEdit.Append(id=wxID_PWDHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot HKLs',
2112            help='Plot HKLs from powder pattern')
2113        self.ReflEdit.Append(id=wxID_PWD3DHKLPLOT,kind=wx.ITEM_NORMAL,text='Plot 3D HKLs',
2114            help='Plot HKLs from powder pattern in 3D')
2115        self.PostfillDataMenu()
2116       
2117        # SASD / Instrument Parameters
2118        self.SASDInstMenu = wx.MenuBar()
2119        self.PrefillDataMenu(self.SASDInstMenu)
2120        self.SASDInstEdit = wx.Menu(title='')
2121        self.SASDInstMenu.Append(menu=self.SASDInstEdit, title='Operations')
2122        self.InstEdit.Append(help='Reset instrument profile parameters to default', 
2123            id=wxID_INSTPRMRESET, kind=wx.ITEM_NORMAL,text='Reset profile')
2124        self.SASDInstEdit.Append(help='Copy instrument profile parameters to other histograms', 
2125            id=wxID_INSTCOPY, kind=wx.ITEM_NORMAL,text='Copy')
2126        self.PostfillDataMenu()
2127       
2128        #SASD & REFL/ Substance editor
2129        self.SubstanceMenu = wx.MenuBar()
2130        self.PrefillDataMenu(self.SubstanceMenu)
2131        self.SubstanceEdit = wx.Menu(title='')
2132        self.SubstanceMenu.Append(menu=self.SubstanceEdit, title='Edit substance')
2133        self.SubstanceEdit.Append(id=wxID_LOADSUBSTANCE, kind=wx.ITEM_NORMAL,text='Load substance',
2134            help='Load substance from file')
2135        self.SubstanceEdit.Append(id=wxID_RELOADSUBSTANCES, kind=wx.ITEM_NORMAL,text='Reload substances',
2136            help='Reload all substances from file')
2137        self.SubstanceEdit.Append(id=wxID_ADDSUBSTANCE, kind=wx.ITEM_NORMAL,text='Add substance',
2138            help='Add new substance to list')
2139        self.SubstanceEdit.Append(id=wxID_COPYSUBSTANCE, kind=wx.ITEM_NORMAL,text='Copy substances',
2140            help='Copy substances')
2141        self.SubstanceEdit.Append(id=wxID_DELETESUBSTANCE, kind=wx.ITEM_NORMAL,text='Delete substance',
2142            help='Delete substance from list')           
2143        self.SubstanceEdit.Append(id=wxID_ELEMENTADD, kind=wx.ITEM_NORMAL,text='Add elements',
2144            help='Add elements to substance')
2145        self.SubstanceEdit.Append(id=wxID_ELEMENTDELETE, kind=wx.ITEM_NORMAL,text='Delete elements',
2146            help='Delete elements from substance')
2147        self.PostfillDataMenu()
2148       
2149        # SASD/ Models
2150        self.ModelMenu = wx.MenuBar()
2151        self.PrefillDataMenu(self.ModelMenu)
2152        self.ModelEdit = wx.Menu(title='')
2153        self.ModelMenu.Append(menu=self.ModelEdit, title='Models')
2154        self.ModelEdit.Append(id=wxID_MODELADD,kind=wx.ITEM_NORMAL,text='Add',
2155            help='Add new term to model')
2156        self.ModelEdit.Append(id=wxID_MODELFIT, kind=wx.ITEM_NORMAL,text='Fit',
2157            help='Fit model parameters to data')
2158        self.SasdUndo = self.ModelEdit.Append(id=wxID_MODELUNDO, kind=wx.ITEM_NORMAL,text='Undo',
2159            help='Undo model fit')
2160        self.SasdUndo.Enable(False)           
2161        self.ModelEdit.Append(id=wxID_MODELFITALL, kind=wx.ITEM_NORMAL,text='Sequential fit',
2162            help='Sequential fit of model parameters to all SASD data')
2163        self.ModelEdit.Append(id=wxID_MODELCOPY, kind=wx.ITEM_NORMAL,text='Copy',
2164            help='Copy model parameters to other histograms')
2165        self.ModelEdit.Append(id=wxID_MODELCOPYFLAGS, kind=wx.ITEM_NORMAL,text='Copy flags',
2166            help='Copy model refinement flags to other histograms')
2167        self.PostfillDataMenu()
2168       
2169        # REFD/ Models
2170        self.REFDModelMenu = wx.MenuBar()
2171        self.PrefillDataMenu(self.REFDModelMenu)
2172        self.REFDModelEdit = wx.Menu(title='')
2173        self.REFDModelMenu.Append(menu=self.REFDModelEdit, title='Models')
2174        self.REFDModelEdit.Append(id=wxID_MODELFIT, kind=wx.ITEM_NORMAL,text='Fit',
2175            help='Fit model parameters to data')
2176        self.REFDUndo = self.REFDModelEdit.Append(id=wxID_MODELUNDO, kind=wx.ITEM_NORMAL,text='Undo',
2177            help='Undo model fit')
2178        self.REFDUndo.Enable(False)           
2179        self.REFDModelEdit.Append(id=wxID_MODELFITALL, kind=wx.ITEM_NORMAL,text='Sequential fit',
2180            help='Sequential fit of model parameters to all REFD data')
2181        self.REFDModelEdit.Append(id=wxID_MODELCOPY, kind=wx.ITEM_NORMAL,text='Copy',
2182            help='Copy model parameters to other histograms')
2183        self.REFDModelEdit.Append(id=wxID_MODELPLOT, kind=wx.ITEM_NORMAL,text='Plot',
2184            help='Plot model SDL for selected histograms')
2185        self.PostfillDataMenu()
2186
2187        # IMG / Image Controls
2188        self.ImageMenu = wx.MenuBar()
2189        self.PrefillDataMenu(self.ImageMenu)
2190       
2191        self.ImageEdit = wx.Menu(title='')
2192        self.ImageMenu.Append(menu=self.ImageEdit, title='Calibration')
2193        self.ImageEdit.Append(help='Calibrate detector by fitting to calibrant lines', 
2194            id=wxID_IMCALIBRATE, kind=wx.ITEM_NORMAL,text='Calibrate')
2195        self.ImageEdit.Append(help='Recalibrate detector by fitting to calibrant lines', 
2196            id=wxID_IMRECALIBRATE, kind=wx.ITEM_NORMAL,text='Recalibrate')
2197        self.ImageEdit.Append(help='Recalibrate all images by fitting to calibrant lines', 
2198            id=wxID_IMRECALIBALL, kind=wx.ITEM_NORMAL,text='Recalibrate all')           
2199        self.ImageEdit.Append(help='Clear calibration data points and rings',
2200            id=wxID_IMCLEARCALIB, kind=wx.ITEM_NORMAL,text='Clear calibration')
2201       
2202        ImageIntegrate = wx.Menu(title='')
2203        self.ImageMenu.Append(menu=ImageIntegrate, title='Integration')
2204        ImageIntegrate.Append(help='Integrate selected image',id=wxID_IMINTEGRATE, 
2205            kind=wx.ITEM_NORMAL,text='Integrate')
2206        ImageIntegrate.Append(help='Integrate all images selected from list',id=wxID_INTEGRATEALL,
2207            kind=wx.ITEM_NORMAL,text='Integrate all')
2208        ImageIntegrate.Append(help='Open Auto-integration window to integrate a series of images', 
2209            id=wxID_IMAUTOINTEG, kind=wx.ITEM_NORMAL,text='Auto Integrate')
2210
2211        ImageParams = wx.Menu(title='')
2212        self.ImageMenu.Append(menu=ImageParams, title='Parms')
2213        ImageParams.Append(help='Copy image controls to other images', 
2214            id=wxID_IMCOPYCONTROLS, kind=wx.ITEM_NORMAL,text='Copy Controls')
2215        ImageParams.Append(help='Copy selected image controls to other images', 
2216            id=wxID_IMCOPYSELECTED, kind=wx.ITEM_NORMAL,text='Copy Selected')
2217        ImageParams.Append(help='Save image controls to file', 
2218            id=wxID_IMSAVECONTROLS, kind=wx.ITEM_NORMAL,text='Save Controls')
2219        ImageParams.Append(help='Save controls from selected images to file', 
2220            id=wxID_SAVESELECTEDCONTROLS, kind=wx.ITEM_NORMAL,text='Save Multiple Controls')
2221        ImageParams.Append(help='Load image controls from file',
2222            id=wxID_IMLOADCONTROLS, kind=wx.ITEM_NORMAL,text='Load Controls')
2223        ImageParams.Append(help='Transfer integration range for other detector distances', 
2224            id=wxID_IMXFERCONTROLS, kind=wx.ITEM_NORMAL,text='Xfer angles')
2225        ImageParams.Append(help='Reset all detector dist to set dist', 
2226            id=wxID_IMRESETDIST, kind=wx.ITEM_NORMAL,text='Reset dist')
2227       
2228        self.PostfillDataMenu()
2229           
2230        # IMG / Masks
2231        self.MaskMenu = wx.MenuBar()
2232        self.PrefillDataMenu(self.MaskMenu)
2233        self.MaskEdit = wx.Menu(title='')
2234        self.MaskMenu.Append(menu=self.MaskEdit, title='Operations')
2235        submenu = wx.Menu()
2236        self.MaskEdit.AppendMenu(
2237            wx.ID_ANY,'Create new', submenu,
2238            help=''
2239            )
2240        self.MaskEdit.Append(help='Copy mask to other images', 
2241            id=wxID_MASKCOPY, kind=wx.ITEM_NORMAL,text='Copy mask')
2242        self.MaskEdit.Append(help='Save mask to file', 
2243            id=wxID_MASKSAVE, kind=wx.ITEM_NORMAL,text='Save mask')
2244        self.MaskEdit.Append(help='Load mask from file; ignoring threshold', 
2245            id=wxID_MASKLOADNOT, kind=wx.ITEM_NORMAL,text='Load mask')
2246        self.MaskEdit.Append(help='Load mask from file keeping the threshold value', 
2247            id=wxID_MASKLOAD, kind=wx.ITEM_NORMAL,text='Load mask w/threshold')
2248        self.MaskEdit.Append(help='Auto search for spot masks; NB: will clear old spot masks', 
2249            id=wxID_FINDSPOTS, kind=wx.ITEM_NORMAL,text='Auto spot masks')
2250        self.MaskEdit.Append(help='Delete all spot masks', 
2251            id=wxID_DELETESPOTS, kind=wx.ITEM_NORMAL,text='Delete spot masks')       
2252        submenu.Append(help='Create an arc mask with mouse input', 
2253            id=wxID_NEWMASKARC, kind=wx.ITEM_NORMAL,text='Arc mask')
2254        submenu.Append(help='Create a frame mask with mouse input', 
2255            id=wxID_NEWMASKFRAME, kind=wx.ITEM_NORMAL,text='Frame mask')
2256        submenu.Append(help='Create a polygon mask with mouse input', 
2257            id=wxID_NEWMASKPOLY, kind=wx.ITEM_NORMAL,text='Polygon mask')
2258        submenu.Append(help='Create a ring mask with mouse input', 
2259            id=wxID_NEWMASKRING, kind=wx.ITEM_NORMAL,text='Ring mask')
2260        submenu.Append(help='Create spot masks with mouse input', 
2261            id=wxID_NEWMASKSPOT, kind=wx.ITEM_NORMAL,text='Spot mask')
2262        self.PostfillDataMenu()
2263           
2264        # IMG / Stress/Strain
2265        self.StrStaMenu = wx.MenuBar()
2266        self.PrefillDataMenu(self.StrStaMenu)
2267        self.StrStaEdit = wx.Menu(title='')
2268        self.StrStaMenu.Append(menu=self.StrStaEdit, title='Operations')
2269        self.StrStaEdit.Append(help='Append d-zero for one ring', 
2270            id=wxID_APPENDDZERO, kind=wx.ITEM_NORMAL,text='Append d-zero')
2271        self.StrStaEdit.Append(help='Fit stress/strain data', 
2272            id=wxID_STRSTAFIT, kind=wx.ITEM_NORMAL,text='Fit stress/strain')
2273        self.StrStaEdit.Append(help='Plot intensity distribution', 
2274            id=wxID_STRSTAPLOT, kind=wx.ITEM_NORMAL,text='Plot intensity distribution')
2275        self.StrStaEdit.Append(help='Save intensity distribution', 
2276            id=wxID_STRRINGSAVE, kind=wx.ITEM_NORMAL,text='Save intensity distribution')
2277        self.StrStaEdit.Append(help='Update d-zero from ave d-zero',
2278            id=wxID_UPDATEDZERO, kind=wx.ITEM_NORMAL,text='Update d-zero')       
2279        self.StrStaEdit.Append(help='Fit stress/strain data for all images', 
2280            id=wxID_STRSTAALLFIT, kind=wx.ITEM_NORMAL,text='All image fit')
2281        self.StrStaEdit.Append(help='Copy stress/strain data to other images', 
2282            id=wxID_STRSTACOPY, kind=wx.ITEM_NORMAL,text='Copy stress/strain')
2283        self.StrStaEdit.Append(help='Save stress/strain data to file', 
2284            id=wxID_STRSTASAVE, kind=wx.ITEM_NORMAL,text='Save stress/strain')
2285        self.StrStaEdit.Append(help='Load stress/strain data from file', 
2286            id=wxID_STRSTALOAD, kind=wx.ITEM_NORMAL,text='Load stress/strain')
2287        self.StrStaEdit.Append(help='Load sample data from file', 
2288            id=wxID_STRSTSAMPLE, kind=wx.ITEM_NORMAL,text='Load sample data')
2289        self.PostfillDataMenu()
2290           
2291        # PDF / PDF Controls
2292        self.PDFMenu = wx.MenuBar()
2293        self.PrefillDataMenu(self.PDFMenu)
2294        self.PDFEdit = wx.Menu(title='')
2295        self.PDFMenu.Append(menu=self.PDFEdit, title='PDF Controls')
2296        self.PDFEdit.Append(help='Add one or more elements to sample composition',id=wxID_PDFADDELEMENT, kind=wx.ITEM_NORMAL,
2297            text='Add elements')
2298        self.PDFEdit.Append(help='Delete element from sample composition',id=wxID_PDFDELELEMENT, kind=wx.ITEM_NORMAL,
2299            text='Delete element')
2300        self.PDFEdit.Append(help='Copy PDF controls', id=wxID_PDFCOPYCONTROLS, kind=wx.ITEM_NORMAL,
2301            text='Copy controls')
2302        self.PDFEdit.Append(help='Load PDF controls from file',id=wxID_PDFLOADCONTROLS, kind=wx.ITEM_NORMAL,
2303            text='Load Controls')
2304        self.PDFEdit.Append(help='Save PDF controls to file', id=wxID_PDFSAVECONTROLS, kind=wx.ITEM_NORMAL,
2305            text='Save controls')
2306        self.PDFEdit.Append(help='Compute PDF', id=wxID_PDFCOMPUTE, kind=wx.ITEM_NORMAL,
2307            text='Compute PDF')
2308        self.PDFEdit.Append(help='Compute all PDFs with or w/o optimization',
2309                            id=wxID_PDFCOMPUTEALL, kind=wx.ITEM_NORMAL,
2310            text='Compute all PDFs')
2311#        self.PDFEdit.Append(help='Optimize PDF', id=wxID_PDFOPT, kind=wx.ITEM_NORMAL,
2312#            text='Optimize corrections for r<Rmin section of current G(r)')
2313        self.PostfillDataMenu()
2314       
2315        # PDF / PDF Peaks
2316        self.PDFPksMenu = wx.MenuBar()
2317        self.PrefillDataMenu(self.PDFPksMenu)
2318        self.PDFPksEdit = wx.Menu(title='')
2319        self.PDFPksMenu.Append(menu=self.PDFPksEdit, title='PDF Peaks')
2320        self.PDFPksEdit.Append(help='Fit PDF peaks', id=wxID_PDFPKSFIT, kind=wx.ITEM_NORMAL,
2321            text='PDF peak fit')
2322        self.PDFPksEdit.Append(help='Sequential Peak fitting for all PDFs', id=wxID_PDFPKSFITALL, kind=wx.ITEM_NORMAL,
2323            text='Seq PDF peak fit')
2324        self.PDFPksEdit.Append(help='Copy PDF peaks', id=wxID_PDFCOPYPEAKS, kind=wx.ITEM_NORMAL,
2325            text='Copy peaks')
2326        self.PDFPksEdit.Append(help='Clear PDF peaks', id=wxID_CLEARPDFPEAKS, kind=wx.ITEM_NORMAL,
2327            text='Clear peaks')       
2328        self.PostfillDataMenu()
2329
2330       
2331        # Phase / General tab
2332        self.DataGeneral = wx.MenuBar()
2333        self.PrefillDataMenu(self.DataGeneral)
2334        self.DataGeneral.Append(menu=wx.Menu(title=''),title='Select tab')
2335        self.GeneralCalc = wx.Menu(title='')
2336        self.DataGeneral.Append(menu=self.GeneralCalc,title='Compute')
2337        self.GeneralCalc.Append(help='Compute Fourier map',id=wxID_FOURCALC, kind=wx.ITEM_NORMAL,
2338            text='Fourier map')
2339        self.GeneralCalc.Append(help='Search Fourier map',id=wxID_FOURSEARCH, kind=wx.ITEM_NORMAL,
2340            text='Search map')
2341        self.GeneralCalc.Append(help='Run charge flipping',id=wxID_CHARGEFLIP, kind=wx.ITEM_NORMAL,
2342            text='Charge flipping')
2343        self.GeneralCalc.Append(help='Run 4D charge flipping',id=wxID_4DCHARGEFLIP, kind=wx.ITEM_NORMAL,
2344            text='4D Charge flipping')
2345        self.GeneralCalc.Enable(wxID_4DCHARGEFLIP,False)   
2346        self.GeneralCalc.Append(help='Clear map',id=wxID_FOURCLEAR, kind=wx.ITEM_NORMAL,
2347            text='Clear map')
2348        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing',id=wxID_SINGLEMCSA, kind=wx.ITEM_NORMAL,
2349            text='MC/SA')
2350        self.GeneralCalc.Append(help='Run Monte Carlo - Simulated Annealing on multiprocessors',id=wxID_MULTIMCSA, kind=wx.ITEM_NORMAL,
2351            text='Multi MC/SA')            #currently not useful
2352        self.GeneralCalc.Append(help='Transform crystal structure',id=wxID_TRANSFORMSTRUCTURE, kind=wx.ITEM_NORMAL,
2353            text='Transform')
2354        self.PostfillDataMenu()
2355       
2356        # Phase / Data tab
2357        self.DataMenu = wx.MenuBar()
2358        self.PrefillDataMenu(self.DataMenu)
2359        self.DataMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2360        self.DataEdit = wx.Menu(title='')
2361        self.DataMenu.Append(menu=self.DataEdit, title='Edit Phase')
2362        self.DataEdit.Append(id=wxID_DATACOPY, kind=wx.ITEM_NORMAL,text='Copy data',
2363            help='Copy phase data to other histograms')
2364        self.DataEdit.Append(id=wxID_DATACOPYFLAGS, kind=wx.ITEM_NORMAL,text='Copy flags',
2365            help='Copy phase data flags to other histograms')
2366        self.DataEdit.Append(id=wxID_DATASELCOPY, kind=wx.ITEM_NORMAL,text='Copy selected data',
2367            help='Copy selected phase data to other histograms')
2368        self.DataEdit.Append(id=wxID_DATAUSE, kind=wx.ITEM_NORMAL,text='Select used data',
2369            help='Select all histograms to use')
2370        self.DataEdit.Append(id=wxID_PWDRADD, kind=wx.ITEM_NORMAL,text='Add powder histograms',
2371            help='Select new powder histograms to be used for this phase')
2372        self.DataEdit.Append(id=wxID_HKLFADD, kind=wx.ITEM_NORMAL,text='Add single crystal histograms',
2373            help='Select new single crystal histograms to be used for this phase')
2374        self.DataEdit.Append(id=wxID_DATADELETE, kind=wx.ITEM_NORMAL,text='Remove histograms',
2375            help='Remove histograms from use for this phase')
2376        self.PostfillDataMenu()
2377           
2378        # Phase / Atoms tab
2379        self.AtomsMenu = wx.MenuBar()
2380        self.PrefillDataMenu(self.AtomsMenu)
2381        self.AtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2382        self.AtomEdit = wx.Menu(title='')
2383        self.AtomCompute = wx.Menu(title='')
2384        self.AtomsMenu.Append(menu=self.AtomEdit, title='Edit Atoms')
2385        self.AtomsMenu.Append(menu=self.AtomCompute, title='Compute')
2386        submenu = wx.Menu()
2387        self.AtomEdit.AppendMenu(wx.ID_ANY, 'On selected atoms...', submenu, 
2388            help='Set/Act on selected atoms')
2389        submenu.Append(wxID_ATOMSSETSEL,
2390            help='Set refinement flags for selected atoms',
2391            kind=wx.ITEM_NORMAL,
2392            text='Refine selected')
2393        submenu.Append(id=wxID_ATOMSMODIFY, kind=wx.ITEM_NORMAL,text='Modify parameters',
2394            help='Modify parameters values for all selected atoms')
2395        submenu.Append(id=wxID_ATOMSEDITINSERT, kind=wx.ITEM_NORMAL,text='Insert atom',
2396            help='Inserts an H atom before all selected atoms')
2397        submenu.Append(id=wxID_ADDHATOM, kind=wx.ITEM_NORMAL,text='Calc H atoms',
2398            help='Insert H atoms in expected bonding positions for selected atoms')
2399        submenu.Append(id=wxID_ATOMSEDITDELETE, kind=wx.ITEM_NORMAL,text='Delete atom',
2400            help='Delete selected atoms')
2401        submenu.Append(id=wxID_ATOMSTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform atoms',
2402            help='Symmetry transform selected atoms')
2403#        self.AtomEdit.Append(id=wxID_ATOMSROTATE, kind=wx.ITEM_NORMAL,text='Rotate atoms',
2404#            help='Select atoms to rotate first')
2405        submenu.Append(wxID_ATOMSSETALL,
2406            help='Set refinement flags for all atoms',
2407            kind=wx.ITEM_NORMAL,
2408            text='Select All')
2409       
2410        self.AtomEdit.Append(id=wxID_ATOMSEDITADD, kind=wx.ITEM_NORMAL,text='Append atom',
2411            help='Appended as an H atom')
2412        self.AtomEdit.Append(id=wxID_ATOMSVIEWADD, kind=wx.ITEM_NORMAL,text='Append view point',
2413            help='Appended as an H atom')
2414        self.AtomEdit.Append(id=wxID_ATOMVIEWINSERT, kind=wx.ITEM_NORMAL,text='Insert view point',
2415            help='Select atom row to insert before; inserted as an H atom')
2416        self.AtomEdit.Append(id=wxID_UPDATEHATOM, kind=wx.ITEM_NORMAL,text='Update H atoms',
2417            help='Update H atoms in standard positions')
2418        self.AtomEdit.Append(id=wxID_ATOMMOVE, kind=wx.ITEM_NORMAL,text='Move selected atom to view point',
2419            help='Select a single atom to be moved to view point in plot')
2420        self.AtomEdit.Append(id=wxID_MAKEMOLECULE, kind=wx.ITEM_NORMAL,text='Assemble molecule',
2421            help='Select a single atom to assemble as a molecule from scattered atom positions')
2422        self.AtomEdit.Append(id=wxID_RELOADDRAWATOMS, kind=wx.ITEM_NORMAL,text='Reload draw atoms',
2423            help='Reload atom drawing list')
2424        submenu = wx.Menu()
2425        self.AtomEdit.AppendMenu(wx.ID_ANY, 'Reimport atoms', submenu, 
2426            help='Reimport atoms from file; sequence must match')
2427        # setup a cascade menu for the formats that have been defined
2428        self.ReImportMenuId = {}  # points to readers for each menu entry
2429        for reader in self.G2frame.ImportPhaseReaderlist:
2430            item = submenu.Append(
2431                wx.ID_ANY,help=reader.longFormatName,
2432                kind=wx.ITEM_NORMAL,text='reimport coordinates from '+reader.formatName+' file')
2433            self.ReImportMenuId[item.GetId()] = reader
2434        item = submenu.Append(
2435            wx.ID_ANY,
2436            help='Reimport coordinates, try to determine format from file',
2437            kind=wx.ITEM_NORMAL,
2438            text='guess format from file')
2439        self.ReImportMenuId[item.GetId()] = None # try all readers
2440
2441        self.AtomCompute.Append(id=wxID_ATOMSDISAGL, kind=wx.ITEM_NORMAL,text='Show Distances && Angles',
2442            help='Compute distances & angles for selected atoms')
2443        self.AtomCompute.Append(id=wxID_ATOMSPDISAGL, kind=wx.ITEM_NORMAL,text='Save Distances && Angles',
2444            help='Compute distances & angles for selected atoms')
2445        self.AtomCompute.ISOcalc = self.AtomCompute.Append(
2446            id=wxID_ISODISP, kind=wx.ITEM_NORMAL,
2447            text='ISODISTORT mode values',
2448            help='Compute values of ISODISTORT modes from atom parameters')
2449        self.AtomCompute.Append(id=wxID_ATOMSDENSITY, kind=wx.ITEM_NORMAL,
2450            text='Density',
2451            help='Compute density for current phase')
2452        self.PostfillDataMenu()
2453       
2454        # Phase / Imcommensurate "waves" tab
2455        self.WavesData = wx.MenuBar()
2456        self.PrefillDataMenu(self.WavesData)
2457        self.WavesData.Append(menu=wx.Menu(title=''),title='Select tab')
2458        self.WavesDataEdit = wx.Menu(title='')
2459        self.WavesData.Append(menu=self.WavesDataEdit, title='Edit Wave')
2460        self.WavesDataEdit.Append(id=wxID_WAVEVARY, kind=wx.ITEM_NORMAL,text='Global wave vary',
2461            help='Global setting of wave vary flags')
2462        self.PostfillDataMenu()
2463       
2464        # Phase / Layer tab
2465        self.LayerData = wx.MenuBar()
2466        self.PrefillDataMenu(self.LayerData)
2467        self.LayerData.Append(menu=wx.Menu(title=''),title='Select tab')
2468        self.LayerDataEdit = wx.Menu(title='')
2469        self.LayerData.Append(menu=self.LayerDataEdit, title='Operations')
2470        self.LayerDataEdit.Append(id=wxID_LOADDIFFAX, kind=wx.ITEM_NORMAL,text='Load from DIFFaX file',
2471            help='Load layer info from DIFFaX file')
2472        self.LayerDataEdit.Append(id=wxID_COPYPHASE, kind=wx.ITEM_NORMAL,text='Copy phase cell',
2473            help='Copy phase cell from another project')
2474        self.LayerDataEdit.Append(id=wxID_LAYERSIMULATE, kind=wx.ITEM_NORMAL,text='Simulate pattern',
2475            help='Simulate diffraction pattern from layer stacking')
2476        self.LayerDataEdit.Append(id=wxID_LAYERSFIT, kind=wx.ITEM_NORMAL,text='Fit pattern',
2477            help='Fit diffraction pattern with layer stacking model')
2478        self.LayerDataEdit.Append(id=wxID_SEQUENCESIMULATE, kind=wx.ITEM_NORMAL,text='Sequence simulations',
2479            help='Sequence simulation changing one parameter')
2480        self.PostfillDataMenu()
2481                 
2482        # Phase / Draw Options tab
2483        self.DataDrawOptions = wx.MenuBar()
2484        self.PrefillDataMenu(self.DataDrawOptions)
2485        self.DataDrawOptions.Append(menu=wx.Menu(title=''),title='Select tab')
2486        self.PostfillDataMenu()
2487       
2488        # Phase / Draw Atoms tab
2489        self.DrawAtomsMenu = wx.MenuBar()
2490        self.PrefillDataMenu(self.DrawAtomsMenu)
2491        self.DrawAtomsMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2492        self.DrawAtomEdit = wx.Menu(title='')
2493        self.DrawAtomCompute = wx.Menu(title='')
2494        self.DrawAtomRestraint = wx.Menu(title='')
2495        self.DrawAtomRigidBody = wx.Menu(title='')
2496        self.DrawAtomsMenu.Append(menu=self.DrawAtomEdit, title='Edit Figure')
2497        self.DrawAtomsMenu.Append(menu=self.DrawAtomCompute,title='Compute')
2498        self.DrawAtomsMenu.Append(menu=self.DrawAtomRestraint, title='Restraints')
2499        self.DrawAtomsMenu.Append(menu=self.DrawAtomRigidBody, title='Rigid body')
2500        self.DrawAtomEdit.Append(id=wxID_DRAWATOMSTYLE, kind=wx.ITEM_NORMAL,text='Atom style',
2501            help='Select atoms first')
2502        self.DrawAtomEdit.Append(id=wxID_DRAWATOMLABEL, kind=wx.ITEM_NORMAL,text='Atom label',
2503            help='Select atoms first')
2504        self.DrawAtomEdit.Append(id=wxID_DRAWATOMCOLOR, kind=wx.ITEM_NORMAL,text='Atom color',
2505            help='Select atoms first')
2506        self.DrawAtomEdit.Append(id=wxID_DRAWATOMRESETCOLOR, kind=wx.ITEM_NORMAL,text='Reset atom colors',
2507            help='Resets all atom colors to defaults')
2508        self.DrawAtomEdit.Append(id=wxID_DRWAEDITRADII, kind=wx.ITEM_NORMAL,text='Edit atom radii',
2509            help='Edit drawing atom radii')
2510        self.DrawAtomEdit.Append(id=wxID_DRAWVIEWPOINT, kind=wx.ITEM_NORMAL,text='View point',
2511            help='View point is 1st atom selected')
2512        self.DrawAtomEdit.Append(id=wxID_DRAWADDEQUIV, kind=wx.ITEM_NORMAL,text='Add atoms',
2513            help='Add symmetry & cell equivalents to drawing set from selected atoms')
2514        self.DrawAtomEdit.Append(id=wxID_DRAWADDSPHERE, kind=wx.ITEM_NORMAL,text='Add sphere of atoms',
2515            help='Add atoms within sphere of enclosure')
2516        self.DrawAtomEdit.Append(id=wxID_DRAWTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform draw atoms',
2517            help='Transform selected atoms by symmetry & cell translations')
2518        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCOORD, kind=wx.ITEM_NORMAL,text='Fill CN-sphere',
2519            help='Fill coordination sphere for selected atoms')           
2520        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCELL, kind=wx.ITEM_NORMAL,text='Fill unit cell',
2521            help='Fill unit cell with selected atoms')
2522        self.DrawAtomEdit.Append(id=wxID_DRAWDELETE, kind=wx.ITEM_NORMAL,text='Delete atoms',
2523            help='Delete atoms from drawing set')
2524        self.DrawAtomCompute.Append(id=wxID_DRAWDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2525            help='Compute distance of selected atoms from view point')   
2526        self.DrawAtomCompute.Append(id=wxID_DRAWDISAGLTOR, kind=wx.ITEM_NORMAL,text='Dist. Ang. Tors.',
2527            help='Compute distance, angle or torsion for 2-4 selected atoms')   
2528        self.DrawAtomCompute.Append(id=wxID_DRAWPLANE, kind=wx.ITEM_NORMAL,text='Best plane',
2529            help='Compute best plane for 4+ selected atoms')   
2530        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRBOND, kind=wx.ITEM_NORMAL,text='Add bond restraint',
2531            help='Add bond restraint for selected atoms (2)')
2532        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRANGLE, kind=wx.ITEM_NORMAL,text='Add angle restraint',
2533            help='Add angle restraint for selected atoms (3: one end 1st)')
2534        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRPLANE, kind=wx.ITEM_NORMAL,text='Add plane restraint',
2535            help='Add plane restraint for selected atoms (4+)')
2536        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRCHIRAL, kind=wx.ITEM_NORMAL,text='Add chiral restraint',
2537            help='Add chiral restraint for selected atoms (4: center atom 1st)')
2538        self.DrawAtomRigidBody.Append(id=wxID_DRAWDEFINERB, kind=wx.ITEM_NORMAL,text='Define rigid body',
2539            help='Define rigid body with selected atoms')
2540        self.PostfillDataMenu()
2541
2542        # Phase / MCSA tab
2543        self.MCSAMenu = wx.MenuBar()
2544        self.PrefillDataMenu(self.MCSAMenu)
2545        self.MCSAMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2546        self.MCSAEdit = wx.Menu(title='')
2547        self.MCSAMenu.Append(menu=self.MCSAEdit, title='MC/SA')
2548        self.MCSAEdit.Append(id=wxID_ADDMCSAATOM, kind=wx.ITEM_NORMAL,text='Add atom', 
2549            help='Add single atom to MC/SA model')
2550        self.MCSAEdit.Append(id=wxID_ADDMCSARB, kind=wx.ITEM_NORMAL,text='Add rigid body', 
2551            help='Add rigid body to MC/SA model' )
2552        self.MCSAEdit.Append(id=wxID_CLEARMCSARB, kind=wx.ITEM_NORMAL,text='Clear rigid bodies', 
2553            help='Clear all atoms & rigid bodies from MC/SA model' )
2554        self.MCSAEdit.Append(id=wxID_MOVEMCSA, kind=wx.ITEM_NORMAL,text='Move MC/SA solution', 
2555            help='Move MC/SA solution to atom list' )
2556        self.MCSAEdit.Append(id=wxID_MCSACLEARRESULTS, kind=wx.ITEM_NORMAL,text='Clear results', 
2557            help='Clear table of MC/SA results' )
2558        self.PostfillDataMenu()
2559           
2560        # Phase / Texture tab
2561        self.TextureMenu = wx.MenuBar()
2562        self.PrefillDataMenu(self.TextureMenu)
2563        self.TextureMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2564        self.TextureEdit = wx.Menu(title='')
2565        self.TextureMenu.Append(menu=self.TextureEdit, title='Texture')
2566        self.TextureEdit.Append(id=wxID_REFINETEXTURE, kind=wx.ITEM_NORMAL,text='Refine texture', 
2567            help='Refine the texture coefficients from sequential results')
2568#        self.TextureEdit.Append(id=wxID_CLEARTEXTURE, kind=wx.ITEM_NORMAL,text='Clear texture',
2569#            help='Clear the texture coefficients' )
2570        self.PostfillDataMenu()
2571           
2572        # Phase / Pawley tab
2573        self.PawleyMenu = wx.MenuBar()
2574        self.PrefillDataMenu(self.PawleyMenu)
2575        self.PawleyMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2576        self.PawleyEdit = wx.Menu(title='')
2577        self.PawleyMenu.Append(menu=self.PawleyEdit,title='Operations')
2578        self.PawleyEdit.Append(id=wxID_PAWLEYSET, kind=wx.ITEM_NORMAL,text='Pawley settings',
2579            help='Change Pawley refinement settings')
2580        self.PawleyEdit.Append(id=wxID_PAWLEYLOAD, kind=wx.ITEM_NORMAL,text='Pawley create',
2581            help='Initialize Pawley reflection list')
2582        self.PawleyEdit.Append(id=wxID_PAWLEYESTIMATE, kind=wx.ITEM_NORMAL,text='Pawley estimate',
2583            help='Estimate initial Pawley intensities')
2584        self.PawleyEdit.Append(id=wxID_PAWLEYUPDATE, kind=wx.ITEM_NORMAL,text='Pawley update',
2585            help='Update negative Pawley intensities with -0.5*Fobs and turn off refinement')
2586        self.PawleyEdit.Append(id=wxID_PAWLEYSELALL, kind=wx.ITEM_NORMAL,text='Select all',
2587            help='Select all reflections to be refined')
2588        self.PawleyEdit.Append(id=wxID_PAWLEYSELNONE, kind=wx.ITEM_NORMAL,text='Select none',
2589            help='Set flag for all reflections for no refinement')
2590        self.PawleyEdit.Append(id=wxID_PAWLEYSELTOGGLE, kind=wx.ITEM_NORMAL,text='Toggle Selection',
2591            help='Toggle Selection flag for all reflections to opposite setting')
2592        self.PostfillDataMenu()
2593           
2594        # Phase / Map peaks tab
2595        self.MapPeaksMenu = wx.MenuBar()
2596        self.PrefillDataMenu(self.MapPeaksMenu)
2597        self.MapPeaksMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2598        self.MapPeaksEdit = wx.Menu(title='')
2599        self.MapPeaksMenu.Append(menu=self.MapPeaksEdit, title='Map peaks')
2600        self.MapPeaksEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks', 
2601            help='Move selected peaks to atom list')
2602        self.MapPeaksEdit.Append(id=wxID_PEAKSVIEWPT, kind=wx.ITEM_NORMAL,text='View point',
2603            help='View point is 1st peak selected')
2604        self.MapPeaksEdit.Append(id=wxID_PEAKSDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
2605            help='Compute distance of selected peaks from view point')   
2606        self.MapPeaksEdit.Append(id=wxID_SHOWBONDS, kind=wx.ITEM_NORMAL,text='Hide bonds',
2607            help='Hide or show bonds between peak positions')   
2608        self.MapPeaksEdit.Append(id=wxID_PEAKSDA, kind=wx.ITEM_NORMAL,text='Calc dist/ang', 
2609            help='Calculate distance or angle for selection')
2610        self.MapPeaksEdit.Append(id=wxID_FINDEQVPEAKS, kind=wx.ITEM_NORMAL,text='Equivalent peaks', 
2611            help='Find equivalent peaks')
2612        self.MapPeaksEdit.Append(id=wxID_PEAKSUNIQUE, kind=wx.ITEM_NORMAL,text='Unique peaks', 
2613            help='Select unique set')
2614        self.MapPeaksEdit.Append(id=wxID_PEAKSDELETE, kind=wx.ITEM_NORMAL,text='Delete peaks', 
2615            help='Delete selected peaks')
2616        self.MapPeaksEdit.Append(id=wxID_PEAKSCLEAR, kind=wx.ITEM_NORMAL,text='Clear peaks', 
2617            help='Clear the map peak list')
2618        self.PostfillDataMenu()
2619
2620        # Phase / Rigid bodies tab
2621        self.RigidBodiesMenu = wx.MenuBar()
2622        self.PrefillDataMenu(self.RigidBodiesMenu)
2623        self.RigidBodiesMenu.Append(menu=wx.Menu(title=''),title='Select tab')
2624        self.RigidBodiesEdit = wx.Menu(title='')
2625        self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit Body')
2626        self.RigidBodiesEdit.Append(id=wxID_ASSIGNATMS2RB, kind=wx.ITEM_NORMAL,text='Assign atoms to rigid body',
2627            help='Select & position rigid body in structure of existing atoms')
2628        self.RigidBodiesEdit.Append(id=wxID_AUTOFINDRESRB, kind=wx.ITEM_NORMAL,text='Auto find residues',
2629            help='Auto find of residue RBs in macromolecule')
2630        self.RigidBodiesEdit.Append(id=wxID_COPYRBPARMS, kind=wx.ITEM_NORMAL,text='Copy rigid body parms',
2631            help='Copy rigid body location & TLS parameters')
2632        self.RigidBodiesEdit.Append(id=wxID_GLOBALTHERM, kind=wx.ITEM_NORMAL,text='Global thermal motion',
2633            help='Global setting of residue thermal motion models')
2634        self.RigidBodiesEdit.Append(id=wxID_GLOBALRESREFINE, kind=wx.ITEM_NORMAL,text='Global residue refine',
2635            help='Global setting of residue RB refinement flags')
2636        self.RigidBodiesEdit.Append(id=wxID_RBREMOVEALL, kind=wx.ITEM_NORMAL,text='Remove all rigid bodies',
2637            help='Remove all rigid body assignment for atoms')
2638        self.PostfillDataMenu()
2639    # end of GSAS-II menu definitions
2640       
2641    def _init_ctrls(self, parent,name=None,size=None,pos=None):
2642        wx.Frame.__init__(
2643            self,parent=parent,
2644            #style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT ,
2645            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX,
2646            size=size,pos=pos,title='GSAS-II data display')
2647        self._init_menus()
2648        if name:
2649            self.SetLabel(name)
2650        self.Show()
2651       
2652    def __init__(self,parent,frame,data=None,name=None, size=None,pos=None):
2653        self.G2frame = frame
2654        self._init_ctrls(parent,name,size,pos)
2655        self.data = data
2656        clientSize = wx.ClientDisplayRect()
2657        Size = self.GetSize()
2658        xPos = clientSize[2]-Size[0]
2659        self.SetPosition(wx.Point(xPos,clientSize[1]+250))
2660        self.AtomGrid = []
2661        self.selectedRow = 0
2662        self.lastSize = Size       
2663        self.manualPhaseSize = None
2664        self.userReSize = False
2665        wx.Frame.Bind(self,wx.EVT_SIZE,self.OnReSize)
2666           
2667    def OnReSize(self,event):
2668        '''Keep track of size changes for Phase windows
2669        '''
2670        id = self.G2frame.PatternTree.GetSelection()
2671        try:
2672            parent = self.G2frame.PatternTree.GetItemParent(id)
2673        except:         #avoid bad tree item on start via gpx file selection
2674            parent = 0
2675        if self.userReSize and parent and self.G2frame.PatternTree.GetItemText(parent) == "Phases":
2676            newSize = event.EventObject.GetSize()
2677            if newSize[1] < 200: return             #avois spurious small window after Refine
2678            if self.lastSize == newSize:
2679#                if GSASIIpath.GetConfigValue('debug'):
2680#                    print 'no save size=',self.lastSize
2681                return
2682            self.manualPhaseSize = newSize
2683            self.lastSize = event.EventObject.GetSize()
2684#            if GSASIIpath.GetConfigValue('debug'):
2685#                print 'Saving Phase size=',self.manualPhaseSize
2686                #HowDidIgetHere()
2687        event.Skip()
2688
2689    def SendSizeEvent(self):
2690        '''Prevent SendSizeEvent from overriding the saved size
2691        '''
2692        self.userReSize = False
2693        wx.Frame.SendSizeEvent(self)
2694        self.userReSize = True
2695       
2696    def setSizePosLeft(self,Size):
2697        '''Place the dataFrame window so that the upper left-hand corner remains in the same place;
2698        The size is dictated by parameter Width, unless overridden by a previous Phase window resize
2699        '''
2700        self.userReSize = False
2701#        if GSASIIpath.GetConfigValue('debug'):
2702#            print 'setSizePosLeft size',Size,self.lastSize
2703        Size = list(Size)
2704        id = self.G2frame.PatternTree.GetSelection()
2705        try:            #avoid bad tree item on start via gpx file selection
2706            pid = self.G2frame.PatternTree.GetItemParent(id)
2707        except:
2708            pid = 0
2709        if pid:
2710            parent = self.G2frame.PatternTree.GetItemText(pid)
2711            # is this a phase window and has a previous window has been resized?
2712            if self.manualPhaseSize and parent == "Phases":
2713                Size = list(self.manualPhaseSize)
2714        Pos = self.GetPosition()
2715        clientSize = wx.ClientDisplayRect()     #display window size (e.g. 1304x768)
2716        Size[1] = min(Size[1],clientSize[2]-300)
2717        Size[0] = max(Size[0],300)
2718#        print 'current position/width:',Pos,Width
2719        self.SetSize(Size)
2720        Size[1] += 1        #kluge to ensure scrollbar settings & window properly displayed
2721        self.SetSize(Size)
2722        Pos[0] += self.lastSize[0]-Size[0]
2723        offSet = 0
2724        if Pos[0] < clientSize[2]:
2725            offSet = Pos[0]+Size[0]-clientSize[2]
2726        if offSet > 0:
2727            Pos[0] -= offSet
2728        self.SetPosition(wx.Point(Pos[0],Pos[1]))
2729        self.lastSize = Size
2730        self.userReSize = True
2731       
2732    def Clear(self):
2733        self.ClearBackground()
2734        self.DestroyChildren()
2735                   
2736
2737################################################################################
2738#####  Notebook Tree Item editor
2739################################################################################                 
2740def UpdateNotebook(G2frame,data):
2741    '''Called when the data tree notebook entry is selected. Allows for
2742    editing of the text in that tree entry
2743    '''
2744    def OnNoteBook(event):
2745        event.Skip()
2746        data = G2frame.dataDisplay.GetValue().split('\n')
2747        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Notebook'),data)
2748        if 'nt' not in os.name:
2749            G2frame.dataDisplay.AppendText('\n')
2750                   
2751    if G2frame.dataDisplay:
2752        G2frame.dataDisplay.Destroy()
2753    G2frame.dataFrame.SetLabel('Notebook')
2754    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2755        style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
2756    G2frame.dataDisplay.Bind(wx.EVT_TEXT_ENTER,OnNoteBook)
2757    G2frame.dataDisplay.Bind(wx.EVT_KILL_FOCUS,OnNoteBook)
2758    for line in data:
2759        G2frame.dataDisplay.AppendText(line+"\n")
2760    G2frame.dataDisplay.AppendText('Notebook entry @ '+time.ctime()+"\n")
2761    G2frame.dataFrame.setSizePosLeft([400,250])
2762           
2763################################################################################
2764#####  Controls Tree Item editor
2765################################################################################           
2766def UpdateControls(G2frame,data):
2767    '''Edit overall GSAS-II controls in main Controls data tree entry
2768    '''
2769    #patch
2770    if 'deriv type' not in data:
2771        data = {}
2772        data['deriv type'] = 'analytic Hessian'
2773        data['min dM/M'] = 0.0001
2774        data['shift factor'] = 1.
2775        data['max cyc'] = 3       
2776        data['F**2'] = False
2777    if 'shift factor' not in data:
2778        data['shift factor'] = 1.
2779    if 'max cyc' not in data:
2780        data['max cyc'] = 3
2781    if 'F**2' not in data:
2782        data['F**2'] = False
2783    if 'Author' not in data:
2784        data['Author'] = 'no name'
2785    if 'FreePrm1' not in data:
2786        data['FreePrm1'] = 'Sample humidity (%)'
2787    if 'FreePrm2' not in data:
2788        data['FreePrm2'] = 'Sample voltage (V)'
2789    if 'FreePrm3' not in data:
2790        data['FreePrm3'] = 'Applied load (MN)'
2791    if 'Copy2Next' not in data:
2792        data['Copy2Next'] = False
2793    if 'Reverse Seq' not in data:
2794        data['Reverse Seq'] = False
2795    if 'UsrReject' not in data:
2796        data['UsrReject'] = {'minF/sig':0,'MinExt':0.01,'MaxDF/F':20.,'MaxD':500.,'MinD':0.05}
2797    if 'HatomFix' not in data:
2798        data['HatomFix'] = False
2799    if 'Marquardt' not in data:
2800        data['Marquardt'] = -3
2801   
2802    #end patch
2803
2804    def SeqSizer():
2805       
2806        def OnSelectData(event):
2807            choices = GetPatternTreeDataNames(G2frame,['PWDR','HKLF',])
2808            sel = []
2809            try:
2810                if 'Seq Data' in data:
2811                    for item in data['Seq Data']:
2812                        sel.append(choices.index(item))
2813                    sel = [choices.index(item) for item in data['Seq Data']]
2814            except ValueError:  #data changed somehow - start fresh
2815                sel = []
2816            dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential refinement',
2817                'Select dataset to include',choices)
2818            dlg.SetSelections(sel)
2819            names = []
2820            if dlg.ShowModal() == wx.ID_OK:
2821                for sel in dlg.GetSelections():
2822                    names.append(choices[sel])
2823                data['Seq Data'] = names               
2824                G2frame.EnableSeqRefineMenu()
2825            dlg.Destroy()
2826            wx.CallAfter(UpdateControls,G2frame,data)
2827           
2828        def OnReverse(event):
2829            data['Reverse Seq'] = reverseSel.GetValue()
2830           
2831        def OnCopySel(event):
2832            data['Copy2Next'] = copySel.GetValue() 
2833                   
2834        seqSizer = wx.BoxSizer(wx.VERTICAL)
2835        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
2836        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Sequential Refinement: '),0,WACV)
2837        selSeqData = wx.Button(G2frame.dataDisplay,-1,label=' Select data')
2838        selSeqData.Bind(wx.EVT_BUTTON,OnSelectData)
2839        dataSizer.Add(selSeqData,0,WACV)
2840        SeqData = data.get('Seq Data',[])
2841        if not SeqData:
2842            lbl = ' (no data selected)'
2843        else:
2844            lbl = ' ('+str(len(SeqData))+' dataset(s) selected)'
2845
2846        dataSizer.Add(wx.StaticText(G2frame.dataDisplay,label=lbl),0,WACV)
2847        seqSizer.Add(dataSizer,0)
2848        if SeqData:
2849            selSizer = wx.BoxSizer(wx.HORIZONTAL)
2850            reverseSel = wx.CheckBox(G2frame.dataDisplay,-1,label=' Reverse order?')
2851            reverseSel.Bind(wx.EVT_CHECKBOX,OnReverse)
2852            reverseSel.SetValue(data['Reverse Seq'])
2853            selSizer.Add(reverseSel,0,WACV)
2854            copySel =  wx.CheckBox(G2frame.dataDisplay,-1,label=' Copy results to next histogram?')
2855            copySel.Bind(wx.EVT_CHECKBOX,OnCopySel)
2856            copySel.SetValue(data['Copy2Next'])
2857            selSizer.Add(copySel,0,WACV)
2858            seqSizer.Add(selSizer,0)
2859        return seqSizer
2860       
2861    def LSSizer():       
2862       
2863        def OnDerivType(event):
2864            data['deriv type'] = derivSel.GetValue()
2865            derivSel.SetValue(data['deriv type'])
2866            wx.CallAfter(UpdateControls,G2frame,data)
2867           
2868#        def OnConvergence(event):
2869#            event.Skip()
2870#            try:
2871#                value = max(1.e-9,min(1.0,float(Cnvrg.GetValue())))
2872#            except ValueError:
2873#                value = 0.0001
2874#            data['min dM/M'] = value
2875#            Cnvrg.SetValue('%.2g'%(value))
2876#           
2877        def OnMaxCycles(event):
2878            data['max cyc'] = int(maxCyc.GetValue())
2879            maxCyc.SetValue(str(data['max cyc']))
2880           
2881        def OnMarqLam(event):
2882            data['Marquardt'] = int(marqLam.GetValue())
2883            marqLam.SetValue(str(data['Marquardt']))
2884                       
2885        def OnFactor(event):
2886            event.Skip()
2887            try:
2888                value = min(max(float(Factr.GetValue()),0.00001),100.)
2889            except ValueError:
2890                value = 1.0
2891            data['shift factor'] = value
2892            Factr.SetValue('%.5f'%(value))
2893           
2894        def OnFsqRef(event):
2895            data['F**2'] = fsqRef.GetValue()
2896           
2897#        def OnHatomFix(event):
2898#            data['HatomFix'] = Hfix.GetValue()
2899       
2900#        def OnUsrRej(event):
2901#            event.Skip()
2902#            Obj = event.GetEventObject()
2903#            item,limits = Indx[Obj]
2904#            try:
2905#                value = min(max(float(Obj.GetValue()),limits[0]),limits[1])
2906#            except ValueError:
2907#                value = data['UsrReject'][item]
2908#            data['UsrReject'][item] = value
2909#            Obj.SetValue('%.2f'%(value))
2910#
2911        LSSizer = wx.FlexGridSizer(cols=4,vgap=5,hgap=5)
2912        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement derivatives: '),0,WACV)
2913        Choice=['analytic Jacobian','numeric','analytic Hessian']
2914        derivSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['deriv type'],choices=Choice,
2915            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2916        derivSel.SetValue(data['deriv type'])
2917        derivSel.Bind(wx.EVT_COMBOBOX, OnDerivType)
2918           
2919        LSSizer.Add(derivSel,0,WACV)
2920        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min delta-M/M: '),0,WACV)
2921        Cnvrg = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'min dM/M',nDig=(10,2,'g'),min=1.e-9,max=1.,typeHint=float)
2922#        Cnvrg = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2g'%(data['min dM/M']),style=wx.TE_PROCESS_ENTER)
2923#        Cnvrg.Bind(wx.EVT_TEXT_ENTER,OnConvergence)
2924#        Cnvrg.Bind(wx.EVT_KILL_FOCUS,OnConvergence)
2925        LSSizer.Add(Cnvrg,0,WACV)
2926#        Indx = {}
2927        if 'Hessian' in data['deriv type']:
2928            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max cycles: '),0,WACV)
2929            Choice = ['0','1','2','3','5','10','15','20']
2930            maxCyc = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['max cyc']),choices=Choice,
2931                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2932#            maxCyc.SetValue(str(data['max cyc']))
2933            maxCyc.Bind(wx.EVT_COMBOBOX, OnMaxCycles)
2934            LSSizer.Add(maxCyc,0,WACV)
2935            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial lambda = 10**'),0,WACV)
2936            MarqChoice = ['-3','-2','-1','0','1','2','3','4']
2937            marqLam = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['Marquardt']),choices=MarqChoice,
2938                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2939            marqLam.Bind(wx.EVT_COMBOBOX,OnMarqLam)
2940            LSSizer.Add(marqLam,0,WACV)
2941        else:
2942            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial shift factor: '),0,WACV)
2943            Factr = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'shift factor',nDig=(10,5),min=1.e-5,max=100.,typeHint=float)
2944#            Factr = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.5f'%(data['shift factor']),style=wx.TE_PROCESS_ENTER)
2945#            Factr.Bind(wx.EVT_TEXT_ENTER,OnFactor)
2946#            Factr.Bind(wx.EVT_KILL_FOCUS,OnFactor)
2947            LSSizer.Add(Factr,0,WACV)
2948        if G2frame.Sngl:
2949            userReject = data['UsrReject']
2950            usrRej = {'minF/sig':[' Min obs/sig (0-5): ',[0,5], ],'MinExt':[' Min extinct. (0-.9): ',[0,.9],],
2951                'MaxDF/F':[' Max delt-F/sig (3-1000): ',[3.,1000.],],'MaxD':[' Max d-spacing (3-500): ',[3,500],],
2952                'MinD':[' Min d-spacing (0.1-2.0): ',[0.1,2.0],]}
2953
2954            fsqRef = wx.CheckBox(G2frame.dataDisplay,-1,label='Refine HKLF as F^2? ')
2955            fsqRef.SetValue(data['F**2'])
2956            fsqRef.Bind(wx.EVT_CHECKBOX,OnFsqRef)
2957            LSSizer.Add(fsqRef,0,WACV)
2958            LSSizer.Add((1,0),)
2959            for item in usrRej:
2960                LSSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=usrRej[item][0]),0,WACV)
2961                usrrej = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,userReject,item,nDig=(10,2),
2962                    min=usrRej[item][1][0],max=usrRej[item][1][1],typeHint=float)
2963#                usrrej = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(userReject[item]),style=wx.TE_PROCESS_ENTER)
2964#                Indx[usrrej] = [item,usrRej[item][1]]
2965#                usrrej.Bind(wx.EVT_TEXT_ENTER,OnUsrRej)
2966#                usrrej.Bind(wx.EVT_KILL_FOCUS,OnUsrRej)
2967                LSSizer.Add(usrrej,0,WACV)
2968#        Hfix = wx.CheckBox(G2frame.dataDisplay,-1,label='Regularize H atoms? ')
2969#        Hfix.SetValue(data['HatomFix'])
2970#        Hfix.Bind(wx.EVT_CHECKBOX,OnHatomFix)
2971#        LSSizer.Add(Hfix,0,WACV)   #for now
2972        return LSSizer
2973       
2974    def AuthSizer():
2975
2976        def OnAuthor(event):
2977            event.Skip()
2978            data['Author'] = auth.GetValue()
2979
2980        Author = data['Author']
2981        authSizer = wx.BoxSizer(wx.HORIZONTAL)
2982        authSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' CIF Author (last, first):'),0,WACV)
2983        auth = wx.TextCtrl(G2frame.dataDisplay,-1,value=Author,style=wx.TE_PROCESS_ENTER)
2984        auth.Bind(wx.EVT_TEXT_ENTER,OnAuthor)
2985        auth.Bind(wx.EVT_KILL_FOCUS,OnAuthor)
2986        authSizer.Add(auth,0,WACV)
2987        return authSizer
2988       
2989       
2990    if G2frame.dataDisplay:
2991        G2frame.dataDisplay.Destroy()
2992    if not G2frame.dataFrame.GetStatusBar():
2993        Status = G2frame.dataFrame.CreateStatusBar()
2994        Status.SetStatusText('')
2995    G2frame.dataFrame.SetLabel('Controls')
2996    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2997    SetDataMenuBar(G2frame,G2frame.dataFrame.ControlsMenu)
2998    mainSizer = wx.BoxSizer(wx.VERTICAL)
2999    mainSizer.Add((5,5),0)
3000    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement Controls:'),0,WACV)   
3001    mainSizer.Add(LSSizer())
3002    mainSizer.Add((5,5),0)
3003    mainSizer.Add(SeqSizer())
3004    mainSizer.Add((5,5),0)
3005    mainSizer.Add(AuthSizer())
3006    mainSizer.Add((5,5),0)
3007       
3008    mainSizer.Layout()   
3009    G2frame.dataDisplay.SetSizer(mainSizer)
3010    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
3011     
3012################################################################################
3013#####  Comments
3014################################################################################           
3015       
3016def UpdateComments(G2frame,data):                   
3017
3018    if G2frame.dataDisplay:
3019        G2frame.dataDisplay.Destroy()
3020    G2frame.dataFrame.SetLabel('Comments')
3021    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
3022        style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP)
3023    for line in data:
3024        if '\n' not in line:
3025            G2frame.dataDisplay.AppendText(line+'\n')
3026        else:
3027            G2frame.dataDisplay.AppendText(line)
3028    G2frame.dataFrame.setSizePosLeft([400,250])
3029           
3030################################################################################
3031#####  Display of Sequential Results
3032################################################################################           
3033       
3034def UpdateSeqResults(G2frame,data,prevSize=None):
3035    """
3036    Called when the Sequential Results data tree entry is selected
3037    to show results from a sequential refinement.
3038   
3039    :param wx.Frame G2frame: main GSAS-II data tree windows
3040
3041    :param dict data: a dictionary containing the following items: 
3042
3043            * 'histNames' - list of histogram names in order as processed by Sequential Refinement
3044            * 'varyList' - list of variables - identical over all refinements in sequence
3045              note that this is the original list of variables, prior to processing
3046              constraints.
3047            * 'variableLabels' -- a dict of labels to be applied to each parameter
3048              (this is created as an empty dict if not present in data).
3049            * keyed by histName - dictionaries for all data sets processed, which contains:
3050
3051              * 'variables'- result[0] from leastsq call
3052              * 'varyList' - list of variables passed to leastsq call (not same as above)
3053              * 'sig' - esds for variables
3054              * 'covMatrix' - covariance matrix from individual refinement
3055              * 'title' - histogram name; same as dict item name
3056              * 'newAtomDict' - new atom parameters after shifts applied
3057              * 'newCellDict' - refined cell parameters after shifts to A0-A5 from Dij terms applied'
3058    """
3059    def GetSampleParms():
3060        '''Make a dictionary of the sample parameters that are not the same over the
3061        refinement series. Controls here is local
3062        '''
3063        if 'IMG' in histNames[0]:
3064            sampleParmDict = {'Sample load':[],}
3065        else:
3066            sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[],
3067                'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[],
3068                'Chi':[],'Phi':[],'Azimuth':[],}
3069        Controls = G2frame.PatternTree.GetItemPyData(
3070            GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
3071        sampleParm = {}
3072        for name in histNames:
3073            if 'IMG' in name:
3074                if name not in data:
3075                    continue
3076                for item in sampleParmDict:
3077                    sampleParmDict[item].append(data[name]['parmDict'].get(item,0))
3078            else:
3079                if 'PDF' in name:
3080                    name = 'PWDR' + name[4:]
3081                Id = GetPatternTreeItemId(G2frame,G2frame.root,name)
3082                if Id:
3083                    sampleData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
3084                    for item in sampleParmDict:
3085                        sampleParmDict[item].append(sampleData.get(item,0))
3086        for item in sampleParmDict:
3087            if sampleParmDict[item]:
3088                frstValue = sampleParmDict[item][0]
3089                if np.any(np.array(sampleParmDict[item])-frstValue):
3090                    if item.startswith('FreePrm'):
3091                        sampleParm[Controls[item]] = sampleParmDict[item]
3092                    else:
3093                        sampleParm[item] = sampleParmDict[item]
3094        return sampleParm
3095
3096    def GetColumnInfo(col):
3097        '''returns column label, lists of values and errors (or None) for each column in the table
3098        for plotting. The column label is reformatted from Unicode to MatPlotLib encoding
3099        '''
3100        colName = G2frame.SeqTable.GetColLabelValue(col)
3101        plotName = variableLabels.get(colName,colName)
3102        plotName = plotSpCharFix(plotName)
3103        return plotName,G2frame.colList[col],G2frame.colSigs[col]
3104           
3105    def PlotSelect(event):
3106        'Plots a row (covariance) or column on double-click'
3107        cols = G2frame.dataDisplay.GetSelectedCols()
3108        rows = G2frame.dataDisplay.GetSelectedRows()
3109        if cols:
3110            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
3111        elif rows:
3112            name = histNames[rows[0]]       #only does 1st one selected
3113            G2plt.PlotCovariance(G2frame,data[name])
3114        else:
3115            G2frame.ErrorDialog(
3116                'Select row or columns',
3117                'Nothing selected in table. Click on column or row label(s) to plot. N.B. Grid selection can be a bit funky.'
3118                )
3119           
3120    def OnPlotSelSeq(event):
3121        'plot the selected columns or row from menu command'
3122        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
3123        rows = G2frame.dataDisplay.GetSelectedRows()
3124        if cols:
3125            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
3126        elif rows:
3127            name = histNames[rows[0]]       #only does 1st one selected
3128            G2plt.PlotCovariance(G2frame,data[name])
3129        else:
3130            G2frame.ErrorDialog(
3131                'Select columns',
3132                'No columns or rows selected in table. Click on row or column labels to select fields for plotting.'
3133                )
3134               
3135    def OnAveSelSeq(event):
3136        'average the selected columns from menu command'
3137        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
3138        useCol = -np.array(G2frame.SeqTable.GetColValues(0),dtype=bool)
3139        if cols:
3140            for col in cols:
3141                items = GetColumnInfo(col)[1]
3142                noneMask = np.array([item is None for item in items])
3143                info = ma.array(items,mask=useCol+noneMask)
3144                ave = ma.mean(ma.compressed(info))
3145                sig = ma.std(ma.compressed(info))
3146                print ' Average for '+G2frame.SeqTable.GetColLabelValue(col)+': '+'%.6g'%(ave)+' +/- '+'%.6g'%(sig)
3147        else:
3148            G2frame.ErrorDialog(
3149                'Select columns',
3150                'No columns selected in table. Click on column labels to select fields for averaging.'
3151                )
3152               
3153    def OnRenameSelSeq(event):
3154        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
3155        colNames = [G2frame.SeqTable.GetColLabelValue(c) for c in cols]
3156        newNames = colNames[:]
3157        for i,name in enumerate(colNames):
3158            if name in variableLabels:
3159                newNames[i] = variableLabels[name]
3160        if not cols:
3161            G2frame.ErrorDialog('Select columns',
3162                'No columns selected in table. Click on column labels to select fields for rename.')
3163            return
3164        dlg = G2G.MultiStringDialog(G2frame.dataDisplay,'Set column names',colNames,newNames)
3165        if dlg.Show():
3166            newNames = dlg.GetValues()           
3167            variableLabels.update(dict(zip(colNames,newNames)))
3168        data['variableLabels'] = variableLabels
3169        dlg.Destroy()
3170        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
3171        G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
3172           
3173    def OnReOrgSelSeq(event):
3174        'Reorder the columns'
3175        G2G.GetItemOrder(G2frame,VaryListChanges,vallookup,posdict)   
3176        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
3177
3178    def OnSaveSelSeqCSV(event):
3179        'export the selected columns to a .csv file from menu command'
3180        OnSaveSelSeq(event,csv=True)
3181       
3182    def OnSaveSeqCSV(event):
3183        'export all columns to a .csv file from menu command'
3184        OnSaveSelSeq(event,csv=True,allcols=True)
3185       
3186    def OnSaveSelSeq(event,csv=False,allcols=False):
3187        'export the selected columns to a .txt or .csv file from menu command'
3188        def WriteCSV():
3189            def WriteList(headerItems):
3190                line = ''
3191                for lbl in headerItems:
3192                    if line: line += ','
3193                    line += '"'+lbl+'"'
3194                return line
3195            head = ['name']
3196            for col in cols:
3197                item = G2frame.SeqTable.GetColLabelValue(col)
3198                # get rid of labels that have Unicode characters
3199                if not all([ord(c) < 128 and ord(c) != 0 for c in item]): item = '?'
3200                if col in havesig:
3201                    head += [item,'esd-'+item]
3202                else:
3203                    head += [item]
3204            SeqFile.write(WriteList(head)+'\n')
3205            for row,name in enumerate(saveNames):
3206                line = '"'+saveNames[row]+'"'
3207                for col in cols:
3208                    if col in havesig:
3209                        line += ','+str(saveData[col][row])+','+str(saveSigs[col][row])
3210                    else:
3211                        line += ','+str(saveData[col][row])
3212                SeqFile.write(line+'\n')
3213        def WriteSeq():
3214            lenName = len(saveNames[0])
3215            line = %s  '%('name'.center(lenName))
3216            for col in cols:
3217                item = G2frame.SeqTable.GetColLabelValue(col)
3218                if col in havesig:
3219                    line += ' %12s %12s '%(item.center(12),'esd'.center(12))
3220                else:
3221                    line += ' %12s '%(item.center(12))
3222            SeqFile.write(line+'\n')
3223            for row,name in enumerate(saveNames):
3224                line = " '%s' "%(saveNames[row])
3225                for col in cols:
3226                    if col in havesig:
3227                        line += ' %12.6f %12.6f '%(saveData[col][row],saveSigs[col][row])
3228                    else:
3229                        line += ' %12.6f '%saveData[col][row]
3230                SeqFile.write(line+'\n')
3231
3232        # start of OnSaveSelSeq code
3233        if allcols:
3234            cols = range(G2frame.SeqTable.GetNumberCols())
3235        else:
3236            cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
3237        nrows = G2frame.SeqTable.GetNumberRows()
3238        if not cols:
3239            G2frame.ErrorDialog('Select columns',
3240                             'No columns selected in table. Click on column labels to select fields for output.')
3241            return
3242        saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(nrows)]
3243        saveData = {}
3244        saveSigs = {}
3245        havesig = []
3246        for col in cols:
3247            name,vals,sigs = GetColumnInfo(col)
3248            saveData[col] = vals
3249            if sigs:
3250                havesig.append(col)
3251                saveSigs[col] = sigs
3252        if csv:
3253            wild = 'CSV output file (*.csv)|*.csv'
3254        else:
3255            wild = 'Text output file (*.txt)|*.txt'
3256        pth = G2G.GetExportPath(G2frame)
3257        dlg = wx.FileDialog(
3258            G2frame,
3259            'Choose text output file for your selection', pth, '', 
3260            wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
3261        try:
3262            if dlg.ShowModal() == wx.ID_OK:
3263                SeqTextFile = dlg.GetPath()
3264                SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) 
3265                SeqFile = open(SeqTextFile,'w')
3266                if csv:
3267                    WriteCSV()
3268                else:
3269                    WriteSeq()
3270                SeqFile.close()
3271        finally:
3272            dlg.Destroy()
3273               
3274    def striphist(var,insChar=''):
3275        'strip a histogram number from a var name'
3276        sv = var.split(':')
3277        if len(sv) <= 1: return var
3278        if sv[1]:
3279            sv[1] = insChar
3280        return ':'.join(sv)
3281       
3282    def plotSpCharFix(lbl):
3283        'Change selected unicode characters to their matplotlib equivalent'
3284        for u,p in [
3285            (u'\u03B1',r'$\alpha$'),
3286            (u'\u03B2',r'$\beta$'),
3287            (u'\u03B3',r'$\gamma$'),
3288            (u'\u0394\u03C7',r'$\Delta\chi$'),
3289            ]:
3290            lbl = lbl.replace(u,p)
3291        return lbl
3292   
3293    def SelectXaxis():
3294        'returns a selected column number (or None) as the X-axis selection'
3295        ncols = G2frame.SeqTable.GetNumberCols()
3296        colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)]
3297        dlg = G2G.G2SingleChoiceDialog(
3298            G2frame.dataDisplay,
3299            'Select x-axis parameter for plot or Cancel for sequence number',
3300            'Select X-axis',
3301            colNames)
3302        try:
3303            if dlg.ShowModal() == wx.ID_OK:
3304                col = dlg.GetSelection()
3305            else:
3306                col = None
3307        finally:
3308            dlg.Destroy()
3309        return col
3310   
3311    def EnablePseudoVarMenus():
3312        'Enables or disables the PseudoVar menu items that require existing defs'
3313        if data['SeqPseudoVars']:
3314            val = True
3315        else:
3316            val = False
3317        G2frame.dataFrame.SequentialPvars.Enable(wxDELSEQVAR,val)
3318        G2frame.dataFrame.SequentialPvars.Enable(wxEDITSEQVAR,val)
3319
3320    def DelPseudoVar(event):
3321        'Ask the user to select a pseudo var expression to delete'
3322        choices = data['SeqPseudoVars'].keys()
3323        selected = G2G.ItemSelector(
3324            choices,G2frame.dataFrame,
3325            multiple=True,
3326            title='Select expressions to remove',
3327            header='Delete expression')
3328        if selected is None: return
3329        for item in selected:
3330            del data['SeqPseudoVars'][choices[item]]
3331        if selected:
3332            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
3333
3334    def EditPseudoVar(event):
3335        'Edit an existing pseudo var expression'
3336        choices = data['SeqPseudoVars'].keys()
3337        if len(choices) == 1:
3338            selected = 0
3339        else:
3340            selected = G2G.ItemSelector(
3341                choices,G2frame.dataFrame,
3342                multiple=False,
3343                title='Select an expression to edit',
3344                header='Edit expression')
3345        if selected is not None:
3346            dlg = G2exG.ExpressionDialog(
3347                G2frame.dataDisplay,PSvarDict,
3348                data['SeqPseudoVars'][choices[selected]],
3349                header="Edit the PseudoVar expression",
3350                VarLabel="PseudoVar #"+str(selected+1),
3351                fit=False)
3352            newobj = dlg.Show(True)
3353            if newobj:
3354                calcobj = G2obj.ExpressionCalcObj(newobj)
3355                del data['SeqPseudoVars'][choices[selected]]
3356                data['SeqPseudoVars'][calcobj.eObj.expression] = newobj
3357                UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
3358       
3359    def AddNewPseudoVar(event):
3360        'Create a new pseudo var expression'
3361        dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,PSvarDict,
3362            header='Enter an expression for a PseudoVar here',
3363            VarLabel = "New PseudoVar",fit=False)
3364        obj = dlg.Show(True)
3365        dlg.Destroy()
3366        if obj:
3367            calcobj = G2obj.ExpressionCalcObj(obj)
3368            data['SeqPseudoVars'][calcobj.eObj.expression] = obj
3369            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
3370           
3371    def AddNewDistPseudoVar(event):
3372        obj = None
3373        dlg = G2exG.BondDialog(
3374            G2frame.dataDisplay,Phases,PSvarDict,
3375            header='Select a Bond here',
3376            VarLabel = "New Bond")
3377        if dlg.ShowModal() == wx.ID_OK:
3378            pName,Oatom,Tatom = dlg.GetSelection()
3379            if Tatom:
3380                Phase = Phases[pName]
3381                General = Phase['General']
3382                cx,ct = General['AtomPtrs'][:2]
3383                pId = Phase['pId']
3384                SGData = General['SGData']
3385                sB = Tatom.find('(')+1
3386                symNo = 0
3387                if sB:
3388                    sF = Tatom.find(')')
3389                    symNo = int(Tatom[sB:sF])
3390                cellNo = [0,0,0]
3391                cB = Tatom.find('[')
3392                if cB>0:
3393                    cF = Tatom.find(']')+1
3394                    cellNo = eval(Tatom[cB:cF])
3395                Atoms = Phase['Atoms']
3396                aNames = [atom[ct-1] for atom in Atoms]
3397                oId = aNames.index(Oatom)
3398                tId = aNames.index(Tatom.split(' +')[0])
3399                # create an expression object
3400                obj = G2obj.ExpressionObj()
3401                obj.expression = 'Dist(%s,\n%s)'%(Oatom,Tatom.split(' d=')[0].replace(' ',''))
3402                obj.distance_dict = {'pId':pId,'SGData':SGData,'symNo':symNo,'cellNo':cellNo}
3403                obj.distance_atoms = [oId,tId]
3404        else: 
3405            dlg.Destroy()
3406            return
3407        dlg.Destroy()
3408        if obj:
3409            data['SeqPseudoVars'][obj.expression] = obj
3410            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
3411
3412    def AddNewAnglePseudoVar(event):
3413        obj = None
3414        dlg = G2exG.AngleDialog(
3415            G2frame.dataDisplay,Phases,PSvarDict,
3416            header='Enter an Angle here',
3417            VarLabel = "New Angle")
3418        if dlg.ShowModal() == wx.ID_OK:
3419            pName,Oatom,Tatoms = dlg.GetSelection()
3420            if Tatoms:
3421                Phase = Phases[pName]
3422                General = Phase['General']
3423                cx,ct = General['AtomPtrs'][:2]
3424                pId = Phase['pId']
3425                SGData = General['SGData']
3426                Atoms = Phase['Atoms']
3427                aNames = [atom[ct-1] for atom in Atoms]
3428                tIds = []
3429                symNos = []
3430                cellNos = []
3431                oId = aNames.index(Oatom)
3432                Tatoms = Tatoms.split(';')
3433                for Tatom in Tatoms:
3434                    sB = Tatom.find('(')+1
3435                    symNo = 0
3436                    if sB:
3437                        sF = Tatom.find(')')
3438                        symNo = int(Tatom[sB:sF])
3439                    symNos.append(symNo)
3440                    cellNo = [0,0,0]
3441                    cB = Tatom.find('[')
3442                    if cB>0:
3443                        cF = Tatom.find(']')+1
3444                        cellNo = eval(Tatom[cB:cF])
3445                    cellNos.append(cellNo)
3446                    tIds.append(aNames.index(Tatom.split('+')[0]))
3447                # create an expression object
3448                obj = G2obj.ExpressionObj()
3449                obj.expression = 'Angle(%s,%s,\n%s)'%(Tatoms[0],Oatom,Tatoms[1])
3450                obj.angle_dict = {'pId':pId,'SGData':SGData,'symNo':symNos,'cellNo':cellNos}
3451                obj.angle_atoms = [oId,tIds]
3452        else: 
3453            dlg.Destroy()
3454            return
3455        dlg.Destroy()
3456        if obj:
3457            data['SeqPseudoVars'][obj.expression] = obj
3458            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
3459           
3460    def UpdateParmDict(parmDict):
3461        '''generate the atom positions and the direct & reciprocal cell values,
3462        because they might be needed to evaluate the pseudovar
3463        '''
3464        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
3465                         ['A'+str(i) for i in range(6)])
3466                     )
3467        delList = []
3468        phaselist = []
3469        for item in parmDict: 
3470            if ':' not in item: continue
3471            key = item.split(':')
3472            if len(key) < 3: continue
3473            # remove the dA[xyz] terms, they would only bring confusion
3474            if key[0] and key[0] not in phaselist: phaselist.append(key[0])
3475            if key[2].startswith('dA'):
3476                delList.append(item)
3477            # compute and update the corrected reciprocal cell terms using the Dij values
3478            elif key[2] in Ddict:
3479                akey = key[0]+'::'+Ddict[key[2]]
3480                parmDict[akey] -= parmDict[item]
3481                delList.append(item)
3482        for item in delList:
3483            del parmDict[item]               
3484        for i in phaselist:
3485            pId = int(i)
3486            # apply cell symmetry
3487            A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId])
3488            # convert to direct cell & add the unique terms to the dictionary
3489            for i,val in enumerate(G2lat.A2cell(A)):
3490                if i in uniqCellIndx[pId]:
3491                    lbl = str(pId)+'::'+cellUlbl[i]
3492                    parmDict[lbl] = val
3493            lbl = str(pId)+'::'+'Vol'
3494            parmDict[lbl] = G2lat.calc_V(A)
3495        return parmDict
3496
3497    def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD):
3498        '''Evaluate an expression derivative with respect to a
3499        GSAS-II variable name.
3500
3501        Note this likely could be faster if the loop over calcobjs were done
3502        inside after the Dict was created.
3503        '''
3504        if not ESD:
3505            return 0.
3506        step = ESD/10
3507        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
3508                         ['A'+str(i) for i in range(6)])
3509                     )
3510        results = []
3511        phaselist = []
3512        VparmDict = sampleDict.copy()
3513        for incr in step,-step:
3514            VparmDict.update(parmDict.copy())           
3515            # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]'
3516            # values are not zeroed: fix that!
3517            VparmDict.update({item:0.0 for item in parmDict if 'dA' in item})
3518            VparmDict[var] += incr
3519            G2mv.Dict2Map(VparmDict,[]) # apply constraints
3520            # generate the atom positions and the direct & reciprocal cell values now, because they might
3521            # needed to evaluate the pseudovar
3522            for item in VparmDict:
3523                if item in sampleDict:
3524                    continue 
3525                if ':' not in item: continue
3526                key = item.split(':')
3527                if len(key) < 3: continue
3528                # apply any new shifts to atom positions
3529                if key[2].startswith('dA'):
3530                    VparmDict[''.join(item.split('d'))] += VparmDict[item]
3531                    VparmDict[item] = 0.0
3532                # compute and update the corrected reciprocal cell terms using the Dij values
3533                if key[2] in Ddict:
3534                    if key[0] not in phaselist: phaselist.append(key[0])
3535                    akey = key[0]+'::'+Ddict[key[2]]
3536                    VparmDict[akey] -= VparmDict[item]
3537            for i in phaselist:
3538                pId = int(i)
3539                # apply cell symmetry
3540                A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId])
3541                # convert to direct cell & add the unique terms to the dictionary
3542                for i,val in enumerate(G2lat.A2cell(A)):
3543                    if i in uniqCellIndx[pId]:
3544                        lbl = str(pId)+'::'+cellUlbl[i]
3545                        VparmDict[lbl] = val
3546                lbl = str(pId)+'::'+'Vol'
3547                VparmDict[lbl] = G2lat.calc_V(A)
3548            # dict should be fully updated, use it & calculate
3549            calcobj.SetupCalc(VparmDict)
3550            results.append(calcobj.EvalExpression())
3551        if None in results:
3552            return None
3553        return (results[0] - results[1]) / (2.*step)
3554       
3555    def EnableParFitEqMenus():
3556        'Enables or disables the Parametric Fit menu items that require existing defs'
3557        if data['SeqParFitEqList']:
3558            val = True
3559        else:
3560            val = False
3561        G2frame.dataFrame.SequentialPfit.Enable(wxDELPARFIT,val)
3562        G2frame.dataFrame.SequentialPfit.Enable(wxEDITPARFIT,val)
3563        G2frame.dataFrame.SequentialPfit.Enable(wxDOPARFIT,val)
3564
3565    def ParEqEval(Values,calcObjList,varyList):
3566        '''Evaluate the parametric expression(s)
3567        :param list Values: a list of values for each variable parameter
3568        :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj`
3569          expression objects to evaluate
3570        :param list varyList: a list of variable names for each value in Values
3571        '''
3572        result = []
3573        for calcobj in calcObjList:
3574            calcobj.UpdateVars(varyList,Values)
3575            if calcobj.depSig:
3576                result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig)
3577            else:
3578                result.append(calcobj.depVal-calcobj.EvalExpression())
3579        return result
3580
3581    def DoParEqFit(event,eqObj=None):
3582        'Parametric fit minimizer'
3583        varyValueDict = {} # dict of variables and their initial values
3584        calcObjList = [] # expression objects, ready to go for each data point
3585        if eqObj is not None:
3586            eqObjList = [eqObj,]
3587        else:
3588            eqObjList = data['SeqParFitEqList']
3589        UseFlags = G2frame.SeqTable.GetColValues(0)         
3590        for obj in eqObjList:
3591            # assemble refined vars for this equation
3592            varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()})
3593            # lookup dependent var position
3594            depVar = obj.GetDepVar()
3595            if depVar in colLabels:
3596                indx = colLabels.index(depVar)
3597            else:
3598                raise Exception('Dependent variable '+depVar+' not found')
3599            # assemble a list of the independent variables
3600            indepVars = obj.GetIndependentVars()
3601            # loop over each datapoint
3602            for j,row in enumerate(zip(*G2frame.colList)):
3603                if not UseFlags[j]: continue
3604                # assemble equations to fit
3605                calcobj = G2obj.ExpressionCalcObj(obj)
3606                # prepare a dict of needed independent vars for this expression
3607                indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
3608                calcobj.SetupCalc(indepVarDict)               
3609                # values and sigs for current value of dependent var
3610                if row[indx] is None: continue
3611                calcobj.depVal = row[indx]
3612                calcobj.depSig = G2frame.colSigs[indx][j]
3613                calcObjList.append(calcobj)
3614        # varied parameters
3615        varyList = varyValueDict.keys()
3616        values = varyValues = [varyValueDict[key] for key in varyList]
3617        if not varyList:
3618            print 'no variables to refine!'
3619            return
3620        try:
3621            result = so.leastsq(ParEqEval,varyValues,full_output=True,   #ftol=Ftol,
3622                args=(calcObjList,varyList))
3623            values = result[0]
3624            covar = result[1]
3625            if covar is None:
3626                raise Exception
3627            chisq = np.sum(result[2]['fvec']**2)
3628            GOF = np.sqrt(chisq/(len(calcObjList)-len(varyList)))
3629            esdDict = {}
3630            for i,avar in enumerate(varyList):
3631                esdDict[avar] = np.sqrt(covar[i,i])
3632        except:
3633            print('====> Fit failed')
3634            return
3635        print('==== Fit Results ====')
3636        print '  chisq =  %.2f, GOF = %.2f'%(chisq,GOF)
3637        for obj in eqObjList:
3638            obj.UpdateVariedVars(varyList,values)
3639            ind = '      '
3640            print('  '+obj.GetDepVar()+' = '+obj.expression)
3641            for var in obj.assgnVars:
3642                print(ind+var+' = '+obj.assgnVars[var])
3643            for var in obj.freeVars:
3644                avar = "::"+obj.freeVars[var][0]
3645                val = obj.freeVars[var][1]
3646                if obj.freeVars[var][2]:
3647                    print(ind+var+' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar]))
3648                else:
3649                    print(ind+var+' = '+avar + " =" + G2mth.ValEsd(val,0))
3650        # create a plot for each parametric variable
3651        for fitnum,obj in enumerate(eqObjList):
3652            calcobj = G2obj.ExpressionCalcObj(obj)
3653            # lookup dependent var position
3654            indx = colLabels.index(obj.GetDepVar())
3655            # assemble a list of the independent variables
3656            indepVars = obj.GetIndependentVars()           
3657            # loop over each datapoint
3658            fitvals = []
3659            for j,row in enumerate(zip(*G2frame.colList)):
3660                calcobj.SetupCalc({var:row[i] for i,var in enumerate(colLabels) if var in indepVars})
3661                fitvals.append(calcobj.EvalExpression())
3662            G2plt.PlotSelectedSequence(G2frame,[indx],GetColumnInfo,SelectXaxis,fitnum,fitvals)
3663
3664    def SingleParEqFit(eqObj):
3665        DoParEqFit(None,eqObj)
3666
3667    def DelParFitEq(event):
3668        'Ask the user to select function to delete'
3669        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']]
3670        selected = G2G.ItemSelector(
3671            txtlst,G2frame.dataFrame,
3672            multiple=True,
3673            title='Select a parametric equation(s) to remove',
3674            header='Delete equation')
3675        if selected is None: return
3676        data['SeqParFitEqList'] = [obj for i,obj in enumerate(data['SeqParFitEqList']) if i not in selected]
3677        EnableParFitEqMenus()
3678        if data['SeqParFitEqList']: DoParEqFit(event)
3679       
3680    def EditParFitEq(event):
3681        'Edit an existing parametric equation'
3682        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']]
3683        if len(txtlst) == 1:
3684            selected = 0
3685        else:
3686            selected = G2G.ItemSelector(
3687                txtlst,G2frame.dataFrame,
3688                multiple=False,
3689                title='Select a parametric equation to edit',
3690                header='Edit equation')
3691        if selected is not None:
3692            dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,VarDict,
3693                data['SeqParFitEqList'][selected],depVarDict=VarDict,
3694                header="Edit the formula for this minimization function",
3695                ExtraButton=['Fit',SingleParEqFit])
3696            newobj = dlg.Show(True)
3697            if newobj:
3698                data['SeqParFitEqList'][selected] = newobj
3699                EnableParFitEqMenus()
3700            if data['SeqParFitEqList']: DoParEqFit(event)
3701
3702    def AddNewParFitEq(event):
3703        'Create a new parametric equation to be fit to sequential results'
3704
3705        # compile the variable names used in previous freevars to avoid accidental name collisions
3706        usedvarlist = []
3707        for obj in data['SeqParFitEqList']:
3708            for var in obj.freeVars:
3709                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3710
3711        dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,VarDict,depVarDict=VarDict,
3712            header='Define an equation to minimize in the parametric fit',
3713            ExtraButton=['Fit',SingleParEqFit],usedVars=usedvarlist)
3714        obj = dlg.Show(True)
3715        dlg.Destroy()
3716        if obj:
3717            data['SeqParFitEqList'].append(obj)
3718            EnableParFitEqMenus()
3719            if data['SeqParFitEqList']: DoParEqFit(event)
3720               
3721    def CopyParFitEq(event):
3722        'Copy an existing parametric equation to be fit to sequential results'
3723        # compile the variable names used in previous freevars to avoid accidental name collisions
3724        usedvarlist = []
3725        for obj in data['SeqParFitEqList']:
3726            for var in obj.freeVars:
3727                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
3728        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']]
3729        if len(txtlst) == 1:
3730            selected = 0
3731        else:
3732            selected = G2G.ItemSelector(
3733                txtlst,G2frame.dataFrame,
3734                multiple=False,
3735                title='Select a parametric equation to copy',
3736                header='Copy equation')
3737        if selected is not None:
3738            newEqn = copy.deepcopy(data['SeqParFitEqList'][selected])
3739            for var in newEqn.freeVars:
3740                newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist)
3741            dlg = G2exG.ExpressionDialog(
3742                G2frame.dataDisplay,VarDict,newEqn,depVarDict=VarDict,
3743                header="Edit the formula for this minimization function",
3744                ExtraButton=['Fit',SingleParEqFit])
3745            newobj = dlg.Show(True)
3746            if newobj:
3747                data['SeqParFitEqList'].append(newobj)
3748                EnableParFitEqMenus()
3749            if data['SeqParFitEqList']: DoParEqFit(event)
3750                                           
3751    def GridSetToolTip(row,col):
3752        '''Routine to show standard uncertainties for each element in table
3753        as a tooltip
3754        '''
3755        if G2frame.colSigs[col]:
3756            return u'\u03c3 = '+str(G2frame.colSigs[col][row])
3757        return ''
3758       
3759    def GridColLblToolTip(col):
3760        '''Define a tooltip for a column. This will be the user-entered value
3761        (from data['variableLabels']) or the default name
3762        '''
3763        if col < 0 or col > len(colLabels):
3764            print 'Illegal column #',col
3765            return
3766        var = colLabels[col]
3767        return variableLabels.get(var,G2obj.fmtVarDescr(var))
3768       
3769    def SetLabelString(event):
3770        '''Define or edit the label for a column in the table, to be used
3771        as a tooltip and for plotting
3772        '''
3773        col = event.GetCol()
3774        if col < 0 or col > len(colLabels):
3775            return
3776        var = colLabels[col]
3777        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
3778        dlg = G2G.SingleStringDialog(G2frame.dataFrame,'Set variable label',
3779                                 'Set a new name for variable '+var,lbl,size=(400,-1))
3780        if dlg.Show():
3781            variableLabels[var] = dlg.GetValue()
3782        dlg.Destroy()
3783
3784    def DoSequentialExport(event):
3785        '''Event handler for all Sequential Export menu items
3786        '''
3787        vals = G2frame.dataFrame.SeqExportLookup.get(event.GetId())
3788        if vals is None:
3789            print('Error: Id not found. This should not happen!')
3790        G2IO.ExportSequential(G2frame,data,*vals)
3791   
3792    #def GridRowLblToolTip(row): return 'Row ='+str(row)
3793   
3794    # lookup table for unique cell parameters by symmetry
3795    cellGUIlist = [
3796        [['m3','m3m'],(0,)],
3797        [['3R','3mR'],(0,3)],
3798        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
3799        [['mmm'],(0,1,2)],
3800        [['2/m'+'a'],(0,1,2,3)],
3801        [['2/m'+'b'],(0,1,2,4)],
3802        [['2/m'+'c'],(0,1,2,5)],
3803        [['-1'],(0,1,2,3,4,5)],
3804        ]
3805    # cell labels
3806    cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
3807
3808    #======================================================================
3809    # start processing sequential results here (UpdateSeqResults)
3810    #======================================================================
3811    if not data:
3812        print 'No sequential refinement results'
3813        return
3814    variableLabels = data.get('variableLabels',{})
3815    data['variableLabels'] = variableLabels
3816    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
3817    Controls = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
3818    # create a place to store Pseudo Vars & Parametric Fit functions, if not present
3819    if 'SeqPseudoVars' not in data: data['SeqPseudoVars'] = {}
3820    if 'SeqParFitEqList' not in data: data['SeqParFitEqList'] = []
3821    histNames = data['histNames']
3822    if G2frame.dataDisplay:
3823        G2frame.dataDisplay.Destroy()
3824    if not G2frame.dataFrame.GetStatusBar():
3825        Status = G2frame.dataFrame.CreateStatusBar()
3826        Status.SetStatusText("Select column to export; Double click on column to plot data; on row for Covariance")
3827    sampleParms = GetSampleParms()
3828
3829    # make dict of varied atom coords keyed by absolute position
3830    newAtomDict = data[histNames[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
3831    # Possible error: the next might need to be data[histNames[0]]['varyList']
3832    # error will arise if there constraints on coordinates?
3833    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in data['varyList']}
3834   
3835    # make dict of varied cell parameters equivalents
3836    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
3837    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
3838    # N.B. These Dij vars are missing a histogram #
3839    newCellDict = {}
3840    for name in histNames:
3841        if name in data and 'newCellDict' in data[name]:
3842            newCellDict.update(data[name]['newCellDict'])
3843#    newCellDict = data[histNames[0]].get('newCellDict',{})
3844    cellAlist = []
3845    for item in newCellDict:
3846        cellAlist.append(newCellDict[item][0])
3847        if item in data.get('varyList',[]):
3848            ESDlookup[newCellDict[item][0]] = item
3849            Dlookup[item] = newCellDict[item][0]
3850    # add coordinate equivalents to lookup table
3851    for parm in atomLookup:
3852        Dlookup[atomLookup[parm]] = parm
3853        ESDlookup[parm] = atomLookup[parm]
3854
3855    # get unit cell & symmetry for all phases & initial stuff for later use
3856    RecpCellTerms = {}
3857    SGdata = {}
3858    uniqCellIndx = {}
3859    initialCell = {}
3860    RcellLbls = {}
3861    zeroDict = {}
3862    for phase in Phases:
3863        phasedict = Phases[phase]
3864        pId = phasedict['pId']
3865        pfx = str(pId)+'::' # prefix for A values from phase
3866        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
3867        RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7])
3868        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
3869        SGdata[pId] = phasedict['General']['SGData']
3870        laue = SGdata[pId]['SGLaue']
3871        if laue == '2/m':
3872            laue += SGdata[pId]['SGUniq']
3873        for symlist,celllist in cellGUIlist:
3874            if laue in symlist:
3875                uniqCellIndx[pId] = celllist
3876                break
3877        else: # should not happen
3878            uniqCellIndx[pId] = range(6)
3879        for i in uniqCellIndx[pId]:
3880            initialCell[str(pId)+'::A'+str(i)] =  RecpCellTerms[pId][i]
3881
3882    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
3883    G2frame.dataFrame.SetLabel('Sequential refinement results')
3884    if not G2frame.dataFrame.GetStatusBar():
3885        Status = G2frame.dataFrame.CreateStatusBar()
3886        Status.SetStatusText('')
3887    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=wxID_RENAMESEQSEL)
3888    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
3889    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=wxID_SAVESEQSELCSV)
3890    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=wxID_SAVESEQCSV)
3891    G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=wxID_PLOTSEQSEL)
3892    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAveSelSeq, id=wxID_AVESEQSEL)
3893    G2frame.dataFrame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=wxID_ORGSEQSEL)
3894    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=wxADDSEQVAR)
3895    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewDistPseudoVar, id=wxADDSEQDIST)
3896    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewAnglePseudoVar, id=wxADDSEQANGLE)
3897    G2frame.dataFrame.Bind(wx.EVT_MENU, DelPseudoVar, id=wxDELSEQVAR)
3898    G2frame.dataFrame.Bind(wx.EVT_MENU, EditPseudoVar, id=wxEDITSEQVAR)
3899    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewParFitEq, id=wxADDPARFIT)
3900    G2frame.dataFrame.Bind(wx.EVT_MENU, CopyParFitEq, id=wxCOPYPARFIT)
3901    G2frame.dataFrame.Bind(wx.EVT_MENU, DelParFitEq, id=wxDELPARFIT)
3902    G2frame.dataFrame.Bind(wx.EVT_MENU, EditParFitEq, id=wxEDITPARFIT)
3903    G2frame.dataFrame.Bind(wx.EVT_MENU, DoParEqFit, id=wxDOPARFIT)
3904
3905    for id in G2frame.dataFrame.SeqExportLookup:       
3906        G2frame.dataFrame.Bind(wx.EVT_MENU, DoSequentialExport, id=id)
3907
3908    EnablePseudoVarMenus()
3909    EnableParFitEqMenus()
3910
3911    # scan for locations where the variables change
3912    VaryListChanges = [] # histograms where there is a change
3913    combinedVaryList = []
3914    firstValueDict = {}
3915    vallookup = {}
3916    posdict = {}
3917    prevVaryList = []
3918    foundNames = []
3919    missing = 0
3920    for i,name in enumerate(histNames):
3921        if name not in data:
3922            if missing < 5:
3923                print(" Warning: "+name+" not found")
3924            elif missing == 5:
3925                print ' Warning: more are missing'
3926            missing += 1
3927            continue
3928        foundNames.append(name)
3929        maxPWL = 5
3930        for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']):
3931            svar = striphist(var,'*') # wild-carded
3932            if 'PWL' in svar:
3933                if int(svar.split(':')[-1]) > maxPWL:
3934                    continue
3935            if svar not in combinedVaryList:
3936                # add variables to list as they appear
3937                combinedVaryList.append(svar)
3938                firstValueDict[svar] = (val,sig)
3939        if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous
3940            prevVaryList = data[name]['varyList']
3941            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
3942            posdict[name] = {}
3943            for var in data[name]['varyList']:
3944                svar = striphist(var,'*')
3945                if 'PWL' in svar:
3946                    if int(svar.split(':')[-1]) > maxPWL:
3947                        continue
3948                posdict[name][combinedVaryList.index(svar)] = svar
3949            VaryListChanges.append(name)
3950    if missing:
3951        print ' Warning: Total of %d data sets missing from sequential results'%(missing)
3952    if len(VaryListChanges) > 1:
3953        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,True)
3954    else:
3955        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,False)
3956    #-----------------------------------------------------------------------------------
3957    # build up the data table by columns -----------------------------------------------
3958    histNames = foundNames
3959    nRows = len(histNames)
3960    G2frame.colList = [nRows*[True]]
3961    G2frame.colSigs = [None]
3962    colLabels = ['Use']
3963    Types = [wg.GRID_VALUE_BOOL]
3964    # start with Rwp values
3965    if 'IMG ' not in histNames[0][:4]:
3966        G2frame.colList += [[data[name]['Rvals']['Rwp'] for name in histNames]]
3967        G2frame.colSigs += [None]
3968        colLabels += ['Rwp']
3969        Types += [wg.GRID_VALUE_FLOAT+':10,3',]
3970    # add % change in Chi^2 in last cycle
3971    if histNames[0][:4] not in ['SASD','IMG ','REFD'] and Controls.get('ShowCell'):
3972        G2frame.colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]]
3973        G2frame.colSigs += [None]
3974        colLabels += [u'\u0394\u03C7\u00B2 (%)']
3975        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
3976    deltaChiCol = len(colLabels)-1
3977    # add changing sample parameters to table
3978    for key in sampleParms:
3979        G2frame.colList += [sampleParms[key]]
3980        G2frame.colSigs += [None]
3981        colLabels += [key]
3982        Types += [wg.GRID_VALUE_FLOAT,]
3983    sampleDict = {}
3984    for i,name in enumerate(histNames):
3985        sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) 
3986    # add unique cell parameters TODO: review this where the cell symmetry changes (when possible)
3987    if Controls.get('ShowCell',False) and len(newCellDict):
3988        for pId in sorted(RecpCellTerms):
3989            pfx = str(pId)+'::' # prefix for A values from phase
3990            cells = []
3991            cellESDs = []
3992            colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
3993            colLabels += [pfx+'Vol']
3994            Types += (len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT+':10,5',]
3995            Types += [wg.GRID_VALUE_FLOAT+':10,3',]
3996            Albls = [pfx+'A'+str(i) for i in range(6)]
3997            for hId,name in enumerate(histNames):
3998                phfx = '%d:%d:'%(pId,hId)
3999                esdLookUp = {}
4000                dLookup = {}
4001                for item in data[name]['newCellDict']:
4002                    if phfx+item.split('::')[1] in data[name]['varyList']:
4003                        esdLookUp[newCellDict[item][0]] = item
4004                        dLookup[item] = newCellDict[item][0]
4005                covData = {'varyList': [dLookup.get(striphist(v),v) for v in data[name]['varyList']],
4006                    'covMatrix': data[name]['covMatrix']}
4007                A = RecpCellTerms[pId][:] # make copy of starting A values
4008                # update with refined values
4009                for i in range(6):
4010                    var = str(pId)+'::A'+str(i)
4011                    if var in cellAlist:
4012                        try:
4013                            val = data[name]['newCellDict'][esdLookUp[var]][1] # get refined value
4014                            A[i] = val # override with updated value
4015                        except KeyError:
4016                            A[i] = None
4017                # apply symmetry
4018                cellDict = dict(zip(Albls,A))
4019                if None in A:
4020                    c = 6*[None]
4021                    cE = 6*[None]
4022                    vol = None
4023                else:
4024                    A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
4025                    # convert to direct cell & add only unique values to table
4026                    c = G2lat.A2cell(A)
4027                    vol = G2lat.calc_V(A)
4028                    cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
4029                cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
4030                cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
4031            G2frame.colList += zip(*cells)
4032            G2frame.colSigs += zip(*cellESDs)
4033    # sort out the variables in their selected order
4034    varcols = 0
4035    for d in posdict.itervalues():
4036        varcols = max(varcols,max(d.keys())+1)
4037    # get labels for each column
4038    for i in range(varcols):
4039        lbl = ''
4040        for h in VaryListChanges:
4041            if posdict[h].get(i):
4042                if posdict[h].get(i) in lbl: continue
4043                if lbl != "": lbl += '/'
4044                lbl += posdict[h].get(i)
4045        colLabels.append(lbl)
4046    Types += varcols*[wg.GRID_VALUE_FLOAT,]
4047    vals = []
4048    esds = []
4049    varsellist = None        # will be a list of variable names in the order they are selected to appear
4050    # tabulate values for each hist, leaving None for blank columns
4051    for name in histNames:
4052        if name in posdict:
4053            varsellist = [posdict[name].get(i) for i in range(varcols)]
4054            # translate variable names to how they will be used in the headings
4055            vs = [striphist(v,'*') for v in data[name]['varyList']]
4056            # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists
4057            sellist = [vs.index(v) if v is not None else None for v in varsellist]
4058            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])]
4059        if not varsellist: raise Exception()
4060        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
4061        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
4062        #GSASIIpath.IPyBreak()
4063    G2frame.colList += zip(*vals)
4064    G2frame.colSigs += zip(*esds)
4065    # compute and add weight fractions to table if varied
4066    for phase in Phases:
4067        var = str(Phases[phase]['pId'])+':*:Scale'
4068        if var not in combinedVaryList: continue
4069        wtFrList = []
4070        sigwtFrList = []
4071        for i,name in enumerate(histNames):
4072            wtFrSum = 0.
4073            for phase1 in Phases:
4074                wtFrSum += Phases[phase1]['Histograms'][name]['Scale'][0]*Phases[phase1]['General']['Mass']
4075            var = str(Phases[phase]['pId'])+':'+str(i)+':Scale'
4076            wtFr = Phases[phase]['Histograms'][name]['Scale'][0]*Phases[phase]['General']['Mass']/wtFrSum
4077            wtFrList.append(wtFr)
4078            if var in data[name]['varyList']:
4079                sig = data[name]['sig'][data[name]['varyList'].index(var)]*wtFr/Phases[phase]['Histograms'][name]['Scale'][0]
4080            else:
4081                sig = 0.0
4082            sigwtFrList.append(sig)
4083        colLabels.append(str(Phases[phase]['pId'])+':*:WgtFrac')
4084        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
4085        G2frame.colList += [wtFrList]
4086        G2frame.colSigs += [sigwtFrList]
4087               
4088    # tabulate constrained variables, removing histogram numbers if needed
4089    # from parameter label
4090    depValDict = {}
4091    depSigDict = {}
4092    for name in histNames:
4093        for var in data[name].get('depParmDict',{}):
4094            val,sig = data[name]['depParmDict'][var]
4095            svar = striphist(var,'*')
4096            if svar not in depValDict:
4097               depValDict[svar] = [val]
4098               depSigDict[svar] = [sig]
4099            else:
4100               depValDict[svar].append(val)
4101               depSigDict[svar].append(sig)
4102    # add the dependent constrained variables to the table
4103    for var in sorted(depValDict):
4104        if len(depValDict[var]) != len(histNames): continue
4105        colLabels.append(var)
4106        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
4107        G2frame.colSigs += [depSigDict[var]]
4108        G2frame.colList += [depValDict[var]]
4109
4110    # add atom parameters to table
4111    colLabels += atomLookup.keys()
4112    for parm in sorted(atomLookup):
4113        G2frame.colList += [[data[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
4114        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
4115        if atomLookup[parm] in data[histNames[0]]['varyList']:
4116            col = data[histNames[0]]['varyList'].index(atomLookup[parm])
4117            G2frame.colSigs += [[data[name]['sig'][col] for name in histNames]]
4118        else:
4119            G2frame.colSigs += [None]
4120    # evaluate Pseudovars, their ESDs and add them to grid
4121    for expr in data['SeqPseudoVars']:
4122        obj = data['SeqPseudoVars'][expr]
4123        calcobj = G2obj.ExpressionCalcObj(obj)
4124        valList = []
4125        esdList = []
4126        for seqnum,name in enumerate(histNames):
4127            sigs = data[name]['sig']
4128            G2mv.InitVars()
4129            parmDict = data[name].get('parmDict')
4130            constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum])
4131            groups,parmlist,constrDict,fixedList,ihst = constraintInfo
4132            varyList = data[name]['varyList']
4133            parmDict = data[name]['parmDict']
4134            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmDict,SeqHist=ihst)
4135            if 'Dist' in expr:
4136                derivs = G2mth.CalcDistDeriv(obj.distance_dict,obj.distance_atoms, parmDict)
4137                pId = obj.distance_dict['pId']
4138                aId,bId = obj.distance_atoms
4139                varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']]
4140                varyNames += ['%d::dA%s:%d'%(pId,ip,bId) for ip in ['x','y','z']]
4141                VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix'])
4142                esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) ))
4143#                GSASIIpath.IPyBreak()
4144            elif 'Angle' in expr:
4145                derivs = G2mth.CalcAngleDeriv(obj.angle_dict,obj.angle_atoms, parmDict)
4146                pId = obj.angle_dict['pId']
4147                aId,bId = obj.angle_atoms
4148                varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']]
4149                varyNames += ['%d::dA%s:%d'%(pId,ip,bId[0]) for ip in ['x','y','z']]
4150                varyNames += ['%d::dA%s:%d'%(pId,ip,bId[1]) for ip in ['x','y','z']]
4151                VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix'])
4152                esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) ))
4153            else:
4154                derivs = np.array(
4155                    [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD)
4156                     for var,ESD in zip(varyList,sigs)])
4157                if None in list(derivs):
4158                    esdList.append(None)
4159                else:
4160                    esdList.append(np.sqrt(
4161                        np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T)) ))
4162            PSvarDict = parmDict.copy()
4163            PSvarDict.update(sampleDict[name])
4164            UpdateParmDict(PSvarDict)
4165            calcobj.UpdateDict(PSvarDict)
4166            valList.append(calcobj.EvalExpression())
4167#            if calcobj.su is not None: esdList[-1] = calcobj.su
4168        if not esdList:
4169            esdList = None
4170        G2frame.colList += [valList]
4171        G2frame.colSigs += [esdList]
4172        colLabels += [expr]
4173        Types += [wg.GRID_VALUE_FLOAT+':10,3']
4174    #---- table build done -------------------------------------------------------------
4175
4176    # Make dict needed for creating & editing pseudovars (PSvarDict).
4177   
4178    name = histNames[0]
4179    parmDict = data[name].get('parmDict',{})
4180    PSvarDict = parmDict.copy()
4181    PSvarDict.update(sampleParms)
4182    UpdateParmDict(PSvarDict)
4183    # Also dicts of variables
4184    # for Parametric fitting from the data table
4185    parmDict = dict(zip(colLabels,zip(*G2frame.colList)[0])) # scratch dict w/all values in table
4186    parmDict.update({var:val for var,val in newCellDict.values()}) #  add varied reciprocal cell terms
4187    del parmDict['Use']
4188    name = histNames[0]
4189
4190    #******************************************************************************
4191    # create a set of values for example evaluation of pseudovars and
4192    # this does not work for refinements that have differing numbers of variables.
4193    #raise Exception
4194    VarDict = {}
4195    for i,var in enumerate(colLabels):
4196        if var in ['Use','Rwp',u'\u0394\u03C7\u00B2 (%)']: continue
4197        if G2frame.colList[i][0] is None:
4198            val,sig = firstValueDict.get(var,[None,None])
4199        elif G2frame.colSigs[i]:
4200            val,sig = G2frame.colList[i][0],G2frame.colSigs[i][0]
4201        else:
4202            val,sig = G2frame.colList[i][0],None
4203#        if val is None: continue
4204#        elif sig is None or sig == 0.:
4205#            VarDict[var] = val
4206        if striphist(var) not in Dlookup:
4207            VarDict[var] = val
4208    # add recip cell coeff. values
4209    VarDict.update({var:val for var,val in newCellDict.values()})
4210
4211    G2frame.dataFrame.currentGrids = []
4212    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
4213    G2frame.SeqTable = G2G.Table([list(cl) for cl in zip(*G2frame.colList)],     # convert from columns to rows
4214        colLabels=colLabels,rowLabels=histNames,types=Types)
4215    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
4216    #G2frame.dataDisplay.EnableEditing(False)
4217    # make all but first column read-only
4218    for c in range(1,len(colLabels)):
4219        for r in range(nRows):
4220            G2frame.dataDisplay.SetCellReadOnly(r,c)
4221    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, PlotSelect)
4222    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, SetLabelString)
4223    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
4224    G2frame.dataDisplay.SetMargins(0,0)
4225    G2frame.dataDisplay.AutoSizeColumns(False)
4226    if prevSize:
4227        G2frame.dataFrame.setSizePosLeft(prevSize)
4228    else:
4229        G2frame.dataFrame.setSizePosLeft([700,350])
4230    # highlight unconverged shifts
4231    if histNames[0][:4] not in ['SASD','IMG ','REFD',]:
4232        for row,name in enumerate(histNames):
4233            deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol)
4234            if deltaChi > 10.:
4235                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0))
4236            elif deltaChi > 1.0:
4237                G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0))
4238    G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip)
4239    G2frame.dataDisplay.SendSizeEvent() # resize needed on mac
4240    G2frame.dataDisplay.Refresh() # shows colored text on mac
4241   
4242################################################################################
4243#####  Main PWDR panel
4244################################################################################           
4245       
4246def UpdatePWHKPlot(G2frame,kind,item):
4247    '''Called when the histogram main tree entry is called. Displays the
4248    histogram weight factor, refinement statistics for the histogram
4249    and the range of data for a simulation.
4250
4251    Also invokes a plot of the histogram.
4252    '''
4253    def onEditSimRange(event):
4254        'Edit simulation range'
4255        inp = [
4256            min(data[1][0]),
4257            max(data[1][0]),
4258            None
4259            ]
4260        inp[2] = (inp[1] - inp[0])/(len(data[1][0])-1.)
4261        names = ('start angle', 'end angle', 'step size')
4262        dlg = G2G.ScrolledMultiEditor(
4263            G2frame,[inp] * len(inp), range(len(inp)), names,
4264            header='Edit simulation range',
4265            minvals=(0.001,0.001,0.0001),
4266            maxvals=(180.,180.,.1),
4267            )
4268        dlg.CenterOnParent()
4269        val = dlg.ShowModal()
4270        dlg.Destroy()
4271        if val != wx.ID_OK: return
4272        if inp[0] > inp[1]:
4273            end,start,step = inp
4274        else:               
4275            start,end,step = inp
4276        step = abs(step)
4277        N = int((end-start)/step)+1
4278        newdata = np.linspace(start,end,N,True)
4279        if len(newdata) < 2: return # too small a range - reject
4280        data[1] = [newdata,np.zeros_like(newdata),np.ones_like(newdata),
4281            np.zeros_like(newdata),np.zeros_like(newdata),np.zeros_like(newdata)]
4282        Tmin = newdata[0]
4283        Tmax = newdata[-1]
4284        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,item,'Limits'),
4285            [(Tmin,Tmax),[Tmin,Tmax]])
4286        UpdatePWHKPlot(G2frame,kind,item) # redisplay data screen
4287
4288    def OnPlot3DHKL(event):
4289        refList = data[1]['RefList']
4290        FoMax = np.max(refList.T[8+Super])
4291        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
4292        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
4293        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
4294        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
4295            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
4296            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
4297            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
4298        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
4299       
4300    def OnPlotAll3DHKL(event):
4301        choices = GetPatternTreeDataNames(G2frame,['HKLF',])
4302        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select reflection sets to plot',
4303            'Use data',choices)
4304        try:
4305            if dlg.ShowModal() == wx.ID_OK:
4306                refNames = [choices[i] for i in dlg.GetSelections()]
4307            else:
4308                return
4309        finally:
4310            dlg.Destroy()
4311        refList = np.zeros(0)
4312        for name in refNames:
4313            Id = GetPatternTreeItemId(G2frame,G2frame.root, name)
4314            reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
4315            if len(refList):
4316                refList = np.concatenate((refList,reflData['RefList']))
4317            else:
4318                refList = reflData['RefList']
4319           
4320        FoMax = np.max(refList.T[8+Super])
4321        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
4322        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
4323        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
4324        controls = {'Type' : 'Fosq','Iscale' : False,'HKLmax' : Hmax,'HKLmin' : Hmin,'Zone':False,'viewKey':'L',
4325            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
4326            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
4327            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
4328        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
4329                 
4330    def OnMergeHKL(event):
4331        Name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
4332        Inst = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,
4333            G2frame.PatternId,'Instrument Parameters'))
4334        CId = GetPatternTreeItemId(G2frame,G2frame.PatternId,'Comments')
4335        if CId:
4336            Comments = G2frame.PatternTree.GetItemPyData(CId)
4337        else:
4338            Comments = []
4339        refList = np.copy(data[1]['RefList'])
4340        Comments.append(' Merging %d reflections from %s'%(len(refList),Name))
4341        dlg = MergeDialog(G2frame,data)
4342        try:
4343            if dlg.ShowModal() == wx.ID_OK:
4344                Trans,Cent,Laue = dlg.GetSelection()
4345            else:
4346                return
4347        finally:
4348            dlg.Destroy()
4349        Super = data[1]['Super']
4350        refList,badRefs = G2lat.transposeHKLF(Trans,Super,refList)
4351        if len(badRefs):    #do I want to list badRefs?
4352            G2frame.ErrorDialog('Failed transformation','Matrix yields fractional hkl indices')
4353            return
4354        Comments.append(" Transformation M*H = H' applied; M=")
4355        Comments.append(str(Trans))
4356        refList = G2lat.LaueUnique(Laue,refList)
4357        dlg = wx.ProgressDialog('Build HKL dictonary','',len(refList)+1, 
4358            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
4359        HKLdict = {}
4360        for ih,hkl in enumerate(refList):
4361            if str(hkl[:3+Super]) not in HKLdict:
4362                HKLdict[str(hkl[:3+Super])] = [hkl[:3+Super],[hkl[3+Super:],]]
4363            else:
4364                HKLdict[str(hkl[:3+Super])][1].append(hkl[3+Super:])
4365            dlg.Update(ih)
4366        dlg.Destroy()
4367        mergeRef = []
4368        dlg = wx.ProgressDialog('Processing merge','',len(HKLdict)+1, 
4369            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
4370        sumDf = 0.
4371        sumFo = 0.
4372        for ih,hkl in enumerate(HKLdict):
4373            HKL = HKLdict[hkl]
4374            newHKL = list(HKL[0])+list(HKL[1][0])
4375            if len(HKL[1]) > 1:
4376                fos = np.array(HKL[1])
4377                wFo = 1/fos[:,3]**2
4378                Fo = np.average(fos[:,2],weights=wFo)
4379                std = np.std(fos[:,2])
4380                sig = np.sqrt(np.mean(fos[:,3])**2+std**2)
4381                sumFo += np.sum(fos[:,2])
4382                sumDf += np.sum(np.abs(fos[:,2]-Fo))
4383                dlg.Update(ih)
4384                newHKL[5+Super] = Fo
4385                newHKL[6+Super] = sig
4386                newHKL[8+Super] = Fo
4387            if newHKL[5+Super] > 0.:
4388                mergeRef.append(list(newHKL)) 
4389        dlg.Destroy()
4390        if Super:
4391            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,3),2),1),0)
4392        else:
4393            mergeRef = G2mth.sortArray(G2mth.sortArray(G2mth.sortArray(mergeRef,2),1),0)
4394        mergeRef = np.array(mergeRef)
4395        if sumFo:
4396            mtext = ' merge R = %6.2f%s for %d reflections in %s'%(100.*sumDf/sumFo,'%',mergeRef.shape[0],Laue)
4397            print mtext
4398            Comments.append(mtext)
4399        else:
4400            print 'nothing to merge for %s reflections'%(mergeRef.shape[0])
4401        HKLFlist = []
4402        newName = Name+' '+Laue
4403        if G2frame.PatternTree.GetCount():
4404            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
4405            while item:
4406                name = G2frame.PatternTree.GetItemText(item)
4407                if name.startswith('HKLF ') and name not in HKLFlist:
4408                    HKLFlist.append(name)
4409                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
4410        newName = G2obj.MakeUniqueLabel(newName,HKLFlist)
4411        newData = copy.deepcopy(data)
4412        newData[0]['ranId'] = ran.randint(0,sys.maxint)
4413        newData[1]['RefList'] = mergeRef
4414        Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=newName)
4415        G2frame.PatternTree.SetItemPyData(
4416            G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)
4417        G2frame.PatternTree.SetItemPyData(Id,newData)
4418        G2frame.PatternTree.SetItemPyData(
4419            G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
4420        G2frame.PatternTree.SetItemPyData(
4421            G2frame.PatternTree.AppendItem(Id,text='Reflection List'),{})  #dummy entry for GUI use
4422                   
4423    def OnErrorAnalysis(event):
4424        G2plt.PlotDeltSig(G2frame,kind)
4425       
4426#    def OnWtFactor(event):
4427#        event.Skip()
4428#        try:
4429#            val = float(wtval.GetValue())
4430#        except ValueError:
4431#            val = data[0]['wtFactor']
4432#        data[0]['wtFactor'] = val
4433#        wtval.SetValue('%.3f'%(val))
4434#       
4435#    def OnCompression(event):
4436#        data[0] = int(comp.GetValue())
4437       
4438    def onCopyPlotCtrls(event):
4439        '''Respond to menu item to copy multiple sections from a histogram.
4440        Need this here to pass on the G2frame object.
4441        '''
4442        G2pdG.CopyPlotCtrls(G2frame)
4443
4444    def onCopySelectedItems(event):
4445        '''Respond to menu item to copy multiple sections from a histogram.
4446        Need this here to pass on the G2frame object.
4447        '''
4448        G2pdG.CopySelectedHistItems(G2frame)
4449           
4450    data = G2frame.PatternTree.GetItemPyData(item)
4451#patches
4452    if not data:
4453        return
4454    if 'wtFactor' not in data[0]:
4455        data[0] = {'wtFactor':1.0}
4456#    if kind == 'PWDR' and 'Compression' not in data[0]:
4457#        data[0]['Compression'] = 1
4458    #if isinstance(data[1],list) and kind == 'HKLF':
4459    if 'list' in str(type(data[1])) and kind == 'HKLF':
4460        RefData = {'RefList':[],'FF':[]}
4461        for ref in data[1]:
4462            RefData['RefList'].append(ref[:11]+[ref[13],])
4463            RefData['FF'].append(ref[14])
4464        data[1] = RefData
4465        G2frame.PatternTree.SetItemPyData(item,data)
4466#end patches
4467    if G2frame.dataDisplay:
4468        G2frame.dataDisplay.Destroy()
4469    if kind in ['PWDR','SASD','REFD']:
4470        SetDataMenuBar(G2frame,G2frame.dataFrame.PWDRMenu)
4471        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
4472        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
4473        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopyPlotCtrls, id=wxID_PLOTCTRLCOPY)
4474    elif kind in ['HKLF',]:
4475        SetDataMenuBar(G2frame,G2frame.dataFrame.HKLFMenu)
4476        G2frame.dataFrame.Bind(wx.EVT_MENU, OnErrorAnalysis, id=wxID_PWDANALYSIS)
4477        G2frame.dataFrame.Bind(wx.EVT_MENU, OnMergeHKL, id=wxID_MERGEHKL)
4478        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=wxID_PWD3DHKLPLOT)
4479        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotAll3DHKL, id=wxID_3DALLHKLPLOT)
4480#        G2frame.dataFrame.Bind(wx.EVT_MENU, onCopySelectedItems, id=wxID_PWDCOPY)
4481    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
4482   
4483    mainSizer = wx.BoxSizer(wx.VERTICAL)
4484    mainSizer.Add((5,5),)
4485    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
4486    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,WACV)
4487    wtval = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data[0],'wtFactor',nDig=(10,3),min=1.e-9,typeHint=float)
4488#    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
4489#    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
4490#    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
4491    wtSizer.Add(wtval,0,WACV)
4492#    if kind == 'PWDR':         #possible future compression feature; NB above patch as well
4493#        wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Compression factor: '),0,WACV)
4494#        choice = ['1','2','3','4','5','6']
4495#        comp = wx.ComboBox(parent=G2frame.dataDisplay,choices=choice,
4496#            style=wx.CB_READONLY|wx.CB_DROPDOWN)
4497#        comp.SetValue(str(data[0]['Compression']))
4498#        comp.Bind(wx.EVT_COMBOBOX, OnCompression)
4499#        wtSizer.Add(comp,0,WACV)
4500    mainSizer.Add(wtSizer)
4501    if data[0].get('Dummy'):
4502        simSizer = wx.BoxSizer(wx.HORIZONTAL)
4503        Tmin = min(data[1][0])
4504        Tmax = max(data[1][0])
4505        num = len(data[1][0])
4506        step = (Tmax - Tmin)/(num-1)
4507        t = u'2\u03b8' # 2theta
4508        lbl =  u'Simulation range: {:.2f} to {:.2f} {:s}\nwith {:.4f} steps ({:d} points)'
4509        lbl += u'\n(Edit range resets observed intensities).'
4510        lbl = lbl.format(Tmin,Tmax,t,step,num)
4511        simSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,lbl),
4512                    0,WACV)
4513        but = wx.Button(G2frame.dataDisplay,wx.ID_ANY,"Edit range")
4514        but.Bind(wx.EVT_BUTTON,onEditSimRange)
4515        simSizer.Add(but,0,WACV)
4516        mainSizer.Add(simSizer)
4517    if 'Nobs' in data[0]:
4518        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
4519            ' Data residual wR: %.3f%% on %d observations'%(data[0]['wR'],data[0]['Nobs'])))
4520        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
4521            ' Durbin-Watson statistic: %.3f'%(data[0].get('Durbin-Watson',0.))))
4522        for value in data[0]:
4523            if 'Nref' in value:
4524                pfx = value.split('Nref')[0]
4525                name = data[0].get(pfx.split(':')[0]+'::Name','?')
4526                if 'SS' in value:
4527                    mainSizer.Add((5,5),)
4528                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For incommensurate phase '+name+':'))
4529                    for m,(Rf2,Rf,Nobs) in enumerate(zip(data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])):
4530                        mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
4531                            u' m = +/- %d: RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
4532                            (m,Rf2,Rf,Nobs)))
4533                else:
4534                    mainSizer.Add((5,5),)
4535                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' For phase '+name+':'))
4536                    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,
4537                        u' Unweighted phase residuals RF\u00b2: %.3f%%, RF: %.3f%% on %d reflections  '% \
4538                        (data[0][pfx+'Rf^2'],data[0][pfx+'Rf'],data[0][value])))
4539                   
4540    mainSizer.Add((5,5),)
4541    mainSizer.Layout()   
4542    G2frame.dataDisplay.SetSizer(mainSizer)
4543    Size = mainSizer.Fit(G2frame.dataFrame)
4544    Size[1] += 10
4545    G2frame.dataFrame.setSizePosLeft(Size)
4546    G2frame.PatternTree.SetItemPyData(item,data)
4547    G2frame.PatternId = item
4548    if kind in ['PWDR','SASD','REFD',]:
4549        NewPlot = True
4550        if 'xylim' in dir(G2frame):
4551            NewPlot = False
4552        G2plt.PlotPatterns(G2frame,plotType=kind,newPlot=NewPlot)
4553    elif kind == 'HKLF':
4554        Name = G2frame.PatternTree.GetItemText(item)
4555        phaseName = G2pdG.IsHistogramInAnyPhase(G2frame,Name)
4556        if phaseName:
4557            pId = GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
4558            phaseId =  GetPatternTreeItemId(G2frame,pId,phaseName)
4559            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
4560            Super = General.get('Super',0)
4561            SuperVec = General.get('SuperVec',[])
4562        else:
4563            Super = 0
4564            SuperVec = []       
4565        refList = data[1]['RefList']
4566#        GSASIIpath.IPyBreak()
4567        FoMax = np.max(refList.T[5+data[1].get('Super',0)])
4568        page = G2frame.G2plotNB.nb.GetSelection()
4569        tab = ''
4570        if page >= 0:
4571            tab = G2frame.G2plotNB.nb.GetPageText(page)
4572        if '3D' in tab:
4573            Page = G2frame.G2plotNB.nb.GetPage(page)
4574            controls = Page.controls
4575            G2plt.Plot3DSngl(G2frame,newPlot=False,Data=controls,hklRef=refList,Title=phaseName)
4576        else:
4577            controls = {'Type' : 'Fo','ifFc' : True,     
4578                'HKLmax' : [int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))],
4579                'HKLmin' : [int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))],
4580                'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
4581            G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList)
4582                 
4583################################################################################
4584#####  Pattern tree routines
4585################################################################################           
4586       
4587def GetPatternTreeDataNames(G2frame,dataTypes):
4588    '''Finds all items in tree that match a 4 character prefix
4589   
4590    :param wx.Frame G2frame: Data tree frame object
4591    :param list dataTypes: Contains one or more data tree item types to be matched
4592      such as ['IMG '] or ['PWDR','HKLF']
4593    :returns: a list of tree item names for the matching items 
4594    '''
4595    names = []
4596    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
4597    while item:
4598        name = G2frame.PatternTree.GetItemText(item)
4599        if name[:4] in dataTypes:
4600            names.append(name)
4601        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
4602    return names
4603                         
4604def GetPatternTreeItemId(G2frame, parentId, itemText):
4605    '''Find the tree item that matches the text in itemText starting with parentId
4606
4607    :param wx.Frame G2frame: Data tree frame object
4608    :param wx.TreeItemId parentId: tree item to start search with
4609    :param str itemText: text for tree item
4610    '''
4611    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
4612    while item:
4613        if G2frame.PatternTree.GetItemText(item) == itemText:
4614            return item
4615        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
4616    return 0               
4617
4618def SelectDataTreeItem(G2frame,item):
4619    '''Called from :meth:`GSASII.GSASII.OnDataTreeSelChanged` when a item is selected on the tree.
4620    Also called from GSASII.OnPatternTreeEndDrag, OnAddPhase -- might be better to select item, triggering
4621    the the bind to SelectDataTreeItem
4622
4623    Also Called in GSASIIphsGUI.UpdatePhaseData by OnTransform callback.
4624    '''
4625    if G2frame.PickIdText == G2frame.GetTreeItemsList(item): # don't redo the current data tree item
4626        return
4627    oldPage = None # will be set later if already on a Phase item
4628    if G2frame.dataFrame:
4629        # save or finish processing of outstanding events
4630        for grid in G2frame.dataFrame.currentGrids:  # complete any open wx.Grid edits
4631            #if GSASIIpath.GetConfigValue('debug'): print 'Testing grid edit in',grid
4632            try: 
4633                if grid.IsCellEditControlEnabled(): # complete any grid edits in progress
4634                    if GSASIIpath.GetConfigValue('debug'): print 'Completing grid edit in',grid
4635                    grid.HideCellEditControl()
4636                    grid.DisableCellEditControl()
4637            except:
4638                pass
4639        if G2frame.dataFrame.GetLabel() == 'Comments': # save any recently entered comments
4640            try:
4641                data = [G2frame.dataDisplay.GetValue()]
4642                G2frame.dataDisplay.Clear() 
4643                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
4644                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
4645            except:     #clumsy but avoids dead window problem when opening another project
4646                pass
4647        elif G2frame.dataFrame.GetLabel() == 'Notebook': # save any recent notebook entries
4648            try:
4649                data = [G2frame.dataDisplay.GetValue()]
4650                G2frame.dataDisplay.Clear() 
4651                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
4652                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
4653            except:     #clumsy but avoids dead window problem when opening another project
4654                pass
4655        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
4656            if G2frame.dataDisplay: 
4657                oldPage = G2frame.dataDisplay.GetSelection()
4658        G2frame.dataFrame.Clear()
4659        G2frame.dataFrame.SetLabel('')
4660    else:
4661        #create the frame for the data item window
4662        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
4663        G2frame.dataFrame.PhaseUserSize = None
4664       
4665    SetDataMenuBar(G2frame)
4666    G2frame.dataFrame.Raise()           
4667    G2frame.dataFrame.currentGrids = [] # this will contain pointers to a grid placed in the frame
4668    G2frame.PickId = item
4669    G2frame.PickIdText = None
4670    parentID = G2frame.root
4671    #for i in G2frame.ExportPattern: i.Enable(False)
4672    defWid = [250,150]
4673    if item == G2frame.root:
4674        G2frame.dataFrame.helpKey = "Data tree"
4675        G2frame.dataFrame.setSizePosLeft(defWid)
4676        wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
4677                    value='Select an item from the tree to see/edit parameters')       
4678        return
4679    else:
4680        parentID = G2frame.PatternTree.GetItemParent(item)
4681        # save name of calling tree item for help. N.B. may want to override this later
4682        prfx = G2frame.PatternTree.GetItemText(item).split()[0]
4683        prfx1 = G2frame.PatternTree.GetItemText(parentID).split()[0]
4684        if prfx in ('IMG','PKS','PWDR','SASD','HKLF','PDF','refd',):
4685            G2frame.dataFrame.helpKey = prfx
4686        elif prfx1 in ('IMG','PKS','PWDR','SASD','HKLF','PDF','REFD',):
4687            suffix = G2frame.PatternTree.GetItemText(item)
4688            suffix1 = suffix.split()[0]
4689            if '(Q)' in suffix1 or '(R)' in suffix1: suffix = suffix1
4690            G2frame.dataFrame.helpKey = prfx1 + '_' + suffix
4691        else:
4692            G2frame.dataFrame.helpKey = G2frame.PatternTree.GetItemText(item) # save name of calling tree item for help
4693    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
4694        G2frame.PatternId = 0
4695        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
4696            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
4697            #for i in G2frame.ExportPattern: i.Enable(False)
4698            data = G2frame.PatternTree.GetItemPyData(item)
4699            UpdateNotebook(G2frame,data)
4700        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
4701            #for i in G2frame.ExportPattern: i.Enable(False)
4702            data = G2frame.PatternTree.GetItemPyData(item)
4703            if not data:           #fill in defaults
4704                data = copy.copy(G2obj.DefaultControls)    #least squares controls
4705                G2frame.PatternTree.SetItemPyData(item,data)                             
4706            for i in G2frame.Refine: i.Enable(True)
4707            G2frame.EnableSeqRefineMenu()
4708            UpdateControls(G2frame,data)
4709        elif G2frame.PatternTree.GetItemText(item).startswith('Sequential '):
4710            G2frame.dataFrame.helpKey = 'Sequential'  # for now all sequential refinements are documented in one place
4711            data = G2frame.PatternTree.GetItemPyData(item)
4712            UpdateSeqResults(G2frame,data)
4713        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
4714            data = G2frame.PatternTree.GetItemPyData(item)
4715            G2frame.dataFrame.setSizePosLeft(defWid)
4716            text = ''
4717            if 'Rvals' in data:
4718                Nvars = len(data['varyList'])
4719                Rvals = data['Rvals']
4720                text = '\nFinal residuals: \nwR = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
4721                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
4722                if 'lamMax' in Rvals:
4723                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
4724            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
4725                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
4726            G2plt.PlotCovariance(G2frame,data)
4727        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
4728            data = G2frame.PatternTree.GetItemPyData(item)
4729            G2cnstG.UpdateConstraints(G2frame,data)
4730        elif G2frame.PatternTree.GetItemText(item) == 'Rigid bodies':
4731            data = G2frame.PatternTree.GetItemPyData(item)
4732            G2cnstG.UpdateRigidBodies(G2frame,data)
4733        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
4734            data = G2frame.PatternTree.GetItemPyData(item)
4735            Phases = G2frame.GetPhaseData()
4736            phaseName = ''
4737            if Phases:
4738                phaseName = Phases.keys()[0]
4739            G2frame.dataFrame.setSizePosLeft(defWid)
4740            G2restG.UpdateRestraints(G2frame,data,Phases,phaseName)
4741        elif G2frame.PatternTree.GetItemText(item).startswith('IMG '):
4742            G2frame.Image = item
4743            G2frame.dataFrame.SetTitle('Image Data')
4744            data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(
4745                G2frame,item,'Image Controls'))
4746            G2imG.UpdateImageData(G2frame,data)
4747            G2plt.PlotImage(G2frame,newPlot=True)
4748        elif G2frame.PatternTree.GetItemText(item).startswith('PKS '):
4749            G2plt.PlotPowderLines(G2frame)
4750        elif G2frame.PatternTree.GetItemText(item).startswith('PWDR '):
4751            G2frame.PatternId = item
4752            #for i in G2frame.ExportPattern: i.Enable(True)
4753            if G2frame.EnablePlot:
4754                UpdatePWHKPlot(G2frame,'PWDR',item)
4755        elif G2frame.PatternTree.GetItemText(item).startswith('SASD '):
4756            G2frame.PatternId = item
4757            #for i in G2frame.ExportPattern: i.Enable(True)
4758            if G2frame.EnablePlot:
4759                UpdatePWHKPlot(G2frame,'SASD',item)
4760        elif G2frame.PatternTree.GetItemText(item).startswith('REFD '):
4761            G2frame.PatternId = item
4762            #for i in G2frame.ExportPattern: i.Enable(True)
4763            if G2frame.EnablePlot:
4764                UpdatePWHKPlot(G2frame,'REFD',item)
4765        elif G2frame.PatternTree.GetItemText(item).startswith('HKLF '):
4766            G2frame.Sngl = True
4767            UpdatePWHKPlot(G2frame,'HKLF',item)
4768        elif G2frame.PatternTree.GetItemText(item).startswith('PDF '):
4769            G2frame.PatternId = item
4770            for i in G2frame.ExportPDF: i.Enable(True) # this should be done on .gpx load; is done on OnMakePDFs (GSASII.py)
4771            data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,item,'PDF Controls'))
4772            G2pdG.UpdatePDFGrid(G2frame,data)
4773            if len(data['G(R)']):
4774                G2plt.PlotISFG(G2frame,data,plotType='G(R)')
4775        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
4776            G2frame.dataFrame.setSizePosLeft(defWid)
4777            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
4778                value='Select one phase to see its parameters')           
4779    elif G2frame.PatternTree.GetItemText(item) == 'PDF Peaks':
4780        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4781        peaks = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Peaks'))
4782        data = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,G2frame.PatternId,'PDF Controls'))
4783        G2pdG.UpdatePDFPeaks(G2frame,peaks,data)
4784        if len(data['G(R)']):
4785            G2plt.PlotISFG(G2frame,data,plotType='G(R)',newPlot=True,peaks=peaks)           
4786    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
4787        for i in G2frame.ExportPDF: i.Enable(True) # this should be done on .gpx load; is done on OnMakePDFs (GSASII.py)
4788        G2frame.dataFrame.helpKey = G2frame.PatternTree.GetItemText(item) # special treatment to avoid PDF_PDF Controls
4789        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4790        data = G2frame.PatternTree.GetItemPyData(item)
4791        G2pdG.UpdatePDFGrid(G2frame,data)
4792        if len(data['G(R)']):
4793            if 'I(Q)' in data:  G2plt.PlotISFG(G2frame,data,plotType='I(Q)')
4794            if 'S(Q)' in data:  G2plt.PlotISFG(G2frame,data,plotType='S(Q)')
4795            if 'F(Q)' in data:  G2plt.PlotISFG(G2frame,data,plotType='F(Q)')
4796            G2plt.PlotISFG(G2frame,data,plotType='G(R)')
4797    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
4798        data = G2frame.PatternTree.GetItemPyData(item)
4799        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
4800    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
4801        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
4802        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4803        data = G2frame.PatternTree.GetItemPyData(item)
4804        UpdateComments(G2frame,data)
4805    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
4806        G2frame.dataFrame.SetTitle('Image Controls')
4807        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4808        masks = G2frame.PatternTree.GetItemPyData(
4809            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
4810        data = G2frame.PatternTree.GetItemPyData(item)
4811        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4812        G2imG.UpdateImageControls(G2frame,data,masks)
4813        G2plt.PlotImage(G2frame,newPlot=False)
4814    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
4815        G2frame.dataFrame.SetTitle('Masks')
4816        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4817        masks = G2frame.PatternTree.GetItemPyData(item)
4818        data = G2frame.PatternTree.GetItemPyData(
4819            GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4820        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data)
4821        G2imG.UpdateMasks(G2frame,masks)
4822        G2plt.PlotImage(G2frame,newPlot=False)
4823    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
4824        G2frame.dataFrame.SetTitle('Stress/Strain')
4825        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
4826        data = G2frame.PatternTree.GetItemPyData(
4827            GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4828        G2frame.ImageZ = G2imG.GetImageZ(G2frame,data,newRange=False)
4829        strsta = G2frame.PatternTree.GetItemPyData(item)
4830        G2plt.PlotStrain(G2frame,strsta,newPlot=True)
4831        G2plt.PlotImage(G2frame,newPlot=False)
4832        G2imG.UpdateStressStrain(G2frame,strsta)
4833    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
4834        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4835        for i in G2frame.ExportPeakList: i.Enable(True)
4836        data = G2frame.PatternTree.GetItemPyData(item)
4837#patch
4838        if 'list' in str(type(data)):
4839            data = {'peaks':data,'sigDict':{}}
4840            G2frame.PatternTree.SetItemPyData(item,data)
4841#end patch
4842        G2pdG.UpdatePeakGrid(G2frame,data)
4843        G2plt.PlotPatterns(G2frame)
4844    elif G2frame.PatternTree.GetItemText(item) == 'Background':
4845        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4846        data = G2frame.PatternTree.GetItemPyData(item)
4847        G2pdG.UpdateBackground(G2frame,data)
4848        G2plt.PlotPatterns(G2frame)
4849    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
4850        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4851        datatype = G2frame.PatternTree.GetItemText(G2frame.PatternId)[:4]
4852        data = G2frame.PatternTree.GetItemPyData(item)
4853        G2pdG.UpdateLimitsGrid(G2frame,data,datatype)
4854        G2plt.PlotPatterns(G2frame,plotType=datatype)
4855    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
4856        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4857        data = G2frame.PatternTree.GetItemPyData(item)[0]
4858        G2pdG.UpdateInstrumentGrid(G2frame,data)
4859        if 'P' in data['Type'][0]:          #powder data only
4860            G2plt.PlotPeakWidths(G2frame)
4861    elif G2frame.PatternTree.GetItemText(item) == 'Models':
4862        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4863        data = G2frame.PatternTree.GetItemPyData(item)
4864        if prfx1 == 'SASD':
4865            G2pdG.UpdateModelsGrid(G2frame,data)
4866        elif prfx1 == 'REFD':
4867            G2pdG.UpdateREFDModelsGrid(G2frame,data)
4868        G2plt.PlotPatterns(G2frame,plotType=prfx1)
4869        if prfx1 == 'SASD' and len(data['Size']['Distribution']):
4870            G2plt.PlotSASDSizeDist(G2frame)
4871    elif G2frame.PatternTree.GetItemText(item) == 'Substances':
4872        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4873        data = G2frame.PatternTree.GetItemPyData(item)
4874        G2pdG.UpdateSubstanceGrid(G2frame,data)
4875    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
4876        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4877        data = G2frame.PatternTree.GetItemPyData(item)
4878        datatype = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[2][:4]
4879
4880        if 'Temperature' not in data:           #temp fix for old gpx files
4881            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
4882                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,
4883                    'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
4884                    'Gonio. radius':200.0}
4885            G2frame.PatternTree.SetItemPyData(item,data)
4886   
4887        G2pdG.UpdateSampleGrid(G2frame,data)
4888        G2plt.PlotPatterns(G2frame,plotType=datatype)
4889    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
4890        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4891        for i in G2frame.ExportPeakList: i.Enable(True)
4892        data = G2frame.PatternTree.GetItemPyData(item)
4893#patch
4894        if len(data) != 2:
4895            data = [data,[]]
4896            G2frame.PatternTree.SetItemPyData(item,data)
4897#end patch
4898        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
4899        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4900            G2plt.PlotPowderLines(G2frame)
4901        else:
4902            G2plt.PlotPatterns(G2frame)
4903    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
4904        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4905        data = G2frame.PatternTree.GetItemPyData(item)
4906        if not data:
4907            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
4908            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
4909            data.append([])                                 #empty cell list
4910            data.append([])                                 #empty dmin
4911            data.append({})                                 #empty superlattice stuff
4912            G2frame.PatternTree.SetItemPyData(item,data)                             
4913#patch
4914        if len(data) < 5:
4915            data.append({'Use':False,'ModVec':[0,0,0.1],'maxH':1,'ssSymb':''})                                 #empty superlattice stuff
4916            G2frame.PatternTree.SetItemPyData(item,data) 
4917#end patch
4918        G2pdG.UpdateUnitCellsGrid(G2frame,data)
4919        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
4920            G2plt.PlotPowderLines(G2frame)
4921        else:
4922            G2plt.PlotPatterns(G2frame)
4923    elif G2frame.PatternTree.GetItemText(item) == 'Reflection Lists':   #powder reflections
4924        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4925        data = G2frame.PatternTree.GetItemPyData(item)
4926        G2frame.RefList = ''
4927        if len(data):
4928            G2frame.RefList = data.keys()[0]
4929        G2pdG.UpdateReflectionGrid(G2frame,data)
4930        G2plt.PlotPatterns(G2frame)
4931    elif G2frame.PatternTree.GetItemText(item) == 'Reflection List':    #HKLF reflections
4932        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
4933        name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
4934        data = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
4935        G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
4936
4937    if G2frame.PickId:
4938        G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
4939    G2frame.dataFrame.Raise()
4940
4941def SetDataMenuBar(G2frame,menu=None):
4942    '''Set the menu for the data frame. On the Mac put this
4943    menu for the data tree window instead.
4944
4945    Note that data frame items do not have menus, for these (menu=None)
4946    display a blank menu or on the Mac display the standard menu for
4947    the data tree window.
4948    '''
4949    if sys.platform == "darwin":
4950        if menu is None:
4951            G2frame.SetMenuBar(G2frame.GSASIIMenu)
4952        else:
4953            G2frame.SetMenuBar(menu)
4954    else:
4955        if menu is None:
4956            G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
4957        else:
4958            G2frame.dataFrame.SetMenuBar(menu)
4959
4960def HowDidIgetHere():
4961    '''Show a traceback with calls that brought us to the current location.
4962    Used for debugging.
4963    '''
4964    import traceback
4965    print 70*'*'   
4966    for i in traceback.format_list(traceback.extract_stack()[:-1]): print(i.strip().rstrip())
4967    print 70*'*'   
4968       
Note: See TracBrowser for help on using the repository browser.