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

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 cb270ad2 was cb270ad2, checked in by Miguel Gonzalez <onzalezm@…>, 11 years ago

Added checkbutton in fittingview perspective to allow log spacing of points for theory models

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