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

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 1f8eecb was 5777106, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Moving things around. Will definitely not build.

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