source: trunk/GSASIIexprGUI.py @ 1396

Last change on this file since 1396 was 1396, checked in by toby, 8 years ago

fix bugs in multieq seq fits; print results better

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 28.7 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIexprGUI - Expression Definition and Evaluation
3########### SVN repository information ###################
4# $Date: 2014-06-25 23:20:41 +0000 (Wed, 25 Jun 2014) $
5# $Author: toby $
6# $Revision: 1396 $
7# $URL: trunk/GSASIIexprGUI.py $
8# $Id: GSASIIexprGUI.py 1396 2014-06-25 23:20:41Z toby $
9########### SVN repository information ###################
10'''
11*GSASIIexprGUI: Expression Handling*
12-------------------------------------
13
14This module defines a class for defining an expression in terms of values
15in a parameter dictionary via a wx.Dialog. The dialog creates a :class:`GSASII.ExpressionObj`
16which is used to evaluate the expression against a supplied parameter dictionary.
17
18The expression is parsed to find variables used in the expression and then
19the user is asked to assign parameters from the dictionary to each variable.
20
21'''
22import re
23import sys
24import wx
25import wx.lib.scrolledpanel as wxscroll
26import numpy as np
27import GSASIIgrid as G2gd
28import GSASIIpy3 as G2py3
29import GSASIIobj as G2obj
30
31def IndexParmDict(parmDict,wildcard):
32    '''Separate the parameters in parmDict into list of keys by parameter
33    type.
34   
35    :param dict parmDict: a dict with GSAS-II parameters
36    :param bool wildcard: True if wildcard versions of parameters should
37      be generated and added to the lists
38    :returns: a dict of lists where key 1 is a list of phase parameters,
39      2 is histogram/phase parms, 3 is histogram parms and 4 are global parameters
40    '''
41    prex = re.compile('[0-9]+::.*')
42    hrex = re.compile(':[0-9]+:.*')
43    parmLists = {}
44    for i in (1,2,3,4):
45        parmLists[i] = []
46    for i in sorted(parmDict.keys()):
47        if i.startswith("::") or i.find(':') == -1: # globals
48            parmLists[4].append(i)
49        elif prex.match(i):
50            parmLists[1].append(i)
51        elif hrex.match(i):
52            parmLists[3].append(i)
53        else:
54            parmLists[2].append(i)
55    if wildcard:
56        for i in (1,2,3,4):
57            parmLists[i] += G2obj.GenWildCard(parmLists[i]) # generate wildcard versions
58    for i in (1,2,3,4):
59        parmLists[i].sort()
60    return parmLists
61
62#==========================================================================
63class ExpressionDialog(wx.Dialog):
64    '''A wx.Dialog that allows a user to input an arbitrary expression
65    to be evaluated and possibly minimized.
66
67    To do this, the user assigns a new (free) or existing
68    GSAS-II parameter to each parameter label used in the expression.
69    The free parameters can optionally be designated to be refined.
70    For example, is an expression is used such as::
71
72    'A*np.exp(-B/C)'
73
74    then A, B and C can each be assigned as Free parameter with a user-selected
75    value or to any existing GSAS-II variable in the parameter dictionary.
76    As the expression is entered it is checked for validity.
77
78    After the :class:`ExpressionDialog` object is created, use :meth:`Show` to
79    run it and obtain a :class:`GSASIIobj.ExpressionObj` object with the user
80    input.
81
82    :param wx.Frame parent: The parent of the Dialog. Can be None,
83      but better is to provide the name of the Frame where the dialog
84      is called.
85    :param dict parmDict: a dict with defined parameters and their values. Each value
86      may be a list with parameter values and a refine flag or may just contain
87      the parameter value (non-float/int values in dict are ignored)
88    :param str exprObj: a :class:`GSASIIobj.ExpressionObj` object with an expression and
89      label assignments or None (default)
90    :param str wintitle: String placed on title bar of dialog;
91      defaults to "Expression Editor"
92    :param str header: String placed at top of dialog to tell the user
93      what they will do here; default is "Enter restraint expression here"
94    :param bool fit: determines if the expression will be used in fitting (default=True).
95      If set to False, and refinement flags are not shown
96      and Free parameters are not offered as an assignment option.
97    :param str VarLabel: an optional variable label to include before the expression
98      input. Ignored if None (default)
99    :param list depVarDict: a dict of choices for the dependent variable to be
100      fitted to the expression and their values. Ignored if None (default).
101    :param list ExtraButton: a list with two terms that define [0]: the label
102      for an extra button and [1] the callback routine to be used when the
103      button is pressed. The button will only be enabled when the OK button can be
104      used (meaning the equation/expression is valid). The default is None, meaning this
105      will not be used.
106    :param list usedVars: defines a list of previously used variable names. These names
107      will not be reused as defaults for new free variables.
108      (The default is an empty list).
109    '''
110    def __init__(self, parent, parmDict, exprObj=None,
111                 header='Enter restraint expression here',
112                 wintitle='Expression Editor',
113                 fit=True,VarLabel=None,depVarDict=None,
114                 ExtraButton=None,usedVars=[]):
115        self.fit = fit
116        self.depVarDict = depVarDict
117        'dict for dependent variables'
118        self.parmDict = {}
119        '''A copy of the G2 parameter dict (parmDict) except only numerical
120        values are included and only the value (not the vary flag, if present)
121        is included.
122        '''
123        self.exprVarLst = []
124        '''A list containing the variables utilized in the current expression.
125        Placed into a :class:`GSASIIobj.ExpressionObj` object when the dialog is closed
126        with "OK", saving any changes.
127        '''
128        self.varSelect = {}
129        '''A dict that shows the variable type for each label
130        found in the expression.
131
132        * If the value is None or is not defined, the value is not assigned.
133        * If the value is 0, then the varible is "free" -- a new refineable
134          parameter.
135        * Values above 1 determine what variables will be shown
136          when the option is selected.
137        '''
138        self.varName = {}
139        'Name assigned to each variable'
140        self.varValue = {}
141        'Value for a variable (Free parameters only)'
142        self.varRefflag = {}
143        'Refinement flag for a variable (Free parameters only)'
144        self.expr = ''
145        'Expression as a text string'
146        self.dependentVar = None
147        'name for dependent variable selection, when depVarDict is specified'
148        self.usedVars = usedVars
149        'variable names that have been used and should not be reused by default'
150
151        # process dictionary of values and create an index
152        for key in parmDict:
153            try: # deal with values that are in lists
154                val = parmDict[key][0]
155            except (TypeError,IndexError):
156                val = parmDict[key]
157            if isinstance(val, basestring): continue
158            try:
159                self.parmDict[key] = float(val)
160            except:
161                pass
162        # separate the variables by type
163        self.parmLists = IndexParmDict(self.parmDict,self.fit)
164        self.timer = wx.Timer()
165        self.timer.Bind(wx.EVT_TIMER,self.OnValidate)
166
167        style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER
168        wx.Dialog.__init__(self, parent, wx.ID_ANY, wintitle, style=style)
169        self.mainsizer = wx.BoxSizer(wx.VERTICAL)
170        label = wx.StaticText(self,  wx.ID_ANY, header)
171        self.mainsizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
172
173        self.exsizer = wx.BoxSizer(wx.HORIZONTAL)
174        if VarLabel:
175            label = wx.StaticText(self,  wx.ID_ANY, VarLabel + ' = ')
176            self.exsizer.Add(label, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0)
177        elif depVarDict:
178            self.depParmLists = IndexParmDict(self.depVarDict,False)
179            choices = ['','Phase','Hist./Phase','Hist.','Global']
180            for i in range(1,len(choices)): # remove empty menus from choice list
181                if not len(self.depParmLists[i]): choices[i] = ''
182            self.depChoices = [i for i in range(len(choices)) if choices[i]]
183            choice = wx.Choice(
184                self, wx.ID_ANY,
185                choices = [choices[i] for i in self.depChoices]
186                )
187            choice.SetSelection(wx.NOT_FOUND)
188            choice.Bind(wx.EVT_CHOICE,self.OnDepChoice)
189            self.exsizer.Add(choice, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0)
190            self.exsizer.Add((5,5))
191            self.depLabel = wx.StaticText(self,  wx.ID_ANY, ' ')
192            self.exsizer.Add(self.depLabel, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0)
193            label = wx.StaticText(self,  wx.ID_ANY, ' = ')
194            self.exsizer.Add(label, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0)
195
196        self.exCtrl = wx.TextCtrl(self,  wx.ID_ANY, size=(150,-1),style=wx.TE_PROCESS_ENTER)
197        self.exCtrl.Bind(wx.EVT_CHAR, self.OnChar)
198        self.exCtrl.Bind(wx.EVT_TEXT_ENTER, self.OnValidate)
199        self.exsizer.Add(self.exCtrl, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0)
200        #self.mainsizer.Add(self.exCtrl, 0, wx.ALL|wx.EXPAND, 5)
201        self.mainsizer.Add(self.exsizer, 0, wx.ALL|wx.EXPAND, 5)
202        self.mainsizer.Add((-1,5),0,wx.EXPAND,1)
203
204        evalSizer = wx.BoxSizer(wx.HORIZONTAL)
205        self.mainsizer.Add(evalSizer,0,wx.ALL|wx.EXPAND,0)
206        btn = wx.Button(self, wx.ID_ANY,"Validate")
207        btn.Bind(wx.EVT_BUTTON,self.OnValidate)
208        evalSizer.Add(btn,0,wx.LEFT|wx.RIGHT,5)
209        self.result = wx.StaticText(self,  wx.ID_ANY, '')
210        evalSizer.Add(self.result, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
211
212        self.varSizer = wx.BoxSizer(wx.HORIZONTAL)
213        self.mainsizer.Add(self.varSizer,1,wx.ALL|wx.EXPAND,1)
214        self.mainsizer.Add((-1,5),0,wx.EXPAND,1)
215
216        bSizer = wx.BoxSizer(wx.HORIZONTAL)
217        btnsizer = wx.StdDialogButtonSizer()
218        if ExtraButton:
219            self.ExtraBtn = wx.Button(self, wx.ID_ANY, ExtraButton[0])
220            self.ExtraBtn.Bind(wx.EVT_BUTTON,self.OnExtra)
221            self.ExtraCallBack = ExtraButton[1]
222            self.ExtraBtn.Disable()
223            bSizer.Add(self.ExtraBtn, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 2)
224        else:
225            self.ExtraBtn = None
226        bSizer.Add((1,1), 1, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 0)
227        self.OKbtn = wx.Button(self, wx.ID_OK)
228        self.OKbtn.SetDefault()
229        self.OKbtn.Disable()
230        btnsizer.AddButton(self.OKbtn)
231        btn = wx.Button(self, wx.ID_CANCEL)
232        btnsizer.AddButton(btn)
233        btnsizer.Realize()
234        bSizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
235        self.mainsizer.Add(bSizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5)
236        self.SetSizer(self.mainsizer)
237        self.CenterOnParent()
238        if exprObj:
239            self.expr = exprObj.EditExpression(
240                self.exprVarLst,
241                self.varSelect,
242                self.varName,
243                self.varValue,
244                self.varRefflag,
245                )
246            # set the initial value for the dependent value
247            if self.depVarDict:
248                var = exprObj.GetDepVar()
249                if var in self.depVarDict:
250                    self.depLabel.SetLabel(var)
251                    self.dependentVar = var
252                   
253        self.exCtrl.SetValue(self.expr)
254        self.OnValidate(None)
255        self.SetMinSize((620,300)) # seems like a good size
256        #self.errbox.SetAutoLayout(1)
257        #self.errbox.SetupScrolling()
258        #self.varbox.SetAutoLayout(1)
259        #self.varbox.SetupScrolling()
260        #self.mainsizer.Fit(self)
261
262    def OnExtra(self,event):
263        exprObj = G2obj.ExpressionObj()
264        exprObj.LoadExpression(
265            self.expr,
266            self.exprVarLst,
267            self.varSelect,
268            self.varName,
269            self.varValue,
270            self.varRefflag,
271            )
272        if self.depVarDict:
273            exprObj.SetDepVar(self.dependentVar)
274        self.ExtraCallBack(exprObj)
275        # put results back into displayed dialog
276        resDict = dict(exprObj.GetVariedVarVal())
277        for v,var in self.varName.items():
278            varname = "::" + var.lstrip(':').replace(' ','_').replace(':',';')
279            val =  resDict.get(varname)
280            if val:
281                self.varValue[v] = val
282        wx.CallAfter(self.ShowVars)
283
284    def Show(self,mode=True):
285        '''Call to use the dialog after it is created.
286
287        :returns: None (On Cancel) or a new :class:`~GSASIIobj.ExpressionObj`
288        '''
289        self.Layout()
290        self.mainsizer.Fit(self)
291        self.SendSizeEvent() # force repaint
292        if self.ShowModal() == wx.ID_OK:
293            # store the edit results in the object and return it
294            exprObj = G2obj.ExpressionObj()
295            exprObj.LoadExpression(
296                self.expr,
297                self.exprVarLst,
298                self.varSelect,
299                self.varName,
300                self.varValue,
301                self.varRefflag,
302                )
303            if self.depVarDict:
304                exprObj.SetDepVar(self.dependentVar)
305            return exprObj
306        else:
307            return None
308       
309    def setEvalResult(self,msg):
310        'Show a string in the expression result area'
311        self.result.SetLabel(msg)
312
313    def RestartTimer(self):
314        '''Cancels any running timer and starts a new one.
315        The timer causes a check of syntax after 2 seconds unless there is further input.
316        Disables the OK button until a validity check is complete.
317        '''
318        if self.timer.IsRunning():
319            self.timer.Stop()
320        self.timer.Start(2000,oneShot=True)
321       
322    def OnChar(self,event):
323        '''Called as each character is entered. Cancels any running timer
324        and starts a new one. The timer causes a check of syntax after 2 seconds
325        without input.
326        Disables the OK button until a validity check is complete.
327        '''
328        self.RestartTimer()
329        self.OKbtn.Disable()
330        if self.ExtraBtn: self.ExtraBtn.Disable()
331        event.Skip()
332        return
333   
334    def CheckVars(self):
335        '''Check that appropriate variables are defined for each
336        symbol used in :data:`self.expr`
337
338        :returns: a text error message or None if all needed input is present       
339        '''
340        invalid = 0
341        for v in self.exprVarLst:
342            if self.varSelect.get(v) is None:
343                invalid += 1
344        if invalid==1:
345            return '(a variable is not assigned)'
346        elif invalid:
347            return '('+str(invalid)+' variables are not assigned)'
348        msg = ''
349        for v in self.exprVarLst:
350            varname = self.varName.get(v)
351            if not varname:
352                invalid += 1
353                if msg: msg += "; "
354                msg += 'No variable for '+str(v)
355            elif self.varSelect.get(v) > 0:
356               if '*' in varname:
357                   l = G2obj.LookupWildCard(varname,self.parmDict.keys())
358                   if len(l) == 0:
359                       invalid += 1
360                       if msg: msg += "; "
361                       msg += 'No variables match '+str(varname)
362               elif varname not in self.parmDict.keys():
363                   invalid += 1
364                   if msg: msg += "; "
365                   msg += 'No variables match '+str(varname)
366            else:
367                # value assignment: this check is likely unneeded
368                val = self.varValue.get(v)
369                try:
370                    float(val)
371                except ValueError,TypeError:
372                    invalid += 1
373                    if msg: msg += "; "
374                    if val is None:
375                        msg += 'No value for '+str(v)
376                    else:
377                        msg += 'Value '+str(val)+' invalid for '+str(v)
378        if invalid:
379            return '('+msg+')'       
380        return
381
382    def ShowVars(self):
383        # create widgets to associate vars with labels and/or show messages
384        self.varSizer.Clear(True)
385        self.errbox = wxscroll.ScrolledPanel(self,style=wx.HSCROLL)
386        self.errbox.SetMinSize((100,130))
387        self.varSizer.Add(self.errbox,0,wx.ALL|wx.EXPAND,1)
388        self.varbox = wxscroll.ScrolledPanel(self,style=wx.HSCROLL)
389        self.varSizer.Add(self.varbox,1,wx.ALL|wx.EXPAND,1)
390        Siz = wx.BoxSizer(wx.VERTICAL)
391        Siz.Add(
392            wx.StaticText(self.varbox,wx.ID_ANY,
393                          'Assignment of variables to labels:'),
394            0,wx.EXPAND|wx.ALIGN_CENTER,0)
395        GridSiz = wx.FlexGridSizer(0,5,2,2)
396        GridSiz.Add(
397            wx.StaticText(self.varbox,wx.ID_ANY,'label',style=wx.CENTER),
398            0,wx.ALIGN_CENTER)
399        lbls = ('varib. type\nselection','variable\nname','value')
400        choices = ['Free','Phase','Hist./Phase','Hist.','Global']
401        if self.fit:
402            lbls += ('refine\nflag',)
403        else:
404            lbls += ('',)
405            choices[0] = ''
406        for i in range(1,len(choices)): # remove empty menus from choice list
407            if not len(self.parmLists[i]): choices[i] = ''
408        self.AllowedChoices = [i for i in range(len(choices)) if choices[i]]
409        for lbl in lbls:
410            w = wx.StaticText(self.varbox,wx.ID_ANY,lbl,style=wx.CENTER)
411            w.SetMinSize((80,-1))
412            GridSiz.Add(w,0,wx.ALIGN_CENTER)
413
414        # show input for each var in expression.
415        for v in self.exprVarLst:
416            # label
417            GridSiz.Add(wx.StaticText(self.varbox,wx.ID_ANY,v),0,wx.ALIGN_CENTER,0)
418            # assignment type
419            ch = wx.Choice(
420                self.varbox, wx.ID_ANY,
421                choices = [choices[i] for i in self.AllowedChoices]
422                )
423            GridSiz.Add(ch,0,wx.ALIGN_LEFT,0)
424            if v in self.varSelect and self.varSelect.get(v) in self.AllowedChoices:
425                i = self.AllowedChoices.index(self.varSelect[v])
426                ch.SetSelection(i)
427            else:
428                ch.SetSelection(wx.NOT_FOUND)
429            ch.label = v
430            ch.Bind(wx.EVT_CHOICE,self.OnChoice)
431
432            # var name/var assignment
433            if self.varSelect.get(v) is None:
434                GridSiz.Add((-1,-1),0,wx.ALIGN_LEFT|wx.EXPAND,0)
435            elif self.varSelect.get(v) == 0:
436                wid = G2gd.ValidatedTxtCtrl(self.varbox,self.varName,v,
437                                            #OnLeave=self.OnTxtLeave,
438                                            size=(50,-1))
439                GridSiz.Add(wid,0,wx.ALIGN_LEFT|wx.EXPAND,0)
440            else:
441                wid = wx.StaticText(self.varbox,wx.ID_ANY,self.varName[v])
442                GridSiz.Add(wid,0,wx.ALIGN_LEFT,0)
443
444            # value
445            if self.varSelect.get(v) is None:
446                GridSiz.Add((-1,-1),0,wx.ALIGN_RIGHT|wx.EXPAND,0)
447            elif self.varSelect.get(v) == 0:
448                wid = G2gd.ValidatedTxtCtrl(self.varbox,self.varValue,v,
449                                            #OnLeave=self.OnTxtLeave,
450                                            size=(75,-1))
451                GridSiz.Add(wid,0,wx.ALIGN_LEFT|wx.EXPAND,0)
452                wid.Bind(wx.EVT_CHAR,self.OnChar)
453            else:
454                var = self.varName[v]
455                if '*' in var:
456                    #[self.parmDict[v] for v in LookupWildCard(var,self.parmDict.keys())]
457                    #print self.varValue[v]
458                    vs = G2obj.LookupWildCard(var,self.parmDict.keys())
459                    s = '('+str(len(vs))+' values)'
460                elif var in self.parmDict:
461                    val = self.parmDict[var]
462                    s = G2py3.FormatSigFigs(val).rstrip('0')
463                else:
464                    s = '?'
465                wid = wx.StaticText(self.varbox,wx.ID_ANY,s)
466                GridSiz.Add(wid,0,wx.ALIGN_LEFT,0)
467
468            # show a refine flag for Free Vars only
469            if self.varSelect.get(v) == 0 and self.fit:
470                self.varRefflag[v] = self.varRefflag.get(v,True)
471                wid = G2gd.G2CheckBox(self.varbox,'',self.varRefflag,v)
472                GridSiz.Add(wid,0,wx.ALIGN_LEFT|wx.EXPAND,0)
473            else:
474                wid = (-1,-1)
475                GridSiz.Add(wid,0,wx.ALIGN_LEFT|wx.EXPAND,0)
476
477        Siz.Add(GridSiz)
478        self.varbox.SetSizer(Siz,True)
479        xwid,yhgt = Siz.Fit(self.varbox)
480        self.varbox.SetMinSize((xwid,130))
481        self.varbox.SetAutoLayout(1)
482        self.varbox.SetupScrolling()
483        self.varbox.Refresh()
484        self.Layout()
485        self.mainsizer.Fit(self)
486        self.SendSizeEvent() # force repaint
487        return
488
489    def OnDepChoice(self,event):
490        '''Respond to a selection of a variable type for a label in
491        an expression
492        '''
493        sel = self.depChoices[event.GetEventObject().GetSelection()]
494        var = self.SelectG2var(sel,'Dependent variable',self.depParmLists[sel])
495        if not var:
496            self.dependentVar = None
497            self.OnValidate(None)
498            event.GetEventObject().SetSelection(wx.NOT_FOUND)
499            return
500        self.dependentVar = var
501        self.depLabel.SetLabel(var)
502        self.OnValidate(None)
503        self.Layout()
504
505    def GetDepVar(self):
506        '''Returns the name of the dependent variable, when depVarDict is used.
507        '''
508        return self.dependentVar
509       
510    def OnChoice(self,event):
511        '''Respond to a selection of a variable type for a label in
512        an expression
513        '''
514        v = event.GetEventObject().label
515        sel = self.AllowedChoices[event.GetEventObject().GetSelection()]
516        self.varSelect[v] = sel
517        if sel == 0:
518            sv = G2obj.MakeUniqueLabel(v,self.usedVars)
519            self.varName[v] = sv
520            self.varValue[v] = self.varValue.get(v,0.0)
521        else:
522            var = self.SelectG2var(sel,v,self.parmLists[sel])
523            if not var:
524                del self.varSelect[v]
525                self.OnValidate(None)
526                return
527            self.varName[v] = var
528        self.OnValidate(None)
529
530    def SelectG2var(self,sel,var,parmList):
531        '''Offer a selection of a GSAS-II variable.
532
533        :param int sel: Determines the type of variable to be selected.
534          where 1 is used for Phase variables, and 2 for Histogram/Phase vars,
535          3 for Histogram vars and 4 for Global vars.
536        :returns: a variable name or None (if Cancel is pressed)
537        '''
538        if not parmList:
539            return None
540        l2 = l1 = 1
541        for i in parmList:
542            l1 = max(l1,len(i))
543            loc,desc = G2obj.VarDescr(i)
544            l2 = max(l2,len(loc))
545        fmt = u"{:"+str(l1)+"s} {:"+str(l2)+"s} {:s}"
546        varListlbl = [fmt.format(i,*G2obj.VarDescr(i)) for i in parmList]
547
548        dlg = G2gd.G2SingleChoiceDialog(
549            self,'Select GSAS-II variable for '+str(var)+':',
550            'Select variable',
551            varListlbl,monoFont=True)
552        dlg.SetSize((625,250))
553        dlg.CenterOnParent()
554        var = None
555        if dlg.ShowModal() == wx.ID_OK:
556            i = dlg.GetSelection()
557            var = parmList[i]
558        dlg.Destroy()
559        return var
560
561    def showError(self,msg1,msg2='',msg3=''):
562        '''Show an error message of 1 to 3 sections. The second
563        section is shown in an equally-spaced font.
564       
565        :param str msg1: msg1 is shown in a the standard font
566        :param str msg2: msg2 is shown in a equally-spaced (wx.MODERN) font
567        :param str msg3: msg3 is shown in a the standard font
568        '''
569        self.OKbtn.Disable()
570        if self.ExtraBtn: self.ExtraBtn.Disable()
571        self.varSizer.Clear(True)
572        self.errbox = wxscroll.ScrolledPanel(self,style=wx.HSCROLL)
573        self.errbox.SetMinSize((200,130))
574        self.varSizer.Add(self.errbox,1,wx.ALL|wx.EXPAND,1)
575        Siz = wx.BoxSizer(wx.VERTICAL)
576        errMsg1 = wx.StaticText(self.errbox, wx.ID_ANY,"")
577        Siz.Add(errMsg1, 0, wx.ALIGN_LEFT|wx.LEFT|wx.EXPAND, 5)
578        errMsg2 = wx.StaticText(self.errbox, wx.ID_ANY,"\n\n")
579        font1 = wx.Font(errMsg2.GetFont().GetPointSize(),
580                        wx.MODERN, wx.NORMAL, wx.NORMAL, False)
581        errMsg2.SetFont(font1)
582        Siz.Add(errMsg2, 0, wx.ALIGN_LEFT|wx.LEFT|wx.EXPAND, 5)
583        errMsg3 = wx.StaticText(self.errbox, wx.ID_ANY,"")
584        Siz.Add(errMsg3, 0, wx.ALIGN_LEFT|wx.LEFT|wx.EXPAND, 5)
585        self.errbox.SetSizer(Siz,True)
586        Siz.Fit(self.errbox)
587        errMsg1.SetLabel(msg1)
588        errMsg2.SetLabel("  "+msg2)
589        errMsg2.Wrap(-1)
590        errMsg3.SetLabel(msg3)
591        self.Layout()
592
593    def OnValidate(self,event):
594        '''Respond to a press of the Validate button or when a variable
595        is associated with a label (in :meth:`OnChoice`)
596        '''
597        self.setEvalResult('(expression cannot be evaluated)')
598        self.timer.Stop()
599        self.expr = self.exCtrl.GetValue().strip()
600        self.varSizer.Clear(True)
601        if not self.expr: 
602            self.showError(
603                "Invalid Expression:","",
604                "(an expression must be entered)")
605            return
606        exprObj = G2obj.ExpressionObj()
607        ret = exprObj.ParseExpression(self.expr)
608        if not ret:
609            self.showError(*exprObj.lastError)
610            return
611        self.exprVarLst,pkgdict = ret
612        wx.CallAfter(self.Repaint,exprObj)
613           
614    def Repaint(self,exprObj):
615        'Redisplay the variables and continue the validation'
616        self.ShowVars() # show widgets to set vars
617        msg = self.CheckVars() 
618        if msg:
619            self.setEvalResult(msg)
620            return
621        exprObj.LoadExpression(
622            self.expr,
623            self.exprVarLst,
624            self.varSelect,
625            self.varName,
626            self.varValue,
627            self.varRefflag,
628            )
629        try:
630            calcobj = G2obj.ExpressionCalcObj(exprObj)
631            calcobj.SetupCalc(self.parmDict)
632            val = calcobj.EvalExpression()
633        except Exception as msg:
634            self.setEvalResult("Error in evaluation: "+str(msg))
635            return
636        if not np.isfinite(val):
637            self.setEvalResult("Expression value is infinite or out-of-bounds")
638            return
639        s = G2py3.FormatSigFigs(val).rstrip('0')
640        depVal = ""
641        if self.depVarDict:
642            if not self.dependentVar:
643                self.setEvalResult("A dependent variable must be selected.")
644                return
645            depVal = '; Variable "' + self.dependentVar + '" = ' + str(
646                self.depVarDict.get(self.dependentVar,'?')
647                )
648        self.setEvalResult("Expression evaluates to: "+str(s)+depVal)
649        self.OKbtn.Enable()
650        if self.ExtraBtn: self.ExtraBtn.Enable()
651       
652if __name__ == "__main__":
653    app = wx.PySimpleApp() # create the App
654    frm = wx.Frame(None)
655    frm.Show()
656    PSvarDict = {'::a':1.0,'::b':1.1,'0::c':1.2,'::AlongVaraiableName':1000.}
657    #PSvars = PSvarDict.keys()
658    indepvarDict = {'Temperature':1.0,'Pressure':1.1,'Phase of Moon':1.2,'1:1:HAP':1.3}
659    dlg = ExpressionDialog(frm,indepvarDict,
660                           header="Edit the PseudoVar expression",
661                           fit=False,
662                           depVarDict=PSvarDict,
663                           #VarLabel="New PseudoVar",                           
664                           )
665    newobj = dlg.Show(True)
666    dlg = ExpressionDialog(frm,indepvarDict,newobj,
667                           header="Edit the PseudoVar expression",
668                           fit=False,
669                           depVarDict=PSvarDict,
670                           #VarLabel="New PseudoVar",                           
671                           )
672    newobj = dlg.Show(True)
673    print dlg.GetDepVar()
674    dlg = ExpressionDialog(frm,PSvarDict,
675                           header="Edit the PseudoVar expression",
676                           fit=True)
677    newobj = dlg.Show(True)
678    print dlg.GetDepVar()
679    import sys
680    #sys.exit()
681
682    #app.MainLoop()
683
684
685    import cPickle
686    def showEQ(calcobj):
687        print
688        print calcobj.eObj.expression
689        for v in sorted(calcobj.eObj.freeVars.keys()+calcobj.eObj.assgnVars.keys()):
690            print "  ",v,'=',calcobj.exprDict[v]
691        print calcobj.EvalExpression()
692    print "starting test"
693    obj = G2obj.ExpressionObj()
694    obj.expression = "A*np.exp(B)"
695    obj.assgnVars =  {'B': '0::Afrac:*'}
696    obj.freeVars =  {'A': [u'A', 0.5, True]}
697    obj.CheckVars()
698    parmDict2 = {'0::Afrac:0':1.0, '0::Afrac:1': 1.0}
699    calcobj = G2obj.ExpressionCalcObj(obj)
700    calcobj.SetupCalc(parmDict2)
701    showEQ(calcobj)
702    fp = open('/tmp/obj.pickle','w')
703    cPickle.dump(obj,fp)
704    fp.close()
705   
706    obj.expression = "A*np.exp(-2/B)"
707    obj.assgnVars =  {'A': '0::Afrac:0', 'B': '0::Afrac:1'}
708    obj.freeVars =  {}
709    parmDict1 = {'0::Afrac:0':1.0, '0::Afrac:1': -2.0}
710    calcobj = G2obj.ExpressionCalcObj(obj)
711    calcobj.SetupCalc(parmDict1)
712    showEQ(calcobj)
713
714    fp = open('/tmp/obj.pickle','r')
715    obj = cPickle.load(fp)
716    fp.close()
717    parmDict2 = {'0::Afrac:0':0.0, '0::Afrac:1': 1.0}
718    calcobj = G2obj.ExpressionCalcObj(obj)
719    calcobj.SetupCalc(parmDict2)
720    showEQ(calcobj)
721
722    parmDict2 = {'0::Afrac:0':1.0, '0::Afrac:1': 1.0}
723    calcobj = G2obj.ExpressionCalcObj(obj)
724    calcobj.SetupCalc(parmDict2)
725    showEQ(calcobj)
726   
Note: See TracBrowser for help on using the repository browser.