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

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 4ec242e was 22ae2f7, checked in by pkienzle, 10 years ago

set default bounds from model in UI (closes #229)

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