source: trunk/GSASIIseqGUI.py

Last change on this file was 5038, checked in by toby, 28 hours ago

Major revision to constraints including an update to the Sequential Refinement tutorial

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