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

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

Changed fitpage to disable dropdown data list when only one entry.

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