Changeset 12db2db6 in sasview for src


Ignore:
Timestamp:
Sep 7, 2018 12:25:19 PM (6 years ago)
Author:
Laura Forster <Awork@…>
Branches:
ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
2f14b5d, 0101c9f
Parents:
339e22b (diff), f0365a2e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'ESS_GUI' of https://github.com/SasView/sasview into ESS_GUI

Location:
src/sas/qtgui
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/MainWindow/DataExplorer.py

    r339e22b r12db2db6  
    560560        # Now query the model item for available plots 
    561561        plots = GuiUtils.plotsFromFilename(filename, model) 
    562         ids_keys = list(self.active_plots.keys()) 
    563         ids_vals = [val.data.id for val in self.active_plots.values()] 
    564562 
    565563        new_plots = [] 
    566564        for item, plot in plots.items(): 
    567             plot_id = plot.id 
    568             if plot_id in ids_keys: 
    569                 self.active_plots[plot_id].replacePlot(plot_id, plot) 
    570             elif plot_id in ids_vals: 
    571                 list(self.active_plots.values())[ids_vals.index(plot_id)].replacePlot(plot_id, plot) 
    572             else: 
     565            if not self.updatePlot(plot): 
    573566                # Don't plot intermediate results, e.g. P(Q), S(Q) 
    574                 match = GuiUtils.theory_plot_ID_pattern.match(plot_id) 
     567                match = GuiUtils.theory_plot_ID_pattern.match(plot.id) 
    575568                # 2nd match group contains the identifier for the intermediate result, if present (e.g. "[P(Q)]") 
    576569                if match and match.groups()[1] != None: 
     
    706699                self.active_plots[plot_set.id] = old_plot 
    707700 
    708     def updatePlot(self, new_data): 
    709         """ 
    710         Modify existing plot for immediate response 
    711         """ 
    712         data = new_data[0] 
     701    def updatePlot(self, data): 
     702        """ 
     703        Modify existing plot for immediate response and returns True. 
     704        Returns false, if the plot does not exist already. 
     705        """ 
     706        try: # there might be a list or a single value being passed 
     707            data = data[0] 
     708        except TypeError: 
     709            pass 
    713710        assert type(data).__name__ in ['Data1D', 'Data2D'] 
    714711 
     
    719716        if data_id in ids_keys: 
    720717            self.active_plots[data_id].replacePlot(data_id, data) 
     718            return True 
    721719        elif data_id in ids_vals: 
    722720            list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 
     721            return True 
     722        return False 
    723723 
    724724    def chooseFiles(self): 
  • src/sas/qtgui/Perspectives/Fitting/FittingLogic.py

    rb4d05bd rdcabba7  
    161161        Create a new 1D data instance based on fitting results 
    162162        """ 
    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) 
     163 
     164        return self._create1DPlot(tab_id, return_data['x'], return_data['y'], 
     165                                  return_data['model'], return_data['data']) 
    172166 
    173167    def new2DPlot(self, return_data): 
     
    175169        Create a new 2D data instance based on fitting results 
    176170        """ 
    177         image, data, page_id, model, state, toggle_mode_on,\ 
    178         elapsed, index, fid, qmin, qmax, weight, \ 
    179         update_chisqr, source = return_data 
     171        image = return_data['image'] 
     172        data = return_data['data'] 
     173        model = return_data['model'] 
    180174 
    181175        np.nan_to_num(image) 
     
    183177        new_plot.name = model.name + '2d' 
    184178        new_plot.title = "Analytical model 2D " 
    185         new_plot.id = str(page_id) + " " + data.name 
    186         new_plot.group_id = str(page_id) + " Model2D" 
     179        new_plot.id = str(return_data['page_id']) + " " + data.name 
     180        new_plot.group_id = str(return_data['page_id']) + " Model2D" 
    187181        new_plot.detector = data.detector 
    188182        new_plot.source = data.source 
     
    218212        (pq_plot, sq_plot). If either are unavailable, the corresponding plot is None. 
    219213        """ 
    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 
    227214 
    228215        pq_plot = None 
    229216        sq_plot = None 
    230217 
    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)") 
     218        if return_data.get('pq_values', None) is not None: 
     219            pq_plot = self._create1DPlot(tab_id, return_data['x'], 
     220                    return_data['pq_values'], return_data['model'], 
     221                    return_data['data'], component="P(Q)") 
     222        if return_data.get('sq_values', None) is not None: 
     223            sq_plot = self._create1DPlot(tab_id, return_data['x'], 
     224                    return_data['sq_values'], return_data['model'], 
     225                    return_data['data'], component="S(Q)") 
    235226 
    236227        return pq_plot, sq_plot 
  • src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py

    rb764ae5 rb69b549  
    88from sas.qtgui.Plotting.PlotterData import Data1D 
    99from sas.qtgui.Plotting.PlotterData import Data2D 
     10 
     11from sas.qtgui.Perspectives.Fitting.AssociatedComboBox import AssociatedComboBox 
    1012 
    1113model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units'] 
     
    6163    return (param_name, param_length) 
    6264 
    63 def addParametersToModel(parameters, kernel_module, is2D): 
    64     """ 
    65     Update local ModelModel with sasmodel parameters 
     65def 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 
     93def 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. 
    6698    """ 
    6799    multishell_parameters = getIterParams(parameters) 
     
    72104    else: 
    73105        params = parameters.iq_parameters 
    74     item = [] 
     106 
     107    rows = [] 
    75108    for param in params: 
    76109        # don't include shell parameters 
    77110        if param.name == multishell_param_name: 
    78111            continue 
     112 
    79113        # Modify parameter name from <param>[n] to <param>1 
    80114        item_name = param.name 
    81115        if param in multishell_parameters: 
    82116            continue 
    83         #    item_name = replaceShellName(param.name, 1) 
    84117 
    85118        item1 = QtGui.QStandardItem(item_name) 
    86119        item1.setCheckable(True) 
    87120        item1.setEditable(False) 
    88         # item_err = QtGui.QStandardItem() 
     121 
    89122        # check for polydisp params 
    90123        if param.polydisperse: 
     
    93126            item1_1 = QtGui.QStandardItem("Distribution") 
    94127            item1_1.setEditable(False) 
     128 
    95129            # Find param in volume_params 
    96130            for p in parameters.form_volume_parameters: 
     
    99133                width = kernel_module.getParam(p.name+'.width') 
    100134                ptype = kernel_module.getParam(p.name+'.type') 
    101  
    102135                item1_2 = QtGui.QStandardItem(str(width)) 
    103136                item1_2.setEditable(False) 
     
    110143                poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 
    111144                break 
     145 
    112146            # Add the polydisp item as a child 
    113147            item1.appendRow([poly_item]) 
     148 
    114149        # Param values 
    115150        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() 
    119151        item3 = QtGui.QStandardItem(str(param.limits[0])) 
    120152        item4 = QtGui.QStandardItem(str(param.limits[1])) 
    121         item5 = QtGui.QStandardItem(param.units) 
     153        item5 = QtGui.QStandardItem(str(param.units)) 
    122154        item5.setEditable(False) 
    123         item.append([item1, item2, item3, item4, item5]) 
    124     return item 
    125  
    126 def addSimpleParametersToModel(parameters, is2D): 
    127     """ 
    128     Update local ModelModel with sasmodel parameters 
     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 
     169def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=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) 
    129177    """ 
    130178    if is2D: 
     
    132180    else: 
    133181        params = parameters.iq_parameters 
    134     item = [] 
    135     for param in params: 
     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): 
    136197        # Create the top level, checkable item 
    137         item_name = param.name 
     198        item_name = param_orig.name 
    138199        item1 = QtGui.QStandardItem(item_name) 
     200        item1.setData(param.name, QtCore.Qt.UserRole) 
    139201        item1.setCheckable(True) 
    140202        item1.setEditable(False) 
     203 
    141204        # Param values 
    142205        # TODO: add delegate for validation of cells 
    143206        item2 = QtGui.QStandardItem(str(param.default)) 
    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 
     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            model.appendRow(row) 
     219            if cbox: 
     220                view.setIndexWidget(item2.index(), cbox) 
     221        rows.append(row) 
     222 
     223    return rows 
    150224 
    151225def markParameterDisabled(model, row): 
     
    182256    model.appendRow(item_list) 
    183257 
     258def addHeadingRowToModel(model, name): 
     259    """adds a non-interactive top-level row to the model""" 
     260    header_row = [QtGui.QStandardItem() for i in range(5)] 
     261    header_row[0].setText(name) 
     262 
     263    font = header_row[0].font() 
     264    font.setBold(True) 
     265    header_row[0].setFont(font) 
     266 
     267    for item in header_row: 
     268        item.setEditable(False) 
     269        item.setCheckable(False) 
     270        item.setSelectable(False) 
     271 
     272    model.appendRow(header_row) 
     273 
    184274def addHeadersToModel(model): 
    185275    """ 
     
    227317    model.header_tooltips = copy.copy(poly_header_error_tooltips) 
    228318 
    229 def addShellsToModel(parameters, model, index): 
    230     """ 
    231     Find out multishell parameters and update the model with the requested number of them 
     319def addShellsToModel(parameters, model, index, row_num=None, view=None): 
     320    """ 
     321    Find out multishell parameters and update the model with the requested number of them. 
     322    Inserts them after the row at row_num, if not None; otherwise, appends to end. 
     323    If view param is not None, supports fixed-choice params. 
     324    Returns a list of lists of QStandardItem objects. 
    232325    """ 
    233326    multishell_parameters = getIterParams(parameters) 
    234327 
     328    rows = [] 
    235329    for i in range(index): 
    236330        for par in multishell_parameters: 
     
    250344                    item1_3 = QtGui.QStandardItem(str(p.limits[0])) 
    251345                    item1_4 = QtGui.QStandardItem(str(p.limits[1])) 
    252                     item1_5 = QtGui.QStandardItem(p.units) 
     346                    item1_5 = QtGui.QStandardItem(str(p.units)) 
    253347                    poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 
    254348                    break 
     
    258352            item3 = QtGui.QStandardItem(str(par.limits[0])) 
    259353            item4 = QtGui.QStandardItem(str(par.limits[1])) 
    260             item5 = QtGui.QStandardItem(par.units) 
    261             model.appendRow([item1, item2, item3, item4, item5]) 
     354            item5 = QtGui.QStandardItem(str(par.units)) 
     355            item5.setEditable(False) 
     356 
     357            # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 
     358            row = [item1, item2, item3, item4, item5] 
     359            cbox = createFixedChoiceComboBox(par, row) 
     360 
     361            # Always add to the model 
     362            if row_num is None: 
     363                model.appendRow(row) 
     364            else: 
     365                model.insertRow(row_num, row) 
     366                row_num += 1 
     367 
     368            # Apply combobox if required 
     369            if None not in (view, cbox): 
     370                view.setIndexWidget(item2.index(), cbox) 
     371 
     372            rows.append(row) 
     373 
     374    return rows 
    262375 
    263376def calculateChi2(reference_data, current_data): 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    r339e22b r12db2db6  
    9090    fittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    9191    batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    92     Calc1DFinishedSignal = QtCore.pyqtSignal(tuple) 
    93     Calc2DFinishedSignal = QtCore.pyqtSignal(tuple) 
     92    Calc1DFinishedSignal = QtCore.pyqtSignal(dict) 
     93    Calc2DFinishedSignal = QtCore.pyqtSignal(dict) 
    9494 
    9595    def __init__(self, parent=None, data=None, tab_id=1): 
     
    219219        # Utility variable to enable unselectable option in category combobox 
    220220        self._previous_category_index = 0 
    221         # Utility variable for multishell display 
    222         self._last_model_row = 0 
     221        # Utility variables for multishell display 
     222        self._n_shells_row = 0 
     223        self._num_shell_params = 0 
    223224        # Dictionary of {model name: model class} for the current category 
    224225        self.models = {} 
     
    247248        # copy of current kernel model 
    248249        self.kernel_module_copy = None 
     250 
     251        # dictionaries of current params 
     252        self.poly_params = {} 
     253        self.magnet_params = {} 
    249254 
    250255        # Page id for fitting 
     
    672677        Return list of all parameters for the current model 
    673678        """ 
    674         return [self._model_model.item(row).text() for row in range(self._model_model.rowCount())] 
     679        return [self._model_model.item(row).text() 
     680                for row in range(self._model_model.rowCount()) 
     681                if self.isCheckable(row)] 
    675682 
    676683    def modifyViewOnRow(self, row, font=None, brush=None): 
     
    700707        assert isinstance(constraint, Constraint) 
    701708        assert 0 <= row <= self._model_model.rowCount() 
     709        assert self.isCheckable(row) 
    702710 
    703711        item = QtGui.QStandardItem() 
     
    720728        max_col = self.lstParams.itemDelegate().param_max 
    721729        for row in self.selectedParameters(): 
     730            assert(self.isCheckable(row)) 
    722731            param = self._model_model.item(row, 0).text() 
    723732            value = self._model_model.item(row, 1).text() 
     
    762771        max_col = self.lstParams.itemDelegate().param_max 
    763772        for row in range(self._model_model.rowCount()): 
     773            if not self.isCheckable(row): 
     774                continue 
    764775            if not self.rowHasConstraint(row): 
    765776                continue 
     
    790801        For the given row, return its constraint, if any 
    791802        """ 
    792         try: 
     803        if self.isCheckable(row): 
    793804            item = self._model_model.item(row, 1) 
    794             return item.child(0).data() 
    795         except AttributeError: 
    796             # return none when no constraints 
    797             return None 
     805            try: 
     806                return item.child(0).data() 
     807            except AttributeError: 
     808                # return none when no constraints 
     809                pass 
     810        return None 
    798811 
    799812    def rowHasConstraint(self, row): 
     
    801814        Finds out if row of the main model has a constraint child 
    802815        """ 
    803         item = self._model_model.item(row, 1) 
    804         if item.hasChildren(): 
    805             c = item.child(0).data() 
    806             if isinstance(c, Constraint): 
    807                 return True 
     816        if self.isCheckable(row): 
     817            item = self._model_model.item(row, 1) 
     818            if item.hasChildren(): 
     819                c = item.child(0).data() 
     820                if isinstance(c, Constraint): 
     821                    return True 
    808822        return False 
    809823 
     
    812826        Finds out if row of the main model has an active constraint child 
    813827        """ 
    814         item = self._model_model.item(row, 1) 
    815         if item.hasChildren(): 
    816             c = item.child(0).data() 
    817             if isinstance(c, Constraint) and c.active: 
    818                 return True 
     828        if self.isCheckable(row): 
     829            item = self._model_model.item(row, 1) 
     830            if item.hasChildren(): 
     831                c = item.child(0).data() 
     832                if isinstance(c, Constraint) and c.active: 
     833                    return True 
    819834        return False 
    820835 
     
    823838        Finds out if row of the main model has an active, nontrivial constraint child 
    824839        """ 
    825         item = self._model_model.item(row, 1) 
    826         if item.hasChildren(): 
    827             c = item.child(0).data() 
    828             if isinstance(c, Constraint) and c.func and c.active: 
    829                 return True 
     840        if self.isCheckable(row): 
     841            item = self._model_model.item(row, 1) 
     842            if item.hasChildren(): 
     843                c = item.child(0).data() 
     844                if isinstance(c, Constraint) and c.func and c.active: 
     845                    return True 
    830846        return False 
    831847 
     
    11861202            # Update the sasmodel 
    11871203            # PD[ratio] -> width, npts -> npts, nsigs -> nsigmas 
    1188             self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 
     1204            #self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 
     1205            key = parameter_name + '.' + delegate.columnDict()[model_column] 
     1206            self.poly_params[key] = value 
    11891207 
    11901208            # Update plot 
     
    11951213            row = self.getRowFromName(parameter_name) 
    11961214            param_item = self._model_model.item(row) 
     1215            self._model_model.blockSignals(True) 
    11971216            param_item.child(0).child(0, model_column).setText(item.text()) 
     1217            self._model_model.blockSignals(False) 
    11981218 
    11991219    def onMagnetModelChange(self, item): 
     
    12241244            # Unparsable field 
    12251245            return 
    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: 
     1246        delegate = self.lstMagnetic.itemDelegate() 
     1247 
     1248        if model_column > 1: 
     1249            if model_column == delegate.mag_min: 
     1250                pos = 1 
     1251            elif model_column == delegate.mag_max: 
     1252                pos = 2 
     1253            elif model_column == delegate.mag_unit: 
     1254                pos = 0 
     1255            else: 
     1256                raise AttributeError("Wrong column in magnetism table.") 
     1257            # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 
     1258            self.kernel_module.details[parameter_name][pos] = value 
     1259        else: 
     1260            self.magnet_params[parameter_name] = value 
     1261            #self.kernel_module.setParam(parameter_name) = value 
     1262            # Force the chart update when actual parameters changed 
    12371263            self.recalculatePlotData() 
    12381264 
     
    14811507        # update charts 
    14821508        self.onPlot() 
     1509        #self.recalculatePlotData() 
     1510 
    14831511 
    14841512        # Read only value - we can get away by just printing it here 
     
    14951523        # Data going in 
    14961524        data = self.logic.data 
    1497         model = self.kernel_module 
     1525        model = copy.deepcopy(self.kernel_module) 
    14981526        qmin = self.q_range_min 
    14991527        qmax = self.q_range_max 
     1528        # add polydisperse/magnet parameters if asked 
     1529        self.updateKernelModelWithExtraParams(model) 
    15001530 
    15011531        params_to_fit = self.main_params_to_fit 
     
    15611591            # internal so can use closure for param_dict 
    15621592            param_name = str(self._model_model.item(row, 0).text()) 
    1563             if param_name not in list(param_dict.keys()): 
     1593            if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 
    15641594                return 
    15651595            # modify the param value 
    15661596            param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 
    15671597            self._model_model.item(row, 1).setText(param_repr) 
     1598            self.kernel_module.setParam(param_name, param_dict[param_name][0]) 
    15681599            if self.has_error_column: 
    15691600                error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
     
    15731604            # Utility function for updateof polydispersity part of the main model 
    15741605            param_name = str(self._model_model.item(row, 0).text())+'.width' 
    1575             if param_name not in list(param_dict.keys()): 
     1606            if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 
    15761607                return 
    15771608            # modify the param value 
     
    16071638            poly_item.insertColumn(2, [QtGui.QStandardItem("")]) 
    16081639 
    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  
    16131640        if not self.has_error_column: 
    16141641            # create top-level error column 
     
    16171644            self.iterateOverModel(createErrorColumn) 
    16181645 
    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) 
    16221646            self._model_model.insertColumn(2, error_column) 
    1623             self._model_model.blockSignals(True) 
    16241647 
    16251648            FittingUtilities.addErrorHeadersToModel(self._model_model) 
     
    16301653            self.has_error_column = True 
    16311654 
     1655        # block signals temporarily, so we don't end up 
     1656        # updating charts with every single model change on the end of fitting 
     1657        self._model_model.itemChanged.disconnect() 
    16321658        self.iterateOverModel(updateFittedValues) 
    16331659        self.iterateOverModel(updatePolyValues) 
    1634  
    1635         self._model_model.blockSignals(False) 
     1660        self._model_model.itemChanged.connect(self.onMainParamsChange) 
    16361661 
    16371662        # Adjust the table cells width. 
     
    16681693            param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 
    16691694            self._poly_model.item(row_i, 1).setText(param_repr) 
     1695            self.kernel_module.setParam(param_name, param_dict[param_name][0]) 
    16701696            if self.has_poly_error_column: 
    16711697                error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
    16721698                self._poly_model.item(row_i, 2).setText(error_repr) 
    1673  
    16741699 
    16751700        def createErrorColumn(row_i): 
     
    16921717        # block signals temporarily, so we don't end up 
    16931718        # updating charts with every single model change on the end of fitting 
    1694         self._poly_model.blockSignals(True) 
     1719        self._poly_model.itemChanged.disconnect() 
    16951720        self.iterateOverPolyModel(updateFittedValues) 
    1696         self._poly_model.blockSignals(False) 
     1721        self._poly_model.itemChanged.connect(self.onPolyModelChange) 
    16971722 
    16981723        if self.has_poly_error_column: 
     
    17041729 
    17051730        # switch off reponse to model change 
    1706         self._poly_model.blockSignals(True) 
    17071731        self._poly_model.insertColumn(2, error_column) 
    1708         self._poly_model.blockSignals(False) 
    17091732        FittingUtilities.addErrorPolyHeadersToModel(self._poly_model) 
    17101733 
     
    17391762            param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 
    17401763            self._magnet_model.item(row, 1).setText(param_repr) 
     1764            self.kernel_module.setParam(param_name, param_dict[param_name][0]) 
    17411765            if self.has_magnet_error_column: 
    17421766                error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
     
    17581782        # block signals temporarily, so we don't end up 
    17591783        # updating charts with every single model change on the end of fitting 
    1760         self._magnet_model.blockSignals(True) 
     1784        self._magnet_model.itemChanged.disconnect() 
    17611785        self.iterateOverMagnetModel(updateFittedValues) 
    1762         self._magnet_model.blockSignals(False) 
     1786        self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 
    17631787 
    17641788        if self.has_magnet_error_column: 
     
    17701794 
    17711795        # switch off reponse to model change 
    1772         self._magnet_model.blockSignals(True) 
    17731796        self._magnet_model.insertColumn(2, error_column) 
    1774         self._magnet_model.blockSignals(False) 
    17751797        FittingUtilities.addErrorHeadersToModel(self._magnet_model) 
    17761798 
     
    17841806        self.cmdPlot.setText("Show Plot") 
    17851807        # Force data recalculation so existing charts are updated 
     1808        self.showPlot() 
    17861809        self.recalculatePlotData() 
    1787         self.showPlot() 
    17881810 
    17891811    def onSmearingOptionsUpdate(self): 
     
    19501972        # Crete/overwrite model items 
    19511973        self._model_model.clear() 
    1952  
    1953         # First, add parameters from the main model 
    1954         if model_name is not None: 
     1974        self._poly_model.clear() 
     1975        self._magnet_model.clear() 
     1976 
     1977        if model_name is None: 
     1978            if structure_factor not in (None, "None"): 
     1979                # S(Q) on its own, treat the same as a form factor 
     1980                self.kernel_module = None 
     1981                self.fromStructureFactorToQModel(structure_factor) 
     1982            else: 
     1983                # No models selected 
     1984                return 
     1985        else: 
    19551986            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) 
    1963         else: 
     1987            self.addExtraShells() 
     1988 
    19641989            # Allow the SF combobox visibility for the given sasmodel 
    19651990            self.enableStructureFactorControl(structure_factor) 
     1991         
     1992            # Add S(Q) 
    19661993            if self.cbStructureFactor.isEnabled(): 
    19671994                structure_factor = self.cbStructureFactor.currentText() 
    19681995                self.fromStructureFactorToQModel(structure_factor) 
    19691996 
    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() 
     1997            # Add polydispersity to the model 
     1998            self.poly_params = {} 
     1999            self.setPolyModel() 
     2000            # Add magnetic parameters to the model 
     2001            self.magnet_params = {} 
     2002            self.setMagneticModel() 
    19792003 
    19802004        # Adjust the table cells width 
     
    20492073        self.shell_names = self.shellNamesList() 
    20502074 
     2075        # Add heading row 
     2076        FittingUtilities.addHeadingRowToModel(self._model_model, model_name) 
     2077 
    20512078        # Update the QModel 
    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() 
     2079        FittingUtilities.addParametersToModel( 
     2080                self.model_parameters, 
     2081                self.kernel_module, 
     2082                self.is2D, 
     2083                self._model_model, 
     2084                self.lstParams) 
    20582085 
    20592086    def fromStructureFactorToQModel(self, structure_factor): 
     
    20632090        if structure_factor is None or structure_factor=="None": 
    20642091            return 
    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() 
     2092 
     2093        if self.kernel_module is None: 
     2094            # Structure factor is the only selected model; build it and show all its params 
     2095            self.kernel_module = self.models[structure_factor]() 
     2096            s_params = self.kernel_module._model_info.parameters 
     2097            s_params_orig = s_params 
     2098 
     2099        else: 
     2100            s_kernel = self.models[structure_factor]() 
     2101            p_kernel = self.kernel_module 
     2102 
     2103            p_pars_len = len(p_kernel._model_info.parameters.kernel_parameters) 
     2104            s_pars_len = len(s_kernel._model_info.parameters.kernel_parameters) 
     2105 
     2106            self.kernel_module = MultiplicationModel(p_kernel, s_kernel) 
     2107            all_params = self.kernel_module._model_info.parameters.kernel_parameters 
     2108            all_param_names = [param.name for param in all_params] 
     2109 
     2110            # S(Q) params from the product model are not necessarily the same as those from the S(Q) model; any 
     2111            # conflicting names with P(Q) params will cause a rename 
     2112 
     2113            if "radius_effective_mode" in all_param_names: 
     2114                # Show all parameters 
     2115                s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len]) 
     2116                s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters) 
     2117            else: 
     2118                # Ensure radius_effective is not displayed 
     2119                s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters[1:]) 
     2120                if "radius_effective" in all_param_names: 
     2121                    s_params = modelinfo.ParameterTable(all_params[p_pars_len+1:p_pars_len+s_pars_len]) 
     2122                else: 
     2123                    s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len-1]) 
     2124 
     2125        # Add heading row 
     2126        FittingUtilities.addHeadingRowToModel(self._model_model, structure_factor) 
     2127 
     2128        # Get new rows for QModel 
     2129        # Any renamed parameters are stored as data in the relevant item, for later handling 
     2130        FittingUtilities.addSimpleParametersToModel( 
     2131                s_params, 
     2132                self.is2D, 
     2133                s_params_orig, 
     2134                self._model_model, 
     2135                self.lstParams) 
    20832136 
    20842137    def haveParamsToFit(self): 
     
    21062159        model_row = item.row() 
    21072160        name_index = self._model_model.index(model_row, 0) 
     2161        name_item = self._model_model.itemFromIndex(name_index) 
    21082162 
    21092163        # Extract changed value. 
     
    21142168            return 
    21152169 
    2116         parameter_name = str(self._model_model.data(name_index)) # sld, background etc. 
     2170        # if the item has user data, this is the actual parameter name (e.g. to handle duplicate names) 
     2171        if name_item.data(QtCore.Qt.UserRole): 
     2172            parameter_name = str(name_item.data(QtCore.Qt.UserRole)) 
     2173        else: 
     2174            parameter_name = str(self._model_model.data(name_index)) 
    21172175 
    21182176        # Update the parameter value - note: this supports +/-inf as well 
     
    22372295        return self.completed1D if isinstance(self.data, Data1D) else self.completed2D 
    22382296 
     2297    def updateKernelModelWithExtraParams(self, model=None): 
     2298        """ 
     2299        Updates kernel model 'model' with extra parameters from 
     2300        the polydisp and magnetism tab, if the tabs are enabled 
     2301        """ 
     2302        if model is None: return 
     2303        if not hasattr(model, 'setParam'): return 
     2304 
     2305        # add polydisperse parameters if asked 
     2306        if self.chkPolydispersity.isChecked(): 
     2307            for key, value in self.poly_params.items(): 
     2308                model.setParam(key, value) 
     2309        # add magnetic params if asked 
     2310        if self.chkMagnetism.isChecked(): 
     2311            for key, value in self.magnet_params.items(): 
     2312                model.setParam(key, value) 
     2313 
    22392314    def calculateQGridForModelExt(self, data=None, model=None, completefn=None, use_threads=True): 
    22402315        """ 
     
    22442319            data = self.data 
    22452320        if model is None: 
    2246             model = self.kernel_module 
     2321            model = copy.deepcopy(self.kernel_module) 
     2322            self.updateKernelModelWithExtraParams(model) 
     2323 
    22472324        if completefn is None: 
    22482325            completefn = self.methodCompleteForData() 
     
    23292406            new_plots.append(sq_data) 
    23302407 
     2408        for plot in new_plots: 
     2409            self.communicate.plotUpdateSignal.emit([plot]) 
     2410 
     2411    def complete2D(self, return_data): 
     2412        """ 
     2413        Plot the current 2D data 
     2414        """ 
     2415        fitted_data = self.logic.new2DPlot(return_data) 
     2416        residuals = self.calculateResiduals(fitted_data) 
     2417        self.model_data = fitted_data 
     2418        new_plots = [fitted_data] 
     2419        if residuals is not None: 
     2420            new_plots.append(residuals) 
     2421 
    23312422        # Update/generate plots 
    23322423        for plot in new_plots: 
    23332424            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 
    23422425 
    23432426    def calculateResiduals(self, fitted_data): 
     
    24702553        _, min, max = self.kernel_module.details[param_name] 
    24712554 
     2555        # Update local param dict 
     2556        self.poly_params[param_name + '.width'] = width 
     2557        self.poly_params[param_name + '.npts'] = npts 
     2558        self.poly_params[param_name + '.nsigmas'] = nsigs 
     2559 
    24722560        # Construct a row with polydisp. related variable. 
    24732561        # This will get added to the polydisp. model 
     
    25172605        def updateFunctionCaption(row): 
    25182606            # Utility function for update of polydispersity function name in the main model 
     2607            if not self.isCheckable(row): 
     2608                return 
     2609            self._model_model.blockSignals(True) 
    25192610            param_name = str(self._model_model.item(row, 0).text()) 
     2611            self._model_model.blockSignals(False) 
    25202612            if param_name !=  param.name: 
    25212613                return 
    25222614            # Modify the param value 
     2615            self._model_model.blockSignals(True) 
    25232616            if self.has_error_column: 
    25242617                # err column changes the indexing 
     
    25262619            else: 
    25272620                self._model_model.item(row, 0).child(0).child(0,4).setText(combo_string) 
     2621            self._model_model.blockSignals(False) 
    25282622 
    25292623        if combo_string == 'array': 
     
    26442738                        param.units] 
    26452739 
     2740        self.magnet_params[param.name] = param.default 
     2741 
    26462742        FittingUtilities.addCheckedListToModel(model, checked_list) 
    26472743 
     
    26832779 
    26842780        self.lstParams.setIndexWidget(shell_index, func) 
    2685         self._last_model_row = self._model_model.rowCount() 
     2781        self._n_shells_row = shell_row - 1 
    26862782 
    26872783        # Set the index to the state-kept value 
     
    26942790        """ 
    26952791        # Find row location of the combobox 
    2696         last_row = self._last_model_row 
    2697         remove_rows = self._model_model.rowCount() - last_row 
     2792        first_row = self._n_shells_row + 1 
     2793        remove_rows = self._num_shell_params 
    26982794 
    26992795        if remove_rows > 1: 
    2700             self._model_model.removeRows(last_row, remove_rows) 
    2701  
    2702         FittingUtilities.addShellsToModel(self.model_parameters, self._model_model, index) 
     2796            self._model_model.removeRows(first_row, remove_rows) 
     2797 
     2798        new_rows = FittingUtilities.addShellsToModel( 
     2799                self.model_parameters, 
     2800                self._model_model, 
     2801                index, 
     2802                first_row, 
     2803                self.lstParams) 
     2804 
     2805        self._num_shell_params = len(new_rows) 
    27032806        self.current_shell_displayed = index 
    27042807 
  • src/sas/qtgui/Perspectives/Fitting/ModelThread.py

    r2df558e rdcabba7  
    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 
    103111        if LocalConfig.USING_TWISTED: 
    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  
     112            return res 
     113        else: 
     114            self.completefn(res) 
    135115 
    136116class Calc1D(CalcThread): 
     
    236216        elapsed = time.time() - self.starttime 
    237217 
     218        res = dict(x = self.data.x[index], y = output[index], 
     219            page_id = self.page_id, state = self.state, weight = self.weight, 
     220            fid = self.fid, toggle_mode_on = self.toggle_mode_on, 
     221            elapsed = elapsed, index = index, model = self.model, 
     222            data = self.data, update_chisqr = self.update_chisqr, 
     223            source = self.source, unsmeared_output = unsmeared_output, 
     224            unsmeared_data = unsmeared_data, unsmeared_error = unsmeared_error, 
     225            pq_values = pq_values, sq_values = sq_values) 
     226 
    238227        if LocalConfig.USING_TWISTED: 
    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)) 
     228            return res 
     229        else: 
     230            self.completefn(res) 
    264231 
    265232    def results(self): 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py

    r605d944 r4ea8020  
    256256        self.widget.cbStructureFactor.setCurrentIndex(structure_index) 
    257257 
    258         # We have 4 more rows now 
     258        # We have 3 more param rows now (radius_effective is removed), and a new heading 
    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? 
    279         self.assertEqual(self.widget._model_model.rowCount(), 4) 
     278        # Do we have all the rows (incl. radius_effective & heading row)? 
     279        self.assertEqual(self.widget._model_model.rowCount(), 5) 
    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 
    447450        # Change the number of points 
    448         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 
     451        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 35) 
    449452        self.widget._poly_model.item(0,4).setText("22") 
    450         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
     453        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
    451454        # try something stupid 
    452455        self.widget._poly_model.item(0,4).setText("butt") 
    453456        # see that this didn't annoy the control at all 
    454         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
     457        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
    455458 
    456459        # Change the number of sigmas 
    457         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 3) 
     460        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 3) 
    458461        self.widget._poly_model.item(0,5).setText("222") 
    459         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
     462        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
    460463        # try something stupid again 
    461464        self.widget._poly_model.item(0,4).setText("beer") 
    462465        # no efect 
    463         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
     466        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
    464467 
    465468    def testOnPolyComboIndexChange(self): 
     
    482485        self.widget.onPolyComboIndexChange('rectangle', 0) 
    483486        # check values 
    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) 
     487        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 35) 
     488        self.assertAlmostEqual(self.widget.poly_params['radius_bell.nsigmas'], 1.73205, 5) 
    486489        # Change the index 
    487490        self.widget.onPolyComboIndexChange('lognormal', 0) 
    488491        # check values 
    489         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
    490         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 
     492        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 80) 
     493        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 8) 
    491494        # Change the index 
    492495        self.widget.onPolyComboIndexChange('schulz', 0) 
    493496        # check values 
    494         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
    495         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 
     497        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 80) 
     498        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 8) 
    496499 
    497500        # mock up file load 
     
    506509        Test opening of the load file dialog for 'array' polydisp. function 
    507510        """ 
     511 
     512        # open a non-existent file 
    508513        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) 
    509516        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 
    510517        self.widget.show() 
     
    522529 
    523530        # 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 
    524534        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") 
    525539        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 
    526540 
     
    588602 
    589603        # Assure we have the combobox available 
    590         last_row = self.widget._last_model_row 
    591         func_index = self.widget._model_model.index(last_row-1, 1) 
     604        cbox_row = self.widget._n_shells_row 
     605        func_index = self.widget._model_model.index(cbox_row, 1) 
    592606        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() 
    593610 
    594611        # Change the combo box index 
     
    10241041 
    10251042         # Check the model 
    1026         self.assertEqual(self.widget._model_model.rowCount(), 6) 
     1043        self.assertEqual(self.widget._model_model.rowCount(), 7) 
    10271044        self.assertEqual(self.widget._model_model.columnCount(), 5) 
    10281045 
     
    11401157        # two rows selected 
    11411158        index1 = self.widget.lstParams.model().index(1, 0, QtCore.QModelIndex()) 
    1142         index2 = self.widget.lstParams.model().index(2, 0, QtCore.QModelIndex()) 
     1159        index2 = self.widget.lstParams.model().index(3, 0, QtCore.QModelIndex()) 
    11431160        selection_model = self.widget.lstParams.selectionModel() 
    11441161        selection_model.select(index1, selection_model.Select | selection_model.Rows) 
     
    11761193        # several random parameters 
    11771194        self.assertEqual(self.widget.getRowFromName('scale'), 0) 
    1178         self.assertEqual(self.widget.getRowFromName('length'), 5) 
     1195        self.assertEqual(self.widget.getRowFromName('length'), 6) 
    11791196 
    11801197    def testGetParamNames(self): 
     
    12131230        # Create a constraint object 
    12141231        const = Constraint(parent=None, value=7.0) 
    1215         row = 2 
     1232        row = 3 
    12161233 
    12171234        spy = QtSignalSpy(self.widget, self.widget.constraintAddedSignal) 
     
    12321249        # assign complex constraint now 
    12331250        const = Constraint(parent=None, param='radius', func='5*sld') 
    1234         row = 4 
     1251        row = 5 
    12351252        # call the method tested 
    12361253        self.widget.addConstraintToRow(constraint=const, row=row) 
     
    12911308        self.widget.cbModel.setCurrentIndex(model_index) 
    12921309 
     1310        row1 = 1 
     1311        row2 = 5 
     1312 
     1313        param1 = "background" 
     1314        param2 = "radius" 
     1315 
     1316        #default_value1 = "0.001" 
     1317        default_value2 = "20" 
     1318 
    12931319        # select two rows 
    1294         row1 = 1 
    1295         row2 = 4 
    12961320        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    12971321        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13101334 
    13111335        # delete one of the constraints 
    1312         self.widget.deleteConstraintOnParameter(param='background') 
     1336        self.widget.deleteConstraintOnParameter(param=param1) 
    13131337 
    13141338        # see that the other constraint is still present 
    1315         cons = self.widget.getConstraintForRow(4) # 4 = radius 
    1316         self.assertEqual(cons.param, "radius") 
    1317         self.assertEqual(cons.value, "20") 
     1339        cons = self.widget.getConstraintForRow(row2) 
     1340        self.assertEqual(cons.param, param2) 
     1341        self.assertEqual(cons.value, default_value2) 
    13181342 
    13191343        # kill the other constraint 
     
    13211345 
    13221346        # see that the other constraint is still present 
    1323         self.assertEqual(self.widget.getConstraintsForModel(), [('radius', None)]) 
     1347        self.assertEqual(self.widget.getConstraintsForModel(), [(param2, None)]) 
    13241348 
    13251349    def testGetConstraintForRow(self): 
     
    13411365        self.widget.cbModel.setCurrentIndex(model_index) 
    13421366 
     1367        row1 = 1 
     1368        row2 = 5 
     1369 
    13431370        # select two rows 
    1344         row1 = 1 
    1345         row2 = 4 
    13461371        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    13471372        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13531378        self.widget.addSimpleConstraint() 
    13541379 
    1355         con_list = [False, True, False, False, True, False] 
     1380        con_list = [False, True, False, False, False, True, False] 
    13561381        new_list = [] 
    13571382        for row in range(self.widget._model_model.rowCount()): 
     
    13711396        self.widget.cbModel.setCurrentIndex(model_index) 
    13721397 
     1398        row1 = 1 
     1399        row2 = 5 
     1400 
    13731401        # select two rows 
    1374         row1 = 1 
    1375         row2 = 4 
    13761402        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    13771403        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13871413        constraint_objects[0].active = False 
    13881414 
    1389         con_list = [False, False, False, False, True, False] 
     1415        con_list = [False, False, False, False, False, True, False] 
    13901416        new_list = [] 
    13911417        for row in range(self.widget._model_model.rowCount()): 
     
    14081434        self.assertEqual(self.widget.getConstraintsForModel(),[]) 
    14091435 
     1436        row1 = 1 
     1437        row2 = 5 
     1438 
     1439        param1 = "background" 
     1440        param2 = "radius" 
     1441 
     1442        default_value1 = "0.001" 
     1443        default_value2 = "20" 
     1444 
    14101445        # select two rows 
    1411         row1 = 1 
    1412         row2 = 4 
    14131446        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    14141447        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    14221455        # simple constraints 
    14231456        # self.assertEqual(self.widget.getConstraintsForModel(), [('background', '0.001'), ('radius', '20')]) 
    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") 
     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) 
    14301463 
    14311464        objects = self.widget.getConstraintObjectsForModel() 
    14321465        self.assertEqual(len(objects), 2) 
    1433         self.assertEqual(objects[1].value, '20') 
    1434         self.assertEqual(objects[0].param, 'background') 
     1466        self.assertEqual(objects[1].value, default_value2) 
     1467        self.assertEqual(objects[0].param, param1) 
     1468 
     1469        row = 0 
     1470        param = "scale" 
     1471        func = "5*sld" 
    14351472 
    14361473        # add complex constraint 
    1437         const = Constraint(parent=None, param='scale', func='5*sld') 
    1438         row = 0 
     1474        const = Constraint(parent=None, param=param, func=func) 
    14391475        self.widget.addConstraintToRow(constraint=const, row=row) 
    14401476        #self.assertEqual(self.widget.getConstraintsForModel(),[('scale', '5*sld'), ('background', '0.001'), ('radius', None)]) 
    1441         cons = self.widget.getConstraintForRow(4) # 4 = radius 
    1442         self.assertEqual(cons.param, "radius") 
    1443         self.assertEqual(cons.value, "20") 
     1477        cons = self.widget.getConstraintForRow(row2) 
     1478        self.assertEqual(cons.param, param2) 
     1479        self.assertEqual(cons.value, default_value2) 
    14441480 
    14451481        objects = self.widget.getConstraintObjectsForModel() 
    14461482        self.assertEqual(len(objects), 3) 
    1447         self.assertEqual(objects[0].func, '5*sld') 
     1483        self.assertEqual(objects[0].func, func) 
    14481484 
    14491485    def testReplaceConstraintName(self): 
  • src/sas/qtgui/Plotting/Plotter.py

    rb764ae5 rc2f3ca2  
    3030        # Dictionary of {plot_id:Data1d} 
    3131        self.plot_dict = {} 
    32  
     32        # Dictionaty of {plot_id:line} 
     33 
     34        self.plot_lines = {} 
    3335        # Window for text add 
    3436        self.addText = AddText(self) 
     
    182184        self.plot_dict[self._data.id] = self.data 
    183185 
     186        self.plot_lines[self._data.id] = line 
     187 
    184188        # Now add the legend with some customizations. 
    185189 
     
    196200 
    197201        # refresh canvas 
    198         self.canvas.draw_idle() 
     202        self.canvas.draw() 
    199203        # This is an important processEvent. 
    200204        # This allows charts to be properly updated in order 
     
    416420        This effectlvely refreshes the chart with changes to one of its plots 
    417421        """ 
     422        import logging 
    418423        self.removePlot(id) 
    419424        self.plot(data=new_plot) 
     
    470475        """ 
    471476        selected_plot = self.plot_dict[id] 
    472  
     477        selected_line = self.plot_lines[id] 
    473478        # Old style color - single integer for enum color 
    474479        # New style color - #hhhhhh 
  • src/sas/qtgui/MainWindow/GuiManager.py

    rf84d793 r339e22b  
    422422        self._workspace.actionExcel.triggered.connect(self.actionExcel) 
    423423        self._workspace.actionLatex.triggered.connect(self.actionLatex) 
    424  
    425424        # View 
    426425        self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window) 
     
    452451        self._workspace.actionManage_Custom_Models.triggered.connect(self.actionManage_Custom_Models) 
    453452        self._workspace.actionAddMult_Models.triggered.connect(self.actionAddMult_Models) 
     453        self._workspace.actionEditMask.triggered.connect(self.actionEditMask) 
     454 
    454455        # Window 
    455456        self._workspace.actionCascade.triggered.connect(self.actionCascade) 
     
    781782        self.add_mult_editor.show() 
    782783 
     784    def actionEditMask(self): 
     785 
     786        self.communicate.extMaskEditorSignal.emit() 
     787 
    783788    #============ ANALYSIS ================= 
    784789    def actionFitting(self): 
  • src/sas/qtgui/MainWindow/UI/MainWindowUI.ui

    rdda8f16 r339e22b  
    113113    <addaction name="actionManage_Custom_Models"/> 
    114114    <addaction name="actionAddMult_Models"/> 
     115    <addaction name="separator"/> 
     116    <addaction name="EditMask"/> 
    115117   </widget> 
    116118   <widget class="QMenu" name="menuWindow"> 
     
    413415   </property> 
    414416  </action> 
     417    <action name="EditMask"> 
     418   <property name="text"> 
     419    <string>Edit Mask</string> 
     420   </property> 
     421  </action> 
    415422  <action name="actionCascade"> 
    416423   <property name="text"> 
  • src/sas/qtgui/Utilities/GuiUtils.py

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