source: trunk/GSASIIseqGUI.py @ 4881

Last change on this file since 4881 was 4872, checked in by toby, 4 years ago

export project to giant ASCII file; add CIF tutorial; set misc svn flags

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 70.3 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIseqGUI - Sequential Results Display routines
3########### SVN repository information ###################
4# $Date: 2021-04-03 21:04:54 +0000 (Sat, 03 Apr 2021) $
5# $Author: vondreele $
6# $Revision: 4872 $
7# $URL: trunk/GSASIIseqGUI.py $
8# $Id: GSASIIseqGUI.py 4872 2021-04-03 21:04:54Z vondreele $
9########### SVN repository information ###################
10'''
11*GSASIIseqGUI: Sequential Results GUI*
12----------------------------------------
13
14Module that defines GUI routines and classes for the main GUI Frame (window)
15and the main routines that define the GSAS-II tree panel and much of the
16data editing panel.
17'''
18from __future__ import division, print_function
19import platform
20#import time
21#import math
22#import random as ran
23import copy
24#import sys
25#import os
26#import inspect
27
28#import re
29import numpy as np
30import numpy.ma as ma
31#import scipy as sp
32import scipy.optimize as so
33try:
34    import wx
35    import wx.grid as wg
36#    import wx.lib.scrolledpanel as wxscroll
37except ImportError:
38    pass
39import GSASIIpath
40GSASIIpath.SetVersionNumber("$Revision: 4872 $")
41import GSASIImath as G2mth
42import GSASIIIO as G2IO
43#import GSASIIfiles as G2fil
44import GSASIIdataGUI as G2gd
45import GSASIIstrIO as G2stIO
46import GSASIIlattice as G2lat
47import GSASIIplot as G2plt
48#import GSASIIpwdGUI as G2pdG
49#import GSASIIimgGUI as G2imG
50#import GSASIIphsGUI as G2phG
51#import GSASIIspc as G2spc
52import GSASIImapvars as G2mv
53#import GSASIIconstrGUI as G2cnstG
54#import GSASIIrestrGUI as G2restG
55import GSASIIobj as G2obj
56import GSASIIexprGUI as G2exG
57#import GSASIIlog as log
58import GSASIIctrlGUI as G2G
59#import GSASIIElem as G2elem
60#import GSASIIpwd as G2pwd
61#import GSASIIstrMain as G2stMn
62#import defaultIparms as dI
63#import GSASIIfpaGUI as G2fpa
64
65#####  Display of Sequential Results ##########################################
66def UpdateSeqResults(G2frame,data,prevSize=None):
67    """
68    Called when the Sequential Results data tree entry is selected
69    to show results from a sequential refinement.
70   
71    :param wx.Frame G2frame: main GSAS-II data tree windows
72
73    :param dict data: a dictionary containing the following items: 
74
75            * 'histNames' - list of histogram names in order as processed by Sequential Refinement
76            * 'varyList' - list of variables - identical over all refinements in sequence
77              note that this is the original list of variables, prior to processing
78              constraints.
79            * 'variableLabels' -- a dict of labels to be applied to each parameter
80              (this is created as an empty dict if not present in data).
81            * keyed by histName - dictionaries for all data sets processed, which contains:
82
83              * 'variables'- result[0] from leastsq call
84              * 'varyList' - list of variables passed to leastsq call (not same as above)
85              * 'sig' - esds for variables
86              * 'covMatrix' - covariance matrix from individual refinement
87              * 'title' - histogram name; same as dict item name
88              * 'newAtomDict' - new atom parameters after shifts applied
89              * 'newCellDict' - refined cell parameters after shifts to A0-A5 from Dij terms applied'
90    """
91    def GetSampleParms():
92        '''Make a dictionary of the sample parameters that are not the same over the
93        refinement series. Controls here is local
94        '''
95        if 'IMG' in histNames[0]:
96            sampleParmDict = {'Sample load':[],}
97        else:
98            sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[],
99                'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[],
100                'Chi':[],'Phi':[],'Azimuth':[],}
101        Controls = G2frame.GPXtree.GetItemPyData(
102            G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls'))
103        sampleParm = {}
104        for name in histNames:
105            if 'IMG' in name:
106                if name not in data:
107                    continue
108                for item in sampleParmDict:
109                    sampleParmDict[item].append(data[name]['parmDict'].get(item,0))
110            else:
111                if 'PDF' in name:
112                    name = 'PWDR' + name[4:]
113                Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,name)
114                if Id:
115                    sampleData = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id,'Sample Parameters'))
116                    for item in sampleParmDict:
117                        sampleParmDict[item].append(sampleData.get(item,0))
118        for item in sampleParmDict:
119            if sampleParmDict[item]:
120                frstValue = sampleParmDict[item][0]
121                if np.any(np.array(sampleParmDict[item])-frstValue):
122                    if item.startswith('FreePrm'):
123                        sampleParm[Controls[item]] = sampleParmDict[item]
124                    else:
125                        sampleParm[item] = sampleParmDict[item]
126        return sampleParm
127
128    def GetColumnInfo(col):
129        '''returns column label, lists of values and errors (or None) for each column in the table
130        for plotting. The column label is reformatted from Unicode to MatPlotLib encoding
131        '''
132        colName = G2frame.SeqTable.GetColLabelValue(col)
133        plotName = variableLabels.get(colName,colName)
134        plotName = plotSpCharFix(plotName)
135        return plotName,G2frame.colList[col],G2frame.colSigs[col]
136           
137    def PlotSelectedColRow(calltyp=''):
138        '''Called to plot a selected column or row by clicking or
139        double-clicking on a row or column label. N.B. This is called
140        after the event is processed so that the column or row has been
141        selected.
142
143        :param str calltyp: ='single'/'double', specifies if this was
144          a single- or double-click, where a single click on row
145          plots histogram; Double click on row plots V-C matrix;
146          Single or double click on column: plots values in column
147        '''
148        cols = G2frame.dataDisplay.GetSelectedCols()
149        rows = G2frame.dataDisplay.GetSelectedRows()
150        if cols:
151            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
152        elif rows and calltyp == 'single':
153            name = histNames[rows[0]]       #only does 1st one selected
154            if not name.startswith('PWDR'): return 
155            pickId = G2frame.PickId
156            G2frame.PickId = G2frame.PatternId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, name)
157            G2plt.PlotPatterns(G2frame,newPlot=False,plotType='PWDR')
158            G2frame.PickId = pickId
159        elif rows:
160            name = histNames[rows[0]]       #only does 1st one selected
161            G2plt.PlotCovariance(G2frame,data[name])
162        else:
163            G2frame.ErrorDialog(
164                'Select row or columns',
165                'Nothing selected in table. Click on column or row label(s) to plot. N.B. Grid selection can be a bit funky.'
166                )
167       
168    def PlotSSelect(event):
169        'Called by a single click on a row or column label. '
170        event.Skip()
171        wx.CallAfter(PlotSelectedColRow,'single')
172       
173    def PlotSelect(event):
174        'Called by a double-click on a row or column label'
175        event.Skip()
176        wx.CallAfter(PlotSelectedColRow,'double')
177       
178    def OnKeyUp(event):
179        event.Skip()
180        wx.CallAfter(PlotSelectedColRow,'single')
181           
182    def OnPlotSelSeq(event):
183        'plot the selected columns or row from menu command'
184        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
185        rows = G2frame.dataDisplay.GetSelectedRows()
186        if cols:
187            G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
188        elif rows:
189            name = histNames[rows[0]]       #only does 1st one selected
190            G2plt.PlotCovariance(G2frame,data[name])
191        else:
192            G2frame.ErrorDialog('Select columns',
193                'No columns or rows selected in table. Click on row or column labels to select fields for plotting.')
194               
195    def OnAveSelSeq(event):
196        'average the selected columns from menu command'
197        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
198        useCol =  ~np.array(G2frame.SeqTable.GetColValues(1),dtype=bool)
199        if cols:
200            for col in cols:
201                items = GetColumnInfo(col)[1]
202                noneMask = np.array([item is None for item in items])
203                info = ma.array(items,mask=useCol+noneMask)
204                ave = ma.mean(ma.compressed(info))
205                sig = ma.std(ma.compressed(info))
206                print (u' Average for '+G2frame.SeqTable.GetColLabelValue(col)+u': '+'%.6g'%(ave)+u' +/- '+u'%.6g'%(sig))
207        else:
208            G2frame.ErrorDialog('Select columns',
209                'No columns selected in table. Click on column labels to select fields for averaging.')
210           
211    def OnSelectUse(event):
212        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select rows to use','Select rows',histNames)
213        sellist = [i for i,item in enumerate(G2frame.colList[1]) if item]
214        dlg.SetSelections(sellist)
215        if dlg.ShowModal() == wx.ID_OK:
216            sellist = dlg.GetSelections()
217            for row in range(G2frame.SeqTable.GetNumberRows()):
218                G2frame.SeqTable.SetValue(row,1,False)
219                G2frame.colList[1][row] = False
220            for row in sellist:
221                G2frame.SeqTable.SetValue(row,1,True)
222                G2frame.colList[1][row] = True
223            G2frame.dataDisplay.ForceRefresh()
224        dlg.Destroy()
225               
226    def OnRenameSelSeq(event):
227        cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
228        colNames = [G2frame.SeqTable.GetColLabelValue(c) for c in cols]
229        newNames = colNames[:]
230        for i,name in enumerate(colNames):
231            if name in variableLabels:
232                newNames[i] = variableLabels[name]
233        if not cols:
234            G2frame.ErrorDialog('Select columns',
235                'No columns selected in table. Click on column labels to select fields for rename.')
236            return
237        dlg = G2G.MultiStringDialog(G2frame.dataDisplay,'Set column names',colNames,newNames)
238        if dlg.Show():
239            newNames = dlg.GetValues()           
240            variableLabels.update(dict(zip(colNames,newNames)))
241        data['variableLabels'] = variableLabels
242        dlg.Destroy()
243        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
244        G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
245           
246    def OnSaveSelSeqCSV(event):
247        'export the selected columns to a .csv file from menu command'
248        OnSaveSelSeq(event,csv=True)
249       
250    def OnSaveSeqCSV(event):
251        'export all columns to a .csv file from menu command'
252        OnSaveSelSeq(event,csv=True,allcols=True)
253       
254    def OnSaveSelSeq(event,csv=False,allcols=False):
255        'export the selected columns to a .txt or .csv file from menu command'
256        def WriteLine(line):
257            if '2' in platform.python_version_tuple()[0]:
258                SeqFile.write(G2obj.StripUnicode(line))
259            else:
260                SeqFile.write(line)
261               
262        def WriteCSV():
263            def WriteList(headerItems):
264                line = ''
265                for lbl in headerItems:
266                    if line: line += ','
267                    line += '"'+lbl+'"'
268                return line
269            head = ['name']
270            for col in cols:
271                # Excel does not like unicode
272                item = G2obj.StripUnicode(G2frame.SeqTable.GetColLabelValue(col))
273                if col in havesig:
274                    head += [item,'esd-'+item]
275                else:
276                    head += [item]
277            WriteLine(WriteList(head)+'\n')
278            for row,name in enumerate(saveNames):
279                line = '"'+saveNames[row]+'"'
280                for col in cols:
281                    if saveData[col][row] is None:
282                        if col in havesig:
283#                            line += ',0.0,0.0'
284                            line += ',,'
285                        else:
286#                            line += ',0.0'
287                            line += ','
288                    else:
289                        if col in havesig:
290                            line += ','+str(saveData[col][row])+','+str(saveSigs[col][row])
291                        else:   
292                            line += ','+str(saveData[col][row])
293                WriteLine(line+'\n')
294        def WriteSeq():
295            lenName = len(saveNames[0])
296            line = %s  '%('name'.center(lenName))
297            for col in cols:
298                item = G2frame.SeqTable.GetColLabelValue(col)
299                if col in havesig:
300                    line += ' %12s %12s '%(item.center(12),'esd'.center(12))
301                else:
302                    line += ' %12s '%(item.center(12))
303            WriteLine(line+'\n')
304            for row,name in enumerate(saveNames):
305                line = " '%s' "%(saveNames[row])
306                for col in cols:
307                    if col in havesig:
308                        try:
309                            line += ' %12.6f %12.6f '%(saveData[col][row],saveSigs[col][row])
310                        except TypeError:
311                            line += '                           '
312                    else:
313                        try:
314                            line += ' %12.6f '%saveData[col][row]
315                        except TypeError:
316                            line += '              '
317                WriteLine(line+'\n')
318
319        # start of OnSaveSelSeq code
320        if allcols:
321            cols = range(G2frame.SeqTable.GetNumberCols())
322        else:
323            cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order
324        nrows = G2frame.SeqTable.GetNumberRows()
325        if not cols:
326            choices = [G2frame.SeqTable.GetColLabelValue(r) for r in range(G2frame.SeqTable.GetNumberCols())]
327            dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select columns to write',
328                'select columns',choices)
329            #dlg.SetSelections()
330            if dlg.ShowModal() == wx.ID_OK:
331                cols = dlg.GetSelections()
332                dlg.Destroy()
333            else:
334                dlg.Destroy()
335                return
336            #G2frame.ErrorDialog('Select columns',
337            #                 'No columns selected in table. Click on column labels to select fields for output.')
338            #return
339        saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(nrows)]
340        saveData = {}
341        saveSigs = {}
342        havesig = []
343        for col in cols:
344            name,vals,sigs = GetColumnInfo(col)
345            saveData[col] = vals
346            if sigs:
347                havesig.append(col)
348                saveSigs[col] = sigs
349        if csv:
350            wild = 'CSV output file (*.csv)|*.csv'
351        else:
352            wild = 'Text output file (*.txt)|*.txt'
353        pth = G2G.GetExportPath(G2frame)
354        dlg = wx.FileDialog(
355            G2frame,
356            'Choose text output file for your selection', pth, '', 
357            wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
358        try:
359            if dlg.ShowModal() == wx.ID_OK:
360                SeqTextFile = dlg.GetPath()
361                SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) 
362                SeqFile = open(SeqTextFile,'w')
363                if csv:
364                    WriteCSV()
365                else:
366                    WriteSeq()
367                SeqFile.close()
368        finally:
369            dlg.Destroy()
370               
371    def striphist(var,insChar=''):
372        'strip a histogram number from a var name'
373        sv = var.split(':')
374        if len(sv) <= 1: return var
375        if sv[1]:
376            sv[1] = insChar
377        return ':'.join(sv)
378       
379    def plotSpCharFix(lbl):
380        'Change selected unicode characters to their matplotlib equivalent'
381        for u,p in [
382            (u'\u03B1',r'$\alpha$'),
383            (u'\u03B2',r'$\beta$'),
384            (u'\u03B3',r'$\gamma$'),
385            (u'\u0394\u03C7',r'$\Delta\chi$'),
386            ]:
387            lbl = lbl.replace(u,p)
388        return lbl
389   
390    def SelectXaxis():
391        'returns a selected column number (or None) as the X-axis selection'
392        ncols = G2frame.SeqTable.GetNumberCols()
393        colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)]
394        dlg = G2G.G2SingleChoiceDialog(
395            G2frame.dataDisplay,
396            'Select x-axis parameter for\nplot (Cancel=sequence #)',
397            'Select X-axis',
398            colNames)
399        try:
400            if dlg.ShowModal() == wx.ID_OK:
401                col = dlg.GetSelection()
402            else:
403                col = None
404        finally:
405            dlg.Destroy()
406        return col
407   
408    def EnablePseudoVarMenus():
409        'Enables or disables the PseudoVar menu items that require existing defs'
410        if data['SeqPseudoVars']:
411            val = True
412        else:
413            val = False
414        G2frame.dataWindow.SequentialPvars.Enable(G2G.wxID_DELSEQVAR,val)
415        G2frame.dataWindow.SequentialPvars.Enable(G2G.wxID_EDITSEQVAR,val)
416
417    def DelPseudoVar(event):
418        'Ask the user to select a pseudo var expression to delete'
419        choices = list(data['SeqPseudoVars'].keys())
420        selected = G2G.ItemSelector(
421            choices,G2frame,
422            multiple=True,
423            title='Select expressions to remove',
424            header='Delete expression')
425        if selected is None: return
426        for item in selected:
427            del data['SeqPseudoVars'][choices[item]]
428        if selected:
429            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
430
431    def EditPseudoVar(event):
432        'Edit an existing pseudo var expression'
433        choices = list(data['SeqPseudoVars'].keys())
434        if len(choices) == 1:
435            selected = 0
436        else:
437            selected = G2G.ItemSelector(
438                choices,G2frame,
439                multiple=False,
440                title='Select an expression to edit',
441                header='Edit expression')
442        if selected is not None:
443            dlg = G2exG.ExpressionDialog(
444                G2frame.dataDisplay,PSvarDict,
445                data['SeqPseudoVars'][choices[selected]],
446                header="Edit the PseudoVar expression",
447                VarLabel="PseudoVar #"+str(selected+1),
448                fit=False)
449            newobj = dlg.Show(True)
450            if newobj:
451                calcobj = G2obj.ExpressionCalcObj(newobj)
452                del data['SeqPseudoVars'][choices[selected]]
453                data['SeqPseudoVars'][calcobj.eObj.expression] = newobj
454                UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
455       
456    def AddNewPseudoVar(event):
457        'Create a new pseudo var expression'
458        dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,PSvarDict,
459            header='Enter an expression for a PseudoVar here',
460            VarLabel = "New PseudoVar",fit=False)
461        obj = dlg.Show(True)
462        dlg.Destroy()
463        if obj:
464            calcobj = G2obj.ExpressionCalcObj(obj)
465            data['SeqPseudoVars'][calcobj.eObj.expression] = obj
466            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
467           
468    def AddNewDistPseudoVar(event):
469        obj = None
470        dlg = G2exG.BondDialog(
471            G2frame.dataDisplay,Phases,PSvarDict,
472            header='Select a Bond here',
473            VarLabel = "New Bond")
474        if dlg.ShowModal() == wx.ID_OK:
475            pName,Oatom,Tatom = dlg.GetSelection()
476            if Tatom:
477                Phase = Phases[pName]
478                General = Phase['General']
479                cx,ct = General['AtomPtrs'][:2]
480                pId = Phase['pId']
481                SGData = General['SGData']
482                sB = Tatom.find('(')+1
483                symNo = 0
484                if sB:
485                    sF = Tatom.find(')')
486                    symNo = int(Tatom[sB:sF])
487                cellNo = [0,0,0]
488                cB = Tatom.find('[')
489                if cB>0:
490                    cF = Tatom.find(']')+1
491                    cellNo = eval(Tatom[cB:cF])
492                Atoms = Phase['Atoms']
493                aNames = [atom[ct-1] for atom in Atoms]
494                oId = aNames.index(Oatom)
495                tId = aNames.index(Tatom.split(' +')[0])
496                # create an expression object
497                obj = G2obj.ExpressionObj()
498                obj.expression = 'Dist(%s,\n%s)'%(Oatom,Tatom.split(' d=')[0].replace(' ',''))
499                obj.distance_dict = {'pId':pId,'SGData':SGData,'symNo':symNo,'cellNo':cellNo}
500                obj.distance_atoms = [oId,tId]
501        else: 
502            dlg.Destroy()
503            return
504        dlg.Destroy()
505        if obj:
506            data['SeqPseudoVars'][obj.expression] = obj
507            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
508
509    def AddNewAnglePseudoVar(event):
510        obj = None
511        dlg = G2exG.AngleDialog(
512            G2frame.dataDisplay,Phases,PSvarDict,
513            header='Enter an Angle here',
514            VarLabel = "New Angle")
515        if dlg.ShowModal() == wx.ID_OK:
516            pName,Oatom,Tatoms = dlg.GetSelection()
517            if Tatoms:
518                Phase = Phases[pName]
519                General = Phase['General']
520                cx,ct = General['AtomPtrs'][:2]
521                pId = Phase['pId']
522                SGData = General['SGData']
523                Atoms = Phase['Atoms']
524                aNames = [atom[ct-1] for atom in Atoms]
525                tIds = []
526                symNos = []
527                cellNos = []
528                oId = aNames.index(Oatom)
529                Tatoms = Tatoms.split(';')
530                for Tatom in Tatoms:
531                    sB = Tatom.find('(')+1
532                    symNo = 0
533                    if sB:
534                        sF = Tatom.find(')')
535                        symNo = int(Tatom[sB:sF])
536                    symNos.append(symNo)
537                    cellNo = [0,0,0]
538                    cB = Tatom.find('[')
539                    if cB>0:
540                        cF = Tatom.find(']')+1
541                        cellNo = eval(Tatom[cB:cF])
542                    cellNos.append(cellNo)
543                    tIds.append(aNames.index(Tatom.split('+')[0]))
544                # create an expression object
545                obj = G2obj.ExpressionObj()
546                obj.expression = 'Angle(%s,%s,\n%s)'%(Tatoms[0],Oatom,Tatoms[1])
547                obj.angle_dict = {'pId':pId,'SGData':SGData,'symNo':symNos,'cellNo':cellNos}
548                obj.angle_atoms = [oId,tIds]
549        else: 
550            dlg.Destroy()
551            return
552        dlg.Destroy()
553        if obj:
554            data['SeqPseudoVars'][obj.expression] = obj
555            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
556           
557    def UpdateParmDict(parmDict):
558        '''generate the atom positions and the direct & reciprocal cell values,
559        because they might be needed to evaluate the pseudovar
560        '''
561        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
562                         ['A'+str(i) for i in range(6)])
563                     )
564        delList = []
565        phaselist = []
566        for item in parmDict: 
567            if ':' not in item: continue
568            key = item.split(':')
569            if len(key) < 3: continue
570            # remove the dA[xyz] terms, they would only bring confusion
571            if key[0] and key[0] not in phaselist: phaselist.append(key[0])
572            if key[2].startswith('dA'):
573                delList.append(item)
574            # compute and update the corrected reciprocal cell terms using the Dij values
575            elif key[2] in Ddict:
576                akey = key[0]+'::'+Ddict[key[2]]
577                parmDict[akey] += parmDict[item]
578                delList.append(item)
579        for item in delList:
580            del parmDict[item]               
581        for i in phaselist:
582            pId = int(i)
583            # apply cell symmetry
584            A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId])
585            # convert to direct cell & add the unique terms to the dictionary
586            for i,val in enumerate(G2lat.A2cell(A)):
587                if i in uniqCellIndx[pId]:
588                    lbl = str(pId)+'::'+cellUlbl[i]
589                    parmDict[lbl] = val
590            lbl = str(pId)+'::'+'Vol'
591            parmDict[lbl] = G2lat.calc_V(A)
592        return parmDict
593
594    def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD):
595        '''Evaluate an expression derivative with respect to a
596        GSAS-II variable name.
597
598        Note this likely could be faster if the loop over calcobjs were done
599        inside after the Dict was created.
600        '''
601        if not ESD:
602            return 0.
603        step = ESD/10
604        Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],
605                         ['A'+str(i) for i in range(6)])
606                     )
607        results = []
608        phaselist = []
609        VparmDict = sampleDict.copy()
610        for incr in step,-step:
611            VparmDict.update(parmDict.copy())           
612            # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]'
613            # values are not zeroed: fix that!
614            VparmDict.update({item:0.0 for item in parmDict if 'dA' in item})
615            VparmDict[var] += incr
616            G2mv.Dict2Map(VparmDict,[]) # apply constraints
617            # generate the atom positions and the direct & reciprocal cell values now, because they might
618            # needed to evaluate the pseudovar
619            for item in VparmDict:
620                if item in sampleDict:
621                    continue 
622                if ':' not in item: continue
623                key = item.split(':')
624                if len(key) < 3: continue
625                # apply any new shifts to atom positions
626                if key[2].startswith('dA'):
627                    VparmDict[''.join(item.split('d'))] += VparmDict[item]
628                    VparmDict[item] = 0.0
629                # compute and update the corrected reciprocal cell terms using the Dij values
630                if key[2] in Ddict:
631                    if key[0] not in phaselist: phaselist.append(key[0])
632                    akey = key[0]+'::'+Ddict[key[2]]
633                    VparmDict[akey] += VparmDict[item]
634            for i in phaselist:
635                pId = int(i)
636                # apply cell symmetry
637                A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId])
638                # convert to direct cell & add the unique terms to the dictionary
639                for i,val in enumerate(G2lat.A2cell(A)):
640                    if i in uniqCellIndx[pId]:
641                        lbl = str(pId)+'::'+cellUlbl[i]
642                        VparmDict[lbl] = val
643                lbl = str(pId)+'::'+'Vol'
644                VparmDict[lbl] = G2lat.calc_V(A)
645            # dict should be fully updated, use it & calculate
646            calcobj.SetupCalc(VparmDict)
647            results.append(calcobj.EvalExpression())
648        if None in results:
649            return None
650        return (results[0] - results[1]) / (2.*step)
651       
652    def EnableParFitEqMenus():
653        'Enables or disables the Parametric Fit menu items that require existing defs'
654        if data['SeqParFitEqList']:
655            val = True
656        else:
657            val = False
658        G2frame.dataWindow.SequentialPfit.Enable(G2G.wxID_DELPARFIT,val)
659        G2frame.dataWindow.SequentialPfit.Enable(G2G.wxID_EDITPARFIT,val)
660        G2frame.dataWindow.SequentialPfit.Enable(G2G.wxID_DOPARFIT,val)
661
662    def ParEqEval(Values,calcObjList,varyList):
663        '''Evaluate the parametric expression(s)
664        :param list Values: a list of values for each variable parameter
665        :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj`
666          expression objects to evaluate
667        :param list varyList: a list of variable names for each value in Values
668        '''
669        result = []
670        for calcobj in calcObjList:
671            calcobj.UpdateVars(varyList,Values)
672            if calcobj.depSig:
673                result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig)
674            else:
675                result.append(calcobj.depVal-calcobj.EvalExpression())
676        return result
677
678    def DoParEqFit(event,eqObj=None):
679        'Parametric fit minimizer'
680        varyValueDict = {} # dict of variables and their initial values
681        calcObjList = [] # expression objects, ready to go for each data point
682        if eqObj is not None:
683            eqObjList = [eqObj,]
684        else:
685            eqObjList = data['SeqParFitEqList']
686        UseFlags = G2frame.SeqTable.GetColValues(1)
687        for obj in eqObjList:
688            # assemble refined vars for this equation
689            varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()})
690            # lookup dependent var position
691            depVar = obj.GetDepVar()
692            if depVar in colLabels:
693                indx = colLabels.index(depVar)
694            else:
695                raise Exception('Dependent variable '+depVar+' not found')
696            # assemble a list of the independent variables
697            indepVars = obj.GetIndependentVars()
698            # loop over each datapoint
699            for j,row in enumerate(zip(*G2frame.colList)):
700                if not UseFlags[j]: continue
701                # assemble equations to fit
702                calcobj = G2obj.ExpressionCalcObj(obj)
703                # prepare a dict of needed independent vars for this expression
704                indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars}
705                calcobj.SetupCalc(indepVarDict)               
706                # values and sigs for current value of dependent var
707                if row[indx] is None: continue
708                calcobj.depVal = row[indx]
709                calcobj.depSig = G2frame.colSigs[indx][j]
710                calcObjList.append(calcobj)
711        # varied parameters
712        varyList = varyValueDict.keys()
713        values = varyValues = [varyValueDict[key] for key in varyList]
714        if not varyList:
715            print ('no variables to refine!')
716            return
717        try:
718            result = so.leastsq(ParEqEval,varyValues,full_output=True,   #ftol=Ftol,
719                args=(calcObjList,varyList))
720            values = result[0]
721            covar = result[1]
722            if covar is None:
723                raise Exception
724            chisq = np.sum(result[2]['fvec']**2)
725            GOF = np.sqrt(chisq/(len(calcObjList)-len(varyList)))
726            esdDict = {}
727            for i,avar in enumerate(varyList):
728                esdDict[avar] = np.sqrt(covar[i,i])
729        except:
730            print('====> Fit failed')
731            return
732        print('==== Fit Results ====')
733        print ('  chisq =  %.2f, GOF = %.2f'%(chisq,GOF))
734        for obj in eqObjList:
735            obj.UpdateVariedVars(varyList,values)
736            ind = '      '
737            print(u'  '+obj.GetDepVar()+u' = '+obj.expression)
738            for var in obj.assgnVars:
739                print(ind+var+u' = '+obj.assgnVars[var])
740            for var in obj.freeVars:
741                avar = "::"+obj.freeVars[var][0]
742                val = obj.freeVars[var][1]
743                if obj.freeVars[var][2]:
744                    print(ind+var+u' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar]))
745                else:
746                    print(ind+var+u' = '+avar + u" =" + G2mth.ValEsd(val,0))
747        # create a plot for each parametric variable
748        for fitnum,obj in enumerate(eqObjList):
749            calcobj = G2obj.ExpressionCalcObj(obj)
750            # lookup dependent var position
751            indx = colLabels.index(obj.GetDepVar())
752            # assemble a list of the independent variables
753            indepVars = obj.GetIndependentVars()           
754            # loop over each datapoint
755            fitvals = []
756            for j,row in enumerate(zip(*G2frame.colList)):
757                calcobj.SetupCalc({var:row[i] for i,var in enumerate(colLabels) if var in indepVars})
758                fitvals.append(calcobj.EvalExpression())
759            G2plt.PlotSelectedSequence(G2frame,[indx],GetColumnInfo,SelectXaxis,fitnum,fitvals)
760
761    def SingleParEqFit(eqObj):
762        DoParEqFit(None,eqObj)
763
764    def DelParFitEq(event):
765        'Ask the user to select function to delete'
766        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']]
767        selected = G2G.ItemSelector(
768            txtlst,G2frame,
769            multiple=True,
770            title='Select a parametric equation(s) to remove',
771            header='Delete equation')
772        if selected is None: return
773        data['SeqParFitEqList'] = [obj for i,obj in enumerate(data['SeqParFitEqList']) if i not in selected]
774        EnableParFitEqMenus()
775        if data['SeqParFitEqList']: DoParEqFit(event)
776       
777    def EditParFitEq(event):
778        'Edit an existing parametric equation'
779        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']]
780        if len(txtlst) == 1:
781            selected = 0
782        else:
783            selected = G2G.ItemSelector(
784                txtlst,G2frame,
785                multiple=False,
786                title='Select a parametric equation to edit',
787                header='Edit equation')
788        if selected is not None:
789            dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,VarDict,
790                data['SeqParFitEqList'][selected],depVarDict=VarDict,
791                header="Edit the formula for this minimization function",
792                ExtraButton=['Fit',SingleParEqFit],wildCard=False)
793            newobj = dlg.Show(True)
794            if newobj:
795                data['SeqParFitEqList'][selected] = newobj
796                EnableParFitEqMenus()
797            if data['SeqParFitEqList']: DoParEqFit(event)
798
799    def AddNewParFitEq(event):
800        'Create a new parametric equation to be fit to sequential results'
801
802        # compile the variable names used in previous freevars to avoid accidental name collisions
803        usedvarlist = []
804        for obj in data['SeqParFitEqList']:
805            for var in obj.freeVars:
806                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
807
808        dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,VarDict,depVarDict=VarDict,
809            header='Define an equation to minimize in the parametric fit',
810            ExtraButton=['Fit',SingleParEqFit],usedVars=usedvarlist,wildCard=False)
811        obj = dlg.Show(True)
812        dlg.Destroy()
813        if obj:
814            data['SeqParFitEqList'].append(obj)
815            EnableParFitEqMenus()
816            if data['SeqParFitEqList']: DoParEqFit(event)
817               
818    def CopyParFitEq(event):
819        'Copy an existing parametric equation to be fit to sequential results'
820        # compile the variable names used in previous freevars to avoid accidental name collisions
821        usedvarlist = []
822        for obj in data['SeqParFitEqList']:
823            for var in obj.freeVars:
824                if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0])
825        txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']]
826        if len(txtlst) == 1:
827            selected = 0
828        else:
829            selected = G2G.ItemSelector(
830                txtlst,G2frame,
831                multiple=False,
832                title='Select a parametric equation to copy',
833                header='Copy equation')
834        if selected is not None:
835            newEqn = copy.deepcopy(data['SeqParFitEqList'][selected])
836            for var in newEqn.freeVars:
837                newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist)
838            dlg = G2exG.ExpressionDialog(
839                G2frame.dataDisplay,VarDict,newEqn,depVarDict=VarDict,
840                header="Edit the formula for this minimization function",
841                ExtraButton=['Fit',SingleParEqFit],wildCard=False)
842            newobj = dlg.Show(True)
843            if newobj:
844                data['SeqParFitEqList'].append(newobj)
845                EnableParFitEqMenus()
846            if data['SeqParFitEqList']: DoParEqFit(event)
847                                           
848    def GridSetToolTip(row,col):
849        '''Routine to show standard uncertainties for each element in table
850        as a tooltip
851        '''
852        if G2frame.colSigs[col]:
853            if G2frame.colSigs[col][row] == -0.1: return 'frozen'
854            return u'\u03c3 = '+str(G2frame.colSigs[col][row])
855        return ''
856       
857    def GridColLblToolTip(col):
858        '''Define a tooltip for a column. This will be the user-entered value
859        (from data['variableLabels']) or the default name
860        '''
861        if col < 0 or col > len(colLabels):
862            print ('Illegal column #%d'%col)
863            return
864        var = colLabels[col]
865        return variableLabels.get(var,G2obj.fmtVarDescr(var))
866       
867    def SetLabelString(event):
868        '''Define or edit the label for a column in the table, to be used
869        as a tooltip and for plotting
870        '''
871        col = event.GetCol()
872        if col < 0 or col > len(colLabels):
873            return
874        var = colLabels[col]
875        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
876        head = u'Set a new name for variable {} (column {})'.format(var,col)
877        dlg = G2G.SingleStringDialog(G2frame,'Set variable label',
878                                 head,lbl,size=(400,-1))
879        if dlg.Show():
880            variableLabels[var] = dlg.GetValue()
881            dlg.Destroy()
882            wx.CallAfter(UpdateSeqResults,G2frame,data) # redisplay variables
883        else:
884            dlg.Destroy()
885
886    def DoSequentialExport(event):
887        '''Event handler for all Sequential Export menu items
888        '''
889        vals = G2frame.dataWindow.SeqExportLookup.get(event.GetId())
890        if vals is None:
891            print('Error: Id not found. This should not happen!')
892            return
893        G2IO.ExportSequential(G2frame,data,*vals)
894
895    def onSelectSeqVars(event):
896        '''Select which variables will be shown in table'''
897        hides = [saveColLabels[1:].index(item) for item in G2frame.SeqTblHideList if
898                     item in saveColLabels[1:]]
899        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select columns to hide',
900                'Hide columns',saveColLabels[1:])
901        dlg.SetSelections(hides)
902        if dlg.ShowModal() == wx.ID_OK:
903            G2frame.SeqTblHideList = [saveColLabels[1:][sel] for sel in dlg.GetSelections()]
904            dlg.Destroy()
905            UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
906        else:
907            dlg.Destroy()
908           
909    def OnCellChange(event):
910        r = event.GetRow()
911        val = G2frame.SeqTable.GetValue(r,0)
912#        print (r,val)
913        G2frame.SeqTable.SetValue(r,0, val)
914       
915    def OnSelectUpdate(event):
916        '''Update all phase parameters from a selected column in the Sequential Table.
917        If no histogram is selected (or more than one), ask the user to make a selection.
918
919        Loosely based on :func:`GSASIIstrIO.SetPhaseData`
920        '''
921        rows = G2frame.dataDisplay.GetSelectedRows()
922        if len(rows) == 1:
923            sel = rows[0]
924        else:
925            dlg = G2G.G2SingleChoiceDialog(G2frame, 'Select a histogram to\nupdate phase from',
926                                           'Select row',histNames)
927            if dlg.ShowModal() == wx.ID_OK:
928                sel = dlg.GetSelection()
929                dlg.Destroy()
930            else:
931                dlg.Destroy()
932                return
933        parmDict = data[histNames[sel]]['parmDict']
934        Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
935        for phase in Phases:
936            print('Updating {} from Seq. Ref. row {}'.format(phase,histNames[sel]))
937            Phase = Phases[phase]
938            General = Phase['General']
939            SGData = General['SGData']
940            Atoms = Phase['Atoms']
941            cell = General['Cell']
942            pId = Phase['pId']
943            pfx = str(pId)+'::'
944            # there should not be any changes to the cell because those terms are not refined
945            A,sigA = G2stIO.cellFill(pfx,SGData,parmDict,{})
946            cell[1:7] = G2lat.A2cell(A)
947            cell[7] = G2lat.calc_V(A)
948            textureData = General['SH Texture']   
949            if textureData['Order']:
950#                SHtextureSig = {}
951                for name in ['omega','chi','phi']:
952                    aname = pfx+'SH '+name
953                    textureData['Sample '+name][1] = parmDict[aname]
954                for name in textureData['SH Coeff'][1]:
955                    aname = pfx+name
956                    textureData['SH Coeff'][1][name] = parmDict[aname]
957            ik = 6  #for Pawley stuff below
958            if General.get('Modulated',False):
959                ik = 7
960            # how are these updated?
961            #General['SuperVec']
962            #RBModels = Phase['RBModels']
963            if Phase['General'].get('doPawley'):
964                pawleyRef = Phase['Pawley ref']
965                for i,refl in enumerate(pawleyRef):
966                    key = pfx+'PWLref:'+str(i)
967                    refl[ik] = parmDict[key]
968#                    if key in sigDict:  #TODO: error here sigDict not defined. What was intended
969#                        refl[ik+1] = sigDict[key]
970#                    else:
971#                        refl[ik+1] = 0
972                continue
973            General['Mass'] = 0.
974            cx,ct,cs,cia = General['AtomPtrs']
975            for i,at in enumerate(Atoms):
976                names = {cx:pfx+'Ax:'+str(i),cx+1:pfx+'Ay:'+str(i),cx+2:pfx+'Az:'+str(i),cx+3:pfx+'Afrac:'+str(i),
977                    cia+1:pfx+'AUiso:'+str(i),cia+2:pfx+'AU11:'+str(i),cia+3:pfx+'AU22:'+str(i),cia+4:pfx+'AU33:'+str(i),
978                    cia+5:pfx+'AU12:'+str(i),cia+6:pfx+'AU13:'+str(i),cia+7:pfx+'AU23:'+str(i),
979                    cx+4:pfx+'AMx:'+str(i),cx+5:pfx+'AMy:'+str(i),cx+6:pfx+'AMz:'+str(i)}
980                for ind in range(cx,cx+4):
981                    at[ind] = parmDict[names[ind]]
982                if at[cia] == 'I':
983                    at[cia+1] = parmDict[names[cia+1]]
984                else:
985                    for ind in range(cia+2,cia+8):
986                        at[ind] = parmDict[names[ind]]
987                if General['Type'] == 'magnetic':
988                    for ind in range(cx+4,cx+7):
989                        at[ind] = parmDict[names[ind]]
990                ind = General['AtomTypes'].index(at[ct])
991                General['Mass'] += General['AtomMass'][ind]*at[cx+3]*at[cx+5]
992                if General.get('Modulated',False):
993                    AtomSS = at[-1]['SS1']
994                    waveType = AtomSS['waveType']
995                    for Stype in ['Sfrac','Spos','Sadp','Smag']:
996                        Waves = AtomSS[Stype]
997                        for iw,wave in enumerate(Waves):
998                            stiw = str(i)+':'+str(iw)
999                            if Stype == 'Spos':
1000                                if waveType in ['ZigZag','Block',] and not iw:
1001                                    names = ['Tmin:'+stiw,'Tmax:'+stiw,'Xmax:'+stiw,'Ymax:'+stiw,'Zmax:'+stiw]
1002                                else:
1003                                    names = ['Xsin:'+stiw,'Ysin:'+stiw,'Zsin:'+stiw,
1004                                        'Xcos:'+stiw,'Ycos:'+stiw,'Zcos:'+stiw]
1005                            elif Stype == 'Sadp':
1006                                names = ['U11sin:'+stiw,'U22sin:'+stiw,'U33sin:'+stiw,
1007                                    'U12sin:'+stiw,'U13sin:'+stiw,'U23sin:'+stiw,
1008                                    'U11cos:'+stiw,'U22cos:'+stiw,'U33cos:'+stiw,
1009                                    'U12cos:'+stiw,'U13cos:'+stiw,'U23cos:'+stiw]
1010                            elif Stype == 'Sfrac':
1011                                if 'Crenel' in waveType and not iw:
1012                                    names = ['Fzero:'+stiw,'Fwid:'+stiw]
1013                                else:
1014                                    names = ['Fsin:'+stiw,'Fcos:'+stiw]
1015                            elif Stype == 'Smag':
1016                                names = ['MXsin:'+stiw,'MYsin:'+stiw,'MZsin:'+stiw,
1017                                    'MXcos:'+stiw,'MYcos:'+stiw,'MZcos:'+stiw]
1018                            for iname,name in enumerate(names):
1019                                AtomSS[Stype][iw][0][iname] = parmDict[pfx+name]
1020                               
1021    def OnEditSelectPhaseVars(event): 
1022        '''Select phase parameters in a selected histogram in a sequential
1023        fit. This allows the user to set their value(s)
1024        '''
1025        rows = G2frame.dataDisplay.GetSelectedRows()
1026        if len(rows) >= 1:
1027            selRows = rows
1028        else:
1029            dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select histogram(s) to update\nphase parameters',
1030                                           'Select row',histNames)
1031            if dlg.ShowModal() == wx.ID_OK:
1032                selRows = dlg.GetSelections()
1033            else:
1034                selRows = []
1035            dlg.Destroy()
1036            if len(selRows) == 0: return
1037        parmDict = data[histNames[selRows[0]]]['parmDict']
1038        # narrow down to items w/o a histogram & having float values
1039        phaseKeys = [i for i in parmDict if ':' in i and i.split(':')[1] == '']
1040        phaseKeys = [i for i in phaseKeys if type(parmDict[i]) not in (int,str,bool)]
1041        if len(selRows) == 1:
1042            lbl = "\nin {}      ".format(histNames[selRows[0]])
1043        else:
1044            lbl = "\nin {} histograms".format(len(selRows))
1045        dlg = G2G.G2MultiChoiceDialog(G2frame, 'Choose phase parmDict item(s) to set'+lbl, 
1046                                      'Choose items to edit', phaseKeys)
1047        if dlg.ShowModal() == wx.ID_OK:
1048            select = dlg.GetSelections()
1049            dlg.Destroy()
1050        else:
1051            dlg.Destroy()
1052            return
1053        if len(select) == 0: return
1054        l = [phaseKeys[i] for i in select]
1055        d = {i:parmDict[i] for i in l}
1056        val = G2G.CallScrolledMultiEditor(G2frame,len(l)*[d],l,l,CopyButton=True)
1057        if val:
1058            for sel in selRows:
1059                parmDict = data[histNames[sel]]['parmDict']
1060                for key in d: # update values shown in table
1061                    if parmDict[key] == d[key]: continue
1062                    if key in data[histNames[sel]]['varyList']:
1063                        i = data[histNames[sel]]['varyList'].index(key)
1064                        data[histNames[sel]]['variables'][i] = d[key]
1065                        data[histNames[sel]]['sig'][i] = 0
1066                    if key in data[histNames[sel]].get('depParmDict',{}):
1067                        data[histNames[sel]]['depParmDict'][key] = (d[key],0)
1068                parmDict.update(d) # update values used in next fit
1069        wx.CallAfter(UpdateSeqResults,G2frame,data) # redisplay variables
1070        return
1071           
1072##### UpdateSeqResults: start processing sequential results here ##########
1073    # lookup table for unique cell parameters by symmetry
1074    cellGUIlist = [
1075        [['m3','m3m'],(0,)],
1076        [['3R','3mR'],(0,3)],
1077        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
1078        [['mmm'],(0,1,2)],
1079        [['2/m'+'a'],(0,1,2,3)],
1080        [['2/m'+'b'],(0,1,2,4)],
1081        [['2/m'+'c'],(0,1,2,5)],
1082        [['-1'],(0,1,2,3,4,5)],
1083        ]
1084    # cell labels
1085    cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
1086
1087    if not data:
1088        print ('No sequential refinement results')
1089        return
1090    variableLabels = data.get('variableLabels',{})
1091    data['variableLabels'] = variableLabels
1092    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
1093    Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Controls'))
1094    # create a place to store Pseudo Vars & Parametric Fit functions, if not present
1095    if 'SeqPseudoVars' not in data: data['SeqPseudoVars'] = {}
1096    if 'SeqParFitEqList' not in data: data['SeqParFitEqList'] = []
1097    histNames = data['histNames']
1098    foundNames = [name for name in histNames if name in data]
1099    histNames = foundNames
1100    if G2frame.dataDisplay:
1101        G2frame.dataDisplay.Destroy()
1102    G2frame.GetStatusBar().SetStatusText("Select column to export; Double click on column to plot data; on row for Covariance",1)
1103    sampleParms = GetSampleParms()
1104
1105    # make dict of varied atom coords keyed by absolute position
1106    newAtomDict = data[histNames[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
1107    # Possible error: the next might need to be data[histNames[0]]['varyList']
1108    # error will arise if there constraints on coordinates?
1109    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in data['varyList']}
1110   
1111    # make dict of varied cell parameters equivalents
1112    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
1113    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
1114    # N.B. These Dij vars are missing a histogram #
1115    newCellDict = {}
1116    for name in histNames:
1117        if name in data and 'newCellDict' in data[name]:
1118            newCellDict.update(data[name]['newCellDict'])
1119    cellAlist = []
1120    for item in newCellDict:
1121        cellAlist.append(newCellDict[item][0])
1122        if item in data.get('varyList',[]):
1123            ESDlookup[newCellDict[item][0]] = item
1124            Dlookup[item] = newCellDict[item][0]
1125    # add coordinate equivalents to lookup table
1126    for parm in atomLookup:
1127        Dlookup[atomLookup[parm]] = parm
1128        ESDlookup[parm] = atomLookup[parm]
1129
1130    # get unit cell & symmetry for all phases & initial stuff for later use
1131    RecpCellTerms = {}
1132    SGdata = {}
1133    uniqCellIndx = {}
1134    initialCell = {}
1135    RcellLbls = {}
1136    zeroDict = {}
1137    for phase in Phases:
1138        phasedict = Phases[phase]
1139        pId = phasedict['pId']
1140        pfx = str(pId)+'::' # prefix for A values from phase
1141        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
1142        RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7])
1143        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
1144        SGdata[pId] = phasedict['General']['SGData']
1145        laue = SGdata[pId]['SGLaue']
1146        if laue == '2/m':
1147            laue += SGdata[pId]['SGUniq']
1148        for symlist,celllist in cellGUIlist:
1149            if laue in symlist:
1150                uniqCellIndx[pId] = celllist
1151                break
1152        else: # should not happen
1153            uniqCellIndx[pId] = list(range(6))
1154        for i in uniqCellIndx[pId]:
1155            initialCell[str(pId)+'::A'+str(i)] =  RecpCellTerms[pId][i]
1156
1157    G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.SequentialMenu)
1158    G2frame.Bind(wx.EVT_MENU, OnSelectUse, id=G2G.wxID_SELECTUSE)
1159    G2frame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=G2G.wxID_RENAMESEQSEL)
1160    G2frame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=G2G.wxID_SAVESEQSEL)
1161    G2frame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=G2G.wxID_SAVESEQSELCSV)
1162    G2frame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=G2G.wxID_SAVESEQCSV)
1163    G2frame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=G2G.wxID_PLOTSEQSEL)
1164    G2frame.Bind(wx.EVT_MENU, OnAveSelSeq, id=G2G.wxID_AVESEQSEL)
1165    #G2frame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=G2G.wxID_ORGSEQSEL)
1166    G2frame.Bind(wx.EVT_MENU, OnSelectUpdate, id=G2G.wxID_UPDATESEQSEL)
1167    G2frame.Bind(wx.EVT_MENU, OnEditSelectPhaseVars, id=G2G.wxID_EDITSEQSELPHASE)
1168    G2frame.Bind(wx.EVT_MENU, onSelectSeqVars, id=G2G.wxID_ORGSEQINC)
1169    G2frame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=G2G.wxID_ADDSEQVAR)
1170    G2frame.Bind(wx.EVT_MENU, AddNewDistPseudoVar, id=G2G.wxID_ADDSEQDIST)
1171    G2frame.Bind(wx.EVT_MENU, AddNewAnglePseudoVar, id=G2G.wxID_ADDSEQANGLE)
1172    G2frame.Bind(wx.EVT_MENU, DelPseudoVar, id=G2G.wxID_DELSEQVAR)
1173    G2frame.Bind(wx.EVT_MENU, EditPseudoVar, id=G2G.wxID_EDITSEQVAR)
1174    G2frame.Bind(wx.EVT_MENU, AddNewParFitEq, id=G2G.wxID_ADDPARFIT)
1175    G2frame.Bind(wx.EVT_MENU, CopyParFitEq, id=G2G.wxID_COPYPARFIT)
1176    G2frame.Bind(wx.EVT_MENU, DelParFitEq, id=G2G.wxID_DELPARFIT)
1177    G2frame.Bind(wx.EVT_MENU, EditParFitEq, id=G2G.wxID_EDITPARFIT)
1178    G2frame.Bind(wx.EVT_MENU, DoParEqFit, id=G2G.wxID_DOPARFIT)
1179
1180    for id in G2frame.dataWindow.SeqExportLookup:       
1181        G2frame.Bind(wx.EVT_MENU, DoSequentialExport, id=id)
1182
1183    EnablePseudoVarMenus()
1184    EnableParFitEqMenus()
1185
1186    # scan for locations where the variables change
1187    VaryListChanges = [] # histograms where there is a change
1188    combinedVaryList = []
1189    firstValueDict = {}
1190    vallookup = {}
1191    posdict = {}
1192    prevVaryList = []
1193    foundNames = []
1194    missing = 0
1195    for i,name in enumerate(histNames):
1196        if name not in data:
1197            if missing < 5:
1198                print(" Warning: "+name+" not found")
1199            elif missing == 5:
1200                print (' Warning: more are missing')
1201            missing += 1
1202            continue
1203        foundNames.append(name)
1204        maxPWL = 5
1205        for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']):
1206            svar = striphist(var,'*') # wild-carded
1207            if 'PWL' in svar:
1208                if int(svar.split(':')[-1]) > maxPWL:
1209                    continue
1210            if svar not in combinedVaryList:
1211                # add variables to list as they appear
1212                combinedVaryList.append(svar)
1213                firstValueDict[svar] = (val,sig)
1214        if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous
1215            prevVaryList = data[name]['varyList']
1216            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
1217            posdict[name] = {}
1218            for var in data[name]['varyList']:
1219                svar = striphist(var,'*')
1220                if 'PWL' in svar:
1221                    if int(svar.split(':')[-1]) > maxPWL:
1222                        continue
1223                posdict[name][combinedVaryList.index(svar)] = svar
1224            VaryListChanges.append(name)
1225    if missing:
1226        print (' Warning: Total of %d data sets missing from sequential results'%(missing))
1227    #if len(VaryListChanges) > 1:
1228    #    G2frame.dataWindow.SequentialFile.Enable(G2G.wxID_ORGSEQSEL,True)
1229    #else:
1230    #    G2frame.dataWindow.SequentialFile.Enable(G2G.wxID_ORGSEQSEL,False)
1231    ######  build up the data table by columns -----------------------------------------------
1232    histNames = foundNames
1233    nRows = len(histNames)
1234    G2frame.colList = [list(range(nRows)),nRows*[True]]
1235    G2frame.colSigs = [None,None,]
1236    colLabels = ['No.','Use',]
1237    Types = [wg.GRID_VALUE_LONG,wg.GRID_VALUE_BOOL,]
1238    # start with Rwp values
1239    if 'IMG ' not in histNames[0][:4]:
1240        G2frame.colList += [[data[name]['Rvals']['Rwp'] for name in histNames]]
1241        G2frame.colSigs += [None]
1242        colLabels += ['Rwp']
1243        Types += [wg.GRID_VALUE_FLOAT+':10,3',]
1244    # add % change in Chi^2 in last cycle
1245    if histNames[0][:4] not in ['SASD','IMG ','REFD'] and Controls.get('ShowCell'):
1246        G2frame.colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]]
1247        G2frame.colSigs += [None]
1248        colLabels += [u'\u0394\u03C7\u00B2 (%)']
1249        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
1250    deltaChiCol = len(colLabels)-1
1251    # frozen variables?
1252    if 'parmFrozen' in Controls:
1253        f = [len(Controls['parmFrozen'].get(h,[])) for h in histNames]
1254        if any(f):
1255            G2frame.colList += [f]
1256            G2frame.colSigs += [None]
1257            colLabels += ['frozen']
1258            Types += [wg.GRID_VALUE_LONG]
1259    # add changing sample parameters to table
1260    for key in sampleParms:
1261        G2frame.colList += [sampleParms[key]]
1262        G2frame.colSigs += [None]
1263        colLabels += [key]
1264        Types += [wg.GRID_VALUE_FLOAT,]
1265    sampleDict = {}
1266    for i,name in enumerate(histNames):
1267        sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) 
1268    # add unique cell parameters 
1269    if Controls.get('ShowCell',False) and len(newCellDict):
1270        phaseLookup = {Phases[phase]['pId']:phase for phase in Phases}
1271        for pId in sorted(RecpCellTerms):
1272            pfx = str(pId)+'::' # prefix for A values from phase
1273            cells = []
1274            cellESDs = []
1275            colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
1276            colLabels += [pfx+'Vol']
1277            Types += (len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT+':10,5',]
1278            Types += [wg.GRID_VALUE_FLOAT+':10,3',]
1279            Albls = [pfx+'A'+str(i) for i in range(6)]
1280            for name in histNames:
1281                if name not in Histograms: continue
1282                hId = Histograms[name]['hId']
1283                phfx = '%d:%d:'%(pId,hId)
1284                esdLookUp = {}
1285                dLookup = {}
1286                for item in data[name]['newCellDict']:
1287                    if phfx+item.split('::')[1] in data[name]['varyList']:
1288                        esdLookUp[newCellDict[item][0]] = item
1289                        dLookup[item] = newCellDict[item][0]
1290                covData = {'varyList': [dLookup.get(striphist(v),v) for v in data[name]['varyList']],
1291                    'covMatrix': data[name]['covMatrix']}
1292                A = RecpCellTerms[pId][:] # make copy of starting A values
1293                # update with refined values
1294                for i,j in enumerate(('D11','D22','D33','D12','D13','D23')):
1295                    var = str(pId)+'::A'+str(i)
1296                    Dvar = str(pId)+':'+str(hId)+':'+j
1297                    # apply Dij value if non-zero
1298                    if Dvar in data[name]['parmDict']:
1299                        parmDict = data[name]['parmDict']
1300                        if parmDict[Dvar] != 0.0:
1301                            A[i] += parmDict[Dvar]
1302                    # override with fit result if is Dij varied
1303                    if var in cellAlist:
1304                        try:
1305                            A[i] = data[name]['newCellDict'][esdLookUp[var]][1] # get refined value
1306                        except KeyError:
1307                            pass
1308                # apply symmetry
1309                cellDict = dict(zip(Albls,A))
1310                try:    # convert to direct cell
1311                    A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
1312                    c = G2lat.A2cell(A)
1313                    vol = G2lat.calc_V(A)
1314                    cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
1315                except:
1316                    c = 6*[None]
1317                    cE = 6*[None]
1318                    vol = None
1319                # add only unique values to table
1320                if name in Phases[phaseLookup[pId]]['Histograms']:
1321                    cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
1322                    cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
1323                else:
1324                    cells += [[None for i in uniqCellIndx[pId]]+[None]]
1325                    cellESDs += [[None for i in uniqCellIndx[pId]]+[None]]
1326            G2frame.colList += zip(*cells)
1327            G2frame.colSigs += zip(*cellESDs)
1328    # sort out the variables in their selected order
1329    varcols = 0
1330    for d in posdict.values():
1331        varcols = max(varcols,max(d.keys())+1)
1332    # get labels for each column
1333    for i in range(varcols):
1334        lbl = ''
1335        for h in VaryListChanges:
1336            if posdict[h].get(i):
1337                if posdict[h].get(i) in lbl: continue
1338                if lbl != "": lbl += '/'
1339                lbl += posdict[h].get(i)
1340        colLabels.append(lbl)
1341    Types += varcols*[wg.GRID_VALUE_FLOAT,]
1342    vals = []
1343    esds = []
1344    varsellist = None        # will be a list of variable names in the order they are selected to appear
1345    # tabulate values for each hist, leaving None for blank columns
1346    for name in histNames:
1347        if name in posdict:
1348            varsellist = [posdict[name].get(i) for i in range(varcols)]
1349            # translate variable names to how they will be used in the headings
1350            vs = [striphist(v,'*') for v in data[name]['varyList']]
1351            # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists
1352            sellist = [vs.index(v) if v is not None else None for v in varsellist]
1353            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])]
1354        if not varsellist: raise Exception()
1355        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
1356        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
1357    G2frame.colList += zip(*vals)
1358    G2frame.colSigs += zip(*esds)
1359    # tabulate constrained variables, removing histogram numbers if needed
1360    # from parameter label
1361    depValDict = {}
1362    depSigDict = {}
1363    for name in histNames:
1364        for var in data[name].get('depParmDict',{}):
1365            val,sig = data[name]['depParmDict'][var]
1366            svar = striphist(var,'*')
1367            if svar not in depValDict:
1368               depValDict[svar] = [val]
1369               depSigDict[svar] = [sig]
1370            else:
1371               depValDict[svar].append(val)
1372               depSigDict[svar].append(sig)
1373   
1374    # add the dependent constrained variables to the table
1375    for var in sorted(depValDict):
1376        if len(depValDict[var]) != len(histNames): continue
1377        colLabels.append(var)
1378        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
1379        G2frame.colSigs += [depSigDict[var]]
1380        G2frame.colList += [depValDict[var]]
1381
1382    # add refined atom parameters to table
1383    colLabels += sorted(atomLookup.keys())
1384    for parm in sorted(atomLookup):
1385        G2frame.colList += [[data[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
1386        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
1387        if atomLookup[parm] in data[histNames[0]]['varyList']:
1388            col = data[histNames[0]]['varyList'].index(atomLookup[parm])
1389            G2frame.colSigs += [[data[name]['sig'][col] for name in histNames]]
1390        else:
1391            G2frame.colSigs += [None]
1392           
1393    # compute and add weight fractions to table if varied
1394    for phase in Phases:
1395        var = str(Phases[phase]['pId'])+':*:Scale'
1396        if var not in combinedVaryList+list(depValDict.keys()): continue
1397        wtFrList = []
1398        sigwtFrList = []
1399        for i,name in enumerate(histNames):
1400            if name not in Phases[phase]['Histograms']:
1401                wtFrList.append(None)
1402                sigwtFrList.append(0.0)
1403                continue
1404            elif not Phases[phase]['Histograms'][name]['Use']:
1405                wtFrList.append(None)
1406                sigwtFrList.append(0.0)
1407                continue
1408            wtFrSum = 0.
1409            for phase1 in Phases:
1410                if name not in Phases[phase1]['Histograms']: continue
1411                if not Phases[phase1]['Histograms'][name]['Use']: continue
1412                wtFrSum += Phases[phase1]['Histograms'][name]['Scale'][0]*Phases[phase1]['General']['Mass']
1413            var = str(Phases[phase]['pId'])+':'+str(i)+':Scale'
1414            wtFr = Phases[phase]['Histograms'][name]['Scale'][0]*Phases[phase]['General']['Mass']/wtFrSum
1415            wtFrList.append(wtFr)
1416            if var in data[name]['varyList']:
1417                sig = data[name]['sig'][data[name]['varyList'].index(var)]*wtFr/Phases[phase]['Histograms'][name]['Scale'][0]
1418            else:
1419                sig = 0.0
1420            sigwtFrList.append(sig)
1421        colLabels.append(str(Phases[phase]['pId'])+':*:WgtFrac')
1422        Types += [wg.GRID_VALUE_FLOAT+':10,5',]
1423        G2frame.colList += [wtFrList]
1424        G2frame.colSigs += [sigwtFrList]
1425               
1426    # evaluate Pseudovars, their ESDs and add them to grid
1427    for expr in data['SeqPseudoVars']:
1428        obj = data['SeqPseudoVars'][expr]
1429        calcobj = G2obj.ExpressionCalcObj(obj)
1430        valList = []
1431        esdList = []
1432        for seqnum,name in enumerate(histNames):
1433            sigs = data[name]['sig']
1434            G2mv.InitVars()
1435            parmDict = data[name].get('parmDict')
1436            constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum])
1437            groups,parmlist,constrDict,fixedList,ihst = constraintInfo
1438            varyList = data[name]['varyList']
1439            parmDict = data[name]['parmDict']
1440            msg = G2mv.EvaluateMultipliers(constrDict,parmDict)
1441            if msg:
1442                print('Unable to interpret multiplier(s) for',name,':',msg)
1443                continue
1444            G2mv.GenerateConstraints(varyList,constrDict,fixedList,parmDict,SeqHist=ihst)
1445            if 'Dist' in expr:
1446                derivs = G2mth.CalcDistDeriv(obj.distance_dict,obj.distance_atoms, parmDict)
1447                pId = obj.distance_dict['pId']
1448                aId,bId = obj.distance_atoms
1449                varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']]
1450                varyNames += ['%d::dA%s:%d'%(pId,ip,bId) for ip in ['x','y','z']]
1451                VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix'])
1452                esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) ))
1453#                GSASIIpath.IPyBreak()
1454            elif 'Angle' in expr:
1455                derivs = G2mth.CalcAngleDeriv(obj.angle_dict,obj.angle_atoms, parmDict)
1456                pId = obj.angle_dict['pId']
1457                aId,bId = obj.angle_atoms
1458                varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']]
1459                varyNames += ['%d::dA%s:%d'%(pId,ip,bId[0]) for ip in ['x','y','z']]
1460                varyNames += ['%d::dA%s:%d'%(pId,ip,bId[1]) for ip in ['x','y','z']]
1461                VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix'])
1462                esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) ))
1463            else:
1464                derivs = np.array(
1465                    [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD)
1466                     for var,ESD in zip(varyList,sigs)])
1467                if None in list(derivs):
1468                    esdList.append(None)
1469                else:
1470                    esdList.append(np.sqrt(
1471                        np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T)) ))
1472            PSvarDict = parmDict.copy()
1473            PSvarDict.update(sampleDict[name])
1474            UpdateParmDict(PSvarDict)
1475            calcobj.UpdateDict(PSvarDict)
1476            valList.append(calcobj.EvalExpression())
1477#            if calcobj.su is not None: esdList[-1] = calcobj.su
1478        if not esdList:
1479            esdList = None
1480        G2frame.colList += [valList]
1481        G2frame.colSigs += [esdList]
1482        colLabels += [expr]
1483        Types += [wg.GRID_VALUE_FLOAT+':10,5']
1484    #---- table build done -------------------------------------------------------------
1485
1486    # Make dict needed for creating & editing pseudovars (PSvarDict).
1487   
1488    name = histNames[0]
1489    parmDict = data[name].get('parmDict',{})
1490    PSvarDict = parmDict.copy()
1491    PSvarDict.update(sampleParms)
1492    UpdateParmDict(PSvarDict)
1493    # Also dicts of variables
1494    # for Parametric fitting from the data table
1495    parmDict = dict(zip(colLabels,list(zip(*G2frame.colList))[0])) # scratch dict w/all values in table
1496    parmDict.update({var:val for var,val in newCellDict.values()}) #  add varied reciprocal cell terms
1497    del parmDict['Use']
1498    name = histNames[0]
1499
1500    # remove selected items from table
1501    saveColLabels = colLabels[:]
1502    if G2frame.SeqTblHideList is None:      #set default hides
1503        G2frame.SeqTblHideList = [item for item in saveColLabels if 'Back' in item]
1504        G2frame.SeqTblHideList += [item for item in saveColLabels if 'dA' in item]
1505        G2frame.SeqTblHideList += [item for item in saveColLabels if ':*:D' in item]
1506    #******************************************************************************
1507    # create a set of values for example evaluation of pseudovars and
1508    # this does not work for refinements that have differing numbers of variables.
1509    VarDict = {}
1510    for i,var in enumerate(colLabels):
1511        if var in ['Use','Rwp',u'\u0394\u03C7\u00B2 (%)']: continue
1512        if G2frame.colList[i][0] is None:
1513            val,sig = firstValueDict.get(var,[None,None])
1514        elif G2frame.colSigs[i]:
1515            val,sig = G2frame.colList[i][0],G2frame.colSigs[i][0]
1516        else:
1517            val,sig = G2frame.colList[i][0],None
1518        if striphist(var) not in Dlookup:
1519            VarDict[var] = val
1520    # add recip cell coeff. values
1521    VarDict.update({var:val for var,val in newCellDict.values()})
1522
1523    # remove items to be hidden from table
1524    for l in reversed(range(len(colLabels))):
1525        if colLabels[l] in G2frame.SeqTblHideList:
1526            del colLabels[l]
1527            del G2frame.colList[l]
1528            del G2frame.colSigs[l]
1529
1530    # make a copy of the column labels substituting alternate labels when defined
1531    displayLabels = colLabels[:]
1532    for i,l in enumerate(colLabels):
1533        if l in variableLabels:
1534            displayLabels[i] = variableLabels[l]
1535           
1536    G2frame.dataWindow.ClearData()
1537    G2frame.dataWindow.currentGrids = []
1538    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataWindow)
1539    G2frame.dataDisplay.SetScrollRate(10,10)
1540    G2frame.dataWindow.GetSizer().Add(G2frame.dataDisplay,1,wx.ALL|wx.EXPAND)
1541    if histNames[0].startswith('PWDR'):
1542        #rowLabels = [str(i)+': '+l[5:30] for i,l in enumerate(histNames)]
1543        rowLabels = [l[5:] for i,l in enumerate(histNames)]
1544    else:
1545        rowLabels = histNames
1546    G2frame.SeqTable = G2G.Table([list(cl) for cl in zip(*G2frame.colList)],     # convert from columns to rows
1547        colLabels=displayLabels,rowLabels=rowLabels,types=Types)
1548    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
1549    # make all Use editable all others ReadOnly
1550    for c in range(len(colLabels)):
1551        for r in range(nRows):
1552            if c == 1:
1553                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False)
1554            else:
1555                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True)
1556    if 'phoenix' in wx.version():
1557        G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange)
1558    else:
1559        G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, OnCellChange)
1560#    G2frame.dataDisplay.Bind(wx.EVT_KEY_UP,OnKeyUp)
1561    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, PlotSSelect)
1562    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, PlotSelect)
1563#    G2frame.dataDisplay.Bind(wg.EVT_GRID_SELECT_CELL,PlotSSelect)
1564    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, SetLabelString)
1565    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
1566    G2frame.dataDisplay.SetMargins(0,0)
1567    G2frame.dataDisplay.AutoSizeColumns(False)
1568    # highlight unconverged shifts
1569    if histNames[0][:4] not in ['SASD','IMG ','REFD',]:
1570        for row,name in enumerate(histNames):
1571            deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol)
1572            try:
1573                if deltaChi > 10.:
1574                    G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0))
1575                elif deltaChi > 1.0:
1576                    G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0))
1577            except:
1578                pass
1579    G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip)
1580    #G2frame.dataDisplay.SendSizeEvent() # resize needed on mac
1581    #G2frame.dataDisplay.Refresh() # shows colored text on mac
1582    G2frame.dataWindow.SetDataSize()
Note: See TracBrowser for help on using the repository browser.