Changes in / [dd2c2a31:e0da307] in sasview


Ignore:
Files:
1 deleted
14 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r7cc38a7 rce1f491  
    1616*.pyproj 
    1717*.sln 
    18 .*.swp 
    1918.DS_Store 
    2019/.settings 
  • src/sas/qtgui/MainWindow/DataExplorer.py

    r0cd98a1 re0da307  
    4242        # Main model for keeping loaded data 
    4343        self.model = QtGui.QStandardItemModel(self) 
     44 
    4445        # Secondary model for keeping frozen data sets 
    4546        self.theory_model = QtGui.QStandardItemModel(self) 
     
    9798        self.communicator.plotUpdateSignal.connect(self.updatePlot) 
    9899        self.communicator.maskEditorSignal.connect(self.showEditDataMask) 
    99         self.communicator.extMaskEditorSignal.connect(self.extShowEditDataMask) 
    100100 
    101101        self.cbgraph.editTextChanged.connect(self.enableGraphCombo) 
     
    598598        plot2D.plot(plot_set) 
    599599        self.addPlot(plot2D) 
    600         self.active_plots[plot2D.data.name] = plot2D 
     600        self.active_plots[plot2D.data.id] = plot2D 
    601601        #============================================ 
    602602        # Experimental hook for silx charts 
     
    626626                new_plot.plot(plot_set, transform=transform) 
    627627                # active_plots may contain multiple charts 
    628                 self.active_plots[plot_set.name] = new_plot 
     628                self.active_plots[plot_set.id] = new_plot 
    629629            elif isinstance(plot_set, Data2D): 
    630630                self.addDataPlot2D(plot_set, item) 
     
    697697                old_plot.plot() 
    698698                # need this for lookup - otherwise this plot will never update 
    699                 self.active_plots[plot_set.name] = old_plot 
     699                self.active_plots[plot_set.id] = old_plot 
    700700 
    701701    def updatePlot(self, data): 
     
    711711 
    712712        ids_keys = list(self.active_plots.keys()) 
    713         ids_vals = [val.data.name for val in self.active_plots.values()] 
    714  
    715         data_id = data.name 
     713        ids_vals = [val.data.id for val in self.active_plots.values()] 
     714 
     715        data_id = data.id 
    716716        if data_id in ids_keys: 
    717717            self.active_plots[data_id].replacePlot(data_id, data) 
     
    952952        model = proxy.sourceModel() 
    953953 
    954         if not index.isValid(): 
    955             return 
    956         model_item = model.itemFromIndex(proxy.mapToSource(index)) 
    957         # Find the mapped index 
    958         orig_index = model_item.isCheckable() 
    959         if not orig_index: 
    960             return 
    961         # Check the data to enable/disable actions 
    962         is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D) 
    963         self.actionQuick3DPlot.setEnabled(is_2D) 
    964         self.actionEditMask.setEnabled(is_2D) 
    965         # Fire up the menu 
    966         self.context_menu.exec_(self.current_view.mapToGlobal(position)) 
     954        if index.isValid(): 
     955            model_item = model.itemFromIndex(proxy.mapToSource(index)) 
     956            # Find the mapped index 
     957            orig_index = model_item.isCheckable() 
     958            if orig_index: 
     959                # Check the data to enable/disable actions 
     960                is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D) 
     961                self.actionQuick3DPlot.setEnabled(is_2D) 
     962                self.actionEditMask.setEnabled(is_2D) 
     963                # Fire up the menu 
     964                self.context_menu.exec_(self.current_view.mapToGlobal(position)) 
    967965 
    968966    def showDataInfo(self): 
     
    10611059        self.new_plot.show() 
    10621060 
    1063     def extShowEditDataMask(self): 
    1064         self.showEditDataMask() 
    1065  
    10661061    def showEditDataMask(self, data=None): 
    10671062        """ 
    10681063        Mask Editor for 2D plots 
    10691064        """ 
    1070         try: 
    1071             if data is None or not isinstance(data, Data2D): 
    1072                 index = self.current_view.selectedIndexes()[0] 
    1073                 proxy = self.current_view.model() 
    1074                 model = proxy.sourceModel() 
    1075                 model_item = model.itemFromIndex(proxy.mapToSource(index)) 
    1076  
    1077                 data = GuiUtils.dataFromItem(model_item) 
    1078  
    1079             if data is None or not isinstance(data, Data2D): 
    1080                 msg = QtWidgets.QMessageBox() 
    1081                 msg.setIcon(QtWidgets.QMessageBox.Information) 
    1082                 msg.setText("Error: cannot apply mask. \ 
    1083                                 Please select a 2D dataset.") 
    1084                 msg.setStandardButtons(QtWidgets.QMessageBox.Cancel) 
    1085                 msg.exec_() 
    1086                 return 
    1087         except: 
    1088             msg = QtWidgets.QMessageBox() 
    1089             msg.setIcon(QtWidgets.QMessageBox.Information) 
    1090             msg.setText("Error: No dataset selected. \ 
    1091                             Please select a 2D dataset.") 
    1092             msg.setStandardButtons(QtWidgets.QMessageBox.Cancel) 
    1093             msg.exec_() 
    1094             return 
     1065        if data is None or not isinstance(data, Data2D): 
     1066            index = self.current_view.selectedIndexes()[0] 
     1067            proxy = self.current_view.model() 
     1068            model = proxy.sourceModel() 
     1069            model_item = model.itemFromIndex(proxy.mapToSource(index)) 
     1070 
     1071            data = GuiUtils.dataFromItem(model_item) 
    10951072 
    10961073        mask_editor = MaskEditor(self, data) 
  • src/sas/qtgui/MainWindow/GuiManager.py

    r339e22b rf84d793  
    422422        self._workspace.actionExcel.triggered.connect(self.actionExcel) 
    423423        self._workspace.actionLatex.triggered.connect(self.actionLatex) 
     424 
    424425        # View 
    425426        self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window) 
     
    451452        self._workspace.actionManage_Custom_Models.triggered.connect(self.actionManage_Custom_Models) 
    452453        self._workspace.actionAddMult_Models.triggered.connect(self.actionAddMult_Models) 
    453         self._workspace.actionEditMask.triggered.connect(self.actionEditMask) 
    454  
    455454        # Window 
    456455        self._workspace.actionCascade.triggered.connect(self.actionCascade) 
     
    782781        self.add_mult_editor.show() 
    783782 
    784     def actionEditMask(self): 
    785  
    786         self.communicate.extMaskEditorSignal.emit() 
    787  
    788783    #============ ANALYSIS ================= 
    789784    def actionFitting(self): 
  • src/sas/qtgui/MainWindow/UI/MainWindowUI.ui

    r2f14b5d rdda8f16  
    113113    <addaction name="actionManage_Custom_Models"/> 
    114114    <addaction name="actionAddMult_Models"/> 
    115     <addaction name="separator"/> 
    116     <addaction name="actionEditMask"/> 
    117115   </widget> 
    118116   <widget class="QMenu" name="menuWindow"> 
     
    415413   </property> 
    416414  </action> 
    417     <action name="actionEditMask"> 
    418    <property name="text"> 
    419     <string>Edit Mask</string> 
    420    </property> 
    421   </action> 
    422415  <action name="actionCascade"> 
    423416   <property name="text"> 
  • src/sas/qtgui/Perspectives/Fitting/FittingLogic.py

    rdcabba7 rb4d05bd  
    161161        Create a new 1D data instance based on fitting results 
    162162        """ 
    163         return self._create1DPlot(tab_id, return_data['x'], return_data['y'], 
    164                                   return_data['model'], return_data['data']) 
     163        # Unpack return data from Calc1D 
     164        x, y, page_id, state, weight,\ 
     165        fid, toggle_mode_on, \ 
     166        elapsed, index, model, \ 
     167        data, update_chisqr, source, \ 
     168        unsmeared_output, unsmeared_data, unsmeared_error, \ 
     169        pq_values, sq_values = return_data 
     170 
     171        return self._create1DPlot(tab_id, x, y, model, data) 
    165172 
    166173    def new2DPlot(self, return_data): 
     
    168175        Create a new 2D data instance based on fitting results 
    169176        """ 
    170         image = return_data['image'] 
    171         data = return_data['data'] 
    172         model = return_data['model'] 
     177        image, data, page_id, model, state, toggle_mode_on,\ 
     178        elapsed, index, fid, qmin, qmax, weight, \ 
     179        update_chisqr, source = return_data 
    173180 
    174181        np.nan_to_num(image) 
     
    176183        new_plot.name = model.name + '2d' 
    177184        new_plot.title = "Analytical model 2D " 
    178         new_plot.id = str(return_data['page_id']) + " " + data.name 
    179         new_plot.group_id = str(return_data['page_id']) + " Model2D" 
     185        new_plot.id = str(page_id) + " " + data.name 
     186        new_plot.group_id = str(page_id) + " Model2D" 
    180187        new_plot.detector = data.detector 
    181188        new_plot.source = data.source 
     
    211218        (pq_plot, sq_plot). If either are unavailable, the corresponding plot is None. 
    212219        """ 
    213         plots = [] 
    214         for name, result in return_data['intermediate_results'].items(): 
    215             plots.append(self._create1DPlot(tab_id, return_data['x'], result, 
    216                          return_data['model'], return_data['data'], 
    217                          component=name)) 
    218         return plots 
     220        # Unpack return data from Calc1D 
     221        x, y, page_id, state, weight, \ 
     222        fid, toggle_mode_on, \ 
     223        elapsed, index, model, \ 
     224        data, update_chisqr, source, \ 
     225        unsmeared_output, unsmeared_data, unsmeared_error, \ 
     226        pq_values, sq_values = return_data 
     227 
     228        pq_plot = None 
     229        sq_plot = None 
     230 
     231        if pq_values is not None: 
     232            pq_plot = self._create1DPlot(tab_id, x, pq_values, model, data, component="P(Q)") 
     233        if sq_values is not None: 
     234            sq_plot = self._create1DPlot(tab_id, x, sq_values, model, data, component="S(Q)") 
     235 
     236        return pq_plot, sq_plot 
    219237 
    220238    def computeDataRange(self): 
  • src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py

    r70f4458 rb764ae5  
    88from sas.qtgui.Plotting.PlotterData import Data1D 
    99from sas.qtgui.Plotting.PlotterData import Data2D 
    10  
    11 from sas.qtgui.Perspectives.Fitting.AssociatedComboBox import AssociatedComboBox 
    1210 
    1311model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units'] 
     
    6361    return (param_name, param_length) 
    6462 
    65 def createFixedChoiceComboBox(param, item_row): 
    66     """ 
    67     Determines whether param is a fixed-choice parameter, modifies items in item_row appropriately and returns a combo 
    68     box containing the fixed choices. Returns None if param is not fixed-choice. 
    69      
    70     item_row is a list of QStandardItem objects for insertion into the parameter table.  
    71     """ 
    72  
    73     # Determine whether this is a fixed-choice parameter. There are lots of conditionals, simply because the 
    74     # implementation is not yet concrete; there are several possible indicators that the parameter is fixed-choice. 
    75     # TODO: (when the sasmodels implementation is concrete, clean this up) 
    76     choices = None 
    77     if isinstance(param.choices, (list, tuple)) and len(param.choices) > 0: 
    78         # The choices property is concrete in sasmodels, probably will use this 
    79         choices = param.choices 
    80     elif isinstance(param.units, (list, tuple)): 
    81         choices = [str(x) for x in param.units] 
    82  
    83     cbox = None 
    84     if choices is not None: 
    85         # Use combo box for input, if it is fixed-choice 
    86         cbox = AssociatedComboBox(item_row[1], idx_as_value=True) 
    87         cbox.addItems(choices) 
    88         item_row[2].setEditable(False) 
    89         item_row[3].setEditable(False) 
    90  
    91     return cbox 
    92  
    93 def addParametersToModel(parameters, kernel_module, is2D, model=None, view=None): 
    94     """ 
    95     Update local ModelModel with sasmodel parameters. 
    96     Actually appends to model, if model and view params are not None. 
    97     Always returns list of lists of QStandardItems. 
     63def addParametersToModel(parameters, kernel_module, is2D): 
     64    """ 
     65    Update local ModelModel with sasmodel parameters 
    9866    """ 
    9967    multishell_parameters = getIterParams(parameters) 
     
    10472    else: 
    10573        params = parameters.iq_parameters 
    106  
    107     rows = [] 
     74    item = [] 
    10875    for param in params: 
    10976        # don't include shell parameters 
    11077        if param.name == multishell_param_name: 
    11178            continue 
    112  
    11379        # Modify parameter name from <param>[n] to <param>1 
    11480        item_name = param.name 
    11581        if param in multishell_parameters: 
    11682            continue 
     83        #    item_name = replaceShellName(param.name, 1) 
    11784 
    11885        item1 = QtGui.QStandardItem(item_name) 
    11986        item1.setCheckable(True) 
    12087        item1.setEditable(False) 
    121  
     88        # item_err = QtGui.QStandardItem() 
    12289        # check for polydisp params 
    12390        if param.polydisperse: 
     
    12693            item1_1 = QtGui.QStandardItem("Distribution") 
    12794            item1_1.setEditable(False) 
    128  
    12995            # Find param in volume_params 
    13096            for p in parameters.form_volume_parameters: 
     
    13399                width = kernel_module.getParam(p.name+'.width') 
    134100                ptype = kernel_module.getParam(p.name+'.type') 
     101 
    135102                item1_2 = QtGui.QStandardItem(str(width)) 
    136103                item1_2.setEditable(False) 
     
    143110                poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 
    144111                break 
    145  
    146112            # Add the polydisp item as a child 
    147113            item1.appendRow([poly_item]) 
    148  
    149114        # Param values 
    150115        item2 = QtGui.QStandardItem(str(param.default)) 
     116        # TODO: the error column. 
     117        # Either add a proxy model or a custom view delegate 
     118        #item_err = QtGui.QStandardItem() 
    151119        item3 = QtGui.QStandardItem(str(param.limits[0])) 
    152120        item4 = QtGui.QStandardItem(str(param.limits[1])) 
    153         item5 = QtGui.QStandardItem(str(param.units)) 
     121        item5 = QtGui.QStandardItem(param.units) 
    154122        item5.setEditable(False) 
    155  
    156         # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 
    157         row = [item1, item2, item3, item4, item5] 
    158         cbox = createFixedChoiceComboBox(param, row) 
    159  
    160         # Append to the model and use the combobox, if required 
    161         if None not in (model, view): 
    162             model.appendRow(row) 
    163             if cbox: 
    164                 view.setIndexWidget(item2.index(), cbox) 
    165         rows.append(row) 
    166  
    167     return rows 
    168  
    169 def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None, row_num=None): 
    170     """ 
    171     Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic) 
    172     Actually appends to model, if model and view params are not None. 
    173     Always returns list of lists of QStandardItems. 
    174  
    175     parameters_original: list of parameters before any tagging on their IDs, e.g. for product model (so that those are 
    176     the display names; see below) 
     123        item.append([item1, item2, item3, item4, item5]) 
     124    return item 
     125 
     126def addSimpleParametersToModel(parameters, is2D): 
     127    """ 
     128    Update local ModelModel with sasmodel parameters 
    177129    """ 
    178130    if is2D: 
     
    180132    else: 
    181133        params = parameters.iq_parameters 
    182  
    183     if parameters_original: 
    184         # 'parameters_original' contains the parameters as they are to be DISPLAYED, while 'parameters' 
    185         # contains the parameters as they were renamed; this is for handling name collisions in product model. 
    186         # The 'real name' of the parameter will be stored in the item's user data. 
    187         if is2D: 
    188             params_orig = [p for p in parameters_original.kernel_parameters if p.type != 'magnetic'] 
    189         else: 
    190             params_orig = parameters_original.iq_parameters 
    191     else: 
    192         # no difference in names anyway 
    193         params_orig = params 
    194  
    195     rows = [] 
    196     for param, param_orig in zip(params, params_orig): 
     134    item = [] 
     135    for param in params: 
    197136        # Create the top level, checkable item 
    198         item_name = param_orig.name 
     137        item_name = param.name 
    199138        item1 = QtGui.QStandardItem(item_name) 
    200         item1.setData(param.name, QtCore.Qt.UserRole) 
    201139        item1.setCheckable(True) 
    202140        item1.setEditable(False) 
    203  
    204141        # Param values 
    205142        # TODO: add delegate for validation of cells 
    206143        item2 = QtGui.QStandardItem(str(param.default)) 
    207         item3 = QtGui.QStandardItem(str(param.limits[0])) 
    208         item4 = QtGui.QStandardItem(str(param.limits[1])) 
    209         item5 = QtGui.QStandardItem(str(param.units)) 
    210         item5.setEditable(False) 
    211  
    212         # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 
    213         row = [item1, item2, item3, item4, item5] 
    214         cbox = createFixedChoiceComboBox(param, row) 
    215  
    216         # Append to the model and use the combobox, if required 
    217         if None not in (model, view): 
    218             if row_num is None: 
    219                 model.appendRow(row) 
    220             else: 
    221                 model.insertRow(row_num, row) 
    222                 row_num += 1 
    223  
    224             if cbox: 
    225                 view.setIndexWidget(item2.index(), cbox) 
    226  
    227         rows.append(row) 
    228  
    229     return rows 
     144        item4 = QtGui.QStandardItem(str(param.limits[0])) 
     145        item5 = QtGui.QStandardItem(str(param.limits[1])) 
     146        item6 = QtGui.QStandardItem(param.units) 
     147        item6.setEditable(False) 
     148        item.append([item1, item2, item4, item5, item6]) 
     149    return item 
    230150 
    231151def markParameterDisabled(model, row): 
     
    262182    model.appendRow(item_list) 
    263183 
    264 def addHeadingRowToModel(model, name): 
    265     """adds a non-interactive top-level row to the model""" 
    266     header_row = [QtGui.QStandardItem() for i in range(5)] 
    267     header_row[0].setText(name) 
    268  
    269     font = header_row[0].font() 
    270     font.setBold(True) 
    271     header_row[0].setFont(font) 
    272  
    273     for item in header_row: 
    274         item.setEditable(False) 
    275         item.setCheckable(False) 
    276         item.setSelectable(False) 
    277  
    278     model.appendRow(header_row) 
    279  
    280184def addHeadersToModel(model): 
    281185    """ 
     
    323227    model.header_tooltips = copy.copy(poly_header_error_tooltips) 
    324228 
    325 def addShellsToModel(parameters, model, index, row_num=None, view=None): 
    326     """ 
    327     Find out multishell parameters and update the model with the requested number of them. 
    328     Inserts them after the row at row_num, if not None; otherwise, appends to end. 
    329     If view param is not None, supports fixed-choice params. 
    330     Returns a list of lists of QStandardItem objects. 
     229def addShellsToModel(parameters, model, index): 
     230    """ 
     231    Find out multishell parameters and update the model with the requested number of them 
    331232    """ 
    332233    multishell_parameters = getIterParams(parameters) 
    333234 
    334     rows = [] 
    335235    for i in range(index): 
    336236        for par in multishell_parameters: 
     
    350250                    item1_3 = QtGui.QStandardItem(str(p.limits[0])) 
    351251                    item1_4 = QtGui.QStandardItem(str(p.limits[1])) 
    352                     item1_5 = QtGui.QStandardItem(str(p.units)) 
     252                    item1_5 = QtGui.QStandardItem(p.units) 
    353253                    poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 
    354254                    break 
     
    358258            item3 = QtGui.QStandardItem(str(par.limits[0])) 
    359259            item4 = QtGui.QStandardItem(str(par.limits[1])) 
    360             item5 = QtGui.QStandardItem(str(par.units)) 
    361             item5.setEditable(False) 
    362  
    363             # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 
    364             row = [item1, item2, item3, item4, item5] 
    365             cbox = createFixedChoiceComboBox(par, row) 
    366  
    367             # Always add to the model 
    368             if row_num is None: 
    369                 model.appendRow(row) 
    370             else: 
    371                 model.insertRow(row_num, row) 
    372                 row_num += 1 
    373  
    374             # Apply combobox if required 
    375             if None not in (view, cbox): 
    376                 view.setIndexWidget(item2.index(), cbox) 
    377  
    378             rows.append(row) 
    379  
    380     return rows 
     260            item5 = QtGui.QStandardItem(par.units) 
     261            model.appendRow([item1, item2, item3, item4, item5]) 
    381262 
    382263def calculateChi2(reference_data, current_data): 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    rd4ba565 rf84d793  
    4848from sas.qtgui.Perspectives.Fitting.ReportPageLogic import ReportPageLogic 
    4949 
     50 
    5051TAB_MAGNETISM = 4 
    5152TAB_POLY = 3 
     
    9091    fittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    9192    batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    92     Calc1DFinishedSignal = QtCore.pyqtSignal(dict) 
    93     Calc2DFinishedSignal = QtCore.pyqtSignal(dict) 
     93    Calc1DFinishedSignal = QtCore.pyqtSignal(tuple) 
     94    Calc2DFinishedSignal = QtCore.pyqtSignal(tuple) 
    9495 
    9596    def __init__(self, parent=None, data=None, tab_id=1): 
     
    187188 
    188189        # Overwrite data type descriptor 
    189  
    190190        self.is2D = True if isinstance(self.logic.data, Data2D) else False 
    191191 
     
    219219        # Utility variable to enable unselectable option in category combobox 
    220220        self._previous_category_index = 0 
    221         # Utility variables for multishell display 
    222         self._n_shells_row = 0 
    223         self._num_shell_params = 0 
     221        # Utility variable for multishell display 
     222        self._last_model_row = 0 
    224223        # Dictionary of {model name: model class} for the current category 
    225224        self.models = {} 
     
    248247        # copy of current kernel model 
    249248        self.kernel_module_copy = None 
    250  
    251         # dictionaries of current params 
    252         self.poly_params = {} 
    253         self.magnet_params = {} 
    254249 
    255250        # Page id for fitting 
     
    563558        When clicked on white space: model description 
    564559        """ 
    565         rows = [s.row() for s in self.lstParams.selectionModel().selectedRows() 
    566                 if self.isCheckable(s.row())] 
     560        rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()] 
    567561        menu = self.showModelDescription() if not rows else self.modelContextMenu(rows) 
    568562        try: 
     
    678672        Return list of all parameters for the current model 
    679673        """ 
    680         return [self._model_model.item(row).text() 
    681                 for row in range(self._model_model.rowCount()) 
    682                 if self.isCheckable(row)] 
     674        return [self._model_model.item(row).text() for row in range(self._model_model.rowCount())] 
    683675 
    684676    def modifyViewOnRow(self, row, font=None, brush=None): 
     
    708700        assert isinstance(constraint, Constraint) 
    709701        assert 0 <= row <= self._model_model.rowCount() 
    710         assert self.isCheckable(row) 
    711702 
    712703        item = QtGui.QStandardItem() 
     
    729720        max_col = self.lstParams.itemDelegate().param_max 
    730721        for row in self.selectedParameters(): 
    731             assert(self.isCheckable(row)) 
    732722            param = self._model_model.item(row, 0).text() 
    733723            value = self._model_model.item(row, 1).text() 
     
    772762        max_col = self.lstParams.itemDelegate().param_max 
    773763        for row in range(self._model_model.rowCount()): 
    774             if not self.isCheckable(row): 
    775                 continue 
    776764            if not self.rowHasConstraint(row): 
    777765                continue 
     
    800788    def getConstraintForRow(self, row): 
    801789        """ 
    802         For the given row, return its constraint, if any (otherwise None) 
    803         """ 
    804         if not self.isCheckable(row): 
    805             return None 
    806         item = self._model_model.item(row, 1) 
     790        For the given row, return its constraint, if any 
     791        """ 
    807792        try: 
     793            item = self._model_model.item(row, 1) 
    808794            return item.child(0).data() 
    809795        except AttributeError: 
     796            # return none when no constraints 
    810797            return None 
    811798 
     
    814801        Finds out if row of the main model has a constraint child 
    815802        """ 
    816         if not self.isCheckable(row): 
    817             return False 
    818803        item = self._model_model.item(row, 1) 
    819         if not item.hasChildren(): 
    820             return False 
    821         c = item.child(0).data() 
    822         if isinstance(c, Constraint): 
    823             return True 
     804        if item.hasChildren(): 
     805            c = item.child(0).data() 
     806            if isinstance(c, Constraint): 
     807                return True 
    824808        return False 
    825809 
     
    828812        Finds out if row of the main model has an active constraint child 
    829813        """ 
    830         if not self.isCheckable(row): 
    831             return False 
    832814        item = self._model_model.item(row, 1) 
    833         if not item.hasChildren(): 
    834             return False 
    835         c = item.child(0).data() 
    836         if isinstance(c, Constraint) and c.active: 
    837             return True 
     815        if item.hasChildren(): 
     816            c = item.child(0).data() 
     817            if isinstance(c, Constraint) and c.active: 
     818                return True 
    838819        return False 
    839820 
     
    842823        Finds out if row of the main model has an active, nontrivial constraint child 
    843824        """ 
    844         if not self.isCheckable(row): 
    845             return False 
    846825        item = self._model_model.item(row, 1) 
    847         if not item.hasChildren(): 
    848             return False 
    849         c = item.child(0).data() 
    850         if isinstance(c, Constraint) and c.func and c.active: 
    851             return True 
     826        if item.hasChildren(): 
     827            c = item.child(0).data() 
     828            if isinstance(c, Constraint) and c.func and c.active: 
     829                return True 
    852830        return False 
    853831 
     
    10591037            # Show constraint, if present 
    10601038            row = rows[0].row() 
    1061             if not self.rowHasConstraint(row): 
    1062                 return 
    1063             func = self.getConstraintForRow(row).func 
    1064             if func is not None: 
    1065                 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 
     1039            if self.rowHasConstraint(row): 
     1040                func = self.getConstraintForRow(row).func 
     1041                if func is not None: 
     1042                    self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 
    10661043 
    10671044    def replaceConstraintName(self, old_name, new_name=""): 
     
    12091186            # Update the sasmodel 
    12101187            # PD[ratio] -> width, npts -> npts, nsigs -> nsigmas 
    1211             #self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 
    1212             key = parameter_name + '.' + delegate.columnDict()[model_column] 
    1213             self.poly_params[key] = value 
     1188            self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 
    12141189 
    12151190            # Update plot 
     
    12201195            row = self.getRowFromName(parameter_name) 
    12211196            param_item = self._model_model.item(row) 
    1222             self._model_model.blockSignals(True) 
    12231197            param_item.child(0).child(0, model_column).setText(item.text()) 
    1224             self._model_model.blockSignals(False) 
    12251198 
    12261199    def onMagnetModelChange(self, item): 
     
    12511224            # Unparsable field 
    12521225            return 
    1253         delegate = self.lstMagnetic.itemDelegate() 
    1254  
    1255         if model_column > 1: 
    1256             if model_column == delegate.mag_min: 
    1257                 pos = 1 
    1258             elif model_column == delegate.mag_max: 
    1259                 pos = 2 
    1260             elif model_column == delegate.mag_unit: 
    1261                 pos = 0 
    1262             else: 
    1263                 raise AttributeError("Wrong column in magnetism table.") 
    1264             # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 
    1265             self.kernel_module.details[parameter_name][pos] = value 
    1266         else: 
    1267             self.magnet_params[parameter_name] = value 
    1268             #self.kernel_module.setParam(parameter_name) = value 
    1269             # Force the chart update when actual parameters changed 
     1226 
     1227        property_index = self._magnet_model.headerData(1, model_column)-1 # Value, min, max, etc. 
     1228 
     1229        # Update the parameter value - note: this supports +/-inf as well 
     1230        self.kernel_module.params[parameter_name] = value 
     1231 
     1232        # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 
     1233        self.kernel_module.details[parameter_name][property_index] = value 
     1234 
     1235        # Force the chart update when actual parameters changed 
     1236        if model_column == 1: 
    12701237            self.recalculatePlotData() 
    12711238 
     
    15141481        # update charts 
    15151482        self.onPlot() 
    1516         #self.recalculatePlotData() 
    1517  
    15181483 
    15191484        # Read only value - we can get away by just printing it here 
     
    15301495        # Data going in 
    15311496        data = self.logic.data 
    1532         model = copy.deepcopy(self.kernel_module) 
     1497        model = self.kernel_module 
    15331498        qmin = self.q_range_min 
    15341499        qmax = self.q_range_max 
    1535         # add polydisperse/magnet parameters if asked 
    1536         self.updateKernelModelWithExtraParams(model) 
    15371500 
    15381501        params_to_fit = self.main_params_to_fit 
     
    15981561            # internal so can use closure for param_dict 
    15991562            param_name = str(self._model_model.item(row, 0).text()) 
    1600             if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 
     1563            if param_name not in list(param_dict.keys()): 
    16011564                return 
    16021565            # modify the param value 
    16031566            param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 
    16041567            self._model_model.item(row, 1).setText(param_repr) 
    1605             self.kernel_module.setParam(param_name, param_dict[param_name][0]) 
    16061568            if self.has_error_column: 
    16071569                error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
     
    16111573            # Utility function for updateof polydispersity part of the main model 
    16121574            param_name = str(self._model_model.item(row, 0).text())+'.width' 
    1613             if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 
     1575            if param_name not in list(param_dict.keys()): 
    16141576                return 
    16151577            # modify the param value 
     
    16451607            poly_item.insertColumn(2, [QtGui.QStandardItem("")]) 
    16461608 
     1609        # block signals temporarily, so we don't end up 
     1610        # updating charts with every single model change on the end of fitting 
     1611        self._model_model.blockSignals(True) 
     1612 
    16471613        if not self.has_error_column: 
    16481614            # create top-level error column 
     
    16511617            self.iterateOverModel(createErrorColumn) 
    16521618 
     1619            # we need to enable signals for this, otherwise the final column mysteriously disappears (don't ask, I don't 
     1620            # know) 
     1621            self._model_model.blockSignals(False) 
    16531622            self._model_model.insertColumn(2, error_column) 
     1623            self._model_model.blockSignals(True) 
    16541624 
    16551625            FittingUtilities.addErrorHeadersToModel(self._model_model) 
     
    16601630            self.has_error_column = True 
    16611631 
    1662         # block signals temporarily, so we don't end up 
    1663         # updating charts with every single model change on the end of fitting 
    1664         self._model_model.itemChanged.disconnect() 
    16651632        self.iterateOverModel(updateFittedValues) 
    16661633        self.iterateOverModel(updatePolyValues) 
    1667         self._model_model.itemChanged.connect(self.onMainParamsChange) 
     1634 
     1635        self._model_model.blockSignals(False) 
    16681636 
    16691637        # Adjust the table cells width. 
     
    17001668            param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 
    17011669            self._poly_model.item(row_i, 1).setText(param_repr) 
    1702             self.kernel_module.setParam(param_name, param_dict[param_name][0]) 
    17031670            if self.has_poly_error_column: 
    17041671                error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
    17051672                self._poly_model.item(row_i, 2).setText(error_repr) 
     1673 
    17061674 
    17071675        def createErrorColumn(row_i): 
     
    17241692        # block signals temporarily, so we don't end up 
    17251693        # updating charts with every single model change on the end of fitting 
    1726         self._poly_model.itemChanged.disconnect() 
     1694        self._poly_model.blockSignals(True) 
    17271695        self.iterateOverPolyModel(updateFittedValues) 
    1728         self._poly_model.itemChanged.connect(self.onPolyModelChange) 
     1696        self._poly_model.blockSignals(False) 
    17291697 
    17301698        if self.has_poly_error_column: 
     
    17361704 
    17371705        # switch off reponse to model change 
     1706        self._poly_model.blockSignals(True) 
    17381707        self._poly_model.insertColumn(2, error_column) 
     1708        self._poly_model.blockSignals(False) 
    17391709        FittingUtilities.addErrorPolyHeadersToModel(self._poly_model) 
    17401710 
     
    17691739            param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 
    17701740            self._magnet_model.item(row, 1).setText(param_repr) 
    1771             self.kernel_module.setParam(param_name, param_dict[param_name][0]) 
    17721741            if self.has_magnet_error_column: 
    17731742                error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
     
    17891758        # block signals temporarily, so we don't end up 
    17901759        # updating charts with every single model change on the end of fitting 
    1791         self._magnet_model.itemChanged.disconnect() 
     1760        self._magnet_model.blockSignals(True) 
    17921761        self.iterateOverMagnetModel(updateFittedValues) 
    1793         self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 
     1762        self._magnet_model.blockSignals(False) 
    17941763 
    17951764        if self.has_magnet_error_column: 
     
    18011770 
    18021771        # switch off reponse to model change 
     1772        self._magnet_model.blockSignals(True) 
    18031773        self._magnet_model.insertColumn(2, error_column) 
     1774        self._magnet_model.blockSignals(False) 
    18041775        FittingUtilities.addErrorHeadersToModel(self._magnet_model) 
    18051776 
     
    18131784        self.cmdPlot.setText("Show Plot") 
    18141785        # Force data recalculation so existing charts are updated 
     1786        self.recalculatePlotData() 
    18151787        self.showPlot() 
    1816         # This is an important processEvent. 
    1817         # This allows charts to be properly updated in order 
    1818         # of plots being applied. 
    1819         QtWidgets.QApplication.processEvents() 
    1820         self.recalculatePlotData() 
    18211788 
    18221789    def onSmearingOptionsUpdate(self): 
     
    19831950        # Crete/overwrite model items 
    19841951        self._model_model.clear() 
    1985         self._poly_model.clear() 
    1986         self._magnet_model.clear() 
    1987  
    1988         if model_name is None: 
    1989             if structure_factor not in (None, "None"): 
    1990                 # S(Q) on its own, treat the same as a form factor 
    1991                 self.kernel_module = None 
    1992                 self.fromStructureFactorToQModel(structure_factor) 
    1993             else: 
    1994                 # No models selected 
    1995                 return 
     1952 
     1953        # First, add parameters from the main model 
     1954        if model_name is not None: 
     1955            self.fromModelToQModel(model_name) 
     1956 
     1957        # Then, add structure factor derived parameters 
     1958        if structure_factor is not None and structure_factor != "None": 
     1959            if model_name is None: 
     1960                # Instantiate the current sasmodel for SF-only models 
     1961                self.kernel_module = self.models[structure_factor]() 
     1962            self.fromStructureFactorToQModel(structure_factor) 
    19961963        else: 
    1997             self.fromModelToQModel(model_name) 
    1998             self.addExtraShells() 
    1999  
    20001964            # Allow the SF combobox visibility for the given sasmodel 
    20011965            self.enableStructureFactorControl(structure_factor) 
    2002          
    2003             # Add S(Q) 
    20041966            if self.cbStructureFactor.isEnabled(): 
    20051967                structure_factor = self.cbStructureFactor.currentText() 
    20061968                self.fromStructureFactorToQModel(structure_factor) 
    20071969 
    2008             # Add polydispersity to the model 
    2009             self.poly_params = {} 
    2010             self.setPolyModel() 
    2011             # Add magnetic parameters to the model 
    2012             self.magnet_params = {} 
    2013             self.setMagneticModel() 
     1970        # Then, add multishells 
     1971        if model_name is not None: 
     1972            # Multishell models need additional treatment 
     1973            self.addExtraShells() 
     1974 
     1975        # Add polydispersity to the model 
     1976        self.setPolyModel() 
     1977        # Add magnetic parameters to the model 
     1978        self.setMagneticModel() 
    20141979 
    20151980        # Adjust the table cells width 
     
    20842049        self.shell_names = self.shellNamesList() 
    20852050 
    2086         # Add heading row 
    2087         FittingUtilities.addHeadingRowToModel(self._model_model, model_name) 
    2088  
    20892051        # Update the QModel 
    2090         FittingUtilities.addParametersToModel( 
    2091                 self.model_parameters, 
    2092                 self.kernel_module, 
    2093                 self.is2D, 
    2094                 self._model_model, 
    2095                 self.lstParams) 
     2052        new_rows = FittingUtilities.addParametersToModel(self.model_parameters, self.kernel_module, self.is2D) 
     2053 
     2054        for row in new_rows: 
     2055            self._model_model.appendRow(row) 
     2056        # Update the counter used for multishell display 
     2057        self._last_model_row = self._model_model.rowCount() 
    20962058 
    20972059    def fromStructureFactorToQModel(self, structure_factor): 
     
    21012063        if structure_factor is None or structure_factor=="None": 
    21022064            return 
    2103  
    2104         product_params = None 
    2105  
    2106         if self.kernel_module is None: 
    2107             # Structure factor is the only selected model; build it and show all its params 
    2108             self.kernel_module = self.models[structure_factor]() 
    2109             s_params = self.kernel_module._model_info.parameters 
    2110             s_params_orig = s_params 
    2111         else: 
    2112             s_kernel = self.models[structure_factor]() 
    2113             p_kernel = self.kernel_module 
    2114  
    2115             p_pars_len = len(p_kernel._model_info.parameters.kernel_parameters) 
    2116             s_pars_len = len(s_kernel._model_info.parameters.kernel_parameters) 
    2117  
    2118             self.kernel_module = MultiplicationModel(p_kernel, s_kernel) 
    2119             all_params = self.kernel_module._model_info.parameters.kernel_parameters 
    2120             all_param_names = [param.name for param in all_params] 
    2121  
    2122             # S(Q) params from the product model are not necessarily the same as those from the S(Q) model; any 
    2123             # conflicting names with P(Q) params will cause a rename 
    2124  
    2125             if "radius_effective_mode" in all_param_names: 
    2126                 # Show all parameters 
    2127                 # In this case, radius_effective is NOT pruned by sasmodels.product 
    2128                 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len]) 
    2129                 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters) 
    2130                 product_params = modelinfo.ParameterTable( 
    2131                         self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 
    2132             else: 
    2133                 # Ensure radius_effective is not displayed 
    2134                 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters[1:]) 
    2135                 if "radius_effective" in all_param_names: 
    2136                     # In this case, radius_effective is NOT pruned by sasmodels.product 
    2137                     s_params = modelinfo.ParameterTable(all_params[p_pars_len+1:p_pars_len+s_pars_len]) 
    2138                     product_params = modelinfo.ParameterTable( 
    2139                             self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 
    2140                 else: 
    2141                     # In this case, radius_effective is pruned by sasmodels.product 
    2142                     s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len-1]) 
    2143                     product_params = modelinfo.ParameterTable( 
    2144                             self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len-1:]) 
    2145  
    2146         # Add heading row 
    2147         FittingUtilities.addHeadingRowToModel(self._model_model, structure_factor) 
    2148  
    2149         # Get new rows for QModel 
    2150         # Any renamed parameters are stored as data in the relevant item, for later handling 
    2151         FittingUtilities.addSimpleParametersToModel( 
    2152                 parameters=s_params, 
    2153                 is2D=self.is2D, 
    2154                 parameters_original=s_params_orig, 
    2155                 model=self._model_model, 
    2156                 view=self.lstParams) 
    2157  
    2158         # Insert product-only params into QModel 
    2159         if product_params: 
    2160             prod_rows = FittingUtilities.addSimpleParametersToModel( 
    2161                     parameters=product_params, 
    2162                     is2D=self.is2D, 
    2163                     parameters_original=None, 
    2164                     model=self._model_model, 
    2165                     view=self.lstParams, 
    2166                     row_num=2) 
    2167  
    2168             # Since this all happens after shells are dealt with and we've inserted rows, fix this counter 
    2169             self._n_shells_row += len(prod_rows) 
     2065        structure_module = generate.load_kernel_module(structure_factor) 
     2066        structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', [])) 
     2067 
     2068        structure_kernel = self.models[structure_factor]() 
     2069        form_kernel = self.kernel_module 
     2070 
     2071        self.kernel_module = MultiplicationModel(form_kernel, structure_kernel) 
     2072 
     2073        new_rows = FittingUtilities.addSimpleParametersToModel(structure_parameters, self.is2D) 
     2074        for row in new_rows: 
     2075            self._model_model.appendRow(row) 
     2076            # disable fitting of parameters not listed in self.kernel_module (probably radius_effective) 
     2077            if row[0].text() not in self.kernel_module.params.keys(): 
     2078                row_num = self._model_model.rowCount() - 1 
     2079                FittingUtilities.markParameterDisabled(self._model_model, row_num) 
     2080 
     2081        # Update the counter used for multishell display 
     2082        self._last_model_row = self._model_model.rowCount() 
    21702083 
    21712084    def haveParamsToFit(self): 
     
    21932106        model_row = item.row() 
    21942107        name_index = self._model_model.index(model_row, 0) 
    2195         name_item = self._model_model.itemFromIndex(name_index) 
    21962108 
    21972109        # Extract changed value. 
     
    22022114            return 
    22032115 
    2204         # if the item has user data, this is the actual parameter name (e.g. to handle duplicate names) 
    2205         if name_item.data(QtCore.Qt.UserRole): 
    2206             parameter_name = str(name_item.data(QtCore.Qt.UserRole)) 
    2207         else: 
    2208             parameter_name = str(self._model_model.data(name_index)) 
     2116        parameter_name = str(self._model_model.data(name_index)) # sld, background etc. 
    22092117 
    22102118        # Update the parameter value - note: this supports +/-inf as well 
     
    23292237        return self.completed1D if isinstance(self.data, Data1D) else self.completed2D 
    23302238 
    2331     def updateKernelModelWithExtraParams(self, model=None): 
    2332         """ 
    2333         Updates kernel model 'model' with extra parameters from 
    2334         the polydisp and magnetism tab, if the tabs are enabled 
    2335         """ 
    2336         if model is None: return 
    2337         if not hasattr(model, 'setParam'): return 
    2338  
    2339         # add polydisperse parameters if asked 
    2340         if self.chkPolydispersity.isChecked(): 
    2341             for key, value in self.poly_params.items(): 
    2342                 model.setParam(key, value) 
    2343         # add magnetic params if asked 
    2344         if self.chkMagnetism.isChecked(): 
    2345             for key, value in self.magnet_params.items(): 
    2346                 model.setParam(key, value) 
    2347  
    23482239    def calculateQGridForModelExt(self, data=None, model=None, completefn=None, use_threads=True): 
    23492240        """ 
     
    23532244            data = self.data 
    23542245        if model is None: 
    2355             model = copy.deepcopy(self.kernel_module) 
    2356             self.updateKernelModelWithExtraParams(model) 
    2357  
     2246            model = self.kernel_module 
    23582247        if completefn is None: 
    23592248            completefn = self.methodCompleteForData() 
     
    24282317 
    24292318        # Create plots for intermediate product data 
    2430         plots = self.logic.new1DProductPlots(return_data, self.tab_id) 
    2431         for plot in plots: 
    2432             plot.symbol = "Line" 
    2433             self.createNewIndex(plot) 
    2434             new_plots.append(plot) 
    2435  
    2436         for plot in new_plots: 
    2437             self.communicate.plotUpdateSignal.emit([plot]) 
    2438  
    2439     def complete2D(self, return_data): 
    2440         """ 
    2441         Plot the current 2D data 
    2442         """ 
    2443         fitted_data = self.logic.new2DPlot(return_data) 
    2444         residuals = self.calculateResiduals(fitted_data) 
    2445         self.model_data = fitted_data 
    2446         new_plots = [fitted_data] 
    2447         if residuals is not None: 
    2448             new_plots.append(residuals) 
     2319        pq_data, sq_data = self.logic.new1DProductPlots(return_data, self.tab_id) 
     2320        if pq_data is not None: 
     2321            pq_data.symbol = "Line" 
     2322            self.createNewIndex(pq_data) 
     2323            # self.communicate.plotUpdateSignal.emit([pq_data]) 
     2324            new_plots.append(pq_data) 
     2325        if sq_data is not None: 
     2326            sq_data.symbol = "Line" 
     2327            self.createNewIndex(sq_data) 
     2328            # self.communicate.plotUpdateSignal.emit([sq_data]) 
     2329            new_plots.append(sq_data) 
    24492330 
    24502331        # Update/generate plots 
    24512332        for plot in new_plots: 
    24522333            self.communicate.plotUpdateSignal.emit([plot]) 
     2334 
     2335    def complete2D(self, return_data): 
     2336        """ 
     2337        Plot the current 2D data 
     2338        """ 
     2339        fitted_data = self.logic.new2DPlot(return_data) 
     2340        self.calculateResiduals(fitted_data) 
     2341        self.model_data = fitted_data 
    24532342 
    24542343    def calculateResiduals(self, fitted_data): 
     
    25812470        _, min, max = self.kernel_module.details[param_name] 
    25822471 
    2583         # Update local param dict 
    2584         self.poly_params[param_name + '.width'] = width 
    2585         self.poly_params[param_name + '.npts'] = npts 
    2586         self.poly_params[param_name + '.nsigmas'] = nsigs 
    2587  
    25882472        # Construct a row with polydisp. related variable. 
    25892473        # This will get added to the polydisp. model 
     
    26332517        def updateFunctionCaption(row): 
    26342518            # Utility function for update of polydispersity function name in the main model 
    2635             if not self.isCheckable(row): 
    2636                 return 
    2637             self._model_model.blockSignals(True) 
    26382519            param_name = str(self._model_model.item(row, 0).text()) 
    2639             self._model_model.blockSignals(False) 
    26402520            if param_name !=  param.name: 
    26412521                return 
    26422522            # Modify the param value 
    2643             self._model_model.blockSignals(True) 
    26442523            if self.has_error_column: 
    26452524                # err column changes the indexing 
     
    26472526            else: 
    26482527                self._model_model.item(row, 0).child(0).child(0,4).setText(combo_string) 
    2649             self._model_model.blockSignals(False) 
    26502528 
    26512529        if combo_string == 'array': 
     
    27662644                        param.units] 
    27672645 
    2768         self.magnet_params[param.name] = param.default 
    2769  
    27702646        FittingUtilities.addCheckedListToModel(model, checked_list) 
    27712647 
     
    28072683 
    28082684        self.lstParams.setIndexWidget(shell_index, func) 
    2809         self._n_shells_row = shell_row - 1 
     2685        self._last_model_row = self._model_model.rowCount() 
    28102686 
    28112687        # Set the index to the state-kept value 
     
    28182694        """ 
    28192695        # Find row location of the combobox 
    2820         first_row = self._n_shells_row + 1 
    2821         remove_rows = self._num_shell_params 
     2696        last_row = self._last_model_row 
     2697        remove_rows = self._model_model.rowCount() - last_row 
    28222698 
    28232699        if remove_rows > 1: 
    2824             self._model_model.removeRows(first_row, remove_rows) 
    2825  
    2826         new_rows = FittingUtilities.addShellsToModel( 
    2827                 self.model_parameters, 
    2828                 self._model_model, 
    2829                 index, 
    2830                 first_row, 
    2831                 self.lstParams) 
    2832  
    2833         self._num_shell_params = len(new_rows) 
     2700            self._model_model.removeRows(last_row, remove_rows) 
     2701 
     2702        FittingUtilities.addShellsToModel(self.model_parameters, self._model_model, index) 
    28342703        self.current_shell_displayed = index 
    2835  
    2836         # Change 'n' in the parameter model, thereby updating the underlying model 
    2837         self._model_model.item(self._n_shells_row, 1).setText(str(index)) 
    28382704 
    28392705        # Update relevant models 
     
    31803046            formatted_output = FittingUtilities.formatParameters(param_list) 
    31813047        elif format == "Excel": 
    3182             formatted_output = FittingUtilities.formatParametersExcel(param_list[1:]) 
     3048            formatted_output = FittingUtilities.formatParametersExcel(param_list) 
    31833049        elif format == "Latex": 
    3184             formatted_output = FittingUtilities.formatParametersLatex(param_list[1:]) 
     3050            formatted_output = FittingUtilities.formatParametersLatex(param_list) 
    31853051        else: 
    31863052            raise AttributeError("Bad format specifier.") 
     
    33473213        self._poly_model.blockSignals(False) 
    33483214 
    3349  
    3350  
  • src/sas/qtgui/Perspectives/Fitting/ModelThread.py

    r5181e9b r2df558e  
    101101        elapsed = time.time() - self.starttime 
    102102 
    103         res = dict(image = output, data = self.data, page_id = self.page_id, 
    104             model = self.model, state = self.state, 
    105             toggle_mode_on = self.toggle_mode_on, elapsed = elapsed, 
    106             index = index_model, fid = self.fid, 
    107             qmin = self.qmin, qmax = self.qmax, 
    108             weight = self.weight, update_chisqr = self.update_chisqr, 
    109             source = self.source) 
    110  
    111103        if LocalConfig.USING_TWISTED: 
    112             return res 
    113         else: 
    114             self.completefn(res) 
     104            return (output, 
     105                    self.data, 
     106                    self.page_id, 
     107                    self.model, 
     108                    self.state, 
     109                    self.toggle_mode_on, 
     110                    elapsed, 
     111                    index_model, 
     112                    self.fid, 
     113                    self.qmin, 
     114                    self.qmax, 
     115                    self.weight, 
     116                    self.update_chisqr, 
     117                    self.source) 
     118        else: 
     119            self.completefn((output, 
     120                           self.data, 
     121                           self.page_id, 
     122                           self.model, 
     123                           self.state, 
     124                           self.toggle_mode_on, 
     125                           elapsed, 
     126                           index_model, 
     127                           self.fid, 
     128                           self.qmin, 
     129                           self.qmax, 
     130                           self.weight, 
     131                           #qstep=self.qstep, 
     132                           self.update_chisqr, 
     133                           self.source)) 
     134 
    115135 
    116136class Calc1D(CalcThread): 
     
    164184        index = (self.qmin <= self.data.x) & (self.data.x <= self.qmax) 
    165185 
    166         intermediate_results = None 
    167  
    168186        # If we use a smearer, also return the unsmeared model 
    169187        unsmeared_output = None 
     
    176194            mask = self.data.x[first_bin:last_bin+1] 
    177195            unsmeared_output = numpy.zeros((len(self.data.x))) 
    178  
    179             return_data = self.model.calculate_Iq(mask) 
    180             if isinstance(return_data, tuple): 
    181                 # see sasmodels beta_approx: SasviewModel.calculate_Iq 
    182                 # TODO: implement intermediate results in smearers 
    183                 return_data, _ = return_data 
    184             unsmeared_output[first_bin:last_bin+1] = return_data 
     196            unsmeared_output[first_bin:last_bin+1] = self.model.evalDistribution(mask) 
    185197            output = self.smearer(unsmeared_output, first_bin, last_bin) 
    186198 
     
    201213                unsmeared_error=unsmeared_error 
    202214        else: 
    203             return_data = self.model.calculate_Iq(self.data.x[index]) 
    204             if isinstance(return_data, tuple): 
    205                 # see sasmodels beta_approx: SasviewModel.calculate_Iq 
    206                 return_data, intermediate_results = return_data 
    207             output[index] = return_data 
    208  
    209         if intermediate_results: 
    210             # the model returns a callable which is then used to retrieve the data 
    211             intermediate_results = intermediate_results() 
    212         else: 
    213             # TODO: this conditional branch needs refactoring 
    214             sq_values = None 
    215             pq_values = None 
    216             s_model = None 
    217             p_model = None 
    218  
    219             if isinstance(self.model, MultiplicationModel): 
    220                 s_model = self.model.s_model 
    221                 p_model = self.model.p_model 
    222  
    223             elif hasattr(self.model, "calc_composition_models"): 
    224                 results = self.model.calc_composition_models(self.data.x[index]) 
    225                 if results is not None: 
    226                     pq_values, sq_values = results 
    227  
    228             if pq_values is None or sq_values is None: 
    229                 if p_model is not None and s_model is not None: 
    230                     sq_values = numpy.zeros((len(self.data.x))) 
    231                     pq_values = numpy.zeros((len(self.data.x))) 
    232                     sq_values[index] = s_model.evalDistribution(self.data.x[index]) 
    233                     pq_values[index] = p_model.evalDistribution(self.data.x[index]) 
    234  
    235             if pq_values is not None and sq_values is not None: 
    236                 intermediate_results  = { 
    237                     "P(Q)": pq_values, 
    238                     "S(Q)": sq_values 
    239                 } 
    240             else: 
    241                 intermediate_results = {} 
     215            output[index] = self.model.evalDistribution(self.data.x[index]) 
     216 
     217        sq_values = None 
     218        pq_values = None 
     219        s_model = None 
     220        p_model = None 
     221        if isinstance(self.model, MultiplicationModel): 
     222            s_model = self.model.s_model 
     223            p_model = self.model.p_model 
     224        elif hasattr(self.model, "calc_composition_models"): 
     225            results = self.model.calc_composition_models(self.data.x[index]) 
     226            if results is not None: 
     227                pq_values, sq_values = results 
     228 
     229        if pq_values is None or sq_values is None: 
     230            if p_model is not None and s_model is not None: 
     231                sq_values = numpy.zeros((len(self.data.x))) 
     232                pq_values = numpy.zeros((len(self.data.x))) 
     233                sq_values[index] = s_model.evalDistribution(self.data.x[index]) 
     234                pq_values[index] = p_model.evalDistribution(self.data.x[index]) 
    242235 
    243236        elapsed = time.time() - self.starttime 
    244237 
    245         res = dict(x = self.data.x[index], y = output[index], 
    246             page_id = self.page_id, state = self.state, weight = self.weight, 
    247             fid = self.fid, toggle_mode_on = self.toggle_mode_on, 
    248             elapsed = elapsed, index = index, model = self.model, 
    249             data = self.data, update_chisqr = self.update_chisqr, 
    250             source = self.source, unsmeared_output = unsmeared_output, 
    251             unsmeared_data = unsmeared_data, unsmeared_error = unsmeared_error, 
    252             intermediate_results = intermediate_results) 
    253  
    254238        if LocalConfig.USING_TWISTED: 
    255             return res 
    256         else: 
    257             self.completefn(res) 
     239            return (self.data.x[index], output[index], 
     240                    self.page_id, 
     241                    self.state, 
     242                    self.weight, 
     243                    self.fid, 
     244                    self.toggle_mode_on, 
     245                    elapsed, index, self.model, 
     246                    self.data, 
     247                    self.update_chisqr, 
     248                    self.source, 
     249                    unsmeared_output, unsmeared_data, unsmeared_error, 
     250                    pq_values, sq_values) 
     251        else: 
     252            self.completefn((self.data.x[index], output[index], 
     253                        self.page_id, 
     254                        self.state, 
     255                        self.weight, 
     256                        self.fid, 
     257                        self.toggle_mode_on, 
     258                        elapsed, index, self.model, 
     259                        self.data, 
     260                        self.update_chisqr, 
     261                        self.source, 
     262                        unsmeared_output, unsmeared_data, unsmeared_error, 
     263                        pq_values, sq_values)) 
    258264 
    259265    def results(self): 
  • src/sas/qtgui/Perspectives/Fitting/UI/OptionsWidgetUI.ui

    r309fa1b r79bd268  
    3232        <item row="0" column="1"> 
    3333         <widget class="QLineEdit" name="txtMinRange"> 
    34           <property name="minimumSize"> 
    35            <size> 
    36             <width>80</width> 
    37             <height>0</height> 
    38            </size> 
    39           </property> 
    4034          <property name="toolTip"> 
    4135           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum value of Q.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     
    6054        <item row="1" column="1"> 
    6155         <widget class="QLineEdit" name="txtMaxRange"> 
    62           <property name="minimumSize"> 
    63            <size> 
    64             <width>80</width> 
    65             <height>0</height> 
    66            </size> 
    67           </property> 
    6856          <property name="toolTip"> 
    6957           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum value of Q.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingLogicTest.py

    rbfb5d9e re752ab8  
    9999        data.name = "boop" 
    100100        data.id = "poop" 
    101         # Condensed return data (new1DPlot only uses these fields) 
    102         return_data = dict(x = data.x, 
    103                            y = data.y, 
    104                            model = data, 
    105                            data = data) 
    106         # return_data = (data.x,data.y, 7, None, None, 
    107         #                0, True, 0.0, 1, data, 
    108         #                data, False, None, 
    109         #                None, None, None, 
    110         #                None, None) 
     101        return_data = (data.x,data.y, 7, None, None, 
     102                       0, True, 0.0, 1, data, 
     103                       data, False, None, 
     104                       None, None, None, 
     105                       None, None) 
    111106 
    112107        new_plot = self.logic.new1DPlot(return_data=return_data, tab_id=0) 
     
    144139        qmin, qmax, npts = self.logic.computeDataRange() 
    145140 
    146         # Condensed return data (new2DPlot only uses these fields) 
    147         return_data = dict(image = x_0, 
    148                            data = data, 
    149                            page_id = 7, 
    150                            model = data) 
    151         # return_data = (x_0, data, 7, data, None, 
    152         #                 True, 0.0, 1, 0, qmin, qmax, 
    153         #                 0.1, False, None) 
     141        return_data = (x_0, data, 7, data, None, 
     142                        True, 0.0, 1, 0, qmin, qmax, 
     143                        0.1, False, None) 
    154144 
    155145        new_plot = self.logic.new2DPlot(return_data=return_data) 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingOptionsTest.py

    rbfb5d9e r725d9c06  
    3838        # The combo box 
    3939        self.assertIsInstance(self.widget.cbAlgorithm, QtWidgets.QComboBox) 
    40         self.assertEqual(self.widget.cbAlgorithm.count(), 6) 
     40        self.assertEqual(self.widget.cbAlgorithm.count(), 5) 
    4141        self.assertEqual(self.widget.cbAlgorithm.itemText(0), 'Nelder-Mead Simplex') 
    4242        self.assertEqual(self.widget.cbAlgorithm.itemText(4), 'Levenberg-Marquardt') 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py

    r3fbd77b r605d944  
    256256        self.widget.cbStructureFactor.setCurrentIndex(structure_index) 
    257257 
    258         # We have 3 more param rows now (radius_effective is removed), and a new heading 
     258        # We have 4 more rows now 
    259259        self.assertEqual(self.widget._model_model.rowCount(), rowcount+4) 
    260260 
     
    276276        last_index = self.widget.cbStructureFactor.count() 
    277277        self.widget.cbStructureFactor.setCurrentIndex(last_index-1) 
    278         # Do we have all the rows (incl. radius_effective & heading row)? 
    279         self.assertEqual(self.widget._model_model.rowCount(), 5) 
     278        # Do we have all the rows? 
     279        self.assertEqual(self.widget._model_model.rowCount(), 4) 
    280280 
    281281        # Are the command buttons properly enabled? 
     
    445445        self.assertEqual(self.widget.kernel_module.details['radius_bell'][1], 1.0) 
    446446 
    447         #self.widget.show() 
    448         #QtWidgets.QApplication.exec_() 
    449  
    450447        # Change the number of points 
    451         self.assertEqual(self.widget.poly_params['radius_bell.npts'], 35) 
     448        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 
    452449        self.widget._poly_model.item(0,4).setText("22") 
    453         self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
     450        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
    454451        # try something stupid 
    455452        self.widget._poly_model.item(0,4).setText("butt") 
    456453        # see that this didn't annoy the control at all 
    457         self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
     454        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
    458455 
    459456        # Change the number of sigmas 
    460         self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 3) 
     457        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 3) 
    461458        self.widget._poly_model.item(0,5).setText("222") 
    462         self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
     459        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
    463460        # try something stupid again 
    464461        self.widget._poly_model.item(0,4).setText("beer") 
    465462        # no efect 
    466         self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
     463        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
    467464 
    468465    def testOnPolyComboIndexChange(self): 
     
    485482        self.widget.onPolyComboIndexChange('rectangle', 0) 
    486483        # check values 
    487         self.assertEqual(self.widget.poly_params['radius_bell.npts'], 35) 
    488         self.assertAlmostEqual(self.widget.poly_params['radius_bell.nsigmas'], 1.73205, 5) 
     484        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 
     485        self.assertAlmostEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 1.73205, 5) 
    489486        # Change the index 
    490487        self.widget.onPolyComboIndexChange('lognormal', 0) 
    491488        # check values 
    492         self.assertEqual(self.widget.poly_params['radius_bell.npts'], 80) 
    493         self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 8) 
     489        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
     490        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 
    494491        # Change the index 
    495492        self.widget.onPolyComboIndexChange('schulz', 0) 
    496493        # check values 
    497         self.assertEqual(self.widget.poly_params['radius_bell.npts'], 80) 
    498         self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 8) 
     494        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
     495        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 
    499496 
    500497        # mock up file load 
     
    509506        Test opening of the load file dialog for 'array' polydisp. function 
    510507        """ 
    511  
    512         # open a non-existent file 
    513508        filename = os.path.join("UnitTesting", "testdata_noexist.txt") 
    514         with self.assertRaises(OSError, msg="testdata_noexist.txt should be a non-existent file"): 
    515             os.stat(filename) 
    516509        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 
    517510        self.widget.show() 
     
    529522 
    530523        # good file 
    531         # TODO: this depends on the working directory being src/sas/qtgui, 
    532         # TODO: which isn't convenient if you want to run this test suite 
    533         # TODO: individually 
    534524        filename = os.path.join("UnitTesting", "testdata.txt") 
    535         try: 
    536             os.stat(filename) 
    537         except OSError: 
    538             self.assertTrue(False, "testdata.txt does not exist") 
    539525        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 
    540526 
     
    602588 
    603589        # Assure we have the combobox available 
    604         cbox_row = self.widget._n_shells_row 
    605         func_index = self.widget._model_model.index(cbox_row, 1) 
     590        last_row = self.widget._last_model_row 
     591        func_index = self.widget._model_model.index(last_row-1, 1) 
    606592        self.assertIsInstance(self.widget.lstParams.indexWidget(func_index), QtWidgets.QComboBox) 
    607  
    608         # get number of rows before changing shell count 
    609         last_row = self.widget._model_model.rowCount() 
    610593 
    611594        # Change the combo box index 
     
    10411024 
    10421025         # Check the model 
    1043         self.assertEqual(self.widget._model_model.rowCount(), 7) 
     1026        self.assertEqual(self.widget._model_model.rowCount(), 6) 
    10441027        self.assertEqual(self.widget._model_model.columnCount(), 5) 
    10451028 
     
    11571140        # two rows selected 
    11581141        index1 = self.widget.lstParams.model().index(1, 0, QtCore.QModelIndex()) 
    1159         index2 = self.widget.lstParams.model().index(3, 0, QtCore.QModelIndex()) 
     1142        index2 = self.widget.lstParams.model().index(2, 0, QtCore.QModelIndex()) 
    11601143        selection_model = self.widget.lstParams.selectionModel() 
    11611144        selection_model.select(index1, selection_model.Select | selection_model.Rows) 
     
    11931176        # several random parameters 
    11941177        self.assertEqual(self.widget.getRowFromName('scale'), 0) 
    1195         self.assertEqual(self.widget.getRowFromName('length'), 6) 
     1178        self.assertEqual(self.widget.getRowFromName('length'), 5) 
    11961179 
    11971180    def testGetParamNames(self): 
     
    12301213        # Create a constraint object 
    12311214        const = Constraint(parent=None, value=7.0) 
    1232         row = 3 
     1215        row = 2 
    12331216 
    12341217        spy = QtSignalSpy(self.widget, self.widget.constraintAddedSignal) 
     
    12491232        # assign complex constraint now 
    12501233        const = Constraint(parent=None, param='radius', func='5*sld') 
    1251         row = 5 
     1234        row = 4 
    12521235        # call the method tested 
    12531236        self.widget.addConstraintToRow(constraint=const, row=row) 
     
    13081291        self.widget.cbModel.setCurrentIndex(model_index) 
    13091292 
     1293        # select two rows 
    13101294        row1 = 1 
    1311         row2 = 5 
    1312  
    1313         param1 = "background" 
    1314         param2 = "radius" 
    1315  
    1316         #default_value1 = "0.001" 
    1317         default_value2 = "20" 
    1318  
    1319         # select two rows 
     1295        row2 = 4 
    13201296        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    13211297        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13341310 
    13351311        # delete one of the constraints 
    1336         self.widget.deleteConstraintOnParameter(param=param1) 
     1312        self.widget.deleteConstraintOnParameter(param='background') 
    13371313 
    13381314        # see that the other constraint is still present 
    1339         cons = self.widget.getConstraintForRow(row2) 
    1340         self.assertEqual(cons.param, param2) 
    1341         self.assertEqual(cons.value, default_value2) 
     1315        cons = self.widget.getConstraintForRow(4) # 4 = radius 
     1316        self.assertEqual(cons.param, "radius") 
     1317        self.assertEqual(cons.value, "20") 
    13421318 
    13431319        # kill the other constraint 
     
    13451321 
    13461322        # see that the other constraint is still present 
    1347         self.assertEqual(self.widget.getConstraintsForModel(), [(param2, None)]) 
     1323        self.assertEqual(self.widget.getConstraintsForModel(), [('radius', None)]) 
    13481324 
    13491325    def testGetConstraintForRow(self): 
     
    13651341        self.widget.cbModel.setCurrentIndex(model_index) 
    13661342 
     1343        # select two rows 
    13671344        row1 = 1 
    1368         row2 = 5 
    1369  
    1370         # select two rows 
     1345        row2 = 4 
    13711346        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    13721347        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13781353        self.widget.addSimpleConstraint() 
    13791354 
    1380         con_list = [False, True, False, False, False, True, False] 
     1355        con_list = [False, True, False, False, True, False] 
    13811356        new_list = [] 
    13821357        for row in range(self.widget._model_model.rowCount()): 
     
    13961371        self.widget.cbModel.setCurrentIndex(model_index) 
    13971372 
     1373        # select two rows 
    13981374        row1 = 1 
    1399         row2 = 5 
    1400  
    1401         # select two rows 
     1375        row2 = 4 
    14021376        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    14031377        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    14131387        constraint_objects[0].active = False 
    14141388 
    1415         con_list = [False, False, False, False, False, True, False] 
     1389        con_list = [False, False, False, False, True, False] 
    14161390        new_list = [] 
    14171391        for row in range(self.widget._model_model.rowCount()): 
     
    14341408        self.assertEqual(self.widget.getConstraintsForModel(),[]) 
    14351409 
     1410        # select two rows 
    14361411        row1 = 1 
    1437         row2 = 5 
    1438  
    1439         param1 = "background" 
    1440         param2 = "radius" 
    1441  
    1442         default_value1 = "0.001" 
    1443         default_value2 = "20" 
    1444  
    1445         # select two rows 
     1412        row2 = 4 
    14461413        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    14471414        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    14551422        # simple constraints 
    14561423        # self.assertEqual(self.widget.getConstraintsForModel(), [('background', '0.001'), ('radius', '20')]) 
    1457         cons = self.widget.getConstraintForRow(row1) 
    1458         self.assertEqual(cons.param, param1) 
    1459         self.assertEqual(cons.value, default_value1) 
    1460         cons = self.widget.getConstraintForRow(row2) 
    1461         self.assertEqual(cons.param, param2) 
    1462         self.assertEqual(cons.value, default_value2) 
     1424        cons = self.widget.getConstraintForRow(1) # 1 - background 
     1425        self.assertEqual(cons.param, "background") 
     1426        self.assertEqual(cons.value, "0.001") 
     1427        cons = self.widget.getConstraintForRow(4) # 4 = radius 
     1428        self.assertEqual(cons.param, "radius") 
     1429        self.assertEqual(cons.value, "20") 
    14631430 
    14641431        objects = self.widget.getConstraintObjectsForModel() 
    14651432        self.assertEqual(len(objects), 2) 
    1466         self.assertEqual(objects[1].value, default_value2) 
    1467         self.assertEqual(objects[0].param, param1) 
    1468  
     1433        self.assertEqual(objects[1].value, '20') 
     1434        self.assertEqual(objects[0].param, 'background') 
     1435 
     1436        # add complex constraint 
     1437        const = Constraint(parent=None, param='scale', func='5*sld') 
    14691438        row = 0 
    1470         param = "scale" 
    1471         func = "5*sld" 
    1472  
    1473         # add complex constraint 
    1474         const = Constraint(parent=None, param=param, func=func) 
    14751439        self.widget.addConstraintToRow(constraint=const, row=row) 
    14761440        #self.assertEqual(self.widget.getConstraintsForModel(),[('scale', '5*sld'), ('background', '0.001'), ('radius', None)]) 
    1477         cons = self.widget.getConstraintForRow(row2) 
    1478         self.assertEqual(cons.param, param2) 
    1479         self.assertEqual(cons.value, default_value2) 
     1441        cons = self.widget.getConstraintForRow(4) # 4 = radius 
     1442        self.assertEqual(cons.param, "radius") 
     1443        self.assertEqual(cons.value, "20") 
    14801444 
    14811445        objects = self.widget.getConstraintObjectsForModel() 
    14821446        self.assertEqual(len(objects), 3) 
    1483         self.assertEqual(objects[0].func, func) 
     1447        self.assertEqual(objects[0].func, '5*sld') 
    14841448 
    14851449    def testReplaceConstraintName(self): 
  • src/sas/qtgui/Plotting/Plotter.py

    r0cd98a1 rb764ae5  
    3030        # Dictionary of {plot_id:Data1d} 
    3131        self.plot_dict = {} 
    32         # Dictionaty of {plot_id:line} 
    33  
    34         self.plot_lines = {} 
     32 
    3533        # Window for text add 
    3634        self.addText = AddText(self) 
     
    182180 
    183181        # Update the list of data sets (plots) in chart 
    184         self.plot_dict[self._data.name] = self.data 
    185  
    186         self.plot_lines[self._data.name] = line 
     182        self.plot_dict[self._data.id] = self.data 
    187183 
    188184        # Now add the legend with some customizations. 
     
    200196 
    201197        # refresh canvas 
    202         self.canvas.draw() 
     198        self.canvas.draw_idle() 
     199        # This is an important processEvent. 
     200        # This allows charts to be properly updated in order 
     201        # of plots being applied. 
     202        QtWidgets.QApplication.processEvents() 
    203203 
    204204    def createContextMenu(self): 
     
    470470        """ 
    471471        selected_plot = self.plot_dict[id] 
    472         selected_line = self.plot_lines[id] 
     472 
    473473        # Old style color - single integer for enum color 
    474474        # New style color - #hhhhhh 
  • src/sas/qtgui/Utilities/GuiUtils.py

    r339e22b r0eff615  
    265265    # Mask Editor requested 
    266266    maskEditorSignal = QtCore.pyqtSignal(Data2D) 
    267  
    268     #second Mask Editor for external 
    269     extMaskEditorSignal = QtCore.pyqtSignal() 
    270267 
    271268    # Fitting parameter copy to clipboard 
Note: See TracChangeset for help on using the changeset viewer.