source: sasview/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @ 7248d75d

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 7248d75d was 4d457df, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Minor refactoring in the fitting widget

  • Property mode set to 100755
File size: 25.7 KB
RevLine 
[60af928]1import sys
2import json
[cd31251]3import os
[5236449]4import numpy
[60af928]5from collections import defaultdict
6
[5236449]7import logging
8import traceback
[cbcdd2c]9from twisted.internet import threads
[5236449]10
[60af928]11from PyQt4 import QtGui
12from PyQt4 import QtCore
13
14from sasmodels import generate
15from sasmodels import modelinfo
[5236449]16from sasmodels.sasview_model import load_standard_models
17
[60af928]18from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
[5236449]19from sas.sasgui.guiframe.dataFitting import Data1D
20from sas.sasgui.guiframe.dataFitting import Data2D
21import sas.qtgui.GuiUtils as GuiUtils
22from sas.sasgui.perspectives.fitting.model_thread import Calc1D
[cbcdd2c]23from sas.sasgui.perspectives.fitting.model_thread import Calc2D
[5236449]24
25from UI.FittingWidgetUI import Ui_FittingWidgetUI
[4d457df]26from sas.qtgui.Perspectives.Fitting.FittingLogic import FittingLogic
27from sas.qtgui.Perspectives.Fitting import FittingUtilities
[60af928]28
29TAB_MAGNETISM = 4
30TAB_POLY = 3
[cbcdd2c]31CATEGORY_DEFAULT = "Choose category..."
[4d457df]32CATEGORY_STRUCTURE = "Structure Factor"
[cbcdd2c]33QMIN_DEFAULT = 0.0005
34QMAX_DEFAULT = 0.5
35NPTS_DEFAULT = 50
[60af928]36
37class FittingWidget(QtGui.QWidget, Ui_FittingWidgetUI):
38    """
[f46f6dc]39    Main widget for selecting form and structure factor models
[60af928]40    """
[811bec1]41    def __init__(self, parent=None, data=None, id=1):
[60af928]42
43        super(FittingWidget, self).__init__()
44
[86f88d1]45        # Necessary globals
[cbcdd2c]46        self.parent = parent
47        # SasModel is loaded
[60af928]48        self.model_is_loaded = False
[cbcdd2c]49        # Data[12]D passed and set
[5236449]50        self.data_is_loaded = False
[cbcdd2c]51        # Current SasModel in view
[5236449]52        self.kernel_module = None
[cbcdd2c]53        # Current SasModel view dimension
[60af928]54        self.is2D = False
[cbcdd2c]55        # Current SasModel is multishell
[86f88d1]56        self.model_has_shells = False
[cbcdd2c]57        # Utility variable to enable unselectable option in category combobox
[86f88d1]58        self._previous_category_index = 0
[cbcdd2c]59        # Utility variable for multishell display
[86f88d1]60        self._last_model_row = 0
[cbcdd2c]61        # Dictionary of {model name: model class} for the current category
[5236449]62        self.models = {}
63
64        # Which tab is this widget displayed in?
65        self.tab_id = id
66
[811bec1]67        # Range parameters
[cbcdd2c]68        self.q_range_min = QMIN_DEFAULT
69        self.q_range_max = QMAX_DEFAULT
70        self.npts = NPTS_DEFAULT
[811bec1]71
[cbcdd2c]72        # Main Data[12]D holder
[4d457df]73        self.logic = FittingLogic(data=data)
[60af928]74
[86f88d1]75        # Main GUI setup up
[60af928]76        self.setupUi(self)
77        self.setWindowTitle("Fitting")
[cbcdd2c]78        self.communicate = self.parent.communicate
[60af928]79
[86f88d1]80        # Set the main models
[cd31251]81        # We can't use a single model here, due to restrictions on flattening
82        # the model tree with subclassed QAbstractProxyModel...
[60af928]83        self._model_model = QtGui.QStandardItemModel()
84        self._poly_model = QtGui.QStandardItemModel()
85        self._magnet_model = QtGui.QStandardItemModel()
86
87        # Param model displayed in param list
88        self.lstParams.setModel(self._model_model)
[5236449]89        self.readCategoryInfo()
[60af928]90        self.model_parameters = None
[86f88d1]91        self.lstParams.setAlternatingRowColors(True)
[60af928]92
93        # Poly model displayed in poly list
[811bec1]94        self.lstPoly.setModel(self._poly_model)
[60af928]95        self.setPolyModel()
96        self.setTableProperties(self.lstPoly)
97
98        # Magnetism model displayed in magnetism list
99        self.lstMagnetic.setModel(self._magnet_model)
100        self.setMagneticModel()
101        self.setTableProperties(self.lstMagnetic)
102
[5236449]103        # Defaults for the structure factors
[6f7f652]104        self.setDefaultStructureCombo()
105
[5236449]106        # Make structure factor and model CBs disabled
[6f7f652]107        self.disableModelCombo()
108        self.disableStructureCombo()
[60af928]109
[6f7f652]110        # Generate the category list for display
[60af928]111        category_list = sorted(self.master_category_dict.keys())
[86f88d1]112        self.cbCategory.addItem(CATEGORY_DEFAULT)
[60af928]113        self.cbCategory.addItems(category_list)
[4d457df]114        self.cbCategory.addItem(CATEGORY_STRUCTURE)
[6f7f652]115        self.cbCategory.setCurrentIndex(0)
[60af928]116
[5236449]117        self._index = data
118        if data is not None:
119            self.data = data
120
[86f88d1]121        # Connect signals to controls
122        self.initializeSignals()
[60af928]123
[86f88d1]124        # Initial control state
125        self.initializeControls()
[60af928]126
127    @property
128    def data(self):
[4d457df]129        return self.logic.data
[60af928]130
131    @data.setter
132    def data(self, value):
133        """ data setter """
[4d457df]134        assert isinstance(value[0], QtGui.QStandardItem)
[cbcdd2c]135        # _index contains the QIndex with data
[5236449]136        self._index = value
[4d457df]137        # Update logics with data items
138        self.logic.data = GuiUtils.dataFromItem(value[0])
139
[5236449]140        self.data_is_loaded = True
[cbcdd2c]141        # Tag along functionality
[5236449]142        self.updateQRange()
143        self.cmdFit.setEnabled(True)
[60af928]144
[f46f6dc]145    def acceptsData(self):
146        """ Tells the caller this widget can accept new dataset """
[5236449]147        return not self.data_is_loaded
[f46f6dc]148
[6f7f652]149    def disableModelCombo(self):
[cbcdd2c]150        """ Disable the combobox """
[6f7f652]151        self.cbModel.setEnabled(False)
152        self.label_3.setEnabled(False)
153
154    def enableModelCombo(self):
[cbcdd2c]155        """ Enable the combobox """
[6f7f652]156        self.cbModel.setEnabled(True)
157        self.label_3.setEnabled(True)
158
159    def disableStructureCombo(self):
[cbcdd2c]160        """ Disable the combobox """
[6f7f652]161        self.cbStructureFactor.setEnabled(False)
162        self.label_4.setEnabled(False)
163
164    def enableStructureCombo(self):
[cbcdd2c]165        """ Enable the combobox """
[6f7f652]166        self.cbStructureFactor.setEnabled(True)
167        self.label_4.setEnabled(True)
168
[5236449]169    def updateQRange(self):
170        """
171        Updates Q Range display
172        """
173        if self.data_is_loaded:
[4d457df]174            self.q_range_min, self.q_range_max, self.npts = self.logic.computeDataRange()
[cbcdd2c]175        # set Q range labels on the main tab
[5236449]176        self.lblMinRangeDef.setText(str(self.q_range_min))
177        self.lblMaxRangeDef.setText(str(self.q_range_max))
[cbcdd2c]178        # set Q range labels on the options tab
[5236449]179        self.txtMaxRange.setText(str(self.q_range_max))
180        self.txtMinRange.setText(str(self.q_range_min))
181        self.txtNpts.setText(str(self.npts))
182
[86f88d1]183    def initializeControls(self):
184        """
185        Set initial control enablement
186        """
187        self.cmdFit.setEnabled(False)
188        self.cmdPlot.setEnabled(True)
189        self.chkPolydispersity.setEnabled(True)
190        self.chkPolydispersity.setCheckState(False)
191        self.chk2DView.setEnabled(True)
192        self.chk2DView.setCheckState(False)
193        self.chkMagnetism.setEnabled(False)
194        self.chkMagnetism.setCheckState(False)
[cbcdd2c]195        # Tabs
[86f88d1]196        self.tabFitting.setTabEnabled(TAB_POLY, False)
197        self.tabFitting.setTabEnabled(TAB_MAGNETISM, False)
198        self.lblChi2Value.setText("---")
[5236449]199        # Update Q Ranges
200        self.updateQRange()
[86f88d1]201
202    def initializeSignals(self):
203        """
204        Connect GUI element signals
205        """
[cbcdd2c]206        # Comboboxes
[cd31251]207        self.cbStructureFactor.currentIndexChanged.connect(self.onSelectStructureFactor)
208        self.cbCategory.currentIndexChanged.connect(self.onSelectCategory)
209        self.cbModel.currentIndexChanged.connect(self.onSelectModel)
[cbcdd2c]210        # Checkboxes
[86f88d1]211        self.chk2DView.toggled.connect(self.toggle2D)
212        self.chkPolydispersity.toggled.connect(self.togglePoly)
213        self.chkMagnetism.toggled.connect(self.toggleMagnetism)
[cbcdd2c]214        # Buttons
[5236449]215        self.cmdFit.clicked.connect(self.onFit)
[cbcdd2c]216        self.cmdPlot.clicked.connect(self.onPlot)
217        # Line edits
218        self.txtNpts.textChanged.connect(self.onNpts)
219        self.txtMinRange.textChanged.connect(self.onMinRange)
220        self.txtMaxRange.textChanged.connect(self.onMaxRange)
221
222        # Respond to change in parameters from the UI
223        self._model_model.itemChanged.connect(self.updateParamsFromModel)
[cd31251]224        self._poly_model.itemChanged.connect(self.onPolyModelChange)
225        # TODO after the poly_model prototype accepted
226        #self._magnet_model.itemChanged.connect(self.onMagneticModelChange)
[86f88d1]227
[6f7f652]228    def setDefaultStructureCombo(self):
[cbcdd2c]229        """
230        Fill in the structure factors combo box with defaults
231        """
[4d457df]232        structure_factor_list = self.master_category_dict.pop(CATEGORY_STRUCTURE)
[cd31251]233        structure_factors = ["None"]
[6f7f652]234        self.cbStructureFactor.clear()
[811bec1]235        structure_factors = [factor[0] for factor in structure_factor_list]
[6f7f652]236        self.cbStructureFactor.addItems(sorted(structure_factors))
237
[cd31251]238    def onSelectCategory(self):
[60af928]239        """
240        Select Category from list
241        """
[4d457df]242        category = str(self.cbCategory.currentText())
[86f88d1]243        # Check if the user chose "Choose category entry"
[4d457df]244        if category == CATEGORY_DEFAULT:
[86f88d1]245            # if the previous category was not the default, keep it.
246            # Otherwise, just return
247            if self._previous_category_index != 0:
248                self.cbCategory.setCurrentIndex(self._previous_category_index)
249            return
250
[4d457df]251        if category == CATEGORY_STRUCTURE:
[6f7f652]252            self.disableModelCombo()
253            self.enableStructureCombo()
254            return
255
[cbcdd2c]256        # Safely clear and enable the model combo
[6f7f652]257        self.cbModel.blockSignals(True)
258        self.cbModel.clear()
259        self.cbModel.blockSignals(False)
260        self.enableModelCombo()
261        self.disableStructureCombo()
262
[86f88d1]263        self._previous_category_index = self.cbCategory.currentIndex()
[cbcdd2c]264        # Retrieve the list of models
[4d457df]265        model_list = self.master_category_dict[category]
[6f7f652]266        models = []
[cbcdd2c]267        # Populate the models combobox
[4d457df]268        self.cbModel.addItems(sorted([model for (model,_) in model_list]))
269
270    def createDefaultDataset(self):
271        """
272        Generate default Dataset 1D/2D for the given model
273        """
274        # Create default datasets if no data passed
275        if self.is2D:
276            qmax = self.q_range_max/numpy.sqrt(2)
277            qstep = self.npts
278            self.logic.createDefault2dData(qmax, qstep, self.tab_id)
279        else:
280            interval = numpy.linspace(start=self.q_range_min, stop=self.q_range_max,
281                        num=self.npts, endpoint=True)
282            self.logic.createDefault1dData(interval, self.tab_id)
[60af928]283
[cd31251]284    def onSelectModel(self):
[60af928]285        """
[5236449]286        Respond to select Model from list event
[60af928]287        """
[cbcdd2c]288        model = str(self.cbModel.currentText())
[5236449]289
290        # SasModel -> QModel
[4d457df]291        self.SASModelToQModel(model)
[60af928]292
[5236449]293        if self._index is None:
[cbcdd2c]294            # Create default datasets if no data passed
[4d457df]295            self.createDefaultDataset()
[5236449]296        else:
[4d457df]297            self.calculateDataForModel()
[5236449]298
[cd31251]299    def onSelectStructureFactor(self):
[60af928]300        """
301        Select Structure Factor from list
302        """
[cd31251]303        model = str(self.cbModel.currentText())
304        structure = str(self.cbStructureFactor.currentText())
[4d457df]305        self.SASModelToQModel(model, structure_factor=structure)
[60af928]306
[5236449]307    def readCategoryInfo(self):
[60af928]308        """
309        Reads the categories in from file
310        """
311        self.master_category_dict = defaultdict(list)
312        self.by_model_dict = defaultdict(list)
313        self.model_enabled_dict = defaultdict(bool)
314
[cbcdd2c]315        categorization_file = CategoryInstaller.get_user_file()
316        if not os.path.isfile(categorization_file):
317            categorization_file = CategoryInstaller.get_default_file()
318        with open(categorization_file, 'rb') as cat_file:
[60af928]319            self.master_category_dict = json.load(cat_file)
[5236449]320            self.regenerateModelDict()
[60af928]321
[5236449]322        # Load the model dict
323        models = load_standard_models()
324        for model in models:
325            self.models[model.name] = model
326
327    def regenerateModelDict(self):
[60af928]328        """
[cbcdd2c]329        Regenerates self.by_model_dict which has each model name as the
[60af928]330        key and the list of categories belonging to that model
331        along with the enabled mapping
332        """
333        self.by_model_dict = defaultdict(list)
334        for category in self.master_category_dict:
335            for (model, enabled) in self.master_category_dict[category]:
336                self.by_model_dict[model].append(category)
337                self.model_enabled_dict[model] = enabled
338
[86f88d1]339    def addBackgroundToModel(self, model):
340        """
341        Adds background parameter with default values to the model
342        """
[cbcdd2c]343        assert isinstance(model, QtGui.QStandardItemModel)
[86f88d1]344        checked_list = ['background', '0.001', '-inf', 'inf', '1/cm']
[4d457df]345        FittingUtilities.addCheckedListToModel(model, checked_list)
[86f88d1]346
347    def addScaleToModel(self, model):
348        """
349        Adds scale parameter with default values to the model
350        """
[cbcdd2c]351        assert isinstance(model, QtGui.QStandardItemModel)
[86f88d1]352        checked_list = ['scale', '1.0', '0.0', 'inf', '']
[4d457df]353        FittingUtilities.addCheckedListToModel(model, checked_list)
[86f88d1]354
[4d457df]355    def SASModelToQModel(self, model_name, structure_factor=None):
[60af928]356        """
[cbcdd2c]357        Setting model parameters into table based on selected category
[60af928]358        """
359        # Crete/overwrite model items
360        self._model_model.clear()
[5236449]361
[60af928]362        kernel_module = generate.load_kernel_module(model_name)
363        self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', []))
364
[cbcdd2c]365        # Instantiate the current sasmodel
[5236449]366        self.kernel_module = self.models[model_name]()
367
368        # Explicitly add scale and background with default values
[86f88d1]369        self.addScaleToModel(self._model_model)
370        self.addBackgroundToModel(self._model_model)
[60af928]371
[5236449]372        # Update the QModel
[4d457df]373        FittingUtilities.addParametersToModel(self.model_parameters, self._model_model)
374        # Update the counter used for multishell display
375        self._last_model_row = self._model_model.rowCount()
376
377        FittingUtilities.addHeadersToModel(self._model_model)
[cd31251]378
379        # Add structure factor
380        if structure_factor is not None and structure_factor != "None":
381            structure_module = generate.load_kernel_module(structure_factor)
382            structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', []))
[4d457df]383            FittingUtilities.addSimpleParametersToModel(structure_parameters, self._model_model)
384            # Update the counter used for multishell display
385            self._last_model_row = self._model_model.rowCount()
[cd31251]386        else:
387            self.addStructureFactor()
388
[5236449]389        # Multishell models need additional treatment
[86f88d1]390        self.addExtraShells()
391
[5236449]392        # Add polydispersity to the model
[86f88d1]393        self.setPolyModel()
[5236449]394        # Add magnetic parameters to the model
[86f88d1]395        self.setMagneticModel()
[5236449]396
397        # Now we claim the model has been loaded
[86f88d1]398        self.model_is_loaded = True
399
[5236449]400        # Update Q Ranges
401        self.updateQRange()
402
[cd31251]403    def onPolyModelChange(self, item):
[cbcdd2c]404        """
[cd31251]405        Callback method for updating the main model and sasmodel
406        parameters with the GUI values in the polydispersity view
[cbcdd2c]407        """
[cd31251]408        model_column = item.column()
409        model_row = item.row()
410        name_index = self._poly_model.index(model_row, 0)
[cbcdd2c]411        # Extract changed value. Assumes proper validation by QValidator/Delegate
412        value = float(item.text())
[cd31251]413        parameter_name = str(self._poly_model.data(name_index).toPyObject()) # "distribution of sld" etc.
414        if "Distribution of" in parameter_name:
415            parameter_name = parameter_name[16:]
416        property_name = str(self._poly_model.headerData(model_column, 1).toPyObject()) # Value, min, max, etc.
417        print "%s(%s) => %d" % (parameter_name, property_name, value)
418
419        # Update the sasmodel
420        #self.kernel_module.params[parameter_name] = value
421
422        # Reload the main model - may not be required if no variable is shown in main view
423        #model = str(self.cbModel.currentText())
[4d457df]424        #self.SASModelToQModel(model)
[cd31251]425
426        pass # debug anchor
427
428    def updateParamsFromModel(self, item):
429        """
430        Callback method for updating the sasmodel parameters with the GUI values
431        """
[cbcdd2c]432        model_column = item.column()
433        model_row = item.row()
434        name_index = self._model_model.index(model_row, 0)
[cd31251]435
436        if model_column == 0:
437            # Assure we're dealing with checkboxes
438            if not item.isCheckable():
439                return
440            status = item.checkState()
441            # If multiple rows selected - toggle all of them
442            rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()]
443
444            # Switch off signaling from the model to avoid multiple calls
445            self._model_model.blockSignals(True)
446            # Convert to proper indices and set requested enablement
447            items = [self._model_model.item(row, 0).setCheckState(status) for row in rows]
448            self._model_model.blockSignals(False)
449            return
450
451        # Extract changed value. Assumes proper validation by QValidator/Delegate
452        value = float(item.text())
[cbcdd2c]453        parameter_name = str(self._model_model.data(name_index).toPyObject()) # sld, background etc.
454        property_name = str(self._model_model.headerData(1, model_column).toPyObject()) # Value, min, max, etc.
455
456        print "%s(%s) => %d" % (parameter_name, property_name, value)
457        self.kernel_module.params[parameter_name] = value
458
459        # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf]
460
461        # magnetic params in self.kernel_module.details['M0:parameter_name'] = value
462        # multishell params in self.kernel_module.details[??] = value
463
[5236449]464
465    def createTheoryIndex(self):
466        """
467        Create a QStandardModelIndex containing default model data
468        """
[cbcdd2c]469        name = self.kernel_module.name
[5236449]470        if self.is2D:
471            name += "2d"
472        name = "M%i [%s]" % (self.tab_id, name)
473        new_item = GuiUtils.createModelItemWithPlot(QtCore.QVariant(self.data), name=name)
[cbcdd2c]474        # Notify the GUI manager so it can update the theory model in DataExplorer
475        self.communicate.updateTheoryFromPerspectiveSignal.emit(new_item)
[5236449]476
477    def onFit(self):
478        """
479        Perform fitting on the current data
480        """
[cbcdd2c]481        #self.calculate1DForModel()
482        pass
483
484    def onPlot(self):
485        """
486        Plot the current set of data
487        """
488        # TODO: reimplement basepage.py/_update_paramv_on_fit
[4d457df]489        if self.data is None or not self.data.is_data:
490            self.createDefaultDataset()
491        self.calculateDataForModel()
[cbcdd2c]492
493    def onNpts(self, text):
494        """
495        Callback for number of points line edit update
496        """
497        # assumes type/value correctness achieved with QValidator
498        try:
499            self.npts = int(text)
500        except:
501            pass
502
503    def onMinRange(self, text):
504        """
505        Callback for minimum range of points line edit update
506        """
507        # assumes type/value correctness achieved with QValidator
508        try:
509            self.q_range_min = float(text)
510        except:
511            pass
[cd31251]512        # set Q range labels on the main tab
513        self.lblMinRangeDef.setText(str(self.q_range_min))
[cbcdd2c]514
515    def onMaxRange(self, text):
516        """
517        Callback for maximum range of points line edit update
518        """
519        # assumes type/value correctness achieved with QValidator
520        try:
521            self.q_range_max = float(text)
522        except:
523            pass
[cd31251]524        # set Q range labels on the main tab
525        self.lblMaxRangeDef.setText(str(self.q_range_max))
[5236449]526
[4d457df]527    def methodCalculateForData(self):
528        '''return the method for data calculation'''
529        return Calc1D if isinstance(self.data, Data1D) else Calc2D
530
531    def methodCompleteForData(self):
532        '''return the method for result parsin on calc complete '''
533        return self.complete1D if isinstance(self.data, Data1D) else self.complete2D
534
535    def calculateDataForModel(self):
[86f88d1]536        """
537        Prepare the fitting data object, based on current ModelModel
538        """
[4d457df]539        # Awful API to a backend method.
540        method = self.methodCalculateForData()(data=self.data,
[cbcdd2c]541                              model=self.kernel_module,
542                              page_id=0,
543                              qmin=self.q_range_min,
544                              qmax=self.q_range_max,
545                              smearer=None,
546                              state=None,
547                              weight=None,
548                              fid=None,
549                              toggle_mode_on=False,
[4d457df]550                              completefn=None,
[cbcdd2c]551                              update_chisqr=True,
[5236449]552                              exception_handler=self.calcException,
[cbcdd2c]553                              source=None)
[4d457df]554
555        calc_thread = threads.deferToThread(method.compute)
556        calc_thread.addCallback(self.methodCompleteForData())
[5236449]557
[cbcdd2c]558    def complete1D(self, return_data):
[5236449]559        """
[4d457df]560        Plot the current 1D data
561        """
562        self.logic.new1DPlot(return_data)
[cbcdd2c]563        self.createTheoryIndex()
564
565        #output=self._cal_chisqr(data=data,
566        #                        fid=fid,
567        #                        weight=weight,
568        #                        page_id=page_id,
569        #                        index=index)
570
571    def complete2D(self, return_data):
572        """
[4d457df]573        Plot the current 2D data
574        """
575        self.logic.new2DPlot(return_data)
[cbcdd2c]576        self.createTheoryIndex()
577
578        #output=self._cal_chisqr(data=data,
579        #                        weight=weight,
580        #                        fid=fid,
581        #                        page_id=page_id,
582        #                        index=index)
583        #    self._plot_residuals(page_id=page_id, data=data, fid=fid,
584        #                            index=index, weight=weight)
[5236449]585
586    def calcException(self, etype, value, tb):
587        """
[cbcdd2c]588        Something horrible happened in the deferred. Cry me a river.
[5236449]589        """
590        logging.error("".join(traceback.format_exception(etype, value, tb)))
591        msg = traceback.format_exception(etype, value, tb, limit=1)
[60af928]592
593    def setTableProperties(self, table):
594        """
595        Setting table properties
596        """
597        # Table properties
598        table.verticalHeader().setVisible(False)
599        table.setAlternatingRowColors(True)
600        table.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)
601        table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
[f46f6dc]602        table.resizeColumnsToContents()
603
[60af928]604        # Header
605        header = table.horizontalHeader()
[f46f6dc]606        header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
607
608        header.ResizeMode(QtGui.QHeaderView.Interactive)
609        header.setResizeMode(0, QtGui.QHeaderView.ResizeToContents)
610        header.setResizeMode(6, QtGui.QHeaderView.ResizeToContents)
[60af928]611
612    def setPolyModel(self):
613        """
614        Set polydispersity values
615        """
[86f88d1]616        if not self.model_parameters:
617            return
618        self._poly_model.clear()
619        for row, param in enumerate(self.model_parameters.form_volume_parameters):
620            # Counters should not be included
621            if not param.polydisperse:
622                continue
623
624            # Potential multishell params
625            checked_list = ["Distribution of "+param.name, str(param.default),
[cbcdd2c]626                            str(param.limits[0]), str(param.limits[1]),
[86f88d1]627                            "35", "3", ""]
[4d457df]628            FittingUtilities.addCheckedListToModel(self._poly_model, checked_list)
[86f88d1]629
630            #TODO: Need to find cleaner way to input functions
631            func = QtGui.QComboBox()
[cbcdd2c]632            func.addItems(['rectangle', 'array', 'lognormal', 'gaussian', 'schulz',])
633            func_index = self.lstPoly.model().index(row, 6)
634            self.lstPoly.setIndexWidget(func_index, func)
[86f88d1]635
[4d457df]636        FittingUtilities.addPolyHeadersToModel(self._poly_model)
[60af928]637
638    def setMagneticModel(self):
639        """
640        Set magnetism values on model
641        """
[86f88d1]642        if not self.model_parameters:
643            return
644        self._magnet_model.clear()
645        for param in self.model_parameters.call_parameters:
646            if param.type != "magnetic":
647                continue
648            checked_list = [param.name,
649                            str(param.default),
650                            str(param.limits[0]),
651                            str(param.limits[1]),
652                            param.units]
[4d457df]653            FittingUtilities.addCheckedListToModel(self._magnet_model, checked_list)
[86f88d1]654
[4d457df]655        FittingUtilities.addHeadersToModel(self._magnet_model)
[60af928]656
[cd31251]657    def addStructureFactor(self):
658        """
659        Add structure factors to the list of parameters
660        """
661        if self.kernel_module.is_form_factor:
662            self.enableStructureCombo()
663        else:
664            self.disableStructureCombo()
665
[60af928]666    def addExtraShells(self):
667        """
[f46f6dc]668        Add a combobox for multiple shell display
[60af928]669        """
[4d457df]670        param_name, param_length = FittingUtilities.getMultiplicity(self.model_parameters)
[f46f6dc]671
672        if param_length == 0:
673            return
674
[6f7f652]675        # cell 1: variable name
[f46f6dc]676        item1 = QtGui.QStandardItem(param_name)
677
[60af928]678        func = QtGui.QComboBox()
[f46f6dc]679        func.addItems([str(i+1) for i in xrange(param_length)])
[86f88d1]680        func.currentIndexChanged.connect(self.modifyShellsInList)
[60af928]681
[6f7f652]682        # cell 2: combobox
[f46f6dc]683        item2 = QtGui.QStandardItem()
684        self._model_model.appendRow([item1, item2])
[60af928]685
[6f7f652]686        # Beautify the row:  span columns 2-4
[60af928]687        shell_row = self._model_model.rowCount()
[f46f6dc]688        shell_index = self._model_model.index(shell_row-1, 1)
[86f88d1]689
[4d457df]690        self.lstParams.setIndexWidget(shell_index, func)
[86f88d1]691        self._last_model_row = self._model_model.rowCount()
692
693
694    def modifyShellsInList(self, index):
695        """
696        Add/remove additional multishell parameters
697        """
698        # Find row location of the combobox
699        last_row = self._last_model_row
700        remove_rows = self._model_model.rowCount() - last_row
701
702        if remove_rows > 1:
703            self._model_model.removeRows(last_row, remove_rows)
704
[4d457df]705        FittingUtilities.addShellsToModel(self.model_parameters, self._model_model, index)
[60af928]706
707    def togglePoly(self, isChecked):
708        """
[6f7f652]709        Enable/disable the polydispersity tab
[60af928]710        """
711        self.tabFitting.setTabEnabled(TAB_POLY, isChecked)
712
713    def toggleMagnetism(self, isChecked):
714        """
[6f7f652]715        Enable/disable the magnetism tab
[60af928]716        """
717        self.tabFitting.setTabEnabled(TAB_MAGNETISM, isChecked)
718
719    def toggle2D(self, isChecked):
720        """
[6f7f652]721        Enable/disable the controls dependent on 1D/2D data instance
[60af928]722        """
723        self.chkMagnetism.setEnabled(isChecked)
724        self.is2D = isChecked
725
Note: See TracBrowser for help on using the repository browser.