source: trunk/GSASIIgrid.py @ 2175

Last change on this file since 2175 was 2175, checked in by vondreele, 6 years ago

modify DIFFaXDialog - more parameters
add selected are plot as a pylab plot

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