source: trunk/GSASIIgrid.py @ 2018

Last change on this file since 2018 was 2016, checked in by toby, 10 years ago

force zoom out on clicking any image tree click

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