source: trunk/GSASIIseqGUI.py @ 5255

Last change on this file since 5255 was 5255, checked in by toby, 14 months ago

fix for sequential projects w/o ISODISTORT entry

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