source: sasview/fittingview/src/sans/perspectives/fitting/fitting_widgets.py @ e9bd127

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 e9bd127 was 6e01f06, checked in by Jae Cho <jhjcho@…>, 13 years ago

cjanged defaults for combobox in CUstom Sum editor

  • Property mode set to 100644
File size: 23.5 KB
Line 
1
2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2009, University of Tennessee
10################################################################################
11
12
13import wx
14import sys
15import os
16from wx.lib.scrolledpanel import ScrolledPanel
17
18#TextDialog size
19if sys.platform.count("win32") > 0:
20    FONT_VARIANT = 0
21    PNL_WIDTH = 460
22    PNL_HITE = 210
23else:
24    FONT_VARIANT = 1
25    PNL_WIDTH = 500
26    PNL_HITE = 250
27
28MAX_NBR_DATA = 4
29WIDTH = 430
30HEIGHT = 350
31
32class DialogPanel(ScrolledPanel):
33    def __init__(self, *args, **kwds):
34        ScrolledPanel.__init__(self, *args, **kwds)
35        self.SetupScrolling()
36       
37class BatchDataDialog(wx.Dialog):
38    """
39    The current design of Batch  fit allows only of type of data in the data
40    set. This allows the user to make a quick selection of the type of data
41    to use in fit tab.
42    """
43    def __init__(self, parent=None,  *args, **kwds):
44        wx.Dialog.__init__(self, parent, *args, **kwds)
45        self.SetSize((WIDTH, HEIGHT))
46        self.data_1d_selected = None
47        self.data_2d_selected = None
48        self._do_layout()
49   
50    def _do_layout(self):
51        """
52        Draw the content of the current dialog window
53        """
54        vbox = wx.BoxSizer(wx.VERTICAL)
55        box_description= wx.StaticBox(self, -1,str("Hint"))
56        hint_sizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
57        selection_sizer = wx.GridBagSizer(5,5)
58        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
59        self.data_1d_selected = wx.RadioButton(self, -1, 'Data1D',
60                                                style=wx.RB_GROUP)
61        self.data_2d_selected  = wx.RadioButton(self, -1, 'Data2D')
62        self.data_1d_selected.SetValue(True)
63        self.data_2d_selected.SetValue(False)
64        button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
65        button_OK = wx.Button(self, wx.ID_OK, "Ok")
66        button_OK.SetFocus()
67        hint = "Selected Data set contains both 1D and 2D Data.\n"
68        hint += "Please select on type of analysis before proceeding.\n"
69        hint_sizer.Add(wx.StaticText(self, -1, hint))
70        #draw area containing radio buttons
71        ix = 0
72        iy = 0
73        selection_sizer.Add(self.data_1d_selected, (iy, ix),
74                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
75        iy += 1
76        selection_sizer.Add(self.data_2d_selected, (iy, ix),
77                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
78        #contruction the sizer contaning button
79        button_sizer.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
80        button_sizer.Add(button_cancel, 0,
81                          wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
82        button_sizer.Add(button_OK, 0,
83                                wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
84        vbox.Add(hint_sizer,  0, wx.EXPAND|wx.ALL, 10)
85        vbox.Add(selection_sizer, 0, wx.TOP|wx.BOTTOM, 10)
86        vbox.Add(wx.StaticLine(self, -1),  0, wx.EXPAND, 0)
87        vbox.Add(button_sizer, 0 , wx.TOP|wx.BOTTOM, 10)
88        self.SetSizer(vbox)
89        self.Layout()
90       
91    def get_data(self):
92        """
93        return 1 if  user requested Data1D , 2 if user requested Data2D
94        """
95        if self.data_1d_selected.GetValue():
96            return 1
97        else:
98            return 2
99
100
101
102class DataDialog(wx.Dialog):
103    """
104    Allow file selection at loading time
105    """
106    def __init__(self, data_list, parent=None, text='',
107                 nb_data=MAX_NBR_DATA, *args, **kwds):
108        wx.Dialog.__init__(self, parent, *args, **kwds)
109        self.SetTitle("Data Selection")
110        self._max_data = nb_data
111        self._nb_selected_data = nb_data
112       
113        self.SetSize((WIDTH, HEIGHT))
114        self.list_of_ctrl = []
115        if not data_list:
116            return 
117        select_data_text = " %s Data selected.\n" % str(self._nb_selected_data)
118        self._data_text_ctrl = wx.StaticText(self, -1, str(select_data_text))
119                               
120        self._data_text_ctrl.SetForegroundColour('blue')
121        self._sizer_main = wx.BoxSizer(wx.VERTICAL)
122        self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
123        self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
124        self._choice_sizer = wx.GridBagSizer(5, 5)
125        self._panel = DialogPanel(self, style=wx.RAISED_BORDER,
126                               size=(WIDTH-20, HEIGHT/3))
127        self.__do_layout(data_list, text=text)
128       
129    def __do_layout(self, data_list, text=''):
130        """
131        layout the dialog
132        """
133        if not data_list or len(data_list) <= 1:
134            return 
135        #add text
136        if text.strip() == "":
137            text = "Fitting: We recommend that you selected"
138            text += " no more than '%s' data\n" % str(self._max_data)
139            text += "for adequate plot display size. \n" 
140            text += "unchecked data won't be send to fitting . \n" 
141        text_ctrl = wx.StaticText(self, -1, str(text))
142        self._sizer_txt.Add(text_ctrl)
143        iy = 0
144        ix = 0
145        data_count = 0
146        for i in range(len(data_list)):
147            data_count += 1
148            cb = wx.CheckBox(self._panel, -1, str(data_list[i].name), (10, 10))
149            wx.EVT_CHECKBOX(self, cb.GetId(), self._count_selected_data)
150            if data_count <= MAX_NBR_DATA:
151                cb.SetValue(True)
152            else:
153                cb.SetValue(False)
154            self.list_of_ctrl.append((cb, data_list[i]))
155            self._choice_sizer.Add(cb, (iy, ix),
156                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
157            iy += 1
158        self._panel.SetSizer(self._choice_sizer)
159        #add sizer
160        self._sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
161        button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
162        self._sizer_button.Add(button_cancel, 0,
163                          wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
164        button_OK = wx.Button(self, wx.ID_OK, "Ok")
165        button_OK.SetFocus()
166        self._sizer_button.Add(button_OK, 0,
167                                wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
168        static_line = wx.StaticLine(self, -1)
169        self._sizer_txt.Add(self._panel, 0, wx.EXPAND|wx.ALL, 10)
170        self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND|wx.ALL, 10)
171        self._sizer_main.Add(self._data_text_ctrl, 0,  wx.EXPAND|wx.ALL, 10)
172        self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
173        self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND|wx.ALL, 10)
174        self.SetSizer(self._sizer_main)
175        self.Layout()
176       
177    def get_data(self):
178        """
179        return the selected data
180        """
181        temp = []
182        for item in self.list_of_ctrl:
183            cb, data = item
184            if cb.GetValue():
185                temp.append(data)
186        return temp
187   
188    def _count_selected_data(self, event):
189        """
190        count selected data
191        """
192        if event.GetEventObject().GetValue():
193            self._nb_selected_data += 1
194        else:
195            self._nb_selected_data -= 1
196        select_data_text = " %s Data selected.\n" % str(self._nb_selected_data)
197        self._data_text_ctrl.SetLabel(select_data_text)
198        if self._nb_selected_data <= self._max_data:
199            self._data_text_ctrl.SetForegroundColour('blue')
200        else:
201            self._data_text_ctrl.SetForegroundColour('red')
202       
203 
204class TextDialog(wx.Dialog):
205    """
206    Dialog for easy custom sum models 
207    """
208    def __init__(self, parent=None, id=None, title='', model_list=[]):
209        """
210        Dialog window popup when selecting 'Easy Custom Sum' on the menu
211        """
212        wx.Dialog.__init__(self, parent=parent, id=id, 
213                           title=title, size=(PNL_WIDTH, PNL_HITE))
214        self.parent = parent
215        #Font
216        self.SetWindowVariant(variant=FONT_VARIANT)
217        # default
218        self.model_list = model_list
219        self.model1_string = "SphereModel"
220        self.model2_string = "CylinderModel"
221        self._build_sizer()
222        self.model1_name = str(self.model1.GetValue())
223        self.model2_name = str(self.model2.GetValue())
224       
225    def _build_sizer(self):
226        """
227        Build gui
228        """
229        _BOX_WIDTH = 195 # combobox width
230        vbox  = wx.BoxSizer(wx.VERTICAL)
231        sizer = wx.GridBagSizer(1, 3)
232        sum_description= wx.StaticBox(self, -1, 'Select', 
233                                       size=(PNL_WIDTH-30, 70))
234        sum_box = wx.StaticBoxSizer(sum_description, wx.VERTICAL)
235        model1_box = wx.BoxSizer(wx.HORIZONTAL)
236        model2_box = wx.BoxSizer(wx.HORIZONTAL)
237        model_vbox = wx.BoxSizer(wx.VERTICAL)
238        self.model1 =  wx.ComboBox(self, -1, style=wx.CB_READONLY)
239        wx.EVT_COMBOBOX(self.model1, -1, self.on_model1)
240        self.model1.SetMinSize((_BOX_WIDTH, -1))
241        self.model1.SetToolTipString("model1")
242        self.model2 =  wx.ComboBox(self, -1, style=wx.CB_READONLY)
243        wx.EVT_COMBOBOX(self.model2, -1, self.on_model2)
244        self.model2.SetMinSize((_BOX_WIDTH, -1))
245        self.model2.SetToolTipString("model2")
246        self._set_model_list()
247       
248         # Buttons on the bottom
249        self.static_line_1 = wx.StaticLine(self, -1)
250        self.okButton = wx.Button(self,wx.ID_OK, 'OK', size=(_BOX_WIDTH/2, 25))
251        self.closeButton = wx.Button(self,wx.ID_CANCEL, 'Cancel', 
252                                     size=(_BOX_WIDTH/2, 25))
253        # Intro
254        explanation  = "  custom model = scale_factor * (model1 + model2)\n"
255        model_string = " Model%s (p%s):"
256        vbox.Add(sizer)
257        ix = 0
258        iy = 1
259        sizer.Add(wx.StaticText(self, -1, explanation), (iy, ix),
260                 (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
261        model1_box.Add(wx.StaticText(self,-1, model_string% (1, 1)), -1, 0)
262        model1_box.Add((_BOX_WIDTH-35,10))
263        model1_box.Add(wx.StaticText(self, -1, model_string% (2, 2)), -1, 0)
264        model2_box.Add(self.model1, -1, 0)
265        model2_box.Add((20,10))
266        model2_box.Add(self.model2, -1, 0)
267        model_vbox.Add(model1_box, -1, 0)
268        model_vbox.Add(model2_box, -1, 0)
269        sum_box.Add(model_vbox, -1, 10)
270        iy += 1
271        ix = 0
272        sizer.Add(sum_box, (iy, ix),
273                  (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
274        vbox.Add((10,10))
275        vbox.Add(self.static_line_1, 0, wx.EXPAND, 10)
276        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
277        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
278        sizer_button.Add(self.okButton, 0, 
279                         wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 0)
280        sizer_button.Add(self.closeButton, 0,
281                          wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 15)       
282        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
283        self.SetSizer(vbox)
284        self.Centre()
285                 
286    def _set_model_list(self):
287        """
288        Set the list of models
289        """
290        # list of model names
291        list = self.model_list
292        if len(list) > 1:
293            list.sort()
294        for idx in range(len(list)):
295            self.model1.Append(list[idx],idx) 
296            self.model2.Append(list[idx],idx)
297        self.model1.SetStringSelection(self.model1_string)
298        self.model2.SetStringSelection(self.model2_string)
299           
300    def on_model1(self, event):
301        """
302        Set model1
303        """
304        event.Skip()
305        self.model1_name = str(self.model1.GetValue())
306        self.model1_string = self.model1_name
307           
308    def on_model2(self, event):
309        """
310        Set model2
311        """
312        event.Skip()
313        self.model2_name = str(self.model2.GetValue())
314        self.model2_string = self.model2_name
315 
316    def getText(self):
317        """
318        Returns model name string as list
319        """
320        return [self.model1_name, self.model2_name]
321   
322    def write_string(self, fname, name1, name2):
323        """
324        Write and Save file
325        """
326        try:
327            out_f =  open(fname,'w')
328        except :
329            raise
330        lines = SUM_TEMPLATE.split('\n')
331        for line in lines:
332            if line.count("import %s as P1"):
333                out_f.write(line % (name1, name1) + "\n")
334            elif line.count("import %s as P2"):
335                out_f.write(line % (name2, name2) + "\n")
336            else:
337                out_f.write(line + "\n")
338        out_f.close() 
339       
340    def compile_file(self, path):
341        """
342        Compile the file in the path
343        """
344        try:
345            import py_compile
346            py_compile.compile(file=path, doraise=True)
347        except:
348            type, value, traceback = sys.exc_info()
349            return value
350       
351    def delete_file(self, path):
352        """
353        Delete file in the path
354        """
355        try:
356            os.remove(path)
357        except:
358            raise
359       
360       
361SUM_TEMPLATE = """
362# A sample of an experimental model function for Sum(Pmodel1,Pmodel2)
363import copy
364from sans.models.pluginmodel import Model1DPlugin
365# User can change the name of the model (only with single functional model)
366#P1_model:
367from sans.models.%s import %s as P1
368
369#P2_model:
370from sans.models.%s import %s as P2
371
372class Model(Model1DPlugin):
373    name = ""
374    def __init__(self):
375        Model1DPlugin.__init__(self, name='')
376        p_model1 = P1()
377        p_model2 = P2()
378        ## Setting  model name model description
379        self.description=""
380        self.name = self._get_name(p_model1.name, p_model2.name)
381        self.description = p_model1.name
382        self.description += p_model2.name
383        self.fill_description(p_model1, p_model2)
384
385        ## Define parameters
386        self.params = {}
387
388        ## Parameter details [units, min, max]
389        self.details = {}
390       
391        # non-fittable parameters
392        self.non_fittable = p_model1.non_fittable 
393        self.non_fittable += p_model2.non_fittable 
394           
395        ##models
396        self.p_model1= p_model1
397        self.p_model2= p_model2
398       
399       
400        ## dispersion
401        self._set_dispersion()
402        ## Define parameters
403        self._set_params()
404        ## New parameter:Scaling factor
405        self.params['scale_factor'] = 1
406       
407        ## Parameter details [units, min, max]
408        self._set_details()
409        self.details['scale_factor'] = ['', None, None]
410
411       
412        #list of parameter that can be fitted
413        self._set_fixed_params() 
414        ## parameters with orientation
415        for item in self.p_model1.orientation_params:
416            new_item = "p1_" + item
417            if not new_item in self.orientation_params:
418                self.orientation_params.append(new_item)
419           
420        for item in self.p_model2.orientation_params:
421            new_item = "p2_" + item
422            if not new_item in self.orientation_params:
423                self.orientation_params.append(new_item)
424        # get multiplicity if model provide it, else 1.
425        try:
426            multiplicity1 = p_model1.multiplicity
427            try:
428                multiplicity2 = p_model2.multiplicity
429            except:
430                multiplicity2 = 1
431        except:
432            multiplicity1 = 1
433            multiplicity2 = 1
434        ## functional multiplicity of the model
435        self.multiplicity1 = multiplicity1 
436        self.multiplicity2 = multiplicity2   
437        self.multiplicity_info = []   
438       
439    def _clone(self, obj):
440        obj.params     = copy.deepcopy(self.params)
441        obj.description     = copy.deepcopy(self.description)
442        obj.details    = copy.deepcopy(self.details)
443        obj.dispersion = copy.deepcopy(self.dispersion)
444        obj.p_model1  = self.p_model1.clone()
445        obj.p_model2  = self.p_model2.clone()
446        #obj = copy.deepcopy(self)
447        return obj
448   
449    def _get_name(self, name1, name2):
450        name = self._get_upper_name(name1)
451        name += "+"
452        name += self._get_upper_name(name2)
453        return name
454   
455    def _get_upper_name(self, name=None):
456        if name == None:
457            return ""
458        upper_name = ""
459        str_name = str(name)
460        for index in range(len(str_name)):
461            if str_name[index].isupper():
462                upper_name += str_name[index]
463        return upper_name
464       
465    def _set_dispersion(self):
466        ##set dispersion only from p_model
467        for name , value in self.p_model1.dispersion.iteritems():
468            #if name.lower() not in self.p_model1.orientation_params:
469            new_name = "p1_" + name
470            self.dispersion[new_name]= value
471        for name , value in self.p_model2.dispersion.iteritems():
472            #if name.lower() not in self.p_model2.orientation_params:
473            new_name = "p2_" + name
474            self.dispersion[new_name]= value
475           
476    def function(self, x=0.0):
477        return 0
478                               
479    def getProfile(self):
480        try:
481            x,y = self.p_model1.getProfile()
482        except:
483            x = None
484            y = None
485           
486        return x, y
487   
488    def _set_params(self):
489        for name , value in self.p_model1.params.iteritems():
490            # No 2D-supported
491            #if name not in self.p_model1.orientation_params:
492            new_name = "p1_" + name
493            self.params[new_name]= value
494           
495        for name , value in self.p_model2.params.iteritems():
496            # No 2D-supported
497            #if name not in self.p_model2.orientation_params:
498            new_name = "p2_" + name
499            self.params[new_name]= value
500               
501        # Set "scale" as initializing
502        self._set_scale_factor()
503     
504           
505    def _set_details(self):
506        for name ,detail in self.p_model1.details.iteritems():
507            new_name = "p1_" + name
508            #if new_name not in self.orientation_params:
509            self.details[new_name]= detail
510           
511        for name ,detail in self.p_model2.details.iteritems():
512            new_name = "p2_" + name
513            #if new_name not in self.orientation_params:
514            self.details[new_name]= detail
515   
516    def _set_scale_factor(self):
517        pass
518       
519               
520    def setParam(self, name, value):
521        # set param to p1+p2 model
522        self._setParamHelper(name, value)
523       
524        ## setParam to p model
525        model_pre = name.split('_', 1)[0]
526        new_name = name.split('_', 1)[1]
527        if model_pre == "p1":
528            if new_name in self.p_model1.getParamList():
529                self.p_model1.setParam(new_name, value)
530        elif model_pre == "p2":
531             if new_name in self.p_model2.getParamList():
532                self.p_model2.setParam(new_name, value)
533        elif name.lower() == 'scale_factor':
534            self.params['scale_factor'] = value
535        else:
536            raise ValueError, "Model does not contain parameter %s" % name
537           
538    def getParam(self, name):
539        # Look for dispersion parameters
540        toks = name.split('.')
541        if len(toks)==2:
542            for item in self.dispersion.keys():
543                # 2D not supported
544                if item.lower()==toks[0].lower():
545                    for par in self.dispersion[item]:
546                        if par.lower() == toks[1].lower():
547                            return self.dispersion[item][par]
548        else:
549            # Look for standard parameter
550            for item in self.params.keys():
551                if item.lower()==name.lower():
552                    return self.params[item]
553        return 
554        #raise ValueError, "Model does not contain parameter %s" % name
555       
556    def _setParamHelper(self, name, value):
557        # Look for dispersion parameters
558        toks = name.split('.')
559        if len(toks)== 2:
560            for item in self.dispersion.keys():
561                if item.lower()== toks[0].lower():
562                    for par in self.dispersion[item]:
563                        if par.lower() == toks[1].lower():
564                            self.dispersion[item][par] = value
565                            return
566        else:
567            # Look for standard parameter
568            for item in self.params.keys():
569                if item.lower()== name.lower():
570                    self.params[item] = value
571                    return
572           
573        raise ValueError, "Model does not contain parameter %s" % name
574             
575   
576    def _set_fixed_params(self):
577        for item in self.p_model1.fixed:
578            new_item = "p1" + item
579            self.fixed.append(new_item)
580        for item in self.p_model2.fixed:
581            new_item = "p2" + item
582            self.fixed.append(new_item)
583
584        self.fixed.sort()
585               
586                   
587    def run(self, x = 0.0):
588        self._set_scale_factor()
589        return self.params['scale_factor'] * \
590(self.p_model1.run(x) + self.p_model2.run(x))
591   
592    def runXY(self, x = 0.0):
593        self._set_scale_factor()
594        return self.params['scale_factor'] * \
595(self.p_model1.runXY(x) + self.p_model2.runXY(x))
596   
597    ## Now (May27,10) directly uses the model eval function
598    ## instead of the for-loop in Base Component.
599    def evalDistribution(self, x = []):
600        self._set_scale_factor()
601        return self.params['scale_factor'] * \
602(self.p_model1.evalDistribution(x) + \
603self.p_model2.evalDistribution(x))
604
605    def set_dispersion(self, parameter, dispersion):
606        value= None
607        new_pre = parameter.split("_", 1)[0]
608        new_parameter = parameter.split("_", 1)[1]
609        try:
610            if new_pre == 'p1' and \
611new_parameter in self.p_model1.dispersion.keys():
612                value= self.p_model1.set_dispersion(new_parameter, dispersion)
613            if new_pre == 'p2' and \
614new_parameter in self.p_model2.dispersion.keys():
615                value= self.p_model2.set_dispersion(new_parameter, dispersion)
616            self._set_dispersion()
617            return value
618        except:
619            raise
620
621    def fill_description(self, p_model1, p_model2):
622        description = ""
623        description +="This model gives the summation of  %s and %s. "% \
624( p_model1.name, p_model2.name )
625        self.description += description
626       
627if __name__ == "__main__":
628    m1= Model()
629    #m1.setParam("p1_scale", 25) 
630    #m1.setParam("p1_length", 1000)
631    #m1.setParam("p2_scale", 100)
632    #m1.setParam("p2_rg", 100)
633    out1 = m1.runXY(0.01)
634
635    m2= Model()
636    #m2.p_model1.setParam("scale", 25)
637    #m2.p_model1.setParam("length", 1000)
638    #m2.p_model2.setParam("scale", 100)
639    #m2.p_model2.setParam("rg", 100)
640    out2 = m2.p_model1.runXY(0.01) + m2.p_model2.runXY(0.01)
641    print out1, " = ", out2
642    if out1 == out2:
643        print "===> Simple Test: Passed!"
644    else:
645        print "===> Simple Test: Failed!"
646"""
647       
648if __name__ == "__main__": 
649    app = wx.PySimpleApp()
650    frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"])   
651    frame.Show(True)
652    app.MainLoop()             
653
654         
Note: See TracBrowser for help on using the repository browser.