source: sasview/sansview/perspectives/fitting/fitpage.py @ 957723f

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 957723f was 0806def, checked in by Gervaise Alina <gervyh@…>, 14 years ago

edit fit button color

  • Property mode set to 100644
File size: 114.2 KB
Line 
1
2
3import sys
4import wx
5import wx.lib.newevent
6import numpy
7import copy
8import math
9import time
10from sans.models.dispersion_models import ArrayDispersion, GaussianDispersion
11from DataLoader.data_info import Data1D
12from sans.guiframe.events import StatusEvent   
13from sans.guiframe.utils import format_number,check_float
14
15(Chi2UpdateEvent, EVT_CHI2_UPDATE)   = wx.lib.newevent.NewEvent()
16_BOX_WIDTH = 76
17_DATA_BOX_WIDTH = 300
18SMEAR_SIZE_L = 0.005
19SMEAR_SIZE_H = 0.006
20
21import basepage
22from basepage import BasicPage
23from basepage import PageInfoEvent
24from sans.models.qsmearing import smear_selection
25
26class FitPage(BasicPage):
27    """
28    FitPanel class contains fields allowing to display results when
29    fitting  a model and one data
30   
31    :note: For Fit to be performed the user should check at least one parameter
32        on fit Panel window.
33    """
34   
35    def __init__(self,parent, color='rand'):
36        """
37        Initialization of the Panel
38        """
39        BasicPage.__init__(self, parent, color=color)
40       
41        ## draw sizer
42        self._fill_datainfo_sizer()
43        # get smear info from data
44        self._get_smear_info()
45        self._fill_model_sizer( self.sizer1)
46        self._get_defult_custom_smear()
47        self._fill_range_sizer() 
48        self._set_smear(self.data)
49        self.Bind(EVT_CHI2_UPDATE, self.on_complete_chisqr)
50        self._set_bookmark_flag(False)
51        self._set_save_flag(False)
52
53    def _on_fit_complete(self):
54        """
55        When fit is complete ,reset the fit button label.
56        """
57        self.btFit.SetLabel("Fit")
58        self.bind_fit_button()
59       
60    def _is_2D(self):
61        """
62        Check if data_name is Data2D
63       
64        :return: True or False
65       
66        """
67        if self.data.__class__.__name__ =="Data2D":
68            return True
69        return False
70           
71    def _on_engine_change(self, name):
72        """
73        get the current name of the fit engine type
74         and update the panel accordingly
75        """
76       
77        self.engine_type = str(name)
78        self.state.engine_type = self.engine_type
79        if len(self.parameters) == 0:
80            self.Layout()
81            return
82        for item in self.parameters:
83            if self.engine_type =="scipy" :
84                item[5].SetValue("")
85                item[5].Hide()
86                item[6].SetValue("")
87                item[6].Hide()
88                self.text2_min.Hide()
89                self.text2_max.Hide()
90
91            else:
92                item[5].Show(True)
93                item[6].Show(True)
94                self.text2_min.Show(True)
95                self.text2_max.Show(True)
96        for item in self.fittable_param:
97            if item[5]!=None and item[6]!=None and not \
98                item in self.orientation_params_disp:
99                if self.engine_type =="scipy" and \
100                    not item in self.orientation_params:
101                    item[5].SetValue("")
102                    item[5].Hide()
103                    item[6].SetValue("")
104                    item[6].Hide()
105                    self.text2_min.Hide()
106                    self.text2_max.Hide()
107                    self.text_disp_min.Hide()
108                    self.text_disp_max.Hide()
109                else:
110                    item[5].Show(True)
111                    item[6].Show(True)
112                    self.text2_min.Show(True)
113                    self.text2_max.Show(True)
114                    self.text_disp_min.Show(True)
115                    self.text_disp_max.Show(True)
116           
117        for item in self.orientation_params:
118            if item[5]!=None and item[6]!=None:
119                if self.engine_type =="scipy" or \
120                self.data.__class__.__name__ !="Data2D":
121                    item[5].SetValue("")
122                    item[5].Hide()
123                    item[6].SetValue("")
124                    item[6].Hide()
125                else:
126                    item[5].Show(True)
127                    item[6].Show(True)
128                   
129        for item in self.orientation_params_disp:         
130            if item[5]!=None and item[6]!=None:
131                if self.engine_type =="scipy" or \
132                    self.data.__class__.__name__ !="Data2D":
133                    item[5].SetValue("")
134                    item[5].Hide()
135                    item[6].SetValue("")
136                    item[6].Hide()
137                else:
138                    item[5].Show(True)
139                    item[6].Show(True)
140        self.Layout()
141        self.Refresh()
142       
143 
144       
145    def _fill_range_sizer(self):
146        """
147        Fill the sizer containing the plotting range
148        add  access to npts
149        """
150        is_2Ddata = False
151       
152        # Check if data is 2D
153        if self.data.__class__.__name__ == 'Data2D':
154            is_2Ddata = True
155           
156        title = "Fitting"
157        #smear messages & titles
158        smear_message_none  =  "No smearing is selected..."
159        smear_message_dqdata  =  "The dQ data is being used for smearing..."
160        smear_message_2d  =  "Higher accuracy is very time-expensive. Use it with care..."
161        smear_message_new_ssmear  =  "Please enter only the value of interest to customize smearing..."
162        smear_message_new_psmear  =  "Please enter both; the dQ will be generated by interpolation..."
163        smear_message_2d_x_title = "<dQx>[1/A]:"
164        smear_message_2d_y_title = "<dQy>[1/A]:"
165        smear_message_pinhole_min_title = "dQ_low[1/A]:"
166        smear_message_pinhole_max_title = "dQ_high[1/A]:"
167        smear_message_slit_height_title = "Slit height[1/A]:"
168        smear_message_slit_width_title = "Slit width[1/A]:"
169       
170        self._get_smear_info()
171       
172        #Sizers
173        box_description_range = wx.StaticBox(self, -1,str(title))
174        boxsizer_range = wx.StaticBoxSizer(box_description_range, wx.VERTICAL)     
175        self.sizer_set_smearer = wx.BoxSizer(wx.VERTICAL)
176        sizer_smearer = wx.BoxSizer(wx.HORIZONTAL)
177        self.sizer_new_smear= wx.BoxSizer(wx.HORIZONTAL)
178        self.sizer_set_masking = wx.BoxSizer(wx.HORIZONTAL)
179        sizer_chi2 = wx.BoxSizer(wx.VERTICAL)
180        smear_set_box= wx.StaticBox(self, -1,'Set Instrumental Smearing')
181        sizer_smearer_box = wx.StaticBoxSizer(smear_set_box, wx.HORIZONTAL)
182        sizer_smearer_box.SetMinSize((_DATA_BOX_WIDTH,85))
183        sizer_fit = wx.GridSizer(2, 4,2,6)
184       
185        # combobox for smear2d accuracy selection
186        self.smear_accuracy = wx.ComboBox(self, -1,size=(50,-1),style=wx.CB_READONLY)
187        self._set_accuracy_list()
188        self.smear_accuracy.SetValue(self.smear2d_accuracy)
189        self.smear_accuracy.SetSelection(0)
190        self.smear_accuracy.SetToolTipString("'Higher' uses more Gaussian points for smearing computation.")
191                   
192        wx.EVT_COMBOBOX(self.smear_accuracy,-1, self._on_select_accuracy)
193
194        #Fit button
195        self.btFit = wx.Button(self,wx.NewId(),'Fit', size=(88,25))
196        self.default_bt_colour = self.btFit.GetBackgroundColour()
197        self.btFit.Bind(wx.EVT_BUTTON, self._onFit,id= self.btFit.GetId())
198        self.btFit.SetToolTipString("Start fitting.")
199       
200        #textcntrl for custom resolution
201        self.smear_pinhole_max = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH-25,20),style=wx.TE_PROCESS_ENTER,
202                                            text_enter_callback = self.onPinholeSmear)
203        self.smear_pinhole_min = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH-25,20),style=wx.TE_PROCESS_ENTER,
204                                            text_enter_callback = self.onPinholeSmear)
205        self.smear_slit_height= self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH-25,20),style=wx.TE_PROCESS_ENTER,
206                                            text_enter_callback = self.onSlitSmear)
207        self.smear_slit_width = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH-25,20),style=wx.TE_PROCESS_ENTER,
208                                            text_enter_callback = self.onSlitSmear)
209
210        ## smear
211        self.smear_data_left= BGTextCtrl(self, -1, size=(_BOX_WIDTH-25,20), style=0)
212        self.smear_data_left.SetValue(str(self.dq_l))
213        self.smear_data_right = BGTextCtrl(self, -1, size=(_BOX_WIDTH-25,20), style=0)
214        self.smear_data_right.SetValue(str(self.dq_r))
215
216        #set default values for smear
217        self.smear_pinhole_max.SetValue(str(self.dx_max))
218        self.smear_pinhole_min.SetValue(str(self.dx_min))
219        self.smear_slit_height.SetValue(str(self.dxl))
220        self.smear_slit_width.SetValue(str(self.dxw))
221
222        #Filling the sizer containing instruments smearing info.
223        self.disable_smearer = wx.RadioButton(self, -1, 'None', style=wx.RB_GROUP)
224        self.enable_smearer = wx.RadioButton(self, -1, 'Use dQ Data')
225        #self.enable_smearer.SetToolTipString("Click to use the loaded dQ data for smearing.")
226        self.pinhole_smearer = wx.RadioButton(self, -1, 'Custom Pinhole Smear')
227        #self.pinhole_smearer.SetToolTipString("Click to input custom resolution for pinhole smearing.")
228        self.slit_smearer = wx.RadioButton(self, -1, 'Custom Slit Smear')
229        #self.slit_smearer.SetToolTipString("Click to input custom resolution for slit smearing.")
230        self.Bind(wx.EVT_RADIOBUTTON, self.onSmear, id=self.disable_smearer.GetId())
231        self.Bind(wx.EVT_RADIOBUTTON, self.onSmear, id=self.enable_smearer.GetId())
232        self.Bind(wx.EVT_RADIOBUTTON, self.onPinholeSmear, id=self.pinhole_smearer.GetId())
233        self.Bind(wx.EVT_RADIOBUTTON, self.onSlitSmear, id=self.slit_smearer.GetId())
234        self.disable_smearer.SetValue(True)
235       
236        # add 4 types of smearing to the sizer
237        sizer_smearer.Add( self.disable_smearer,0, wx.LEFT, 10)
238        sizer_smearer.Add((10,10))
239        sizer_smearer.Add( self.enable_smearer)
240        sizer_smearer.Add((10,10))
241        sizer_smearer.Add( self.pinhole_smearer ) 
242        sizer_smearer.Add((10,10))
243        sizer_smearer.Add( self.slit_smearer ) 
244        sizer_smearer.Add((10,10))       
245       
246        # StaticText for chi2, N(for fitting), Npts
247        self.tcChi    =  BGTextCtrl(self, -1, "-", size=(75,20), style=0)
248        self.tcChi.SetToolTipString("Chi2/Npts")
249        self.Npts_fit    =  BGTextCtrl(self, -1, "-", size=(75,20), style=0)
250        self.Npts_fit.SetToolTipString(" Npts : number of points selected for fitting")
251        self.Npts_total  =  BGTextCtrl(self, -1, "-", size=(75,20), style=0)
252        self.Npts_total.SetToolTipString(" Total Npts : total number of data points")
253        box_description_1= wx.StaticText(self, -1,'    Chi2/Npts')
254        box_description_2= wx.StaticText(self, -1,'Fitted Npts')
255        box_description_3= wx.StaticText(self, -1,'Data Npts')
256        box_description_4= wx.StaticText(self, -1,' ')
257       
258       
259        sizer_fit.Add(box_description_1,0,0)
260        sizer_fit.Add(box_description_2,0,0)
261        sizer_fit.Add(box_description_3,0,0)       
262        sizer_fit.Add(box_description_4,0,0)
263        sizer_fit.Add(self.tcChi,0,0)
264        sizer_fit.Add(self.Npts_fit ,0,0)
265        sizer_fit.Add(self.Npts_total,0,0)
266        sizer_fit.Add(self.btFit,0,0) 
267
268        # StaticText for smear
269        #self.tcChi    =  wx.StaticText(self, -1, "-", style=wx.ALIGN_LEFT)
270        self.smear_description_none    =  wx.StaticText(self, -1, smear_message_none , style=wx.ALIGN_LEFT)
271        self.smear_description_dqdata    =  wx.StaticText(self, -1, smear_message_dqdata , style=wx.ALIGN_LEFT)
272        self.smear_description_type    =  wx.StaticText(self, -1, "Type:" , style=wx.ALIGN_LEFT)
273        self.smear_description_accuracy_type    =  wx.StaticText(self, -1, "Accuracy:" , style=wx.ALIGN_LEFT)
274        self.smear_description_smear_type    =  BGTextCtrl(self, -1, size=(57,20), style=0)
275        self.smear_description_smear_type.SetValue(str(self.dq_l))
276        self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
277        self.smear_description_2d     =  wx.StaticText(self, -1, smear_message_2d  , style=wx.ALIGN_LEFT)
278        self.smear_message_new_s = wx.StaticText(self, -1, smear_message_new_ssmear  , style=wx.ALIGN_LEFT)
279        self.smear_message_new_p = wx.StaticText(self, -1, smear_message_new_psmear  , style=wx.ALIGN_LEFT)
280        self.smear_description_2d_x     =  wx.StaticText(self, -1, smear_message_2d_x_title  , style=wx.ALIGN_LEFT)
281        self.smear_description_2d_y     =  wx.StaticText(self, -1, smear_message_2d_y_title  , style=wx.ALIGN_LEFT)
282        self.smear_description_pin_min     =  wx.StaticText(self, -1, smear_message_pinhole_min_title  , style=wx.ALIGN_LEFT)
283        self.smear_description_pin_max     =  wx.StaticText(self, -1, smear_message_pinhole_max_title  , style=wx.ALIGN_LEFT)
284        self.smear_description_slit_height    =  wx.StaticText(self, -1, smear_message_slit_height_title   , style=wx.ALIGN_LEFT)
285        self.smear_description_slit_width    =  wx.StaticText(self, -1, smear_message_slit_width_title   , style=wx.ALIGN_LEFT)
286       
287        #arrange sizers
288        #boxsizer1.Add( self.tcChi ) 
289        self.sizer_set_smearer.Add(sizer_smearer )
290        self.sizer_set_smearer.Add((10,10))
291        self.sizer_set_smearer.Add( self.smear_description_none,0, wx.CENTER, 10 ) 
292        self.sizer_set_smearer.Add( self.smear_description_dqdata,0, wx.CENTER, 10 )
293        self.sizer_set_smearer.Add( self.smear_description_2d,0, wx.CENTER, 10 )
294        self.sizer_new_smear.Add( self.smear_description_type,0, wx.CENTER, 10 )
295        self.sizer_new_smear.Add( self.smear_description_accuracy_type,0, wx.CENTER, 10 )
296        self.sizer_new_smear.Add( self.smear_accuracy )
297        self.sizer_new_smear.Add( self.smear_description_smear_type,0, wx.CENTER, 10 )
298        self.sizer_new_smear.Add((15,-1))
299        self.sizer_new_smear.Add( self.smear_description_2d_x,0, wx.CENTER, 10 )
300        self.sizer_new_smear.Add( self.smear_description_pin_min,0, wx.CENTER, 10 )
301        self.sizer_new_smear.Add( self.smear_description_slit_height,0, wx.CENTER, 10 )
302
303        self.sizer_new_smear.Add( self.smear_pinhole_min,0, wx.CENTER, 10 )
304        self.sizer_new_smear.Add( self.smear_slit_height,0, wx.CENTER, 10 )
305        self.sizer_new_smear.Add( self.smear_data_left,0, wx.CENTER, 10 )
306        self.sizer_new_smear.Add((20,-1))
307        self.sizer_new_smear.Add( self.smear_description_2d_y,0, wx.CENTER, 10 )
308        self.sizer_new_smear.Add( self.smear_description_pin_max,0, wx.CENTER, 10 )
309        self.sizer_new_smear.Add( self.smear_description_slit_width,0, wx.CENTER, 10 )
310
311        self.sizer_new_smear.Add( self.smear_pinhole_max,0, wx.CENTER, 10 )
312        self.sizer_new_smear.Add( self.smear_slit_width,0, wx.CENTER, 10 )
313        self.sizer_new_smear.Add( self.smear_data_right,0, wx.CENTER, 10 )
314           
315        self.sizer_set_smearer.Add( self.smear_message_new_s,0, wx.CENTER, 10)
316        self.sizer_set_smearer.Add( self.smear_message_new_p,0, wx.CENTER, 10)
317        self.sizer_set_smearer.Add((5,2))
318        self.sizer_set_smearer.Add( self.sizer_new_smear,0, wx.CENTER, 10 )
319       
320        # add all to chi2 sizer
321        sizer_smearer_box.Add(self.sizer_set_smearer)       
322        sizer_chi2.Add(sizer_smearer_box)
323        sizer_chi2.Add((-1,5))
324
325        # hide all smear messages and textctrl
326        self._hide_all_smear_info()
327       
328        # get smear_selection
329        self.current_smearer= smear_selection( self.data, self.model )
330
331        # Show only the relevant smear messages, etc
332        if self.current_smearer == None:
333            if not is_2Ddata:
334                self.smear_description_none.Show(True)
335                self.enable_smearer.Disable() 
336            else:
337                self.smear_description_none.Show(True)
338                #self.smear_description_2d.Show(True)
339                #self.pinhole_smearer.Disable()
340                self.slit_smearer.Disable()   
341                #self.enable_smearer.Disable()
342        else: self._show_smear_sizer()
343        boxsizer_range.Add(self.sizer_set_masking)
344         #2D data? default
345        is_2Ddata = False
346       
347        #check if it is 2D data
348        if self.data.__class__.__name__ == 'Data2D':
349            is_2Ddata = True
350           
351        self.sizer5.Clear(True)
352     
353        self.qmin  = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH,20),
354                                          style=wx.TE_PROCESS_ENTER,
355                                    text_enter_callback = self._onQrangeEnter)
356        self.qmin.SetValue(str(self.qmin_x))
357        self.qmin.SetToolTipString("Minimun value of Q in linear scale.")
358     
359        self.qmax  = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH,20),
360                                          style=wx.TE_PROCESS_ENTER,
361                                        text_enter_callback=self._onQrangeEnter)
362        self.qmax.SetValue(str(self.qmax_x))
363        self.qmax.SetToolTipString("Maximum value of Q in linear scale.")
364       
365        self.theory_npts_tcrtl  = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20), 
366                        style=wx.TE_PROCESS_ENTER, 
367                        text_enter_callback=self._onQrangeEnter)
368        self.theory_npts_tcrtl.SetValue(format_number(self.npts_x))
369        self.theory_npts_tcrtl.SetToolTipString("Number of point to plot.")
370        id = wx.NewId()
371        self.reset_qrange =wx.Button(self,id,'Reset',size=(77,20))
372     
373        self.reset_qrange.Bind(wx.EVT_BUTTON, self.on_reset_clicked,id=id)
374        self.reset_qrange.SetToolTipString("Reset Q range to the default values")
375     
376        sizer_horizontal=wx.BoxSizer(wx.HORIZONTAL)
377        sizer= wx.GridSizer(2, 5,0, 0)
378
379        self.btEditMask = wx.Button(self,wx.NewId(),'Editor', size=(88,23))
380        self.btEditMask.Bind(wx.EVT_BUTTON, self._onMask,id= self.btEditMask.GetId())
381        self.btEditMask.SetToolTipString("Edit Mask.")
382        self.EditMask_title = wx.StaticText(self, -1, ' Masking(2D)')
383
384        sizer.Add(wx.StaticText(self, -1, 'Q range'))     
385        sizer.Add(wx.StaticText(self, -1, ' Min[1/A]'))
386        sizer.Add(wx.StaticText(self, -1, ' Max[1/A]'))
387        sizer.Add(wx.StaticText(self, -1, ' Theory Npts'))
388        sizer.Add(self.EditMask_title)
389        sizer.Add(self.reset_qrange)   
390        sizer.Add(self.qmin)
391        sizer.Add(self.qmax)
392        sizer.Add(self.theory_npts_tcrtl)
393        sizer.Add(self.btEditMask)
394        boxsizer_range.Add(sizer_chi2) 
395        boxsizer_range.Add((10,10))
396        boxsizer_range.Add(sizer)
397       
398        boxsizer_range.Add((10,15))
399        boxsizer_range.Add(sizer_fit)
400        if is_2Ddata:
401            self.btEditMask.Enable() 
402            self.EditMask_title.Enable() 
403        else:
404            self.btEditMask.Disable() 
405            self.EditMask_title.Disable()
406        ## save state
407        self.save_current_state()
408        self.sizer5.Add(boxsizer_range,0, wx.EXPAND | wx.ALL, 10)
409        self.sizer5.Layout()
410
411    def _fill_datainfo_sizer(self):
412        """
413        fill sizer 0 with data info
414        """
415        ## no loaded data , don't fill the sizer
416        if self.data is None:
417            data_min = ""
418            data_max = ""
419            data_name = ""
420        else:
421            data_name = self.data.name
422            #set maximum range for x in linear scale
423            if not hasattr(self.data,"data"): #Display only for 1D data fit
424                # Minimum value of data   
425                data_min = min(self.data.x)
426                # Maximum value of data 
427                data_max = max(self.data.x)
428            else:
429                ## Minimum value of data
430                data_min = 0
431                x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax)) 
432                y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
433                ## Maximum value of data 
434                data_max = math.sqrt(x*x + y*y)
435            ## set q range to plot
436            self.qmin_x = data_min
437            self.qmax_x = data_max
438        box_description= wx.StaticBox(self, -1, 'Data')
439        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
440        #----------------------------------------------------------
441        sizer_data = wx.BoxSizer(wx.HORIZONTAL)
442        #Filling the sizer containing data related fields
443        #self.dataSource = wx.StaticText(self, -1,str(self.data.name))
444        self.dataSource = BGTextCtrl(self, -1)
445        self.dataSource.SetValue(str(data_name))
446        #self.dataSource.SetEditable(False)
447        self.dataSource.SetMinSize((_DATA_BOX_WIDTH, -1))
448        sizer_data.Add(wx.StaticText(self, -1, 'Source Name : '))
449        sizer_data.Add(self.dataSource )
450        sizer_data.Add( (0,5) )
451       
452        #---------sizer 2 draw--------------------------------
453        text4_3 = wx.StaticText(self, -1, 'Total Q Range (1/A)',
454                                 style=wx.ALIGN_LEFT)
455        sizer_range = wx.BoxSizer(wx.HORIZONTAL)
456        sizer_range.Add( text4_3 ,0, wx.RIGHT, 10)
457        self.minimum_q = BGTextCtrl(self, -1, size=(_BOX_WIDTH,20))
458        self.minimum_q.SetValue(str(data_min))
459        self.maximum_q = BGTextCtrl(self, -1,size=(_BOX_WIDTH,20))
460        self.maximum_q.SetValue(str(data_max))
461        sizer_range.Add(wx.StaticText(self, -1, "Min: "),0, wx.LEFT, 10)
462        sizer_range.Add(self.minimum_q,0, wx.LEFT, 10)
463        sizer_range.Add(wx.StaticText(self, -1, "Max: "),0, wx.LEFT, 10)
464        sizer_range.Add(self.maximum_q,0, wx.LEFT, 10)
465        boxsizer1.Add(sizer_data,0, wx.ALL, 10)
466        boxsizer1.Add(sizer_range, 0 , wx.LEFT, 10)
467        #------------------------------------------------------------
468        self.sizer0.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
469        self.sizer0.Layout()
470       
471    def _fill_model_sizer(self, sizer):
472        """
473        fill sizer containing model info
474        """
475        ##Add model function Details button in fitpanel.
476        ##The following 3 lines are for Mac. Let JHC know before modifying...
477        title = "Model"
478        box_description= wx.StaticBox(self, -1,str(title))
479        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
480         
481        id = wx.NewId()
482        self.model_help =wx.Button(self,id,'Details', size=(80,23))
483        self.model_help.Bind(wx.EVT_BUTTON, self.on_model_help_clicked,id=id)
484        self.model_help.SetToolTipString("Model Function Help")
485        id = wx.NewId()
486        self.model_view = wx.Button(self, id,"Switch to 2D", size=(80, 23))
487        self.model_view.Bind(wx.EVT_BUTTON, self._onModel2D, id=id)
488        hint = "toggle view of model from 1D to 2D  or 2D from 1D"
489        self.model_view.SetToolTipString(hint)
490     
491        self.shape_rbutton = wx.RadioButton(self, -1, 'Shapes', style=wx.RB_GROUP)
492        self.shape_indep_rbutton = wx.RadioButton(self, -1, "Shape-Independent")
493        self.struct_rbutton = wx.RadioButton(self, -1, "Structure Factor ")
494        self.plugin_rbutton = wx.RadioButton(self, -1, "Customized Models")
495               
496        self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
497                            id= self.shape_rbutton.GetId()) 
498        self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
499                            id= self.shape_indep_rbutton.GetId()) 
500        self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
501                            id= self.struct_rbutton.GetId()) 
502        self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
503                            id= self.plugin_rbutton.GetId()) 
504        #MAC needs SetValue
505        self.shape_rbutton.SetValue(True)
506     
507        sizer_radiobutton = wx.GridSizer(2, 3, 5, 5)
508        sizer_radiobutton.Add(self.shape_rbutton)
509        sizer_radiobutton.Add(self.shape_indep_rbutton)
510        #sizer_radiobutton.Add((5, 5))
511        sizer_radiobutton.Add(self.model_view,1, wx.LEFT, 20)
512        sizer_radiobutton.Add(self.plugin_rbutton)
513        sizer_radiobutton.Add(self.struct_rbutton)
514        #sizer_radiobutton.Add((5, 5))
515        sizer_radiobutton.Add(self.model_help,1, wx.LEFT, 20)
516       
517        sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
518        mutifactor_selection = wx.BoxSizer(wx.HORIZONTAL)
519       
520        self.text1 = wx.StaticText(self,-1,"" )
521        self.text2 = wx.StaticText(self,-1,"P(Q)*S(Q)" )
522        self.mutifactor_text = wx.StaticText( self,-1,"No. of Shells: ")
523        self.mutifactor_text1 = wx.StaticText( self,-1,"" )
524        self.show_sld_button = wx.Button( self,-1,"Show SLD Profile" )
525        self.show_sld_button.Bind(wx.EVT_BUTTON,self._on_show_sld)
526
527        self.formfactorbox = wx.ComboBox(self, -1,style=wx.CB_READONLY)
528        if self.model!= None:
529            self.formfactorbox.SetValue(self.model.name)
530        self.structurebox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
531        self.multifactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
532        self.initialize_combox()
533        wx.EVT_COMBOBOX(self.formfactorbox, -1, self._on_select_model)
534        wx.EVT_COMBOBOX(self.structurebox, -1, self._on_select_model)
535        wx.EVT_COMBOBOX(self.multifactorbox, -1, self._on_select_model)
536        ## check model type to show sizer
537        if self.model !=None:
538            self._set_model_sizer_selection(self.model)
539       
540        sizer_selection.Add(self.text1)
541        sizer_selection.Add((5, 5))
542        sizer_selection.Add(self.formfactorbox)
543        sizer_selection.Add((5, 5))
544        sizer_selection.Add(self.text2)
545        sizer_selection.Add((5, 5))
546        sizer_selection.Add(self.structurebox)
547       
548        mutifactor_selection.Add((10,5))
549        mutifactor_selection.Add(self.mutifactor_text)
550        mutifactor_selection.Add(self.multifactorbox)
551        mutifactor_selection.Add((5, 5))
552        mutifactor_selection.Add(self.mutifactor_text1)
553        mutifactor_selection.Add((10, 5))
554        mutifactor_selection.Add(self.show_sld_button)
555
556       
557        boxsizer1.Add(sizer_radiobutton)
558        boxsizer1.Add((10, 10))
559        boxsizer1.Add(sizer_selection)
560        boxsizer1.Add((10, 10))
561        boxsizer1.Add(mutifactor_selection)
562       
563        self._set_multfactor_combobox()
564        self.multifactorbox.SetSelection(1)
565        self.show_sld_button.Hide()
566        sizer.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
567        sizer.Layout()
568       
569    def _set_sizer_dispersion(self, dispersity):
570        """
571        draw sizer with gaussian dispersity parameters
572        """
573        self.fittable_param=[]
574        self.fixed_param=[]
575        self.orientation_params_disp=[]
576
577        self.sizer4_4.Clear(True)
578        if self.model==None:
579            ##no model is selected
580            return
581        if not self.enable_disp.GetValue():
582            ## the user didn't select dispersity display
583            return 
584           
585        self._reset_dispersity()
586       
587        # Create the dispersion objects
588        for item in self.model.dispersion.keys():
589            #disp_model =  GaussianDispersion()
590            disp_model = dispersity()
591            self._disp_obj_dict[item] = disp_model
592            self.model.set_dispersion(item, disp_model)
593            self.state._disp_obj_dict[item]= disp_model
594
595
596        ix=0
597        iy=1
598        disp = wx.StaticText(self, -1, ' ')
599        self.sizer4_4.Add(disp,( iy, ix),(1,1), 
600                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
601        ix += 1 
602        values = wx.StaticText(self, -1, 'PD[ratio] ')
603        polytext = "Polydispersity (= STD/mean); "
604        polytext +=  "the standard deviation over the mean value."
605        values.SetToolTipString(polytext)
606
607        self.sizer4_4.Add(values,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 
608                          0)
609        ix +=2 
610        self.text_disp_1 = wx.StaticText(self, -1, '')
611        self.sizer4_4.Add( self.text_disp_1,(iy, ix),(1,1),\
612                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
613        self.text_disp_1.Hide()
614       
615       
616        ix +=1 
617        self.text_disp_min = wx.StaticText(self, -1, 'Min')
618        self.sizer4_4.Add(self.text_disp_min,(iy, ix),(1,1),\
619                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
620        self.text_disp_min.Hide()
621        ix +=1 
622        self.text_disp_max = wx.StaticText(self, -1, 'Max')
623        self.sizer4_4.Add(self.text_disp_max,(iy, ix),(1,1),\
624                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
625        self.text_disp_max.Hide()
626                       
627       
628        ix += 1 
629        npts = wx.StaticText(self, -1, 'Npts')
630        npts.SetToolTipString("Number of sampling points for the numerical\n\
631        integration over the distribution function.")
632        self.sizer4_4.Add(npts,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
633        ix += 1 
634        nsigmas = wx.StaticText(self, -1, 'Nsigmas')
635        nsigmas.SetToolTipString("   Number of sigmas between which the range\n\
636         of the distribution function will be used for weighting. \n\
637        The value '3' covers 99.5% for Gaussian distribution \n\
638        function. Note: Not recommended to change this value.")
639        self.sizer4_4.Add(nsigmas,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE,
640                           0)
641       
642        if self.engine_type=="park":
643            self.text_disp_max.Show(True)
644            self.text_disp_min.Show(True)
645
646        for item in self.model.dispersion.keys():
647            if not item in self.model.orientation_params:
648                if not self.disp_cb_dict.has_key(item):
649                    self.disp_cb_dict[item]= None
650                name0="Distribution of " + item
651                name1=item+".width"
652                name2=item+".npts"
653                name3=item+".nsigmas"
654                if not self.model.details.has_key(name1):
655                    self.model.details [name1] = ["",None,None] 
656
657                iy += 1
658                for p in self.model.dispersion[item].keys(): 
659       
660                    if p=="width":
661                        ix = 0
662                        cb = wx.CheckBox(self, -1, name0, (10, 10))
663                        cb.SetToolTipString("Check for fitting")
664                        wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
665                        self.sizer4_4.Add( cb,( iy, ix),(1,1), 
666                                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 
667                                           15)
668                        ix = 1
669                        value= self.model.getParam(name1)
670                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20)
671                                                  ,style=wx.TE_PROCESS_ENTER)
672                        ctl1.SetLabel('PD[ratio]')
673                        poly_text = "Polydispersity (STD/mean) of %s\n" % item
674                        poly_text += "STD: the standard deviation"
675                        poly_text += " from the mean value."
676                        ctl1.SetToolTipString(poly_text)
677                        ctl1.SetValue(str (format_number(value)))
678                        self.sizer4_4.Add(ctl1, (iy,ix),(1,1),wx.EXPAND)
679                        ## text to show error sign
680                        ix = 2
681                        text2=wx.StaticText(self, -1, '+/-')
682                        self.sizer4_4.Add(text2,(iy, ix),(1,1),
683                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
684                        text2.Hide() 
685
686                        ix = 3
687                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), 
688                                           style=0)
689                 
690                        self.sizer4_4.Add(ctl2, (iy,ix),(1,1), 
691                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
692                     
693                        ctl2.Hide()
694
695                        ix = 4
696                        ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,
697                                            20), style=wx.TE_PROCESS_ENTER,
698                                text_enter_callback = self._onparamRangeEnter)
699                       
700                        self.sizer4_4.Add(ctl3, (iy,ix),(1,1), 
701                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
702                        ctl3.Hide()
703               
704                        ix = 5
705                        ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,
706                                            20), style=wx.TE_PROCESS_ENTER,
707                            text_enter_callback = self._onparamRangeEnter)
708                       
709                        self.sizer4_4.Add(ctl4, (iy,ix),(1,1), 
710                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
711
712                        ctl4.Hide()
713                       
714                        if self.engine_type=="park":
715                            ctl3.Show(True)
716                            ctl4.Show(True)
717                                         
718                        self.fittable_param.append([cb,name1,ctl1,text2,
719                                                    ctl2, ctl3, ctl4,None])                   
720                   
721                    elif p=="npts":
722                            ix = 6
723                            value= self.model.getParam(name2)
724                            Tctl = self.ModelTextCtrl(self, -1, 
725                                                      size=(_BOX_WIDTH/2,20),
726                                                style=wx.TE_PROCESS_ENTER)
727                           
728                            Tctl.SetValue(str (format_number(value)))
729                            self.sizer4_4.Add(Tctl, (iy,ix),(1,1),
730                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
731                            self.fixed_param.append([None,name2, Tctl,None,None,
732                                                      None, None,None])
733                    elif p=="nsigmas":
734                            ix = 7
735                            value= self.model.getParam(name3)
736                            Tct2 = self.ModelTextCtrl(self, -1, 
737                                                      size=(_BOX_WIDTH/2,20),
738                                                style=wx.TE_PROCESS_ENTER)
739                           
740                            Tct2.SetValue(str (format_number(value)))
741                            self.sizer4_4.Add(Tct2, (iy,ix),(1,1),
742                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
743                            ix +=1
744                            self.sizer4_4.Add((20,20), (iy,ix),(1,1),
745                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
746                           
747                            self.fixed_param.append([None,name3, Tct2
748                                                     ,None,None,None, 
749                                                     None,None])
750                           
751        ix =0
752        iy +=1 
753        self.sizer4_4.Add((20,20),(iy,ix),(1,1), 
754                          wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15) 
755        first_orient  = True
756        for item in self.model.dispersion.keys():
757            if  item in self.model.orientation_params:
758                if not self.disp_cb_dict.has_key(item):
759                    self.disp_cb_dict[item]= None
760                name0="Distribution of " + item
761                name1=item+".width"
762                name2=item+".npts"
763                name3=item+".nsigmas"
764               
765                if not self.model.details.has_key(name1):
766                    self.model.details [name1] = ["",None,None]                 
767 
768
769                iy += 1
770                for p in self.model.dispersion[item].keys(): 
771       
772                    if p=="width":
773                        ix = 0
774                        cb = wx.CheckBox(self, -1, name0, (10, 10))
775                        cb.SetToolTipString("Check for fitting")
776                        wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
777                        self.sizer4_4.Add( cb,( iy, ix),(1,1), 
778                                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 
779                                           15)
780                        if self.data.__class__.__name__ =="Data2D":
781                            cb.Show(True)
782                        elif cb.IsShown():
783                            cb.Hide()
784                        ix = 1
785                        value= self.model.getParam(name1)
786                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,
787                                        20),style=wx.TE_PROCESS_ENTER)
788                        poly_tip = "Absolute Sigma for %s." % item
789                        ctl1.SetToolTipString(poly_tip)
790                        ctl1.SetValue(str (format_number(value)))
791                        if self.data.__class__.__name__ =="Data2D":
792                            if first_orient:
793                                values.SetLabel('PD[ratio], Sig[deg]')
794                                poly_text = "PD(polydispersity for lengths):\n"
795                                poly_text +=  "It should be a value between"
796                                poly_text +=  "0 and 1\n"
797                                poly_text += "Sigma for angles: \n"
798                                poly_text += "It is the STD (ratio*mean)"
799                                poly_text += " of the distribution.\n "
800                           
801                                values.SetToolTipString(poly_text)
802                                first_orient = False
803                            ctl1.Show(True)
804                        elif ctl1.IsShown():
805                            ctl1.Hide()
806                       
807                        self.sizer4_4.Add(ctl1, (iy,ix),(1,1),wx.EXPAND)
808                        ## text to show error sign
809                        ix = 2
810                        text2=wx.StaticText(self, -1, '+/-')
811                        self.sizer4_4.Add(text2,(iy, ix),(1,1),
812                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
813                        text2.Hide() 
814
815                        ix = 3
816                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), 
817                                           style=0)
818                   
819                        self.sizer4_4.Add(ctl2, (iy,ix),(1,1), 
820                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
821                        ctl2.Hide()
822                           
823                        ix = 4
824                        ctl3 = self.ModelTextCtrl(self, -1, 
825                                                  size=(_BOX_WIDTH/2,20), 
826                                                  style=wx.TE_PROCESS_ENTER,
827                                text_enter_callback = self._onparamRangeEnter)
828
829                        self.sizer4_4.Add(ctl3, (iy,ix),(1,1), 
830                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
831
832                        ctl3.Hide()
833               
834                        ix = 5
835                        ctl4 = self.ModelTextCtrl(self, -1, 
836                            size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
837                                text_enter_callback = self._onparamRangeEnter)
838                        self.sizer4_4.Add(ctl4, (iy,ix),(1,1), 
839                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
840                        ctl4.Hide()
841                        #if self.data.__class__.__name__ =="Data2D":
842                            #ctl4.Enable(True)
843                        #elif ctl4.Shown():
844                            #ctl4.Hide()
845                       
846                        if self.engine_type=="park" and \
847                                    self.data.__class__.__name__ =="Data2D":
848                            ctl3.Show(True)
849                            ctl4.Show(True) 
850                           
851                           
852                           
853                           
854                        self.fittable_param.append([cb,name1,ctl1,text2,
855                                                    ctl2, ctl3, ctl4,None])
856                        self.orientation_params_disp.append([cb,name1,ctl1,
857                                                  text2, ctl2, ctl3, ctl4,None])
858                    elif p=="npts":
859                            ix = 6
860                            value= self.model.getParam(name2)
861                            Tctl = self.ModelTextCtrl(self, -1, 
862                                                      size=(_BOX_WIDTH/2,20),
863                                                style=wx.TE_PROCESS_ENTER)
864                           
865                            Tctl.SetValue(str (format_number(value)))
866                            if self.data.__class__.__name__ =="Data2D":
867                                Tctl.Show(True)
868                            else:
869                                Tctl.Hide()
870                            self.sizer4_4.Add(Tctl, (iy,ix),(1,1),
871                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
872                            self.fixed_param.append([None,name2, Tctl,None,None,
873                                                      None, None,None])
874                            self.orientation_params_disp.append([None,name2, 
875                                                    Tctl,None,None,
876                                                      None, None,None])
877                    elif p=="nsigmas":
878                            ix = 7
879                            value= self.model.getParam(name3)
880                            Tct2 = self.ModelTextCtrl(self, -1, 
881                                                      size=(_BOX_WIDTH/2,20),
882                                                style=wx.TE_PROCESS_ENTER)
883                           
884                            Tct2.SetValue(str (format_number(value)))
885                            if self.data.__class__.__name__ =="Data2D":
886                                Tct2.Show(True)
887                            else:
888                                Tct2.Hide()
889                            self.sizer4_4.Add(Tct2, (iy,ix),(1,1),
890                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
891                            ix +=1
892
893                            self.fixed_param.append([None,name3, Tct2
894                                                 ,None,None, None, None,None])   
895                                                       
896                            self.orientation_params_disp.append([None,name3, 
897                                            Tct2 ,None,None, None, None,None])
898       
899        self.state.disp_cb_dict = copy.deepcopy(self.disp_cb_dict) 
900         
901        self.state.model = self.model.clone() 
902         ## save state into
903        self.state.cb1 = self.cb1.GetValue()
904        self._copy_parameters_state(self.parameters, self.state.parameters)
905        self._copy_parameters_state(self.orientation_params_disp,
906                                     self.state.orientation_params_disp)
907        self._copy_parameters_state(self.fittable_param, 
908                                    self.state.fittable_param)
909        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
910
911
912        wx.PostEvent(self.parent, StatusEvent(status=\
913                        " Selected Distribution: Gaussian"))   
914        #Fill the list of fittable parameters
915        self.select_all_param(event=None)
916       
917        self.Layout()
918
919    def _onFit(self, event):     
920        """
921        Allow to fit
922        """
923        if self.data is None:
924            msg = "Please select a Data first..."
925            wx.MessageBox(msg, 'Info')
926            wx.PostEvent(self._manager.parent, StatusEvent(status=\
927                            "Fit: %s" % msg))
928            return
929        if self.model is None:
930            msg = "Please select a Model first..."
931            wx.MessageBox(msg, 'Info')
932            wx.PostEvent(self._manager.parent, StatusEvent(status=\
933                            "Fit: %s" % msg))
934            return
935
936        flag = self._update_paramv_on_fit() 
937               
938        if not flag:
939            msg= "Fitting range or parameters are invalid"
940            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
941            return 
942       
943        if len(self.param_toFit) <= 0:
944            msg= "Select at least one parameter to fit"
945            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
946            return 
947     
948        self.select_param(event =None)
949       
950        #Clear errors if exist from previous fitting
951        #self._clear_Err_on_Fit()
952
953        # Remove or do not allow fitting on the Q=0 point, especially
954        # when y(q=0)=None at x[0].         
955        self.qmin_x = float(self.qmin.GetValue())
956        self.qmax_x = float( self.qmax.GetValue())
957        self._manager._reset_schedule_problem(value=0)
958        self._manager.schedule_for_fit(uid=self.uid,value=1, fitproblem =None) 
959        self._manager.set_fit_range(uid=self.uid,qmin= self.qmin_x, 
960                                   qmax= self.qmax_x)
961       
962        #single fit
963        self._manager.onFit()
964        self.btFit.SetLabel("Stop")
965        self.bind_fit_button()
966           
967    def bind_fit_button(self):
968        """
969        bind the fit button to either fit handler or stop fit handler
970        """
971        self.btFit.Unbind(event=wx.EVT_BUTTON, id= self.btFit.GetId())
972        if self.btFit.GetLabel().lower() == "stop":
973            self.btFit.SetBackgroundColour('red')
974            self.btFit.Bind(event=wx.EVT_BUTTON, handler=self._StopFit,
975                             id=self.btFit.GetId())
976        elif self.btFit.GetLabel().lower() == "fit":
977            self.btFit.SetBackgroundColour(self.default_bt_colour)
978            self.btFit.Bind(event=wx.EVT_BUTTON, handler=self._onFit, 
979                            id=self.btFit.GetId())
980        else:
981            msg = "FitPage: fit button has unknown label"
982            raise ValuerError, msg
983        self._manager._reset_schedule_problem(value=0)
984         
985
986    def _StopFit(self, event):
987        """
988        Stop fit
989        """
990        #if self.engine_type=="scipy":
991        self._manager.stop_fit(self.uid)
992        self._manager._reset_schedule_problem(value=0)
993        self._on_fit_complete()
994         
995    def _on_select_model(self, event=None): 
996        """
997        call back for model selection
998        """ 
999        self._on_select_model_helper() 
1000        self.set_model_param_sizer(self.model)                   
1001       
1002        if self.model is None:
1003            self._set_bookmark_flag(False)
1004            self._set_save_flag(False)
1005        self.enable_disp.SetValue(False)
1006        self.disable_disp.SetValue(True)
1007        try:
1008            self.set_dispers_sizer()
1009        except:
1010            pass
1011        self.btFit.SetFocus() 
1012        self.state.enable_disp = self.enable_disp.GetValue()
1013        self.state.disable_disp = self.disable_disp.GetValue()
1014        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
1015        self.state.slit_smearer = self.slit_smearer.GetValue()
1016   
1017        self.state.structurecombobox = self.structurebox.GetCurrentSelection()
1018        self.state.formfactorcombobox = self.formfactorbox.GetCurrentSelection()
1019     
1020        if self.model != None:
1021            self._set_bookmark_flag(True)
1022            self._set_save_flag(True)
1023            # Reset smearer, model and data
1024            self._set_smear(self.data)
1025            try:
1026                # update smearer sizer
1027                self.onSmear(None)
1028                temp_smear = None
1029                if self.enable_smearer.GetValue():
1030                    # Set the smearer environments
1031                    temp_smear = self.smearer
1032            except:
1033                raise
1034                ## error occured on chisqr computation
1035                #pass
1036            ## event to post model to fit to fitting plugins
1037            (ModelEventbox, EVT_MODEL_BOX) = wx.lib.newevent.NewEvent()
1038           
1039            ## set smearing value whether or not
1040            #    the data contain the smearing info
1041            evt = ModelEventbox(model=self.model, 
1042                                        smearer=temp_smear, 
1043                                        qmin=float(self.qmin_x),
1044                                        uid=self.uid,
1045                                     qmax=float(self.qmax_x)) 
1046   
1047            self._manager._on_model_panel(evt=evt)
1048            self.state.model = self.model.clone()
1049            self.state.model.name = self.model.name
1050            if event is not None:
1051                self._draw_model()
1052        if event != None:
1053           
1054            ## post state to fit panel
1055            event = PageInfoEvent(page = self)
1056            wx.PostEvent(self.parent, event) 
1057        self.SetupScrolling()
1058     
1059    def _onparamEnter(self,event):
1060        """
1061        when enter value on panel redraw model according to changed
1062        """
1063        if self.model ==None:
1064            msg="Please select a Model first..."
1065            wx.MessageBox(msg, 'Info')
1066            #wx.PostEvent(self._manager.parent, StatusEvent(status=\
1067            #                "Parameters: %s"%msg))
1068            return
1069
1070        #default flag
1071        flag = False
1072        self.fitrange = True
1073        #get event object
1074        tcrtl = event.GetEventObject()
1075       
1076        #wx.PostEvent(self._manager.parent, StatusEvent(status=" \
1077        #                        updating ... ",type="update"))
1078        #Clear msg if previously shown.
1079        msg= ""
1080        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1081
1082        if check_float(tcrtl):
1083            flag = self._onparamEnter_helper() 
1084            self.set_npts2fit() 
1085            if self.fitrange:             
1086                temp_smearer = None
1087                if not self.disable_smearer.GetValue():
1088                    temp_smearer= self.current_smearer
1089                    ## set smearing value whether or not
1090                    #        the data contain the smearing info
1091                    if self.slit_smearer.GetValue():
1092                        flag1 = self.update_slit_smear()
1093                        flag = flag or flag1
1094                    elif self.pinhole_smearer.GetValue():
1095                        flag1 = self.update_pinhole_smear()
1096                        flag = flag or flag1
1097                elif self.data.__class__.__name__ !="Data2D":
1098                    self._manager.set_smearer(smearer=temp_smearer, 
1099                                              uid=self.uid,
1100                                             qmin= float(self.qmin_x),
1101                                            qmax= float(self.qmax_x),
1102                                            draw=True) 
1103                if flag:   
1104                    #self.compute_chisqr(smearer= temp_smearer)
1105       
1106                    ## new state posted
1107                    if self.state_change:
1108                        #self._undo.Enable(True)
1109                        event = PageInfoEvent(page = self)
1110                        wx.PostEvent(self.parent, event)
1111                    self.state_change= False 
1112            else: 
1113                # invalid fit range: do nothing here:
1114                # msg already displayed in validate
1115                return     
1116        else:
1117            self.save_current_state()
1118            msg= "Cannot Plot :Must enter a number!!!  "
1119            wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1120             
1121        self.save_current_state() 
1122        return 
1123   
1124    def _onparamRangeEnter(self, event):
1125        """
1126        Check validity of value enter in the parameters range field
1127        """
1128        #if self.check_invalid_panel():
1129        #    return
1130        tcrtl= event.GetEventObject()
1131        #Clear msg if previously shown.
1132        msg= ""
1133        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1134        # Flag to register when a parameter has changed.
1135        is_modified = False
1136        if tcrtl.GetValue().lstrip().rstrip()!="":
1137            try:
1138                value = float(tcrtl.GetValue())
1139                tcrtl.SetBackgroundColour(wx.WHITE)
1140                self._check_value_enter(self.fittable_param ,is_modified)
1141                self._check_value_enter(self.parameters ,is_modified) 
1142            except:
1143                tcrtl.SetBackgroundColour("pink")
1144                msg= "Model Error:wrong value entered : %s"% sys.exc_value
1145                wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1146                return 
1147        else:
1148           tcrtl.SetBackgroundColour(wx.WHITE)
1149           
1150        #self._undo.Enable(True)
1151        self.save_current_state()
1152        event = PageInfoEvent(page = self)
1153        wx.PostEvent(self.parent, event)
1154        self.state_change= False
1155
1156                   
1157    def _onQrangeEnter(self, event):
1158        """
1159        Check validity of value enter in the Q range field
1160        """
1161        #if self.check_invalid_panel():
1162        #    return
1163        tcrtl= event.GetEventObject()
1164        #Clear msg if previously shown.
1165        msg= ""
1166        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1167        # Flag to register when a parameter has changed.
1168        is_modified = False
1169        if tcrtl.GetValue().lstrip().rstrip()!="":
1170            try:
1171                value = float(tcrtl.GetValue())
1172                tcrtl.SetBackgroundColour(wx.WHITE)
1173
1174                # If qmin and qmax have been modified, update qmin and qmax
1175                if self._validate_qrange( self.qmin, self.qmax):
1176                    tempmin = float(self.qmin.GetValue())
1177                    if tempmin != self.qmin_x:
1178                        self.qmin_x = tempmin
1179                    tempmax = float(self.qmax.GetValue())
1180                    if tempmax != self.qmax_x:
1181                        self.qmax_x = tempmax
1182                else:
1183                    tcrtl.SetBackgroundColour("pink")
1184                    msg= "Model Error:wrong value entered : %s"% sys.exc_value
1185                    wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1186                    return 
1187               
1188            except:
1189                tcrtl.SetBackgroundColour("pink")
1190                msg= "Model Error:wrong value entered : %s"% sys.exc_value
1191                wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1192                return 
1193            #Check if # of points for theory model are valid(>0).
1194            # check for 2d
1195            if self.data.__class__.__name__ =="Data2D":
1196                # set mask   
1197                radius= numpy.sqrt( self.data.qx_data*self.data.qx_data + 
1198                                    self.data.qy_data*self.data.qy_data )
1199                index_data = ((self.qmin_x <= radius)& \
1200                                (radius<= self.qmax_x))
1201                index_data = (index_data)&(self.data.mask)
1202                index_data = (index_data)&(numpy.isfinite(self.data.data))
1203                if len(index_data[index_data]) < 10:
1204                    msg = "Cannot Plot :No or too little npts in"
1205                    msg += " that data range!!!  "
1206                    wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1207                    return
1208                else:
1209                    self.data.mask = index_data
1210                    #self.Npts_fit.SetValue(str(len(self.data.mask)))
1211                    self.set_npts2fit() 
1212            else:
1213                if self.data is not None:
1214                   
1215                    index_data = ((self.qmin_x <= self.data.x)& \
1216                                  (self.data.x <= self.qmax_x))
1217                    self.Npts_fit.SetValue(str(len(self.data.x[index_data])))
1218
1219           
1220        else:
1221           tcrtl.SetBackgroundColour("pink")
1222           msg= "Model Error:wrong value entered!!!"
1223           wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1224       
1225        self._draw_model()
1226        ##update chi2
1227        #self.compute_chisqr(smearer= temp_smearer)
1228        #self._undo.Enable(True)
1229        self.save_current_state()
1230        event = PageInfoEvent(page = self)
1231        wx.PostEvent(self.parent, event)
1232        self.state_change= False
1233        return
1234   
1235    def _clear_Err_on_Fit(self):
1236        """
1237        hide the error text control shown
1238        after fitting
1239        """
1240       
1241        if hasattr(self,"text2_3"):
1242            self.text2_3.Hide()
1243
1244        if len(self.parameters)>0:
1245            for item in self.parameters:
1246                #Skip t ifhe angle parameters if 1D data
1247                if self.data.__class__.__name__ !="Data2D":
1248                    if item in self.orientation_params:
1249                        continue
1250                if item in self.param_toFit:
1251                    continue
1252                ## hide statictext +/-   
1253                if item[3]!=None and item[3].IsShown():
1254                    item[3].Hide()
1255                ## hide textcrtl  for error after fit
1256                if item[4]!=None and item[4].IsShown():                   
1257                    item[4].Hide()
1258 
1259        if len(self.fittable_param)>0:
1260            for item in self.fittable_param:
1261                #Skip t ifhe angle parameters if 1D data
1262                if self.data.__class__.__name__ !="Data2D":
1263                    if item in self.orientation_params:
1264                        continue
1265                if item in self.param_toFit:
1266                    continue
1267                ## hide statictext +/-   
1268                if item[3]!=None and item[3].IsShown():
1269                    item[3].Hide()
1270                ## hide textcrtl  for error after fit
1271                if item[4]!=None and item[4].IsShown():
1272                    item[4].Hide()
1273        return       
1274               
1275    def _get_defult_custom_smear(self):
1276        """
1277        Get the defult values for custum smearing.
1278        """
1279        # get the default values
1280        if self.dxl == None: self.dxl = 0.0
1281        if self.dxw == None: self.dxw = ""
1282        if self.dx_min == None: self.dx_min = SMEAR_SIZE_L
1283        if self.dx_max == None: self.dx_max = SMEAR_SIZE_H
1284       
1285    def _get_smear_info(self):
1286        """
1287        Get the smear info from data.
1288       
1289        :return: self.smear_type, self.dq_l and self.dq_r,
1290            respectively the type of the smear, dq_min and
1291            dq_max for pinhole smear data
1292            while dxl and dxw for slit smear
1293           
1294        """
1295
1296        # default
1297        self.smear_type = None
1298        self.dq_l = None
1299        self.dq_r = None
1300        data = self.data
1301        if self.data is None:
1302            return
1303        elif self.data.__class__.__name__ == 'Data2D': 
1304            if data.dqx_data == None or  data.dqy_data ==None: 
1305                return
1306            elif self.smearer != None and (data.dqx_data.any()!=0) and \
1307                            (data.dqx_data.any()!=0): 
1308                self.smear_type = "Pinhole2d"
1309                self.dq_l = format_number(numpy.average(data.dqx_data)) 
1310                self.dq_r = format_number(numpy.average(data.dqy_data)) 
1311                return 
1312            else: 
1313                return
1314        # check if it is pinhole smear and get min max if it is.
1315        if data.dx != None and all(data.dx !=0): 
1316            self.smear_type = "Pinhole" 
1317            self.dq_l = data.dx[0]
1318            self.dq_r = data.dx[-1]
1319           
1320        # check if it is slit smear and get min max if it is.
1321        elif data.dxl != None or data.dxw != None: 
1322            self.smear_type = "Slit" 
1323            if data.dxl != None and all(data.dxl !=0):
1324                self.dq_l = data.dxl[0]
1325            if data.dxw != None and all(data.dxw !=0): 
1326                self.dq_r = data.dxw[0]   
1327        #return self.smear_type,self.dq_l,self.dq_r       
1328   
1329    def _show_smear_sizer(self):   
1330        """
1331        Show only the sizers depending on smear selection
1332        """
1333        # smear disabled
1334        if self.disable_smearer.GetValue():
1335            self.smear_description_none.Show(True)
1336        # 2Dsmear
1337        elif self._is_2D():
1338            self.smear_description_accuracy_type.Show(True)
1339            self.smear_accuracy.Show(True)
1340            self.smear_description_accuracy_type.Show(True)
1341            self.smear_description_2d.Show(True)
1342            self.smear_description_2d_x.Show(True)
1343            self.smear_description_2d_y.Show(True)
1344            if self.pinhole_smearer.GetValue():
1345                self.smear_pinhole_min.Show(True)
1346                self.smear_pinhole_max.Show(True)
1347        # smear from data
1348        elif self.enable_smearer.GetValue():
1349
1350            self.smear_description_dqdata.Show(True)
1351            if self.smear_type != None:
1352                self.smear_description_smear_type.Show(True)
1353                if self.smear_type == 'Slit':
1354                    self.smear_description_slit_height.Show(True)
1355                    self.smear_description_slit_width.Show(True)               
1356                elif self.smear_type == 'Pinhole':
1357                    self.smear_description_pin_min.Show(True)
1358                    self.smear_description_pin_max.Show(True)
1359                self.smear_description_smear_type.Show(True)
1360                self.smear_description_type.Show(True)
1361                self.smear_data_left.Show(True)
1362                self.smear_data_right.Show(True)
1363        # custom pinhole smear
1364        elif self.pinhole_smearer.GetValue():
1365            if self.smear_type == 'Pinhole':
1366                self.smear_message_new_p.Show(True)
1367                self.smear_description_pin_min.Show(True)
1368                self.smear_description_pin_max.Show(True)
1369
1370            self.smear_pinhole_min.Show(True)
1371            self.smear_pinhole_max.Show(True)
1372        # custom slit smear
1373        elif self.slit_smearer.GetValue():
1374            self.smear_message_new_s.Show(True)
1375            self.smear_description_slit_height.Show(True)
1376            self.smear_slit_height.Show(True)
1377            self.smear_description_slit_width.Show(True)
1378            self.smear_slit_width.Show(True)
1379
1380    def _hide_all_smear_info(self):
1381        """
1382        Hide all smearing messages in the set_smearer sizer
1383        """
1384        self.smear_description_none.Hide()
1385        self.smear_description_dqdata.Hide()
1386        self.smear_description_type.Hide()
1387        self.smear_description_smear_type.Hide()
1388        self.smear_description_accuracy_type.Hide()
1389        self.smear_description_2d_x.Hide()
1390        self.smear_description_2d_y.Hide()
1391        self.smear_description_2d.Hide()
1392       
1393        self.smear_accuracy.Hide()
1394        self.smear_data_left.Hide()
1395        self.smear_data_right.Hide()
1396        self.smear_description_pin_min.Hide()
1397        self.smear_pinhole_min.Hide()
1398        self.smear_description_pin_max.Hide()
1399        self.smear_pinhole_max.Hide()
1400        self.smear_description_slit_height.Hide()
1401        self.smear_slit_height.Hide()
1402        self.smear_description_slit_width.Hide()
1403        self.smear_slit_width.Hide()
1404        self.smear_message_new_p.Hide()
1405        self.smear_message_new_s.Hide()
1406   
1407    def _set_accuracy_list(self):
1408        """
1409        Set the list of an accuracy in 2D custum smear: Xhigh, High, Med, or Low
1410        """
1411        # list of accuracy choices
1412        list = ['Low','Med','High','Xhigh']
1413        for idx in range(len(list)):
1414            self.smear_accuracy.Append(list[idx],idx)
1415           
1416    def _set_fun_box_list(self,fun_box):
1417        """
1418        Set the list of func for multifunctional models
1419        """
1420        # Check if it is multi_functional model
1421        if self.model.__class__ not in self.model_list_box["Multi-Functions"]:
1422            return None
1423        # Get the func name list
1424        list = self.model.fun_list
1425        if len(list) == 0:
1426            return None
1427        # build function (combo)box
1428        ind = 0
1429        while(ind < len(list)):
1430            for key, val in list.iteritems():
1431                if (val == ind):
1432                    fun_box.Append(key,val)
1433                    break
1434            ind += 1
1435       
1436    def _on_select_accuracy(self,event):
1437        """
1438        Select an accuracy in 2D custom smear: Xhigh, High, Med, or Low
1439        """
1440        #event.Skip()
1441        # Check if the accuracy is same as before
1442        #self.smear2d_accuracy = event.GetEventObject().GetValue()
1443        self.smear2d_accuracy = self.smear_accuracy.GetValue()
1444        if self.pinhole_smearer.GetValue():
1445            self.onPinholeSmear(event=None)
1446        else:   
1447            self.onSmear(event=None)
1448            if self.current_smearer != None:
1449                self.current_smearer.set_accuracy(accuracy = 
1450                                                  self.smear2d_accuracy) 
1451        event.Skip()
1452
1453    def _on_fun_box(self,event):
1454        """
1455        Select an func: Erf,Rparabola,LParabola
1456        """
1457        fun_val = None
1458        fun_box = event.GetEventObject()
1459        name = fun_box.Name
1460        value = fun_box.GetValue()
1461        if self.model.fun_list.has_key(value):
1462            fun_val = self.model.fun_list[value]
1463
1464        self.model.setParam(name,fun_val)
1465        # save state
1466        self._copy_parameters_state(self.str_parameters, 
1467                                    self.state.str_parameters)
1468        # update params
1469        self._update_paramv_on_fit() 
1470        # draw
1471        self._draw_model()
1472        self.Refresh()
1473        # get ready for new event
1474        event.Skip()
1475       
1476    def _onMask(self, event):     
1477        """
1478        Build a panel to allow to edit Mask
1479        """
1480       
1481        from sans.guiframe.local_perspectives.plotting.masking \
1482        import MaskPanel as MaskDialog
1483       
1484        self.panel = MaskDialog(self, data=self.data,id =-1 )
1485        self.panel.Bind(wx.EVT_CLOSE, self._draw_masked_model)
1486        self.panel.ShowModal()
1487        #wx.PostEvent(self.parent, event)
1488       
1489    def _draw_masked_model(self,event):
1490        """
1491        Draw model image w/mask
1492        """
1493        event.Skip()
1494
1495        is_valid_qrange = self._update_paramv_on_fit()
1496
1497        if is_valid_qrange:
1498            # try re draw the model plot if it exists
1499            self._draw_model()
1500            self.panel.Destroy() # frame
1501            self.set_npts2fit()
1502        elif self.model == None:
1503            self.panel.Destroy()
1504            self.set_npts2fit()
1505            msg= "No model is found on updating MASK in the model plot... "
1506            wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1507        else:
1508            msg = ' Please consider your Q range, too.'
1509            self.panel.ShowMessage(msg)
1510       
1511    def _set_smear(self, data):
1512        """
1513        """
1514        if data is None:
1515            return
1516        self.smearer = smear_selection(self.data, self.model)
1517        self.disable_smearer.SetValue(True)
1518        if self.smearer == None:
1519            self.enable_smearer.Disable()
1520        else:
1521            self.enable_smearer.Enable()
1522           
1523    def get_view_mode(self):
1524        """
1525        return True if the panel allow 2D or False if 1D
1526        """
1527        return self.enable2D
1528   
1529    def set_data(self, data):
1530        """
1531        reset the current data
1532        """
1533        flag = False
1534        if self.data is None and data is not None:
1535            self.window_name = str(data.name)
1536            ## Title to appear on top of the window
1537            self.window_caption = str(data.name)
1538            flag = True
1539        self.data = data
1540        if self.data is None:
1541            data_min = ""
1542            data_max = ""
1543            data_name = ""
1544            self._set_bookmark_flag(False)
1545            self._set_save_flag(False)
1546        else:
1547            self._set_bookmark_flag(True)
1548            self._set_save_flag(True)
1549            self._set_smear(data)
1550            # more disables for 2D
1551            if self.data.__class__.__name__ =="Data2D":
1552                self.slit_smearer.Disable()
1553                self.default_mask = copy.deepcopy(self.data.mask)
1554               
1555               
1556            self.formfactorbox.Enable()
1557            self.structurebox.Enable()
1558            data_name = self.data.name
1559            #set maximum range for x in linear scale
1560            if not hasattr(self.data,"data"): #Display only for 1D data fit
1561                # Minimum value of data   
1562                data_min = min(self.data.x)
1563                # Maximum value of data 
1564                data_max = max(self.data.x)
1565                #number of total data points
1566                self.Npts_total.SetValue(str(len(self.data.x)))
1567                #default:number of data points selected to fit
1568                self.Npts_fit.SetValue(str(len(self.data.x)))
1569                self.btEditMask.Disable() 
1570                self.EditMask_title.Disable()
1571            else:
1572               
1573                ## Minimum value of data
1574                data_min = 0
1575                x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax)) 
1576                y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
1577                ## Maximum value of data 
1578                data_max = math.sqrt(x*x + y*y)
1579                #number of total data points
1580                self.Npts_total.SetValue(str(len(self.data.data)))
1581                #default:number of data points selected to fit
1582                self.Npts_fit.SetValue(str(len(self.data.data)))
1583                self.btEditMask.Enable() 
1584                self.EditMask_title.Enable() 
1585        self.dataSource.SetValue(data_name)
1586        self.qmin_x = data_min
1587        self.qmax_x = data_max
1588        self.minimum_q.SetValue(str(data_min))
1589        self.maximum_q.SetValue(str(data_max))
1590        self.qmin.SetValue(str(data_min))
1591        self.qmax.SetValue(str(data_max))
1592        self.qmin.SetBackgroundColour("white")
1593        self.qmax.SetBackgroundColour("white")
1594        self.state.data = data
1595        self.state.qmin = self.qmin_x
1596        self.state.qmax = self.qmax_x
1597       
1598        #update model plot with new data information
1599        if flag:
1600            #set model view button
1601            if self.data.__class__.__name__ == "Data2D":
1602                self.enable2D = True
1603                self.model_view.SetLabel("2D Mode")
1604            else:
1605                self.enable2D = False
1606                self.model_view.SetLabel("1D Mode")
1607               
1608            self.model_view.Disable()
1609            self._draw_model()
1610       
1611    def reset_page(self, state,first=False):
1612        """
1613        reset the state
1614        """
1615        self.reset_page_helper(state)
1616        #import sans.guiframe.gui_manager
1617        #evt = ModelEventbox(model=state.model)
1618        #wx.PostEvent(self.event_owner, evt) 
1619   
1620        if self.engine_type != None:
1621            self._manager._on_change_engine(engine=self.engine_type)
1622
1623        self.select_param(event = None) 
1624        #Save state_fit
1625        self.save_current_state_fit()
1626        self._lay_out()
1627        self.Refresh()
1628       
1629    def get_range(self):
1630        """
1631        return the fitting range
1632        """
1633        return float(self.qmin_x) , float(self.qmax_x)
1634   
1635    def get_npts2fit(self):
1636        """
1637        return numbers of data points within qrange
1638       
1639        :Note: This is for Park where chi2 is not normalized by Npts of fit
1640       
1641        """
1642        if self.data is None:
1643            return
1644        npts2fit = 0
1645        qmin,qmax = self.get_range()
1646        if self.data.__class__.__name__ =="Data2D": 
1647            radius= numpy.sqrt( self.data.qx_data*self.data.qx_data + 
1648                                self.data.qy_data*self.data.qy_data )
1649            index_data = (self.qmin_x <= radius)&(radius<= self.qmax_x)
1650            index_data= (index_data)&(self.data.mask)
1651            index_data = (index_data)&(numpy.isfinite(self.data.data))
1652            npts2fit = len(self.data.data[index_data])
1653        else:
1654            for qx in self.data.x:
1655                   if qx >= qmin and qx <= qmax:
1656                       npts2fit += 1
1657        return npts2fit
1658
1659    def set_npts2fit(self):
1660        """
1661        setValue Npts for fitting
1662        """
1663        self.Npts_fit.SetValue(str(self.get_npts2fit()))
1664       
1665    def get_chi2(self):
1666        """
1667        return the current chi2
1668        """
1669        return self.tcChi.GetValue()
1670       
1671    def get_param_list(self):
1672        """
1673        :return self.param_toFit: list containing  references to TextCtrl
1674            checked.Theses TextCtrl will allow reference to parameters to fit.
1675       
1676        :raise: if return an empty list of parameter fit will nnote work
1677            properly so raise ValueError,"missing parameter to fit"
1678        """
1679        if self.param_toFit !=[]:
1680            return self.param_toFit
1681        else:
1682            raise ValueError,"missing parameter to fit"   
1683     
1684    def onsetValues(self,chisqr,p_name, out,cov):
1685        """
1686        Build the panel from the fit result
1687       
1688        :param chisqr: Value of the goodness of fit metric
1689        :param p_name: the name of parameters
1690        :param out: list of parameter with the best value found during fitting
1691        :param cov: Covariance matrix
1692   
1693        """
1694        if out == None or not numpy.isfinite(chisqr):
1695            raise ValueError,"Fit error occured..." 
1696       
1697        is_modified = False
1698        has_error = False   
1699       
1700        #Hide textctrl boxes of errors.
1701        self._clear_Err_on_Fit()   
1702       
1703        #Check if chi2 is finite
1704        if chisqr != None or numpy.isfinite(chisqr):
1705        #format chi2 
1706            if self.engine_type == "park": 
1707                npt_fit = float(self.get_npts2fit()) 
1708                if npt_fit > 0:
1709                    chisqr =chisqr/npt_fit   
1710            chi2 = format_number(chisqr)   
1711            self.tcChi.SetValue(chi2)   
1712            self.tcChi.Refresh()   
1713        else:
1714            self.tcChi.SetValue("-")
1715       
1716        #Hide error title
1717        if self.text2_3.IsShown():
1718            self.text2_3.Hide()
1719     
1720        try:
1721            n = self.disp_box.GetCurrentSelection()
1722            dispersity= self.disp_box.GetClientData(n)
1723            if dispersity !=None and self.enable_disp.GetValue():
1724                name= dispersity.__name__
1725                if name == "GaussianDispersion":
1726                    if hasattr(self,"text_disp_1" ):
1727                        if self.text_disp_1 !=None:
1728                            self.text_disp_1.Hide()
1729        except:
1730            dispersty = None
1731            pass
1732        #set the panel when fit result are float not list
1733        if out.__class__== numpy.float64:
1734            self.param_toFit[0][2].SetValue(format_number(out))
1735           
1736            if self.param_toFit[0][4].IsShown:
1737                self.param_toFit[0][4].Hide()
1738            if cov !=None :
1739                self.text2_3.Show(True)
1740                try:
1741                    if dispersity !=None:
1742                        name= dispersity.__name__
1743                        if name == "GaussianDispersion" and \
1744                        self.enable_disp.GetValue():
1745                            if hasattr(self,"text_disp_1" ):
1746                                if self.text_disp_1 !=None:
1747                                    self.text_disp_1.Show(True)
1748                except:
1749                    pass
1750
1751                if cov[0]==None or  not numpy.isfinite(cov[0]): 
1752                    if self.param_toFit[0][3].IsShown:
1753                        self.param_toFit[0][3].Hide()
1754                else:                   
1755                    self.param_toFit[0][3].Show(True)               
1756                    self.param_toFit[0][4].Show(True)
1757                    self.param_toFit[0][4].SetValue(format_number(cov[0]))
1758                    has_error = True
1759        else:
1760
1761            i = 0
1762            #Set the panel when fit result are list
1763            for item in self.param_toFit:     
1764                if len(item)>5 and item != None:     
1765                    ## reset error value to initial state
1766                    item[3].Hide()
1767                    item[4].Hide()
1768                   
1769                    for ind in range(len(out)):
1770                       
1771                        if item[1] == p_name[ind]:
1772                            break       
1773                    if len(out)<=len(self.param_toFit) and out[ind] !=None:   
1774                        val_out = format_number(out[ind])                 
1775                        item[2].SetValue(val_out)
1776
1777                    if(cov !=None):
1778                       
1779                        try:
1780                            if dispersity !=None:
1781                                name= dispersity.__name__
1782                                if name == "GaussianDispersion" and \
1783                                                self.enable_disp.GetValue():
1784                                    if hasattr(self,"text_disp_1" ):
1785                                        if self.text_disp_1!=None:
1786                                            if not self.text_disp_1.IsShown():
1787                                                self.text_disp_1.Show(True)
1788                        except:
1789                            pass   
1790                   
1791                        if cov[ind]!=None :
1792                            if numpy.isfinite(float(cov[ind])):
1793                                val_err = format_number(cov[ind])
1794                                item[3].Show(True)
1795                                item[4].Show(True)
1796                                item[4].SetValue(val_err)
1797
1798                                has_error = True
1799                    i += 1         
1800        #Show error title when any errors displayed
1801        if has_error: 
1802            if not self.text2_3.IsShown():
1803                self.text2_3.Show(True) 
1804               
1805        ## save current state 
1806        self.save_current_state()         
1807        #plot model
1808        self._draw_model()   
1809        self._lay_out()     
1810        #PostStatusEvent     
1811        msg = "Fit completed! "
1812        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
1813
1814    def onPinholeSmear(self, event):
1815        """
1816        Create a custom pinhole smear object that will change the way residuals
1817        are compute when fitting
1818       
1819        :Note: accuracy is given by strings'High','Med', 'Low' FOR 2d,
1820                     None for 1D
1821                     
1822        """
1823
1824        #if self.check_invalid_panel():
1825        #    return
1826        if self.model ==None:
1827            self.disable_smearer.SetValue(True)
1828            msg="Please select a Model first..."
1829            wx.MessageBox(msg, 'Info')
1830            wx.PostEvent(self._manager.parent, StatusEvent(status=\
1831                            "Smear: %s"%msg))
1832            return
1833
1834        # Need update param values
1835        self._update_paramv_on_fit()     
1836
1837        # msg default
1838        msg = None
1839        if event != None:
1840            tcrtl= event.GetEventObject()
1841            # event case of radio button
1842            if tcrtl.GetValue()== True:
1843                self.dx_min = 0.0
1844                self.dx_max = 0.0
1845                is_new_pinhole = True
1846            else:
1847                is_new_pinhole = self._is_changed_pinhole()
1848        else:
1849            is_new_pinhole = True 
1850        # if any value is changed
1851        if is_new_pinhole:
1852            msg = self._set_pinhole_smear()
1853        # hide all silt sizer   
1854        self._hide_all_smear_info()
1855       
1856        ##Calculate chi2
1857        temp_smearer = self.current_smearer
1858        #self.compute_chisqr(smearer= temp_smearer)
1859           
1860        # show relevant slit sizers
1861        self._show_smear_sizer()
1862
1863        self.sizer_set_smearer.Layout()
1864        self.Layout()   
1865       
1866        if event != None: 
1867            event.Skip()                 
1868        #self._undo.Enable(True)
1869        self.save_current_state()
1870        event = PageInfoEvent(page = self)
1871        wx.PostEvent(self.parent, event)
1872       
1873    def _is_changed_pinhole(self): 
1874        """
1875        check if any of pinhole smear is changed
1876       
1877        :return: True or False
1878       
1879        """
1880        # get the values
1881        pin_min = self.smear_pinhole_min.GetValue()
1882        pin_max = self.smear_pinhole_max.GetValue()
1883                   
1884        # Check changes in slit width   
1885        try:
1886            dx_min = float(pin_min)
1887        except:
1888            return True
1889        if self.dx_min != dx_min:
1890            return True
1891       
1892        # Check changes in slit heigth
1893        try:
1894            dx_max = float(pin_max)
1895        except:
1896            return True
1897        if self.dx_max != dx_max:
1898            return True
1899        return False
1900   
1901    def _set_pinhole_smear(self):
1902        """
1903        Set custom pinhole smear
1904       
1905        :return: msg
1906       
1907        """
1908        # copy data
1909        data = copy.deepcopy(self.data)
1910        if self._is_2D():
1911            self.smear_type = 'Pinhole2d'
1912            len_data = len(data.data)
1913            data.dqx_data = numpy.zeros(len_data)
1914            data.dqy_data = numpy.zeros(len_data)
1915        else:
1916            self.smear_type = 'Pinhole'
1917            len_data = len(data.x)
1918            data.dx = numpy.zeros(len_data)
1919            data.dxl = None
1920            data.dxw = None
1921        msg = None
1922   
1923        get_pin_min = self.smear_pinhole_min
1924        get_pin_max = self.smear_pinhole_max       
1925
1926        if not check_float(get_pin_min):
1927            get_pin_min.SetBackgroundColour("pink")
1928            msg= "Model Error:wrong value entered!!!"
1929        elif not check_float(get_pin_max ):
1930            get_pin_max.SetBackgroundColour("pink")
1931            msg= "Model Error:wrong value entered!!!"
1932        else:
1933            if len_data < 2: len_data = 2     
1934            self.dx_min = float(get_pin_min.GetValue())
1935            self.dx_max = float(get_pin_max.GetValue())
1936            if self.dx_min < 0:
1937                get_pin_min.SetBackgroundColour("pink")
1938                msg= "Model Error:This value can not be negative!!!"
1939            elif self.dx_max <0:
1940                get_pin_max.SetBackgroundColour("pink")
1941                msg= "Model Error:This value can not be negative!!!"
1942            elif self.dx_min != None and self.dx_max != None:   
1943                if self._is_2D():
1944                    data.dqx_data[data.dqx_data==0] = self.dx_min
1945                    data.dqy_data[data.dqy_data==0] = self.dx_max         
1946                elif self.dx_min == self.dx_max:
1947                    data.dx[data.dx==0] = self.dx_min
1948                else:
1949                    step = (self.dx_max - self.dx_min)/(len_data-1)   
1950                    data.dx = numpy.arange(self.dx_min,self.dx_max+step/1.1,
1951                                           step)           
1952            elif self.dx_min != None: 
1953                if self._is_2D(): data.dqx_data[data.dqx_data==0] = self.dx_min
1954                else: data.dx[data.dx==0] = self.dx_min
1955            elif self.dx_max != None:
1956                if self._is_2D(): data.dqy_data[data.dqy_data==0] = self.dx_max
1957                else: data.dx[data.dx==0] = self.dx_max         
1958            self.current_smearer = smear_selection(data, self.model)
1959            # 2D need to set accuracy
1960            if self._is_2D(): 
1961                self.current_smearer.set_accuracy(accuracy = \
1962                                                  self.smear2d_accuracy)
1963
1964        if msg != None:
1965            wx.PostEvent(self._manager.parent, StatusEvent(status = msg ))
1966        else:
1967            get_pin_min.SetBackgroundColour("white")
1968            get_pin_max.SetBackgroundColour("white")
1969        ## set smearing value whether or not the data contain the smearing info
1970        self._manager.set_smearer(smearer=self.current_smearer,
1971                                 qmin=float(self.qmin_x),
1972                                 qmax= float(self.qmax_x),
1973                                 uid=self.uid)
1974        return msg
1975       
1976    def update_pinhole_smear(self):
1977        """
1978        called by kill_focus on pinhole TextCntrl
1979        to update the changes
1980       
1981        :return: False when wrong value was entered
1982       
1983        """
1984        # msg default
1985        msg = None
1986        # check if any value is changed
1987        if self._is_changed_pinhole():
1988            msg = self._set_pinhole_smear()           
1989        #self._undo.Enable(True)
1990        self.save_current_state()
1991
1992        if msg != None:
1993            return False   
1994        else:
1995            return True
1996                     
1997    def onSlitSmear(self, event):
1998        """
1999        Create a custom slit smear object that will change the way residuals
2000        are compute when fitting
2001        """
2002 
2003        #if self.check_invalid_panel():
2004        #    return
2005
2006        if self.model ==None:
2007            self.disable_smearer.SetValue(True)
2008           
2009            msg="Please select a Model first..."
2010            wx.MessageBox(msg, 'Info')
2011            wx.PostEvent(self._manager.parent, StatusEvent(status=\
2012                            "Smear: %s"%msg))
2013            return
2014
2015        # Need update param values
2016        self._update_paramv_on_fit()
2017
2018        # msg default
2019        msg = None
2020        # for event given
2021        if event != None:
2022            tcrtl= event.GetEventObject()
2023            # event case of radio button
2024            if tcrtl.GetValue():
2025                self.dxl = 0.0
2026                self.dxw = 0.0
2027                is_new_slit = True
2028            else:
2029                is_new_slit = self._is_changed_slit()
2030        else:
2031            is_new_slit = True 
2032       
2033        # if any value is changed
2034        if is_new_slit:
2035            msg = self._set_slit_smear()
2036           
2037        # hide all silt sizer
2038        self._hide_all_smear_info()       
2039        ##Calculate chi2
2040        #self.compute_chisqr(smearer= self.current_smearer) 
2041        # show relevant slit sizers       
2042        self._show_smear_sizer()
2043        self.sizer_set_smearer.Layout()
2044        self.Layout()
2045
2046        if event != None:
2047            event.Skip()     
2048        #self._undo.Enable(True)
2049        self.save_current_state()
2050        event = PageInfoEvent(page = self)
2051        wx.PostEvent(self.parent, event)
2052        if msg != None:
2053            wx.PostEvent(self._manager.parent, StatusEvent(status = msg))
2054
2055    def _is_changed_slit(self): 
2056        """
2057        check if any of slit lengths is changed
2058       
2059        :return: True or False
2060       
2061        """
2062        # get the values
2063        width = self.smear_slit_width.GetValue()
2064        height = self.smear_slit_height.GetValue()
2065       
2066        # check and change the box bg color if it was pink
2067        #    but it should be white now
2068        # because this is the case that _set_slit_smear() will not handle
2069        if height.lstrip().rstrip()=="":
2070            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2071        if width.lstrip().rstrip()=="":
2072            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2073           
2074        # Check changes in slit width   
2075        if width == "": 
2076            dxw = 0.0
2077        else:
2078            try:
2079                dxw = float(width)
2080            except:
2081                return True
2082        if self.dxw != dxw:
2083            return True
2084       
2085        # Check changes in slit heigth
2086        if height == "": 
2087            dxl = 0.0
2088        else:
2089            try:
2090                dxl = float(height)
2091            except:
2092                return True
2093        if self.dxl != dxl:
2094            return True
2095
2096        return False
2097   
2098    def _set_slit_smear(self):
2099        """
2100        Set custom slit smear
2101       
2102        :return: message to inform the user about the validity
2103            of the values entered for slit smear
2104        """
2105        if self.data.__class__.__name__ == "Data2D":
2106            return
2107        temp_smearer = None
2108        # make sure once more if it is smearer
2109        data = copy.deepcopy(self.data)
2110        data_len = len(data.x)
2111        data.dx = None
2112        data.dxl = None
2113        data.dxw = None
2114        msg = None
2115   
2116        try:
2117            self.dxl = float(self.smear_slit_height.GetValue())
2118            data.dxl = self.dxl* numpy.ones(data_len)
2119            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2120        except: 
2121            data.dxl = numpy.zeros(data_len)
2122            if self.smear_slit_height.GetValue().lstrip().rstrip()!="":
2123                self.smear_slit_height.SetBackgroundColour("pink")
2124                msg = "Wrong value entered... " 
2125            else:
2126                self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2127        try:
2128            self.dxw = float(self.smear_slit_width.GetValue())
2129            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2130            data.dxw = self.dxw* numpy.ones(data_len)
2131        except: 
2132            data.dxw = numpy.zeros(data_len)
2133            if self.smear_slit_width.GetValue().lstrip().rstrip()!="":
2134                self.smear_slit_width.SetBackgroundColour("pink")
2135                msg = "Wrong Fit value entered... "
2136            else:
2137                self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2138             
2139        self.current_smearer = smear_selection(data, self.model)
2140        #temp_smearer = self.current_smearer
2141        ## set smearing value whether or not the data contain the smearing info
2142        self._manager.set_smearer(smearer=self.current_smearer, 
2143                                 qmin=float(self.qmin_x), 
2144                                 qmax= float(self.qmax_x),
2145                                 id=self.id) 
2146        return msg
2147   
2148    def update_slit_smear(self):
2149        """
2150        called by kill_focus on pinhole TextCntrl
2151        to update the changes
2152       
2153        :return: False when wrong value was entered
2154       
2155        """             
2156        # msg default
2157        msg = None
2158        # check if any value is changed
2159        if self._is_changed_slit():
2160            msg = self._set_slit_smear()           
2161        #self._undo.Enable(True)
2162        self.save_current_state()
2163
2164        if msg != None:
2165            return False   
2166        else:
2167            return True
2168                           
2169    def onSmear(self, event):
2170        """
2171        Create a smear object that will change the way residuals
2172        are compute when fitting
2173        """
2174        if event != None: 
2175            event.Skip()   
2176        if self.data is None:
2177            return
2178       
2179        if self.model == None:
2180            self.disable_smearer.SetValue(True)
2181            msg="Please select a Model first..."
2182            wx.MessageBox(msg, 'Info')
2183            wx.PostEvent(self._manager.parent, StatusEvent(status=\
2184                            "Smear: %s"%msg))
2185            return
2186       
2187        # Need update param values
2188        self._update_paramv_on_fit()
2189       
2190        temp_smearer = None
2191        self._get_smear_info()
2192       
2193        #renew smear sizer
2194        if self.smear_type != None:
2195            self.smear_description_smear_type.SetValue(str(self.smear_type))
2196            self.smear_data_left.SetValue(str(self.dq_l))   
2197            self.smear_data_right.SetValue(str(self.dq_r))       
2198
2199        self._hide_all_smear_info()
2200       
2201        data = copy.deepcopy(self.data)
2202        # make sure once more if it is smearer
2203        self.current_smearer = smear_selection(data, self.model)
2204       
2205        if self.enable_smearer.GetValue():
2206            if hasattr(self.data,"dxl"):
2207               
2208                msg= ": Resolution smearing parameters"
2209            if hasattr(self.data,"dxw"):
2210                msg= ": Slit smearing parameters"
2211            if self.smearer ==None:
2212                wx.PostEvent(self._manager.parent, StatusEvent(status=\
2213                            "Data contains no smearing information"))
2214            else:
2215                wx.PostEvent(self._manager.parent, StatusEvent(status=\
2216                            "Data contains smearing information"))
2217
2218            #self.smear_description_dqdata.Show(True)
2219            self.smear_data_left.Show(True)
2220            self.smear_data_right.Show(True)
2221            temp_smearer= self.current_smearer
2222        elif self.disable_smearer.GetValue():
2223            self.smear_description_none.Show(True)
2224           
2225        self._show_smear_sizer()
2226       
2227        self.sizer_set_smearer.Layout()
2228        self.Layout()
2229        ## set smearing value whether or not the data contain the smearing info
2230        self._manager.set_smearer(uid=self.uid, smearer=temp_smearer, qmin= float(self.qmin_x),
2231                        qmax= float(self.qmax_x), draw=True) 
2232       
2233        ##Calculate chi2
2234        #self.compute_chisqr(smearer= temp_smearer)
2235       
2236        self.state.enable_smearer=  self.enable_smearer.GetValue()
2237        self.state.disable_smearer=self.disable_smearer.GetValue()
2238        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
2239        self.state.slit_smearer = self.slit_smearer.GetValue()
2240     
2241    def on_complete_chisqr(self, event): 
2242        """
2243        print result chisqr
2244       
2245        :event: activated by fitting/ complete after draw
2246       
2247        """
2248        try:
2249            if event ==None:
2250                output= "-"
2251            else:
2252                output = event.output
2253            self.tcChi.SetValue(str(format_number(output)))
2254
2255            self.state.tcChi = self.tcChi.GetValue()
2256        except:
2257            pass 
2258           
2259
2260    def select_all_param(self,event): 
2261        """
2262        set to true or false all checkBox given the main checkbox value cb1
2263        """           
2264        self.param_toFit=[]
2265        if  self.parameters !=[]:
2266            if  self.cb1.GetValue():
2267                for item in self.parameters:
2268                    ## for data2D select all to fit
2269                    if self.data.__class__.__name__=="Data2D":
2270                        item[0].SetValue(True)
2271                        self.param_toFit.append(item )
2272                    else:
2273                        ## for 1D all parameters except orientation
2274                        if not item in self.orientation_params:
2275                            item[0].SetValue(True)
2276                            self.param_toFit.append(item )
2277                #if len(self.fittable_param)>0:
2278                for item in self.fittable_param:
2279                    if self.data.__class__.__name__=="Data2D":
2280                        item[0].SetValue(True)
2281                        self.param_toFit.append(item )
2282                    else:
2283                        ## for 1D all parameters except orientation
2284                        if not item in self.orientation_params_disp:
2285                            item[0].SetValue(True)
2286                            self.param_toFit.append(item )
2287            else:
2288                for item in self.parameters:
2289                    item[0].SetValue(False)
2290                for item in self.fittable_param:
2291                    item[0].SetValue(False)
2292                self.param_toFit=[]
2293           
2294        self.save_current_state_fit() 
2295       
2296        if event !=None:
2297            #self._undo.Enable(True)
2298            ## post state to fit panel
2299            event = PageInfoEvent(page = self)
2300            wx.PostEvent(self.parent, event) 
2301     
2302    def select_param(self,event):
2303        """
2304        Select TextCtrl  checked for fitting purpose and stores them
2305        in  self.param_toFit=[] list
2306        """
2307        self.param_toFit=[]
2308        for item in self.parameters:
2309            #Skip t ifhe angle parameters if 1D data
2310            if self.data.__class__.__name__ !="Data2D":
2311                if item in self.orientation_params:
2312                    continue
2313            #Select parameters to fit for list of primary parameters
2314            if item[0].GetValue():
2315                if not (item in self.param_toFit):
2316                    self.param_toFit.append(item ) 
2317            else:
2318                #remove parameters from the fitting list
2319                if item in self.param_toFit:
2320                    self.param_toFit.remove(item)
2321
2322        #Select parameters to fit for list of fittable parameters
2323        #        with dispersion         
2324        for item in self.fittable_param:
2325            #Skip t ifhe angle parameters if 1D data
2326            if self.data.__class__.__name__ !="Data2D":
2327                if item in self.orientation_params:
2328                    continue
2329            if item[0].GetValue():
2330                if not (item in self.param_toFit):
2331                    self.param_toFit.append(item) 
2332            else:
2333                #remove parameters from the fitting list
2334                if item in self.param_toFit:
2335                    self.param_toFit.remove(item)
2336
2337        #Calculate num. of angle parameters
2338        if self.data.__class__.__name__ =="Data2D": 
2339            len_orient_para = 0
2340        else:
2341            len_orient_para = len(self.orientation_params)  #assume even len
2342        #Total num. of angle parameters
2343        if len(self.fittable_param) > 0:
2344            len_orient_para *= 2
2345        #Set the value of checkbox that selected every checkbox or not           
2346        if len(self.parameters)+len(self.fittable_param)-len_orient_para ==\
2347                len(self.param_toFit):
2348            self.cb1.SetValue(True)
2349        else:
2350            self.cb1.SetValue(False)
2351        self.save_current_state_fit()
2352        if event !=None:
2353            #self._undo.Enable(True)
2354            ## post state to fit panel
2355            event = PageInfoEvent(page = self)
2356            wx.PostEvent(self.parent, event) 
2357   
2358    def set_model_param_sizer(self, model):
2359        """
2360        Build the panel from the model content
2361       
2362        :param model: the model selected in combo box for fitting purpose
2363       
2364        """
2365        self.sizer3.Clear(True)
2366        self.parameters = []
2367        self.str_parameters = []
2368        self.param_toFit=[]
2369        self.fittable_param=[]
2370        self.fixed_param=[]
2371        self.orientation_params=[]
2372        self.orientation_params_disp=[]
2373       
2374        if model ==None:
2375            self.sizer3.Layout()
2376            self.SetupScrolling()
2377            return
2378        ## the panel is drawn using the current value of the fit engine
2379        if self.engine_type==None and self._manager !=None:
2380            self.engine_type= self._manager._return_engine_type()
2381
2382        box_description= wx.StaticBox(self, -1,str("Model Parameters"))
2383        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2384        sizer = wx.GridBagSizer(5,5)
2385        ## save the current model
2386        self.model = model
2387           
2388        keys = self.model.getParamList()
2389        #list of dispersion paramaters
2390        self.disp_list=self.model.getDispParamList()
2391
2392        def custom_compare(a,b):
2393            """
2394            Custom compare to order, first by alphabets then second by number.
2395            """ 
2396            # number at the last digit
2397            a_last = a[len(a)-1]
2398            b_last = b[len(b)-1]
2399            # default
2400            num_a = None
2401            num_b = None
2402            # split the names
2403            a2 = a.lower().split('_')
2404            b2 = b.lower().split('_')
2405            # check length of a2, b2
2406            len_a2 = len(a2)
2407            len_b2 = len(b2)
2408            # check if it contains a int number(<10)
2409            try: 
2410                num_a = int(a_last)
2411            except: pass
2412            try:
2413                num_b = int(b_last)
2414            except: pass
2415            # Put 'scale' near the top; happens
2416            # when numbered param name exists
2417            if a == 'scale':
2418                return -1
2419            # both have a number   
2420            if num_a != None and num_b != None:
2421                if num_a > num_b: return -1
2422                # same number
2423                elif num_a == num_b: 
2424                    # different last names
2425                    if a2[len_a2-1] != b2[len_b2-1] and num_a != 0:
2426                        return -cmp(a2[len_a2-1], b2[len_b2-1])
2427                    else: 
2428                        return cmp(a, b) 
2429                else: return 1
2430            # one of them has a number
2431            elif num_a != None: return 1
2432            elif num_b != None: return -1
2433            # no numbers
2434            else: return cmp(a.lower(), b.lower())
2435
2436                       
2437        keys.sort(custom_compare)
2438   
2439        iy = 0
2440        ix = 0
2441        select_text = "Select All"
2442        self.cb1 = wx.CheckBox(self, -1,str(select_text), (10, 10))
2443        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
2444        self.cb1.SetToolTipString("To check/uncheck all the boxes below.")
2445        #self.cb1.SetValue(True)
2446       
2447        sizer.Add(self.cb1,(iy, ix),(1,1),\
2448                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
2449        ix +=1
2450        self.text2_2 = wx.StaticText(self, -1, 'Values')
2451        sizer.Add(self.text2_2,(iy, ix),(1,1),\
2452                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2453        ix +=2 
2454        self.text2_3 = wx.StaticText(self, -1, 'Errors')
2455        sizer.Add(self.text2_3,(iy, ix),(1,1),\
2456                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2457        self.text2_3.Hide()
2458        ix +=1 
2459        self.text2_min = wx.StaticText(self, -1, 'Min')
2460        sizer.Add(self.text2_min,(iy, ix),(1,1),\
2461                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2462        self.text2_min.Hide()
2463        ix +=1 
2464        self.text2_max = wx.StaticText(self, -1, 'Max')
2465        sizer.Add(self.text2_max,(iy, ix),(1,1),\
2466                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2467        self.text2_max.Hide()
2468        ix += 1
2469        self.text2_4 = wx.StaticText(self, -1, '[Units]')
2470        sizer.Add(self.text2_4,(iy, ix),(1,1),\
2471                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2472        self.text2_4.Hide()
2473        if self.engine_type=="park":
2474            self.text2_max.Show(True)
2475            self.text2_min.Show(True)
2476       
2477        for item in keys:
2478            if not item in self.disp_list and not item in \
2479                    self.model.orientation_params:
2480               
2481                ##prepare a spot to store errors
2482                if not self.model.details.has_key(item):
2483                    self.model.details [item] = ["",None,None] 
2484         
2485                iy += 1
2486                ix = 0
2487                if self.model.__class__ in \
2488                    self.model_list_box["Multi-Functions"] \
2489                    and item in self.model.non_fittable:
2490                    non_fittable_name = wx.StaticText(self, -1, item )
2491                    sizer.Add(non_fittable_name,(iy, ix),(1,1),\
2492                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 21)
2493                    ## add parameter value
2494                    ix += 1
2495                    value= self.model.getParam(item)
2496                    if len(self.model.fun_list) > 0:
2497                        num = item.split('_')[1][5:7]
2498                        fun_box = wx.ComboBox(self, -1,size=(100,-1),
2499                                    style=wx.CB_READONLY, name = '%s'% item)
2500                        self._set_fun_box_list(fun_box)
2501                        fun_box.SetSelection(0)
2502                        #self.fun_box.SetToolTipString("A function
2503                        #    describing the interface")
2504                        wx.EVT_COMBOBOX(fun_box,-1, self._on_fun_box)
2505                    else:
2506                        fun_box = self.ModelTextCtrl(self, -1, 
2507                                                     size=(_BOX_WIDTH,20),
2508                                style=wx.TE_PROCESS_ENTER, name ='%s'% item)
2509                        fun_box.SetToolTipString("Hit 'Enter' after typing.")
2510                        fun_box.SetValue(format_number(value))
2511                    sizer.Add(fun_box, (iy,ix),(1,1), wx.EXPAND)
2512                    self.str_parameters.append([None,item, fun_box,
2513                                                None,None,None,None,None])
2514
2515                   
2516                else:
2517                    ## add parameters name with checkbox for selecting to fit
2518                    cb = wx.CheckBox(self, -1, item )             
2519                    cb.SetToolTipString(" Check for fitting.")
2520                    #cb.SetValue(True)
2521                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2522                   
2523                    sizer.Add( cb,( iy, ix),(1,1),
2524                                 wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
2525
2526                    ## add parameter value
2527                    ix += 1
2528                    value= self.model.getParam(item)
2529                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
2530                                        style=wx.TE_PROCESS_ENTER)
2531                    ctl1.SetToolTipString("Hit 'Enter' after typing.")
2532                    ctl1.SetValue(format_number(value))
2533                    sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
2534                    ## text to show error sign
2535                    ix += 1
2536                    text2=wx.StaticText(self, -1, '+/-')
2537                    sizer.Add(text2,(iy, ix),(1,1),\
2538                                    wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2539                    text2.Hide() 
2540                    ix += 1
2541                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
2542                    sizer.Add(ctl2, (iy,ix),(1,1), 
2543                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2544                    ctl2.Hide()
2545                   
2546                    ix += 1
2547                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
2548                                               style=wx.TE_PROCESS_ENTER,
2549                                text_enter_callback = self._onparamRangeEnter)
2550         
2551                    sizer.Add(ctl3, (iy,ix),(1,1), 
2552                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2553                    ctl3.Hide()
2554           
2555                    ix += 1
2556                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
2557                                               style=wx.TE_PROCESS_ENTER,
2558                                text_enter_callback = self._onparamRangeEnter)
2559                    sizer.Add(ctl4, (iy,ix),(1,1), 
2560                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2561         
2562                    ctl4.Hide()
2563   
2564                    if self.engine_type=="park":
2565                        ctl3.Show(True)
2566                        ctl4.Show(True)
2567                    ix +=1
2568                    # Units
2569                    if self.model.details.has_key(item):
2570                        units = wx.StaticText(self, -1, 
2571                            self.model.details[item][0], style=wx.ALIGN_LEFT)
2572                    else:
2573                        units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
2574                    sizer.Add(units, (iy,ix),(1,1), 
2575                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2576                       
2577                    ##[cb state, name, value, "+/-", error of fit, min, max , units]
2578                    self.parameters.append([cb,item, ctl1,
2579                                            text2,ctl2, ctl3, ctl4,units])
2580                                 
2581        iy+=1
2582        sizer.Add((10,10),(iy,ix),(1,1), 
2583                  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
2584       
2585        # type can be either Guassian or Array
2586        if len(self.model.dispersion.values())>0:
2587            type= self.model.dispersion.values()[0]["type"]
2588        else:
2589            type = "Gaussian"
2590           
2591        iy += 1
2592        ix = 0
2593        #Add tile for orientational angle
2594        for item in keys:
2595            if item in self.model.orientation_params:       
2596                orient_angle = wx.StaticText(self, -1, '[For 2D only]:')
2597                sizer.Add(orient_angle,(iy, ix),(1,1), 
2598                          wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15) 
2599                if not self.data.__class__.__name__ =="Data2D":
2600                    orient_angle.Hide()
2601                else:
2602                    orient_angle.Show(True)
2603                break
2604     
2605        #For Gaussian only
2606        if type.lower() != "array":
2607            for item in self.model.orientation_params:
2608                if not item in self.disp_list:
2609                    ##prepare a spot to store min max
2610                    if not self.model.details.has_key(item):
2611                        self.model.details [item] = ["",None,None] 
2612                         
2613                    iy += 1
2614                    ix = 0
2615                    ## add parameters name with checkbox for selecting to fit
2616                    cb = wx.CheckBox(self, -1, item )
2617                    cb.SetValue(False)
2618                    cb.SetToolTipString("Check for fitting")
2619                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2620                    if self.data.__class__.__name__ =="Data2D":
2621                        cb.Show(True)
2622                    else:
2623                        cb.Hide()
2624                    sizer.Add( cb,( iy, ix),(1,1),
2625                                 wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
2626   
2627                    ## add parameter value
2628                    ix += 1
2629                    value= self.model.getParam(item)
2630                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
2631                                        style=wx.TE_PROCESS_ENTER)
2632                    ctl1.SetToolTipString("Hit 'Enter' after typing.")
2633                    ctl1.SetValue(format_number(value))
2634                    if self.data.__class__.__name__ =="Data2D":
2635                        ctl1.Show(True)
2636                    else:
2637                        ctl1.Hide()
2638                    sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
2639                    ## text to show error sign
2640                    ix += 1
2641                    text2=wx.StaticText(self, -1, '+/-')
2642                    sizer.Add(text2,(iy, ix),(1,1),\
2643                                    wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2644                    text2.Hide() 
2645                    ix += 1
2646                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
2647                    sizer.Add(ctl2, (iy,ix),(1,1), 
2648                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2649                    ctl2.Hide()
2650                   
2651                   
2652                    ix += 1
2653                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), 
2654                                              style=wx.TE_PROCESS_ENTER,
2655                                text_enter_callback = self._onparamRangeEnter)
2656                   
2657                    sizer.Add(ctl3, (iy,ix),(1,1), 
2658                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2659                    ctl3.Hide()
2660                 
2661                    ix += 1
2662                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
2663                                               style=wx.TE_PROCESS_ENTER,
2664                            text_enter_callback = self._onparamRangeEnter)
2665                    sizer.Add(ctl4, (iy,ix),(1,1), 
2666                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2667                   
2668                    ctl4.Hide()
2669                   
2670                    if self.engine_type =="park" and \
2671                            self.data.__class__.__name__ =="Data2D":                     
2672                        ctl3.Show(True)
2673                        ctl4.Show(True)
2674                   
2675                    ix +=1
2676                    # Units
2677                    if self.model.details.has_key(item):
2678                        units = wx.StaticText(self, -1, 
2679                                              self.model.details[item][0], 
2680                                              style=wx.ALIGN_LEFT)
2681                    else:
2682                        units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
2683                    if self.data.__class__.__name__ =="Data2D":
2684                        units.Show(True)
2685                   
2686                    else:
2687                        units.Hide()
2688                   
2689                    sizer.Add(units, (iy,ix),(1,1), 
2690                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2691                                         
2692                    ##[cb state, name, value, "+/-", error of fit,min,max,units]
2693                    self.parameters.append([cb,item, ctl1,
2694                                            text2,ctl2, ctl3, ctl4,units])
2695                    self.orientation_params.append([cb,item, ctl1,
2696                                            text2,ctl2, ctl3, ctl4,units])
2697             
2698        iy+=1
2699       
2700        #Display units text on panel
2701        for item in keys:   
2702            if self.model.details.has_key(item):
2703                self.text2_4.Show()
2704        #Fill the list of fittable parameters
2705        self.select_all_param(event=None)
2706
2707        self.save_current_state_fit()
2708        boxsizer1.Add(sizer)
2709        self.sizer3.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
2710        self.sizer3.Layout()
2711        self.Layout()
2712        self.Refresh()
2713     
2714    def _onModel2D(self, event):
2715        """
2716        toggle view of model from 1D to 2D  or 2D from 1D
2717        """
2718        if self.model_view.GetLabelText() == "Switch to 2D":
2719            self.model_view.SetLabel("Switch to 1D")
2720            self.enable2D = True
2721        else:
2722            self.model_view.SetLabel("Switch to 2D")
2723            self.enable2D = False
2724        self._draw_model()
2725
2726class BGTextCtrl(wx.TextCtrl):
2727    """
2728    Text control used to display outputs.
2729    No editing allowed. The background is
2730    grayed out. User can't select text.
2731    """
2732    def __init__(self, *args, **kwds):
2733        wx.TextCtrl.__init__(self, *args, **kwds)
2734        self.SetEditable(False)
2735        self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
2736       
2737        # Bind to mouse event to avoid text highlighting
2738        # The event will be skipped once the call-back
2739        # is called.
2740        self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
2741       
2742    def _click(self, event):
2743        """
2744        Prevent further handling of the mouse event
2745        by not calling Skip().
2746        """ 
2747        pass
2748 
Note: See TracBrowser for help on using the repository browser.