source: sasview/src/sas/sasgui/perspectives/fitting/simfitpage.py @ fd62331

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.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since fd62331 was 998ca90, checked in by krzywon, 8 years ago

#189 #12 Saving and loading project now fully saves and loads a simultaneous fits. Loading a project will reset Sasview state to its base state (with a warning). One error on load to fix before calling this finished.

  • Property mode set to 100644
File size: 43.0 KB
RevLine 
[f32d144]1"""
2    Simultaneous fit page
3"""
[d7b4decd]4import sys
5from collections import namedtuple
6
7import wx
[f32d144]8import wx.lib.newevent
[d7b4decd]9from wx.lib.scrolledpanel import ScrolledPanel
10
[a95ae9a]11from sas.sasgui.guiframe.events import StatusEvent, PanelOnFocusEvent
[d85c194]12from sas.sasgui.guiframe.panel_base import PanelBase
13from sas.sasgui.guiframe.utils import IdList
14from sas.sasgui.guiframe.documentation_window import DocumentationWindow
[d7b4decd]15
[a95ae9a]16# Control panel width
[f32d144]17if sys.platform.count("darwin") == 0:
[c99a6c5]18    PANEL_WID = 420
[f1aa385]19    FONT_VARIANT = 0
[c99a6c5]20else:
21    PANEL_WID = 490
[f1aa385]22    FONT_VARIANT = 1
[2f4b430]23
24
[d7b4decd]25# Each constraint requires five widgets and sizer.  Package them in
26# a named tuple for easy access.
27ConstraintLine = namedtuple('ConstraintLine',
28        'model_cbox param_cbox egal_txt constraint btRemove sizer')
29
[a95ae9a]30
[f32d144]31def get_fittableParam(model):
[2140e68]32    """
[662d8d87]33    return list of fittable parameters from a model
[2f4b430]34
[5062bbf]35    :param model: the model used
[2f4b430]36
[2140e68]37    """
[f32d144]38    fittable_param = []
[8bd4dc0]39    for item in model.getParamList():
40        if not item  in model.getDispParamList():
[fb59ed9]41            if not item in model.non_fittable:
42                fittable_param.append(item)
[2f4b430]43
[8bd4dc0]44    for item in model.fixed:
45        fittable_param.append(item)
[2f4b430]46
[8bd4dc0]47    return fittable_param
[2140e68]48
[a95ae9a]49
[4bd492f]50class SimultaneousFitPage(ScrolledPanel, PanelBase):
[d89f09b]51    """
[5062bbf]52    Simultaneous fitting panel
53    All that needs to be defined are the
54    two data members window_name and window_caption
[d89f09b]55    """
[a95ae9a]56    # Internal name for the AUI manager
57    window_name = "Simultaneous Fit Page"
58    # Title to appear on top of the window
[d89f09b]59    window_caption = "Simultaneous Fit Page"
[662d8d87]60    ID_DOC = wx.NewId()
[6f16e25]61    ID_SET_ALL = wx.NewId()
62    ID_FIT = wx.NewId()
63    ID_ADD = wx.NewId()
[d7b4decd]64    _id_pool = IdList()
[2f4b430]65
[d7b4decd]66    def __init__(self, parent, page_finder={}, id=wx.ID_ANY, batch_on=False,
67                 *args, **kwargs):
[fa02d95]68        ScrolledPanel.__init__(self, parent, id=id,
[f32d144]69                               style=wx.FULL_REPAINT_ON_RESIZE,
[fa02d95]70                               *args, **kwargs)
[4bd492f]71        PanelBase.__init__(self, parent)
[d89f09b]72        """
[5062bbf]73        Simultaneous page display
[d89f09b]74        """
[d7b4decd]75        self._ids = iter(self._id_pool)
[00daba9]76        self.SetupScrolling()
[a95ae9a]77        # Font size
[f32d144]78        self.SetWindowVariant(variant=FONT_VARIANT)
[922497f]79        self.uid = wx.NewId()
[d89f09b]80        self.parent = parent
[fa02d95]81        self.batch_on = batch_on
[a95ae9a]82        # store page_finder
[b28717b]83        self.page_finder = page_finder
[a95ae9a]84        # list containing info to set constraint
85        # look like self.constraint_dict[page_id]= page
[f32d144]86        self.constraint_dict = {}
[a95ae9a]87        # item list
88        # self.constraints_list=[combobox1, combobox2,=,textcrtl, button ]
[f32d144]89        self.constraints_list = []
[a95ae9a]90        # list of current model
[f32d144]91        self.model_list = []
[a95ae9a]92        # selected model to fit
93        self.model_to_fit = []
94        # Control the fit state
[aac161f1]95        self.fit_started = False
[a95ae9a]96        # number of constraint
[f32d144]97        self.nb_constraint = 0
[a95ae9a]98        self.state = SimFitPageState()
[53fc5ad9]99        self.model_cbox_left = None
100        self.model_cbox_right = None
[a95ae9a]101        # draw page
[2140e68]102        self.define_page_structure()
[b28717b]103        self.draw_page()
[87e1d1a]104        self._set_save_flag(False)
[2f4b430]105
[2140e68]106    def define_page_structure(self):
107        """
[662d8d87]108        Create empty sizers, their hierarchy and set the sizer for the panel
[2140e68]109        """
[f32d144]110        self.vbox = wx.BoxSizer(wx.VERTICAL)
[a95ae9a]111        self.data_selection_sizer = wx.BoxSizer(wx.VERTICAL)
112        self.constraints_sizer = wx.BoxSizer(wx.VERTICAL)
113        self.run_fit_sizer = wx.BoxSizer(wx.VERTICAL)
114
115        self.data_selection_sizer.SetMinSize((PANEL_WID, -1))
116        self.constraints_sizer.SetMinSize((PANEL_WID, -1))
117        self.run_fit_sizer.SetMinSize((PANEL_WID, -1))
118        self.vbox.Add(self.data_selection_sizer)
119        self.vbox.Add(self.constraints_sizer)
120        self.vbox.Add(self.run_fit_sizer)
[662d8d87]121        self.SetSizer(self.vbox)
122        self.Centre()
[2f4b430]123
[a95ae9a]124    def set_state(self):
125        """
126        Define a set of state parameters for saving simultaneous fits.
127        """
128        self._set_constraint()
129        self.state.fit_page_no = self.uid
130        self.state.select_all = self.cb1.GetValue()
131        self.state.model_list = self.model_list
132        self.state.model_to_fit = self.model_to_fit
133        self.state.no_constraint = self.nb_constraint
134        self.state.constraint_dict = self.constraint_dict
135        self.state.constraints_list = self.constraints_list
136        return self.get_state()
137
138    def get_state(self):
139        """
140        Return the state of the current page
141        :return: self.state
142        """
143        return self.state
144
[662d8d87]145    def draw_page(self):
[5062bbf]146        """
[662d8d87]147        Construct the Simultaneous/Constrained fit page. fills the first
148        region (sizer1) with the list of available fit page pairs of data
149        and models.  Then fills sizer2 with the checkbox for adding
150        constraints, and finally fills sizer3 with the fit button and
151        instructions.
[5062bbf]152        """
[2f4b430]153
[662d8d87]154        # create blank list of constraints
155        self.model_list = []
[a95ae9a]156        self.model_to_fit = []
[662d8d87]157        self.constraints_list = []
158        self.constraint_dict = {}
159        self.nb_constraint = 0
160        self.model_cbox_left = None
161        self.model_cbox_right = None
162
163        if len(self.model_list) > 0:
164            for item in self.model_list:
165                item[0].SetValue(False)
166                self.manager.schedule_for_fit(value=0, uid=item[2])
167
168        #-------------------------------------------------------
[a95ae9a]169        # setup sizer1 (which fitpages to include)
170        self.data_selection_sizer.Clear(True)
[662d8d87]171        box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Combinations")
172        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
173        sizer_title = wx.BoxSizer(wx.HORIZONTAL)
174        sizer_couples = wx.GridBagSizer(5, 5)
175
[a95ae9a]176        # The wx GUI has a flag to enable a menu item, but can still be
177        # reached via scripting. There is no guearantee future GUI
178        # implementations force this check, either.
179        # IMHO, this if statement should stay -- JRK 2016-OCT-05
[662d8d87]180        if len(self.page_finder) == 0:
181            msg = " No fit combinations are found! \n\n"
182            msg += " Please load data and set up "
183            msg += "at least one fit panels first..."
184            sizer_title.Add(wx.StaticText(self, wx.ID_ANY, msg))
185        else:
[a95ae9a]186            # store model
[662d8d87]187            self._store_model()
188
189            self.cb1 = wx.CheckBox(self, wx.ID_ANY, 'Select all')
190            self.cb1.SetValue(False)
191            wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.check_all_model_name)
192
193            sizer_title.Add((10, 10), 0,
194                wx.TOP | wx.BOTTOM | wx.EXPAND | wx.ADJUST_MINSIZE, border=5)
195            sizer_title.Add(self.cb1, 0,
[a95ae9a]196                wx.TOP | wx.BOTTOM | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE,
197                border=5)
[662d8d87]198
[a95ae9a]199            # draw list of model and data names
[662d8d87]200            self._fill_sizer_model_list(sizer_couples)
201
202        boxsizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=5)
203        boxsizer1.Add(sizer_couples, 1, flag=wx.TOP | wx.BOTTOM, border=5)
[a95ae9a]204        self.data_selection_sizer.Add(boxsizer1, 1, wx.EXPAND | wx.ALL, 10)
205        # self.sizer1.Layout()
[662d8d87]206
207        #--------------------------------------------------------
[a95ae9a]208        # set up the other 2 sizers: the constraints list and the
209        # buttons (fit, help etc) sizer at the bottom of the page.
210        # Note: the if statement should be removed along with the above
211        # if statement as soon as it can be properly tested.
212        # Nov. 22 2015  --PDB
213        # As above, this page can be accessed through other means than the
214        # base SasView GUI.
215        # Oct. 5, 2016 --JRK
[662d8d87]216        if len(self.page_finder) > 0:
[a95ae9a]217            # draw the sizer containing constraint info
[662d8d87]218            if not self.batch_on:
219                self._fill_sizer_constraint()
[a95ae9a]220            # draw fit button sizer
[662d8d87]221            self._fill_sizer_fit()
222
223    def _fill_sizer_model_list(self, sizer):
[2140e68]224        """
[662d8d87]225        Receive a dictionary containing information to display model name
[2140e68]226        """
[662d8d87]227        ix = 0
228        iy = 0
229        sizer.Clear(True)
230
231        new_name = wx.StaticText(self, wx.ID_ANY, '  Model Title ',
232                                 style=wx.ALIGN_CENTER)
233        new_name.SetBackgroundColour('orange')
234        new_name.SetForegroundColour(wx.WHITE)
235        sizer.Add(new_name, (iy, ix), (1, 1),
[a95ae9a]236                  wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
[662d8d87]237        ix += 2
238        model_type = wx.StaticText(self, wx.ID_ANY, '  Model ')
239        model_type.SetBackgroundColour('grey')
240        model_type.SetForegroundColour(wx.WHITE)
241        sizer.Add(model_type, (iy, ix), (1, 1),
[a95ae9a]242                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
[662d8d87]243        ix += 1
244        data_used = wx.StaticText(self, wx.ID_ANY, '  Data ')
245        data_used.SetBackgroundColour('grey')
246        data_used.SetForegroundColour(wx.WHITE)
247        sizer.Add(data_used, (iy, ix), (1, 1),
[a95ae9a]248                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
[662d8d87]249        ix += 1
250        tab_used = wx.StaticText(self, wx.ID_ANY, '  FitPage ')
251        tab_used.SetBackgroundColour('grey')
252        tab_used.SetForegroundColour(wx.WHITE)
253        sizer.Add(tab_used, (iy, ix), (1, 1),
254                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
255        for id, value in self.page_finder.iteritems():
256            if id not in self.parent.opened_pages:
257                continue
258
259            if self.batch_on != self.parent.get_page_by_id(id).batch_on:
260                continue
261
262            data_list = []
263            model_list = []
264            # get data name and model objetta
265            for fitproblem in value.get_fit_problem():
266
267                data = fitproblem.get_fit_data()
268                if not data.is_data:
269                    continue
270                name = '-'
271                if data is not None and data.is_data:
272                    name = str(data.name)
273                data_list.append(name)
274
275                model = fitproblem.get_model()
276                if model is None:
277                    continue
278                model_list.append(model)
279
280            if len(model_list) == 0:
281                continue
282            # Draw sizer
283            ix = 0
284            iy += 1
285            model = model_list[0]
286            name = '_'
287            if model is not None:
288                name = str(model.name)
289            cb = wx.CheckBox(self, wx.ID_ANY, name)
290            cb.SetValue(False)
291            cb.Enable(model is not None and data.is_data)
292            sizer.Add(cb, (iy, ix), (1, 1),
293                      wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
294            wx.EVT_CHECKBOX(self, cb.GetId(), self.check_model_name)
295            ix += 2
296            model_type = wx.StaticText(self, wx.ID_ANY,
297                                       model.__class__.__name__)
298            sizer.Add(model_type, (iy, ix), (1, 1),
299                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
300            if self.batch_on:
301                data_used = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
302                data_used.AppendItems(data_list)
303                data_used.SetSelection(0)
304            else:
305                data_used = wx.StaticText(self, wx.ID_ANY, data_list[0])
306
307            ix += 1
308            sizer.Add(data_used, (iy, ix), (1, 1),
309                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
310            ix += 1
311            caption = value.get_fit_tab_caption()
312            tab_caption_used = wx.StaticText(self, wx.ID_ANY, str(caption))
313            sizer.Add(tab_caption_used, (iy, ix), (1, 1),
314                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
315
316            self.model_list.append([cb, value, id, model])
317
318        iy += 1
319        sizer.Add((20, 20), (iy, ix), (1, 1),
320                  wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
321
322    def _fill_sizer_constraint(self):
323        """
324        Fill sizer containing constraint info
325        """
326        msg = "Select at least 1 model to add constraint "
327        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
328
[a95ae9a]329        self.constraints_sizer.Clear(True)
[662d8d87]330        if self.batch_on:
[a95ae9a]331            if self.constraints_sizer.IsShown():
332                self.constraints_sizer.Show(False)
[662d8d87]333            return
334        box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Constraints")
[a95ae9a]335        box_sizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
[662d8d87]336        sizer_title = wx.BoxSizer(wx.HORIZONTAL)
337        self.sizer_all_constraints = wx.BoxSizer(wx.HORIZONTAL)
338        self.sizer_constraints = wx.BoxSizer(wx.VERTICAL)
339        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
340
341        self.hide_constraint = wx.RadioButton(self, wx.ID_ANY, 'No', (10, 10),
342                                              style=wx.RB_GROUP)
343        self.show_constraint = wx.RadioButton(self, wx.ID_ANY, 'Yes', (10, 30))
344        self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
345                  id=self.hide_constraint.GetId())
346        self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
347                  id=self.show_constraint.GetId())
348        if self.batch_on:
349            self.hide_constraint.Enable(False)
350            self.show_constraint.Enable(False)
351        self.hide_constraint.SetValue(True)
352        self.show_constraint.SetValue(False)
353
354        sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Model"))
355        sizer_title.Add((10, 10))
356        sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Parameter"))
357        sizer_title.Add((10, 10))
358        sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Add Constraint?"))
359        sizer_title.Add((10, 10))
360        sizer_title.Add(self.show_constraint)
361        sizer_title.Add(self.hide_constraint)
362        sizer_title.Add((10, 10))
363
364        self.btAdd = wx.Button(self, self.ID_ADD, 'Add')
[a95ae9a]365        self.btAdd.Bind(wx.EVT_BUTTON, self._on_add_constraint,
[662d8d87]366                        id=self.btAdd.GetId())
367        self.btAdd.SetToolTipString("Add another constraint?")
368        self.btAdd.Hide()
369
370        text_hint = wx.StaticText(self, wx.ID_ANY,
[a95ae9a]371                                  "Example: [M0][parameter] = M1.parameter")
[662d8d87]372        sizer_button.Add(text_hint, 0,
373                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
374        sizer_button.Add(self.btAdd, 0,
375                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
376
[a95ae9a]377        box_sizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=10)
378        box_sizer1.Add(self.sizer_all_constraints, flag=wx.TOP | wx.BOTTOM,
379                       border=10)
380        box_sizer1.Add(self.sizer_constraints, flag=wx.TOP | wx.BOTTOM,
381                       border=10)
382        box_sizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
[662d8d87]383
[a95ae9a]384        self.constraints_sizer.Add(box_sizer1, 0, wx.EXPAND | wx.ALL, 10)
[662d8d87]385
386    def _fill_sizer_fit(self):
387        """
388        Draw fit button
389        """
[a95ae9a]390        self.run_fit_sizer.Clear(True)
[662d8d87]391        box_description = wx.StaticBox(self, wx.ID_ANY, "Fit ")
392        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
393        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
394
[a95ae9a]395        # Fit button
[662d8d87]396        self.btFit = wx.Button(self, self.ID_FIT, 'Fit', size=wx.DefaultSize)
[a95ae9a]397        self.btFit.Bind(wx.EVT_BUTTON, self.on_fit, id=self.btFit.GetId())
[662d8d87]398        self.btFit.SetToolTipString("Perform fit.")
399
[a95ae9a]400        # General Help button
[662d8d87]401        self.btHelp = wx.Button(self, wx.ID_HELP, 'HELP')
402        self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.")
[a95ae9a]403        self.btHelp.Bind(wx.EVT_BUTTON, self._on_help)
[662d8d87]404
[a95ae9a]405        # hint text on button line
[662d8d87]406        if self.batch_on:
407            text = " Fit in Parallel all Data sets\n"
408            text += "and model selected."
409        else:
410            text = " At least one set of model and data\n"
411            text += " must be selected for fitting."
412        text_hint = wx.StaticText(self, wx.ID_ANY, text)
413
414        sizer_button.Add(text_hint)
415        sizer_button.Add(self.btFit, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
416        sizer_button.Add(self.btHelp, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
417
418        boxsizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
[a95ae9a]419        self.run_fit_sizer.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
[2f4b430]420
[a95ae9a]421    def on_remove(self, event):
[8bd4dc0]422        """
[5062bbf]423        Remove constraint fields
[8bd4dc0]424        """
[f32d144]425        if len(self.constraints_list) == 1:
[a911b48]426            self.hide_constraint.SetValue(True)
427            self._hide_constraint()
[f32d144]428            return
429        if len(self.constraints_list) == 0:
430            return
[d7b4decd]431        wx.CallAfter(self._remove_after, event.GetId())
[a95ae9a]432        # self._onAdd_constraint(None)
[d7b4decd]433
434    def _remove_after(self, id):
[8bd4dc0]435        for item in self.constraints_list:
[d7b4decd]436            if id == item.btRemove.GetId():
437                self.sizer_constraints.Hide(item.sizer)
438                item.sizer.Clear(True)
439                self.sizer_constraints.Remove(item.sizer)
[8bd4dc0]440                self.constraints_list.remove(item)
441                self.nb_constraint -= 1
[a95ae9a]442                self.constraints_sizer.Layout()
[662d8d87]443                self.FitInside()
[8bd4dc0]444                break
[233c121]445
[a95ae9a]446    def on_fit(self, event):
[5062bbf]447        """
448        signal for fitting
[2f4b430]449
[5062bbf]450        """
[aac161f1]451        if self.fit_started:
452            self._stop_fit()
453            self.fit_started = False
454            return
455
[fa02d95]456        flag = False
457        # check if the current page a simultaneous fit page or a batch page
458        if self == self._manager.sim_page:
459            flag = (self._manager.sim_page.uid == self.uid)
460
[a95ae9a]461        # making sure all parameters content a constraint
[06e7c26]462        if not self.batch_on and self.show_constraint.GetValue():
[00daba9]463            if not self._set_constraint():
464                return
[a95ae9a]465        # model was actually selected from this page to be fit
466        if len(self.model_to_fit) >= 1:
[66ff250]467            self.manager._reset_schedule_problem(value=0)
[6f023e8]468            for item in self.model_list:
469                if item[0].GetValue():
[2f4b430]470                    self.manager.schedule_for_fit(value=1, uid=item[2])
[1b14795]471            try:
[aac161f1]472                self.fit_started = True
473                wx.CallAfter(self.set_fitbutton)
[31469d50]474                if not self.manager.onFit(uid=self.uid):
475                    return
[1b14795]476            except:
[f32d144]477                msg = "Select at least one parameter to fit in the FitPages."
[1b14795]478                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[1b07935d]479        else:
[f32d144]480            msg = "Select at least one model check box to fit "
[1b14795]481            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[a95ae9a]482        self.set_state()
[2f4b430]483
[aac161f1]484    def _on_fit_complete(self):
485        """
486        Set the completion flag and display the updated fit button label.
487        """
488        self.fit_started = False
489        self.set_fitbutton()
490
491    def _stop_fit(self, event=None):
492        """
493        Attempt to stop the fitting thread
[a95ae9a]494
495        :param event: Event handler when stop fit is clicked
[aac161f1]496        """
[a95ae9a]497        if event is not None:
[aac161f1]498            event.Skip()
499        self.manager.stop_fit(self.uid)
500        self.manager._reset_schedule_problem(value=0)
501        self._on_fit_complete()
502
503    def set_fitbutton(self):
504        """
505        Set fit button label depending on the fit_started
506        """
507        label = "Stop" if self.fit_started else "Fit"
508        color = "red" if self.fit_started else "black"
509
510        self.btFit.SetLabel(label)
511        self.btFit.SetForegroundColour(color)
512        self.btFit.Enable(True)
513
[a95ae9a]514    def _on_help(self, event):
[662d8d87]515        """
516        Bring up the simultaneous Fitting Documentation whenever the HELP
517        button is clicked.
518
519        Calls DocumentationWindow with the path of the location within the
520        documentation tree (after /doc/ ....".  Note that when using old
521        versions of Wx (before 2.9) and thus not the release version of
522        installers, the help comes up at the top level of the file as
[a95ae9a]523        web browser does not pass anything past the # to the browser when it is
[662d8d87]524        running "file:///...."
525
[a95ae9a]526    :param event: Triggers on clicking the help button
[662d8d87]527    """
[4cafdff]528        _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
[662d8d87]529        _PageAnchor = "#simultaneous-fit-mode"
530        _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation,
531                                          _PageAnchor,
532                                          "Simultaneous/Constrained Fitting Help")
533
[d89f09b]534    def set_manager(self, manager):
535        """
[5062bbf]536        set panel manager
[2f4b430]537
[5062bbf]538        :param manager: instance of plugin fitting
[d89f09b]539        """
540        self.manager = manager
[2f4b430]541
[fa02d95]542    def check_all_model_name(self, event=None):
[d89f09b]543        """
[5062bbf]544        check all models names
[d89f09b]545        """
[a95ae9a]546        self.model_to_fit = []
547        if self.cb1.GetValue():
[d89f09b]548            for item in self.model_list:
[6c08ba5]549                if item[0].IsEnabled():
550                    item[0].SetValue(True)
[a95ae9a]551                    self.model_to_fit.append(item)
[2f4b430]552
[a95ae9a]553            # constraint info
[2140e68]554            self._store_model()
[fa02d95]555            if not self.batch_on:
[a95ae9a]556                # display constraint fields
[d7b4decd]557                if (self.show_constraint.GetValue() and
558                                 len(self.constraints_list) == 0):
[2f4b430]559                    self._show_all_constraint()
[fa02d95]560                    self._show_constraint()
[d89f09b]561        else:
562            for item in self.model_list:
[2f4b430]563                item[0].SetValue(False)
564
[fa02d95]565            if not self.batch_on:
[a95ae9a]566                # constraint info
[fa02d95]567                self._hide_constraint()
[2f4b430]568
[53fc5ad9]569        self._update_easy_setup_cb()
[662d8d87]570        self.FitInside()
571
[f32d144]572    def check_model_name(self, event):
[d89f09b]573        """
[5062bbf]574        Save information related to checkbox and their states
[d89f09b]575        """
[a95ae9a]576        self.model_to_fit = []
[d89f09b]577        for item in self.model_list:
[a95ae9a]578            if item[0].GetValue():
579                self.model_to_fit.append(item)
[d89f09b]580            else:
[a95ae9a]581                if item in self.model_to_fit:
582                    self.model_to_fit.remove(item)
[d89f09b]583                    self.cb1.SetValue(False)
[2f4b430]584
[a95ae9a]585        # display constraint fields
586        if len(self.model_to_fit) >= 1:
[2140e68]587            self._store_model()
[06e7c26]588            if not self.batch_on and self.show_constraint.GetValue() and\
[f32d144]589                             len(self.constraints_list) == 0:
590                self._show_all_constraint()
[2140e68]591                self._show_constraint()
[53fc5ad9]592
[a95ae9a]593        elif len(self.model_to_fit) < 1:
594            # constraint info
[f32d144]595            self._hide_constraint()
[2f4b430]596
[53fc5ad9]597        self._update_easy_setup_cb()
[a95ae9a]598        # set the value of the main check button
599        if len(self.model_list) == len(self.model_to_fit):
[d89f09b]600            self.cb1.SetValue(True)
[662d8d87]601            self.FitInside()
[b28717b]602            return
[d89f09b]603        else:
604            self.cb1.SetValue(False)
[662d8d87]605            self.FitInside()
[2f4b430]606
[f32d144]607    def _update_easy_setup_cb(self):
[53fc5ad9]608        """
609        Update easy setup combobox on selecting a model
610        """
[a95ae9a]611        if self.model_cbox_left is None or self.model_cbox_right is None:
[d7b4decd]612            return
613
[a95ae9a]614        models = [(item[3].name, item[3]) for item in self.model_to_fit]
[d7b4decd]615        setComboBoxItems(self.model_cbox_left, models)
616        setComboBoxItems(self.model_cbox_right, models)
617        for item in self.constraints_list:
618            setComboBoxItems(item[0], models)
619        if self.model_cbox_left.GetSelection() == wx.NOT_FOUND:
[53fc5ad9]620            self.model_cbox_left.SetSelection(0)
[a95ae9a]621        self.constraints_sizer.Layout()
[2f4b430]622
[2140e68]623    def _store_model(self):
[d89f09b]624        """
[5062bbf]625         Store selected model
[d89f09b]626        """
[a95ae9a]627        if len(self.model_to_fit) < 1:
[2140e68]628            return
[a95ae9a]629        for item in self.model_to_fit:
[1d2782d]630            model = item[3]
[f32d144]631            page_id = item[2]
[6bbeacd4]632            self.constraint_dict[page_id] = model
[2f4b430]633
[2140e68]634    def _display_constraint(self, event):
635        """
[5062bbf]636        Show fields to add constraint
[2140e68]637        """
[a95ae9a]638        if len(self.model_to_fit) < 1:
[f32d144]639            msg = "Select at least 1 model to add constraint "
640            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[a95ae9a]641            # hide button
[2140e68]642            self._hide_constraint()
643            return
644        if self.show_constraint.GetValue():
[f32d144]645            self._show_all_constraint()
[2140e68]646            self._show_constraint()
[662d8d87]647            self.FitInside()
[2140e68]648            return
649        else:
[f32d144]650            self._hide_constraint()
651            return
[2f4b430]652
[1b14795]653    def _show_all_constraint(self):
654        """
655        Show constraint fields
656        """
[6f16e25]657        box_description = wx.StaticBox(self, wx.ID_ANY, "Easy Setup ")
[a95ae9a]658        box_sizer = wx.StaticBoxSizer(box_description, wx.HORIZONTAL)
[fb7180c]659        sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
[6f16e25]660        self.model_cbox_left = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
[1b14795]661        self.model_cbox_left.Clear()
[6f16e25]662        self.model_cbox_right = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
[1b14795]663        self.model_cbox_right.Clear()
[6f16e25]664        wx.EVT_COMBOBOX(self.model_cbox_left, wx.ID_ANY, self._on_select_modelcb)
665        wx.EVT_COMBOBOX(self.model_cbox_right, wx.ID_ANY, self._on_select_modelcb)
666        egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
667        self.set_button = wx.Button(self, self.ID_SET_ALL, 'Set All')
[1b14795]668        self.set_button.Bind(wx.EVT_BUTTON, self._on_set_all_equal,
[f32d144]669                             id=self.set_button.GetId())
[1b14795]670        set_tip = "Add constraints for all the adjustable parameters "
671        set_tip += "(checked in FitPages) if exist."
672        self.set_button.SetToolTipString(set_tip)
673        self.set_button.Disable()
[2f4b430]674
[1b14795]675        for id, model in self.constraint_dict.iteritems():
[a95ae9a]676            # check if all parameters have been selected for constraint
677            # then do not allow add constraint on parameters
[f32d144]678            self.model_cbox_left.Append(str(model.name), model)
[1b14795]679        self.model_cbox_left.Select(0)
680        for id, model in self.constraint_dict.iteritems():
[a95ae9a]681            # check if all parameters have been selected for constraint
682            # then do not allow add constraint on parameters
[f32d144]683            self.model_cbox_right.Append(str(model.name), model)
[a95ae9a]684        box_sizer.Add(self.model_cbox_left,
[2f4b430]685                             flag=wx.RIGHT | wx.EXPAND, border=10)
[a95ae9a]686        # box_sizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
[d7b4decd]687        #                     flag=wx.RIGHT | wx.EXPAND, border=5)
[a95ae9a]688        box_sizer.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
689        box_sizer.Add(self.model_cbox_right,
[2f4b430]690                             flag=wx.RIGHT | wx.EXPAND, border=10)
[a95ae9a]691        # box_sizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
[d7b4decd]692        #                     flag=wx.RIGHT | wx.EXPAND, border=5)
[a95ae9a]693        box_sizer.Add((20, -1))
694        box_sizer.Add(self.set_button, flag=wx.RIGHT | wx.EXPAND, border=5)
695        sizer_constraint.Add(box_sizer, flag=wx.RIGHT | wx.EXPAND, border=5)
[1b14795]696        self.sizer_all_constraints.Insert(before=0,
[f32d144]697                             item=sizer_constraint,
[2f4b430]698                             flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=5)
[662d8d87]699        self.FitInside()
[2f4b430]700
[1b14795]701    def _on_select_modelcb(self, event):
702        """
703        On select model left or right combobox
704        """
705        event.Skip()
706        flag = True
707        if self.model_cbox_left.GetValue().strip() == '':
708            flag = False
709        if self.model_cbox_right.GetValue().strip() == '':
710            flag = False
[d7b4decd]711        if (self.model_cbox_left.GetValue() ==
712                self.model_cbox_right.GetValue()):
[1b14795]713            flag = False
714        self.set_button.Enable(flag)
[2f4b430]715
[1b14795]716    def _on_set_all_equal(self, event):
717        """
718        On set button
719        """
720        event.Skip()
721        length = len(self.constraints_list)
722        if length < 1:
[f32d144]723            return
[1b14795]724        param_list = []
[a95ae9a]725        param_list_b = []
[1b14795]726        selection = self.model_cbox_left.GetCurrentSelection()
727        model_left = self.model_cbox_left.GetValue()
728        model = self.model_cbox_left.GetClientData(selection)
[a95ae9a]729        selection_b = self.model_cbox_right.GetCurrentSelection()
[1b14795]730        model_right = self.model_cbox_right.GetValue()
[a95ae9a]731        model_b = self.model_cbox_right.GetClientData(selection_b)
[1b14795]732        for id, dic_model in self.constraint_dict.iteritems():
733            if model == dic_model:
734                param_list = self.page_finder[id].get_param2fit()
[a95ae9a]735            if model_b == dic_model:
736                param_list_b = self.page_finder[id].get_param2fit()
737            if len(param_list) > 0 and len(param_list_b) > 0:
[1b14795]738                break
739        num_cbox = 0
740        has_param = False
741        for param in param_list:
742            num_cbox += 1
[a95ae9a]743            if param in param_list_b:
[d7b4decd]744                item = self.constraints_list[-1]
745                item.model_cbox.SetStringSelection(model_left)
[1b14795]746                self._on_select_model(None)
[d7b4decd]747                item.param_cbox.Clear()
748                item.param_cbox.Append(str(param), model)
749                item.param_cbox.SetStringSelection(str(param))
750                item.constraint.SetValue(str(model_right + "." + str(param)))
[1b14795]751                has_param = True
[00daba9]752                if num_cbox == (len(param_list) + 1):
[1b14795]753                    break
754                self._show_constraint()
[2f4b430]755
[662d8d87]756        self.FitInside()
[1b14795]757        if not has_param:
[f32d144]758            msg = " There is no adjustable parameter (checked to fit)"
[1b14795]759            msg += " either one of the models."
[f32d144]760            wx.PostEvent(self.parent.parent, StatusEvent(info="warning",
761                                                         status=msg))
[1b14795]762        else:
[f32d144]763            msg = " The constraints are added."
764            wx.PostEvent(self.parent.parent, StatusEvent(info="info",
765                                                         status=msg))
766
[2140e68]767    def _show_constraint(self):
768        """
[5062bbf]769        Show constraint fields
[e89aed5]770        :param dict: dictionary mapping constraint values
[2140e68]771        """
[77e23a2]772        self.btAdd.Show(True)
[f32d144]773        if len(self.constraints_list) != 0:
[2140e68]774            nb_fit_param = 0
[1b14795]775            for id, model in self.constraint_dict.iteritems():
[00daba9]776                nb_fit_param += len(self.page_finder[id].get_param2fit())
[a95ae9a]777            # Don't add anymore
[2140e68]778            if len(self.constraints_list) == nb_fit_param:
[d7b4decd]779                msg = "Cannot add another constraint. Maximum of number "
[f32d144]780                msg += "Parameters name reached %s" % str(nb_fit_param)
781                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[b28717b]782                self.sizer_constraints.Layout()
[a95ae9a]783                self.constraints_sizer.Layout()
[ac11e40]784                return
[a95ae9a]785        if len(self.model_to_fit) < 1:
[f32d144]786            msg = "Select at least 1 model to add constraint "
787            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[b28717b]788            self.sizer_constraints.Layout()
[a95ae9a]789            self.constraints_sizer.Layout()
[2140e68]790            return
[2f4b430]791
[f32d144]792        sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
[d7b4decd]793
794        # Model list
[6f16e25]795        model_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
[2140e68]796        model_cbox.Clear()
[1b14795]797        for id, model in self.constraint_dict.iteritems():
[a95ae9a]798            # check if all parameters have been selected for constraint
799            # then do not allow add constraint on parameters
[f32d144]800            model_cbox.Append(str(model.name), model)
[d7b4decd]801        wx.EVT_COMBOBOX(model_cbox, wx.ID_ANY, self._on_select_model)
[2f4b430]802
[d7b4decd]803        # Parameters in model
804        param_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY,
805                                 size=(100, -1))
806        param_cbox.Hide()
807        wx.EVT_COMBOBOX(param_cbox, wx.ID_ANY, self._on_select_param)
[2f4b430]808
[d7b4decd]809        egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
810
811        # Parameter constraint
812        constraint = wx.TextCtrl(self, wx.ID_ANY)
813
814        # Remove button
815        #btRemove = wx.Button(self, self.ID_REMOVE, 'Remove')
[a95ae9a]816        bt_remove = wx.Button(self, self._ids.next(), 'Remove')
817        bt_remove.Bind(wx.EVT_BUTTON, self.on_remove,
818                      id=bt_remove.GetId())
819        bt_remove.SetToolTipString("Remove constraint.")
820        bt_remove.Hide()
[d7b4decd]821
822        # Hid the add button, if it exists
823        if hasattr(self, "btAdd"):
824            self.btAdd.Hide()
825
826        sizer_constraint.Add((5, -1))
[2f4b430]827        sizer_constraint.Add(model_cbox, flag=wx.RIGHT | wx.EXPAND, border=10)
828        sizer_constraint.Add(param_cbox, flag=wx.RIGHT | wx.EXPAND, border=5)
829        sizer_constraint.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
[d7b4decd]830        sizer_constraint.Add(constraint, flag=wx.RIGHT | wx.EXPAND, border=10)
[a95ae9a]831        sizer_constraint.Add(bt_remove, flag=wx.RIGHT | wx.EXPAND, border=10)
[2f4b430]832
[b28717b]833        self.sizer_constraints.Insert(before=self.nb_constraint,
[d7b4decd]834                item=sizer_constraint, flag=wx.TOP | wx.BOTTOM | wx.EXPAND,
835                border=5)
836        c = ConstraintLine(model_cbox, param_cbox, egal_txt,
[a95ae9a]837                           constraint, bt_remove, sizer_constraint)
[d7b4decd]838        self.constraints_list.append(c)
[2f4b430]839
[b28717b]840        self.nb_constraint += 1
841        self.sizer_constraints.Layout()
[a95ae9a]842        self.constraints_sizer.Layout()
843        self.Layout()
[2f4b430]844
[f32d144]845    def _hide_constraint(self):
846        """
847        hide buttons related constraint
[2140e68]848        """
[d7b4decd]849        for id in self.page_finder.iterkeys():
[6bbeacd4]850            self.page_finder[id].clear_model_param()
[2f4b430]851
[f32d144]852        self.nb_constraint = 0
[1b14795]853        self.constraint_dict = {}
[f32d144]854        if hasattr(self, "btAdd"):
[69bee6d]855            self.btAdd.Hide()
[ac11e40]856        self._store_model()
[d7b4decd]857        if self.model_cbox_left is not None:
858            self.model_cbox_left.Clear()
[53fc5ad9]859            self.model_cbox_left = None
[d7b4decd]860        if self.model_cbox_right is not None:
861            self.model_cbox_right.Clear()
[53fc5ad9]862            self.model_cbox_right = None
[f32d144]863        self.constraints_list = []
864        self.sizer_all_constraints.Clear(True)
865        self.sizer_all_constraints.Layout()
866        self.sizer_constraints.Clear(True)
867        self.sizer_constraints.Layout()
[a95ae9a]868        self.constraints_sizer.Layout()
869        self.Layout()
[662d8d87]870        self.FitInside()
[2f4b430]871
[2140e68]872    def _on_select_model(self, event):
873        """
[e89aed5]874        fill combo box with list of parameters
[2140e68]875        """
[d7b4decd]876        if not self.constraints_list:
877            return
878
[a95ae9a]879        # This way PC/MAC both work, instead of using event.GetClientData().
[d7b4decd]880        model_cbox = self.constraints_list[-1].model_cbox
881        n = model_cbox.GetCurrentSelection()
882        if n == wx.NOT_FOUND:
883            return
884
885        model = model_cbox.GetClientData(n)
886        param_list = []
[1b14795]887        for id, dic_model in self.constraint_dict.iteritems():
888            if model == dic_model:
889                param_list = self.page_finder[id].get_param2fit()
[d7b4decd]890                break
891
892        param_cbox = self.constraints_list[-1].param_cbox
[2140e68]893        param_cbox.Clear()
[a95ae9a]894        # insert only fittable paramaters
[2140e68]895        for param in param_list:
[f32d144]896            param_cbox.Append(str(param), model)
[2140e68]897        param_cbox.Show(True)
[d7b4decd]898
[a95ae9a]899        bt_remove = self.constraints_list[-1].btRemove
900        bt_remove.Show(True)
[77a43fb]901        self.btAdd.Show(True)
[662d8d87]902#        self.Layout()
903        self.FitInside()
[2f4b430]904
[2140e68]905    def _on_select_param(self, event):
906        """
[5062bbf]907        Store the appropriate constraint in the page_finder
[2140e68]908        """
[a95ae9a]909        # This way PC/MAC both work, instead of using event.GetClientData().
910        # n = self.param_cbox.GetCurrentSelection()
911        # model = self.param_cbox.GetClientData(n)
912        # param = event.GetString()
[2f4b430]913
[d7b4decd]914        if self.constraints_list:
915            self.constraints_list[-1].egal_txt.Show(True)
916            self.constraints_list[-1].constraint.Show(True)
[2f4b430]917
[a95ae9a]918    def _on_add_constraint(self, event):
[2140e68]919        """
[5062bbf]920        Add another line for constraint
[2140e68]921        """
[8bd4dc0]922        if not self.show_constraint.GetValue():
[f32d144]923            msg = " Select Yes to add Constraint "
924            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
925            return
[a95ae9a]926        # check that a constraint is added
[1b14795]927        # before allow to add another constraint
[2140e68]928        for item in self.constraints_list:
[d7b4decd]929            if item.model_cbox.GetString(0) == "":
[f32d144]930                msg = " Select a model Name! "
931                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[2f4b430]932                return
[d7b4decd]933            if item.param_cbox.GetString(0) == "":
[f32d144]934                msg = " Select a parameter Name! "
935                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[2f4b430]936                return
[d7b4decd]937            if item.constraint.GetValue().lstrip().rstrip() == "":
938                model = item.param_cbox.GetClientData(
939                                        item.param_cbox.GetCurrentSelection())
[a95ae9a]940                if model is not None:
[2f4b430]941                    msg = " Enter a constraint for %s.%s! " % (model.name,
[d7b4decd]942                                        item.param_cbox.GetString(0))
[fe9cb70e]943                else:
[d7b4decd]944                    msg = " Enter a constraint"
[f32d144]945                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
946                return
[a95ae9a]947        # some model or parameters can be constrained
[2140e68]948        self._show_constraint()
[662d8d87]949        self.FitInside()
[2f4b430]950
[2140e68]951    def _set_constraint(self):
[d89f09b]952        """
[662d8d87]953        get values from the constraint textcrtl ,parses them into model name
[5062bbf]954        parameter name and parameters values.
[f32d144]955        store them in a list self.params .when when params is not empty
956        set_model uses it to reset the appropriate model
[1b14795]957        and its appropriates parameters
[d89f09b]958        """
[2140e68]959        for item in self.constraints_list:
[d7b4decd]960            select0 = item.model_cbox.GetSelection()
[fdb1f375]961            if select0 == wx.NOT_FOUND:
962                continue
[d7b4decd]963            model = item.model_cbox.GetClientData(select0)
964            select1 = item.param_cbox.GetSelection()
[fdb1f375]965            if select1 == wx.NOT_FOUND:
966                continue
[d7b4decd]967            param = item.param_cbox.GetString(select1)
968            constraint = item.constraint.GetValue().lstrip().rstrip()
[f32d144]969            if param.lstrip().rstrip() == "":
970                param = None
971                msg = " Constraint will be ignored!. missing parameters"
972                msg += " in combobox to set constraint! "
973                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
[6bbeacd4]974            for id, value in self.constraint_dict.iteritems():
[1f57dfd]975                if model == value:
976                    if constraint == "":
[f32d144]977                        msg = " Constraint will be ignored!. missing value"
978                        msg += " in textcrtl to set constraint! "
979                        wx.PostEvent(self.parent.parent,
980                                     StatusEvent(status=msg))
[1f57dfd]981                        constraint = None
[00daba9]982                    if str(param) in self.page_finder[id].get_param2fit():
983                        msg = " Checking constraint for parameter: %s ", param
[f32d144]984                        wx.PostEvent(self.parent.parent,
985                                     StatusEvent(info="info", status=msg))
[00daba9]986                    else:
987                        model_name = item[0].GetLabel()
988                        fitpage = self.page_finder[id].get_fit_tab_caption()
989                        msg = "All constrainted parameters must be set "
[f32d144]990                        msg += " adjustable: '%s.%s' " % (model_name, param)
991                        msg += "is NOT checked in '%s'. " % fitpage
[00daba9]992                        msg += " Please check it to fit or"
993                        msg += " remove the line of the constraint."
[f32d144]994                        wx.PostEvent(self.parent.parent,
995                                StatusEvent(info="error", status=msg))
[00daba9]996                        return False
[2f4b430]997
[c647377]998                    for fid in self.page_finder[id].iterkeys():
[bf5e985]999                        # wrap in param/constraint in str() to remove unicode
1000                        self.page_finder[id].set_model_param(str(param),
[d7b4decd]1001                                str(constraint), fid=fid)
[1f57dfd]1002                    break
[00daba9]1003        return True
[2f4b430]1004
[4133316]1005    def on_set_focus(self, event=None):
1006        """
[a95ae9a]1007        The derivative class is on focus if implemented
[4133316]1008        """
1009        if self.parent is not None:
[1976004]1010            if self.parent.parent is not None:
1011                wx.PostEvent(self.parent.parent, PanelOnFocusEvent(panel=self))
1012            self.page_finder = self.parent._manager.get_page_finder()
[d7b4decd]1013
1014
1015def setComboBoxItems(cbox, items):
1016    assert isinstance(cbox, wx.ComboBox)
1017    selected = cbox.GetStringSelection()
1018    cbox.Clear()
1019    for k, (name, value) in enumerate(items):
1020        cbox.Append(name, value)
1021    cbox.SetStringSelection(selected)
[a95ae9a]1022
1023
1024class SimFitPageState:
1025    """
1026    State of the simultaneous fit page for saving purposes
1027    """
1028
1029    def __init__(self):
1030        # Sim Fit Page Number
1031        self.fit_page_no = None
1032        # Select all data
1033        self.select_all = False
1034        # Data sets sent to fit page
1035        self.model_list = []
1036        # Data sets to be fit
1037        self.model_to_fit = []
1038        # Number of constraints
1039        self.no_constraint = 0
1040        # Dictionary of constraints
1041        self.constraint_dict = {}
1042        # List of constraints
1043        self.constraints_list = []
[e89aed5]1044
1045    def load_from_save_state(self, fit):
1046        """
1047        Load in a simultaneous/constrained fit from a save state
1048        :param fit: Fitpanel object
1049        :return: None
1050        """
1051
1052        model_map = {}
[4fea1df]1053        if fit.fit_panel.sim_page is None:
1054            fit.fit_panel.add_sim_page()
1055        sim_page = fit.fit_panel.sim_page
[e89aed5]1056
1057        # Process each model and associate old M# with new M#
1058        i = 0
[4fea1df]1059        for model in sim_page.model_list:
[e89aed5]1060            model_id = self._format_id(model[1].keys()[0])
1061            for saved_model in self.model_list:
1062                save_id = saved_model.pop('name')
1063                saved_model['name'] = save_id
1064                save_id = self._format_id(save_id)
1065                if save_id == model_id:
1066                    model_map[saved_model.pop('fit_page_source')] = \
1067                        model[3].name
1068                    check = bool(saved_model.pop('checked'))
[4fea1df]1069                    sim_page.model_list[i][0].SetValue(check)
[998ca90]1070                    break
[e89aed5]1071            i += 1
[4fea1df]1072        sim_page.check_model_name(None)
[e89aed5]1073
1074        if len(self.constraints_list) > 0:
[4fea1df]1075            sim_page.hide_constraint.SetValue(False)
1076            sim_page.show_constraint.SetValue(True)
1077            sim_page._display_constraint(None)
1078
1079        for index, item in enumerate(self.constraints_list):
1080            model_cbox = item.pop('model_cbox')
[998ca90]1081            if model_cbox != "":
1082                constraint_value = item.pop('constraint')
1083                param = item.pop('param_cbox')
1084                equality = item.pop('egal_txt')
1085                for key, value in model_map.iteritems():
1086                    model_cbox.replace(key, value)
1087                    constraint_value.replace(key, value)
1088
1089                sim_page.constraints_list[index][0].SetValue(model_cbox)
1090                sim_page._on_select_model(None)
1091                sim_page.constraints_list[index][1].SetValue(param)
1092                sim_page.constraints_list[index][2].SetLabel(equality)
1093                sim_page.constraints_list[index][3].SetValue(constraint_value)
1094                sim_page._on_add_constraint(None)
[e89aed5]1095
1096    def _format_id(self, original_id):
1097        original_id = original_id.rstrip('1234567890.')
1098        new_id_list = original_id.split()
1099        new_id = ' '.join(new_id_list)
1100        return new_id
Note: See TracBrowser for help on using the repository browser.