source: sasview/src/sas/perspectives/fitting/fitpage.py @ acf8e4a5

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 acf8e4a5 was acf8e4a5, checked in by Paul Kienzle <pkienzle@…>, 9 years ago

reference BumpsFit? directly and remove fit engine selection layer

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