source: trunk/GSASIIgrid.py @ 2229

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

Add Atom Rotate option

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