source: trunk/GSASIIgrid.py @ 2198

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

selected PWDR plot width is retained after Refine, but not if some other plot is selected. Then it reverts to full width
fix problem of PlotCovariance? changing the status bar field widths; had to force the width after a SetFields?

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