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

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 0e4e554 was 0e4e554, checked in by ajj, 9 years ago

start switching to sasmodels including dispersion

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