source: sasview/guitools/fitDialog.py @ c09ac449

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since c09ac449 was 3755d77, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

fixed bug with transforms

  • Property mode set to 100644
File size: 19.7 KB
RevLine 
[6cfe703]1#!/usr/bin/python
2
3# fitDialog.py
4
5import wx
[e40b651]6from PlotPanel import PlotPanel
7from plottables import Theory1D
8import math,pylab,fittings
[831149e]9import transform
10
[05da1f89]11def format_number(value, high=False):
12    """
13        Return a float in a standardized, human-readable formatted string
14    """
[052a66bc]15    try: 
16        value = float(value)
17    except:
18        print "returning 0"
19        return "0"
20   
[05da1f89]21    if high:
22        return "%-6.4g" % value
23    else:
24        return "%-5.3g" % value
25
[831149e]26
[6cfe703]27class LinearFit(wx.Dialog):
[f52bea1]28    def __init__(self, parent, plottable, push_data,transform, id, title):
[1c94a9f1]29        wx.Dialog.__init__(self, parent, id, title, size=(400, 350))
[05da1f89]30
[6cfe703]31        """
[b43a009]32            Dialog window pops- up when select Linear fit on Context menu
33            Displays fitting parameters
[6cfe703]34        """
35        self.parent = parent
[f52bea1]36        self.transform = transform
[05da1f89]37       
[1c94a9f1]38        # Registered owner for close event
39        self._registered_close = None
40       
[e40b651]41        #dialog panel self call function to plot the fitting function
42        self.push_data = push_data
43        #dialog self plottable
44        self.plottable = plottable
[05da1f89]45       
[ddff053]46        # Receive transformations of x and y
[b43a009]47        self.xLabel,self.yLabel,self.Avalue,self.Bvalue,\
48        self.ErrAvalue,self.ErrBvalue,self.Chivalue= self.transform()
[05da1f89]49       
[e40b651]50        #Dialog interface
[6cfe703]51        vbox  = wx.BoxSizer(wx.VERTICAL)
[106ef4d]52        sizer = wx.GridBagSizer(5,5)
53       
[05da1f89]54        _BOX_WIDTH = 100
[6cfe703]55 
[05da1f89]56        self.tcA      = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
57        self.tcA.SetToolTipString("Fit value for the slope parameter.")
58        self.tcErrA   = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
59        self.tcErrA.SetToolTipString("Error on the slope parameter.")
60        self.tcB      = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
61        self.tcA.SetToolTipString("Fit value for the constant parameter.")
62        self.tcErrB   = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
63        self.tcErrB.SetToolTipString("Error on the constant parameter.")
64        self.tcChi    = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
65        self.tcChi.SetToolTipString("Chi^2 over degrees of freedom.")
66        self.xminFit  = wx.TextCtrl(self,-1,size=(_BOX_WIDTH,20))
[6a8adb0]67        self.xminFit.SetToolTipString("Enter the minimum value on the x-axis to be included in the fit.")
[05da1f89]68        self.xmaxFit  = wx.TextCtrl(self,-1,size=(_BOX_WIDTH,20))
[6a8adb0]69        self.xmaxFit.SetToolTipString("Enter the maximum value on the x-axis to be included in the fit.")
[05da1f89]70        self.initXmin = wx.TextCtrl(self,-1,size=(_BOX_WIDTH,20))
[1c94a9f1]71        self.initXmin.SetToolTipString("Minimum value on the x-axis for the plotted data.")
[05da1f89]72        self.initXmax = wx.TextCtrl(self,-1,size=(_BOX_WIDTH,20))
[1c94a9f1]73        self.initXmax.SetToolTipString("Maximum value on the x-axis for the plotted data.")
[05da1f89]74
75        # Make the info box not editable
76        #_BACKGROUND_COLOR = '#ffdf85'
77        _BACKGROUND_COLOR = self.GetBackgroundColour()
78        self.initXmin.SetEditable(False)
79        self.initXmin.SetBackgroundColour(_BACKGROUND_COLOR)
80        self.initXmax.SetEditable(False)
81        self.initXmax.SetBackgroundColour(_BACKGROUND_COLOR)
82       
83       
84        # Buttons on the bottom
85        self.static_line_1 = wx.StaticLine(self, -1)
86        self.btFit =wx.Button(self,-1,'Fit')
87        self.btFit.Bind(wx.EVT_BUTTON, self._onFit)
88        self.btFit.SetToolTipString("Perform fit.")
89        self.btClose =wx.Button(self, wx.ID_CANCEL,'Close')
[1c94a9f1]90        self.btClose.Bind(wx.EVT_BUTTON, self._on_close)
[05da1f89]91       
92        # Intro
93        explanation  = "Perform fit for y(x) = Ax + B"
94       
95        vbox.Add(sizer)
[8e44d51]96       
[106ef4d]97        ix = 0
[6cfe703]98        iy = 1
[05da1f89]99        sizer.Add(wx.StaticText(self, -1, explanation),(iy, ix),\
100                 (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
101        iy += 2
102        sizer.Add(wx.StaticText(self, -1, 'Parameter A'),(iy, ix),\
[106ef4d]103                 (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[6cfe703]104        ix += 1
[106ef4d]105        sizer.Add(self.tcA,(iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]106        ix += 1
[05da1f89]107        sizer.Add(wx.StaticText(self, -1, '+/-'),(iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]108        ix += 1
[106ef4d]109        sizer.Add(self.tcErrA, (iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]110        iy += 1
[106ef4d]111        ix = 0
[05da1f89]112        sizer.Add(wx.StaticText(self, -1, 'Parameter B'),(iy, ix),(1,1),\
[106ef4d]113                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[6cfe703]114        ix += 1
[106ef4d]115        sizer.Add(self.tcB, (iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]116        ix += 1
[05da1f89]117        sizer.Add(wx.StaticText(self, -1, '+/-'),(iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]118        ix += 1
[106ef4d]119        sizer.Add(self.tcErrB, (iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]120        iy += 1
[106ef4d]121        ix = 0
[05da1f89]122        sizer.Add(wx.StaticText(self, -1, 'Chi2/dof'),(iy, ix),(1,1),\
[106ef4d]123                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[6cfe703]124        ix += 1
[106ef4d]125        sizer.Add(self.tcChi, (iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[05da1f89]126        iy += 2
[6cfe703]127        ix = 1
[05da1f89]128        sizer.Add(wx.StaticText(self, -1, 'Min'),(iy, ix),(1,1),\
[106ef4d]129                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]130        ix += 2
[05da1f89]131        sizer.Add(wx.StaticText(self, -1, 'Max'),(iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]132        iy += 1
[831149e]133        ix = 0
[1c94a9f1]134        sizer.Add(wx.StaticText(self, -1, 'Maximum range (linear scale)'),(iy, ix),(1,1),\
[831149e]135                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
136        ix +=1
[83fe2cc]137        sizer.Add(self.initXmin, (iy, ix),(1,1),\
[831149e]138                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
139        ix += 2
[83fe2cc]140        sizer.Add(self.initXmax, (iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[b43a009]141       
[ddff053]142        iy += 1
[831149e]143        ix = 0
[6a8adb0]144        sizer.Add(wx.StaticText(self, -1, 'Fit range of '+self.xLabel),(iy, ix),(1,1),\
[831149e]145                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
146        ix += 1
[83fe2cc]147        sizer.Add(self.xminFit, (iy, ix),(1,1),\
[ddff053]148                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
149        ix += 2
[83fe2cc]150        sizer.Add(self.xmaxFit, (iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[6cfe703]151        iy += 1
[106ef4d]152        ix = 1
153       
[05da1f89]154        vbox.Add(self.static_line_1, 0, wx.EXPAND, 0)
155       
156        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
157        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
158        sizer_button.Add(self.btFit, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
159        sizer_button.Add(self.btClose, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
160        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
161       
162       
163       
[106ef4d]164        sizer.Add(self.btFit, (iy, ix),(1,1), wx.LEFT|wx.ADJUST_MINSIZE, 0)
165       
[05da1f89]166       
167        #panel.SetSizer(sizer)
[6cfe703]168        self.SetSizer(vbox)
169        self.Centre()
[8e44d51]170       
[e40b651]171        # Receives the type of model for the fitting
172        from LineModel import LineModel
173        self.model  = LineModel()
[1fdb81d]174         
175        #Display the fittings values
176        self.default_A = self.model.getParam('A') 
177        self.default_B = self.model.getParam('B') 
178        self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
179        self.cstB  = fittings.Parameter(self.model, 'B', self.default_B)
180       
181        # Set default value of parameter in fit dialog
[90640f2]182       
[b43a009]183        if self.Avalue==None:
[052a66bc]184            self.tcA.SetLabel(format_number(self.default_A))
[b43a009]185        else :
[052a66bc]186            self.tcA.SetLabel(format_number(self.Avalue))
[b43a009]187        if self.Bvalue==None:
[052a66bc]188            self.tcB.SetLabel(format_number(self.default_B))
[b43a009]189        else:
[052a66bc]190            self.tcB.SetLabel(format_number(self.Bvalue))
[b43a009]191        if self.ErrAvalue==None:
[052a66bc]192            self.tcErrA.SetLabel(format_number(0.0))
[b43a009]193        else:
[052a66bc]194            self.tcErrA.SetLabel(format_number(self.ErrAvalue))
[b43a009]195        if self.ErrBvalue==None:
[052a66bc]196            self.tcErrB.SetLabel(format_number(0.0))
[b43a009]197        else:
[052a66bc]198            self.tcErrB.SetLabel(format_number(self.ErrBvalue))
[b43a009]199        if self.Chivalue==None:
[052a66bc]200            self.tcChi.SetLabel(format_number(0.0))
[b43a009]201        else:
[052a66bc]202            self.tcChi.SetLabel(format_number(self.Chivalue))
[831149e]203        if self.plottable.x !=[]:
[83fe2cc]204            #store the values of View in self.x,self.y,self.dx,self.dy
205            self.x,self.y,self.dx,self.dy= self.plottable.returnValuesOfView()
[90640f2]206           
[3755d77]207            #self.mini =min(self.x)
208            #self.maxi =max(self.x)
[90640f2]209           
[3755d77]210            try:
211                self.mini = self.floatForwardTransform(min(self.x))
212            except:
213                self.mini = "Invalid"
214            try:
215                self.maxi = self.floatForwardTransform(max(self.x))
216            except:
217                self.maxi = "Invalid"
[05da1f89]218           
[1c94a9f1]219            self.initXmin.SetValue(format_number(min(self.plottable.x)))
220            self.initXmax.SetValue(format_number(max(self.plottable.x)))
[90640f2]221           
[05da1f89]222            self.xminFit.SetLabel(format_number(self.mini))
223            self.xmaxFit.SetLabel(format_number(self.maxi))
[5e14aee]224       
[90640f2]225     
[1c94a9f1]226    def register_close(self, owner):
227        """
228            Method to register the close event to a parent
229            window that needs notification when the dialog
230            is closed
231            @param owner: parent window
232        """
233        self._registered_close = owner
234       
235    def _on_close(self, event):
236        """
237            Close event.
238            Notify registered owner if available.
239        """
240        event.Skip()
241        if self._registered_close is not None:
242            self._registered_close()
243       
[6cfe703]244    def _onFit(self ,event):
[f52bea1]245        """
246            Performs the fit. Receive an event when clicking on the button Fit.Computes chisqr ,
247            A and B parameters of the best linear fit y=Ax +B
248            Push a plottable to
249        """
250        tempx=[]
251        tempy=[]
[7a03e65]252        tempdy = []
[ddff053]253       
[83fe2cc]254       
255       
[1fdb81d]256       
[106ef4d]257        # Check if View contains a x array .we online fit when x exits
258        # makes transformation for y as a line to fit
[83fe2cc]259        if self.x != []: 
[ddff053]260           
261               
[83fe2cc]262            if(self.checkFitValues(self.xminFit) == True):
[f193585]263                #Check if the field of Fit Dialog contain values and use the x max and min of the user
[1c94a9f1]264                xminView,xmaxView = self._checkVal(self.xminFit.GetValue(),self.xmaxFit.GetValue())
265                xmin = self.floatInvTransform(xminView)
266                xmax = self.floatInvTransform(xmaxView)
267               
[ddff053]268               
[f193585]269                # Store the transformed values of view x, y,dy in variables  before the fit
[b43a009]270                if  self.yLabel.lower() == "log10(y)":
271                    if (self.xLabel.lower() == "log10(x)"):
[83fe2cc]272                        for i in range(len(self.x)):
273                            if self.x[i]>= math.log10(xmin):
274                                tempy.append(math.log10(self.y[i])) 
275                                tempdy.append(transform.errToLogX(self.y[i],0,self.dy[i],0))
[f193585]276                    else:
[83fe2cc]277                        for i in range(len(self.y)):
278                            tempy.append(math.log10(self.y[i])) 
279                            tempdy.append(transform.errToLogX(self.y[i],0,self.dy[i],0))
[f193585]280                else:
[83fe2cc]281                    tempy = self.y
282                    tempdy = self.dy
[f193585]283               
[b43a009]284                if (self.xLabel.lower() == "log10(x)"):
[83fe2cc]285                    for x_i in self.x:
[34ae302]286                        if x_i >= math.log10(xmin):
[f193585]287                            tempx.append(math.log10(x_i)) 
288                else:
[83fe2cc]289                    tempx = self.x
[b43a009]290             
[f193585]291                #Find the fitting parameters
[ad8bcd6]292                # Always use the same defaults, so that fit history doesn't play a role!
293                self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
294                self.cstB  = fittings.Parameter(self.model, 'B', self.default_B)
[ddff053]295               
[b43a009]296                if (self.xLabel.lower() == "log10(x)"):
[34ae302]297                    chisqr, out, cov = fittings.sansfit(self.model, [self.cstA, self.cstB],
298                    tempx, tempy,tempdy,math.log10(xmin),math.log10(xmax))
299                else:
300                    chisqr, out, cov = fittings.sansfit(self.model, 
[f193585]301                                [self.cstA, self.cstB],tempx, tempy,tempdy,xminView,xmaxView)
[05da1f89]302               
303                # Use chi2/dof
304                if len(tempx)>0:
305                    chisqr = chisqr/len(tempx)
306               
[f193585]307                #Check that cov and out are iterable before displaying them
308                if cov ==None:
309                    errA =0.0
310                    errB =0.0
311                else:
312                    errA= math.sqrt(cov[0][0])
313                    errB= math.sqrt(cov[1][1])
314                if out==None:
315                    cstA=0.0
316                    cstB=0.0
317                else:
318                    cstA=out[0]
319                    cstB=out[1]
320                # Reset model with the right values of A and B
321                self.model.setParam('A', float(cstA))
322                self.model.setParam('B', float(cstB))
[3aa7074]323               
[f193585]324                tempx = []
325                tempy = []
326                y_model = 0.0
327                # load tempy with the minimum transformation
328               
[b43a009]329                if self.xLabel == "log10(x)":
[f193585]330                    y_model = self.model.run(math.log10(xmin))
331                    tempx.append(xmin)
332                else:
333                    y_model = self.model.run(xminView)
334                    tempx.append(xminView)
335                   
[b43a009]336                if self.yLabel == "log10(y)":
[f193585]337                    tempy.append(math.pow(10,y_model))
338                    print "tempy",tempy
339                else:
340                    tempy.append(y_model)
341                   
342                # load tempy with the maximum transformation
[b43a009]343                if self.xLabel == "log10(x)":
[f193585]344                    y_model = self.model.run(math.log10(xmax))
345                    tempx.append(xmax)
346                else:
347                    y_model = self.model.run(xmaxView)
348                    tempx.append(xmaxView)
349                   
[b43a009]350                if self.yLabel == "log10(y)":
[f193585]351                    tempy.append(math.pow(10,y_model))
352                else: 
353                    tempy.append(y_model)
[83fe2cc]354                #Set the fit parameter display when  FitDialog is opened again
[2e07e8f]355                self.Avalue=cstB
356                self.Bvalue=cstA
[b43a009]357                self.ErrAvalue=errA
358                self.ErrBvalue=errB
359                self.Chivalue=chisqr
360                self.push_data(tempx,tempy,xminView,xmaxView,xmin,xmax,self._ongetValues())
[f193585]361               
362                # Display the fitting value on the Fit Dialog
[2e07e8f]363                self._onsetValues(cstB, cstA, errA,errB,chisqr)
[b43a009]364               
365               
[7a03e65]366           
[6cfe703]367    def _onsetValues(self,cstA,cstB,errA,errB,Chi):
[f52bea1]368         """
369              Display  the value on fit Dialog
370         """
[05da1f89]371         self.tcA.SetValue(format_number(cstA))
372         self.tcB.SetValue(format_number(cstB))
373         self.tcErrA.SetValue(format_number(errA))
374         self.tcErrB.SetValue(format_number(errB))
375         self.tcChi.SetValue(format_number(Chi))
[b43a009]376       
377    def _ongetValues(self):
378         """
379              Display  the value on fit Dialog
380         """
381         return self.Avalue, self.Bvalue,self.ErrAvalue,self.ErrBvalue,self.Chivalue
[e40b651]382         
383   
[831149e]384    def _checkVal(self,usermin, usermax):
[6cfe703]385        """
[831149e]386                Ensure that fields parameter contains a min and a max value
387                within x min and x max range
[6cfe703]388        """
[831149e]389        if float(usermin) < float(usermax):
390            if float(usermin) >= float(self.mini) and float(usermin) < float(self.maxi):
[3755d77]391                self.xminFit.SetValue(format_number(float(usermin)))
[831149e]392            else:
[3755d77]393                self.xminFit.SetValue(format_number(float(self.mini)))
[831149e]394               
395            if float(usermax) > float(self.mini) and float(usermax) <= float(self.maxi):
[3755d77]396                self.xmaxFit.SetLabel(format_number(float(usermax)))
[831149e]397            else:
[3755d77]398                self.xmaxFit.SetLabel(format_number(float(self.maxi)))
[831149e]399               
[83fe2cc]400            mini =float(self.xminFit.GetValue())
401            maxi =float(self.xmaxFit.GetValue())
[831149e]402           
403            return mini, maxi
[3755d77]404       
405    def floatForwardTransform(self,x):
406        """
407             transform a float.
408        """
409        #TODO: refactor this with proper object-oriented design
410        # This code stinks.
411       
412        if ( self.xLabel=="x" ):
413            return transform.toX(x)
414       
415        if ( self.xLabel=="x^(2)" ): 
416            return transform.toX2(x)
417       
418        if (self.xLabel=="log10(x)" ):
419            return math.log10(x)
420           
[831149e]421    def floatTransform(self,x):
422        """
423             transform a float.It is use to determine the x.View min and x.View max for values
424             not in x
425        """
[1c94a9f1]426        #TODO: refactor this with proper object-oriented design
427        # This code stinks.
428       
[b43a009]429        if ( self.xLabel=="x" ):
[831149e]430            return transform.toX(x)
431       
[b43a009]432        if ( self.xLabel=="x^(2)" ): 
[831149e]433            return transform.toX2(x)
434       
[b43a009]435        if (self.xLabel=="log10(x)" ):
[831149e]436            if x >0:
[34ae302]437                return x
[831149e]438            else:
439                raise ValueError,"cannot compute log of a negative number"
[f193585]440           
[1c94a9f1]441    def floatInvTransform(self,x):
442        """
443             transform a float.It is use to determine the x.View min and x.View max for values
444             not in x
445        """
446        #TODO: refactor this. This is just a hack to make the
447        # functionality work without rewritting the whole code
448        # with good design (which really should be done...).
449       
450        if ( self.xLabel=="x^(2)" ): 
451            return math.sqrt(x)
452       
453        elif (self.xLabel=="log10(x)" ):
454            return math.pow(10, x)
455       
456        return x
457           
[f193585]458    def checkFitValues(self,item):
459        """
460            Check the validity of input values
461        """
462        flag = True
463        value = item.GetValue()
464        # Check for possible values entered
[b43a009]465        if (self.xLabel=="log10(x)"):
[f193585]466            if (float(value) > 0):
467                item.SetBackgroundColour(wx.WHITE)
468                item.Refresh()
469            else:
470                flag = False
471                item.SetBackgroundColour("pink")
472                item.Refresh()
473     
474        return flag
[831149e]475       
[83fe2cc]476    def setFitRange(self,xmin,xmax,xminTrans,xmaxTrans):
477        """
478            Set fit parameters
479        """
[05da1f89]480        self.xminFit.SetValue(format_number(xmin))
481        self.xmaxFit.SetValue(format_number(xmax))
[ddff053]482       
[1c94a9f1]483    def set_fit_region(self, xmin, xmax):
484        """
485            Set the fit region
486            @param xmin: minimum x-value to be included in fit
487            @param xmax: maximum x-value to be included in fit
488        """
489        # Check values
490        try:
491            float(xmin)
492            float(xmax)
493        except:
494            raise ValueError, "LinearFit.set_fit_region: fit range must be floats"
495        self.xminFit.SetValue(format_number(xmin))
496        self.xmaxFit.SetValue(format_number(xmax))
[05da1f89]497 
498class MyApp(wx.App):
499    def OnInit(self):
500        wx.InitAllImageHandlers()
501        plot = Theory1D([],[])
502        dialog = LinearFit(None, plot, self.onFitDisplay,self.returnTrans, -1, 'Linear Fit')
503        if dialog.ShowModal() == wx.ID_OK:
504            pass
505        dialog.Destroy()
506       
507        return 1
508   
509    def onFitDisplay(self, tempx,tempy,xminView,xmaxView,xmin,xmax,func):
510        pass
511       
512    def returnTrans(self):
513        return '','',0,0,0,0,0
[6cfe703]514
[05da1f89]515# end of class MyApp
[6cfe703]516
[05da1f89]517if __name__ == "__main__":
518    app = MyApp(0)
519    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.