source: sasview/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @ 29eb947

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 29eb947 was 29eb947, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Fixed tooltip size. Fixed a bug in structure factor control

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