source: trunk/GSASIIgrid.py @ 2127

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

Add Merge dialog (not working yet)
Fix L & G+L peak width plots per Wenqian Xu's comments
Make '+' powder plot command a toggle

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