source: sasview/src/sans/perspectives/fitting/fitpage.py @ bf5e985

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 bf5e985 was bf5e985, checked in by pkienzle, 10 years ago

restore simultaneous fitting for bumps

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