- Timestamp:
- Sep 7, 2018 12:25:19 PM (6 years ago)
- 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. - Location:
- src/sas/qtgui
- Files:
-
- 1 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/MainWindow/DataExplorer.py
r339e22b r12db2db6 560 560 # Now query the model item for available plots 561 561 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()]564 562 565 563 new_plots = [] 566 564 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): 573 566 # 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) 575 568 # 2nd match group contains the identifier for the intermediate result, if present (e.g. "[P(Q)]") 576 569 if match and match.groups()[1] != None: … … 706 699 self.active_plots[plot_set.id] = old_plot 707 700 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 713 710 assert type(data).__name__ in ['Data1D', 'Data2D'] 714 711 … … 719 716 if data_id in ids_keys: 720 717 self.active_plots[data_id].replacePlot(data_id, data) 718 return True 721 719 elif data_id in ids_vals: 722 720 list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 721 return True 722 return False 723 723 724 724 def chooseFiles(self): -
src/sas/qtgui/Perspectives/Fitting/FittingLogic.py
rb4d05bd rdcabba7 161 161 Create a new 1D data instance based on fitting results 162 162 """ 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']) 172 166 173 167 def new2DPlot(self, return_data): … … 175 169 Create a new 2D data instance based on fitting results 176 170 """ 177 image , data, page_id, model, state, toggle_mode_on,\178 elapsed, index, fid, qmin, qmax, weight, \179 update_chisqr, source = return_data171 image = return_data['image'] 172 data = return_data['data'] 173 model = return_data['model'] 180 174 181 175 np.nan_to_num(image) … … 183 177 new_plot.name = model.name + '2d' 184 178 new_plot.title = "Analytical model 2D " 185 new_plot.id = str( page_id) + " " + data.name186 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" 187 181 new_plot.detector = data.detector 188 182 new_plot.source = data.source … … 218 212 (pq_plot, sq_plot). If either are unavailable, the corresponding plot is None. 219 213 """ 220 # Unpack return data from Calc1D221 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_data227 214 228 215 pq_plot = None 229 216 sq_plot = None 230 217 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)") 235 226 236 227 return pq_plot, sq_plot -
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
rb764ae5 rb69b549 8 8 from sas.qtgui.Plotting.PlotterData import Data1D 9 9 from sas.qtgui.Plotting.PlotterData import Data2D 10 11 from sas.qtgui.Perspectives.Fitting.AssociatedComboBox import AssociatedComboBox 10 12 11 13 model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units'] … … 61 63 return (param_name, param_length) 62 64 63 def addParametersToModel(parameters, kernel_module, is2D): 64 """ 65 Update local ModelModel with sasmodel parameters 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. 66 98 """ 67 99 multishell_parameters = getIterParams(parameters) … … 72 104 else: 73 105 params = parameters.iq_parameters 74 item = [] 106 107 rows = [] 75 108 for param in params: 76 109 # don't include shell parameters 77 110 if param.name == multishell_param_name: 78 111 continue 112 79 113 # Modify parameter name from <param>[n] to <param>1 80 114 item_name = param.name 81 115 if param in multishell_parameters: 82 116 continue 83 # item_name = replaceShellName(param.name, 1)84 117 85 118 item1 = QtGui.QStandardItem(item_name) 86 119 item1.setCheckable(True) 87 120 item1.setEditable(False) 88 # item_err = QtGui.QStandardItem() 121 89 122 # check for polydisp params 90 123 if param.polydisperse: … … 93 126 item1_1 = QtGui.QStandardItem("Distribution") 94 127 item1_1.setEditable(False) 128 95 129 # Find param in volume_params 96 130 for p in parameters.form_volume_parameters: … … 99 133 width = kernel_module.getParam(p.name+'.width') 100 134 ptype = kernel_module.getParam(p.name+'.type') 101 102 135 item1_2 = QtGui.QStandardItem(str(width)) 103 136 item1_2.setEditable(False) … … 110 143 poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 111 144 break 145 112 146 # Add the polydisp item as a child 113 147 item1.appendRow([poly_item]) 148 114 149 # Param values 115 150 item2 = QtGui.QStandardItem(str(param.default)) 116 # TODO: the error column.117 # Either add a proxy model or a custom view delegate118 #item_err = QtGui.QStandardItem()119 151 item3 = QtGui.QStandardItem(str(param.limits[0])) 120 152 item4 = QtGui.QStandardItem(str(param.limits[1])) 121 item5 = QtGui.QStandardItem( param.units)153 item5 = QtGui.QStandardItem(str(param.units)) 122 154 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 169 def 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) 129 177 """ 130 178 if is2D: … … 132 180 else: 133 181 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): 136 197 # Create the top level, checkable item 137 item_name = param .name198 item_name = param_orig.name 138 199 item1 = QtGui.QStandardItem(item_name) 200 item1.setData(param.name, QtCore.Qt.UserRole) 139 201 item1.setCheckable(True) 140 202 item1.setEditable(False) 203 141 204 # Param values 142 205 # TODO: add delegate for validation of cells 143 206 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 150 224 151 225 def markParameterDisabled(model, row): … … 182 256 model.appendRow(item_list) 183 257 258 def 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 184 274 def addHeadersToModel(model): 185 275 """ … … 227 317 model.header_tooltips = copy.copy(poly_header_error_tooltips) 228 318 229 def addShellsToModel(parameters, model, index): 230 """ 231 Find out multishell parameters and update the model with the requested number of them 319 def 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. 232 325 """ 233 326 multishell_parameters = getIterParams(parameters) 234 327 328 rows = [] 235 329 for i in range(index): 236 330 for par in multishell_parameters: … … 250 344 item1_3 = QtGui.QStandardItem(str(p.limits[0])) 251 345 item1_4 = QtGui.QStandardItem(str(p.limits[1])) 252 item1_5 = QtGui.QStandardItem( p.units)346 item1_5 = QtGui.QStandardItem(str(p.units)) 253 347 poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 254 348 break … … 258 352 item3 = QtGui.QStandardItem(str(par.limits[0])) 259 353 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 262 375 263 376 def calculateChi2(reference_data, current_data): -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r339e22b r12db2db6 90 90 fittingFinishedSignal = QtCore.pyqtSignal(tuple) 91 91 batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 92 Calc1DFinishedSignal = QtCore.pyqtSignal( tuple)93 Calc2DFinishedSignal = QtCore.pyqtSignal( tuple)92 Calc1DFinishedSignal = QtCore.pyqtSignal(dict) 93 Calc2DFinishedSignal = QtCore.pyqtSignal(dict) 94 94 95 95 def __init__(self, parent=None, data=None, tab_id=1): … … 219 219 # Utility variable to enable unselectable option in category combobox 220 220 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 223 224 # Dictionary of {model name: model class} for the current category 224 225 self.models = {} … … 247 248 # copy of current kernel model 248 249 self.kernel_module_copy = None 250 251 # dictionaries of current params 252 self.poly_params = {} 253 self.magnet_params = {} 249 254 250 255 # Page id for fitting … … 672 677 Return list of all parameters for the current model 673 678 """ 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)] 675 682 676 683 def modifyViewOnRow(self, row, font=None, brush=None): … … 700 707 assert isinstance(constraint, Constraint) 701 708 assert 0 <= row <= self._model_model.rowCount() 709 assert self.isCheckable(row) 702 710 703 711 item = QtGui.QStandardItem() … … 720 728 max_col = self.lstParams.itemDelegate().param_max 721 729 for row in self.selectedParameters(): 730 assert(self.isCheckable(row)) 722 731 param = self._model_model.item(row, 0).text() 723 732 value = self._model_model.item(row, 1).text() … … 762 771 max_col = self.lstParams.itemDelegate().param_max 763 772 for row in range(self._model_model.rowCount()): 773 if not self.isCheckable(row): 774 continue 764 775 if not self.rowHasConstraint(row): 765 776 continue … … 790 801 For the given row, return its constraint, if any 791 802 """ 792 try:803 if self.isCheckable(row): 793 804 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 798 811 799 812 def rowHasConstraint(self, row): … … 801 814 Finds out if row of the main model has a constraint child 802 815 """ 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 808 822 return False 809 823 … … 812 826 Finds out if row of the main model has an active constraint child 813 827 """ 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 819 834 return False 820 835 … … 823 838 Finds out if row of the main model has an active, nontrivial constraint child 824 839 """ 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 830 846 return False 831 847 … … 1186 1202 # Update the sasmodel 1187 1203 # 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 1189 1207 1190 1208 # Update plot … … 1195 1213 row = self.getRowFromName(parameter_name) 1196 1214 param_item = self._model_model.item(row) 1215 self._model_model.blockSignals(True) 1197 1216 param_item.child(0).child(0, model_column).setText(item.text()) 1217 self._model_model.blockSignals(False) 1198 1218 1199 1219 def onMagnetModelChange(self, item): … … 1224 1244 # Unparsable field 1225 1245 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 1237 1263 self.recalculatePlotData() 1238 1264 … … 1481 1507 # update charts 1482 1508 self.onPlot() 1509 #self.recalculatePlotData() 1510 1483 1511 1484 1512 # Read only value - we can get away by just printing it here … … 1495 1523 # Data going in 1496 1524 data = self.logic.data 1497 model = self.kernel_module1525 model = copy.deepcopy(self.kernel_module) 1498 1526 qmin = self.q_range_min 1499 1527 qmax = self.q_range_max 1528 # add polydisperse/magnet parameters if asked 1529 self.updateKernelModelWithExtraParams(model) 1500 1530 1501 1531 params_to_fit = self.main_params_to_fit … … 1561 1591 # internal so can use closure for param_dict 1562 1592 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()): 1564 1594 return 1565 1595 # modify the param value 1566 1596 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1567 1597 self._model_model.item(row, 1).setText(param_repr) 1598 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1568 1599 if self.has_error_column: 1569 1600 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1573 1604 # Utility function for updateof polydispersity part of the main model 1574 1605 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()): 1576 1607 return 1577 1608 # modify the param value … … 1607 1638 poly_item.insertColumn(2, [QtGui.QStandardItem("")]) 1608 1639 1609 # block signals temporarily, so we don't end up1610 # updating charts with every single model change on the end of fitting1611 self._model_model.blockSignals(True)1612 1613 1640 if not self.has_error_column: 1614 1641 # create top-level error column … … 1617 1644 self.iterateOverModel(createErrorColumn) 1618 1645 1619 # we need to enable signals for this, otherwise the final column mysteriously disappears (don't ask, I don't1620 # know)1621 self._model_model.blockSignals(False)1622 1646 self._model_model.insertColumn(2, error_column) 1623 self._model_model.blockSignals(True)1624 1647 1625 1648 FittingUtilities.addErrorHeadersToModel(self._model_model) … … 1630 1653 self.has_error_column = True 1631 1654 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() 1632 1658 self.iterateOverModel(updateFittedValues) 1633 1659 self.iterateOverModel(updatePolyValues) 1634 1635 self._model_model.blockSignals(False) 1660 self._model_model.itemChanged.connect(self.onMainParamsChange) 1636 1661 1637 1662 # Adjust the table cells width. … … 1668 1693 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1669 1694 self._poly_model.item(row_i, 1).setText(param_repr) 1695 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1670 1696 if self.has_poly_error_column: 1671 1697 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 1672 1698 self._poly_model.item(row_i, 2).setText(error_repr) 1673 1674 1699 1675 1700 def createErrorColumn(row_i): … … 1692 1717 # block signals temporarily, so we don't end up 1693 1718 # updating charts with every single model change on the end of fitting 1694 self._poly_model. blockSignals(True)1719 self._poly_model.itemChanged.disconnect() 1695 1720 self.iterateOverPolyModel(updateFittedValues) 1696 self._poly_model. blockSignals(False)1721 self._poly_model.itemChanged.connect(self.onPolyModelChange) 1697 1722 1698 1723 if self.has_poly_error_column: … … 1704 1729 1705 1730 # switch off reponse to model change 1706 self._poly_model.blockSignals(True)1707 1731 self._poly_model.insertColumn(2, error_column) 1708 self._poly_model.blockSignals(False)1709 1732 FittingUtilities.addErrorPolyHeadersToModel(self._poly_model) 1710 1733 … … 1739 1762 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1740 1763 self._magnet_model.item(row, 1).setText(param_repr) 1764 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1741 1765 if self.has_magnet_error_column: 1742 1766 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1758 1782 # block signals temporarily, so we don't end up 1759 1783 # updating charts with every single model change on the end of fitting 1760 self._magnet_model. blockSignals(True)1784 self._magnet_model.itemChanged.disconnect() 1761 1785 self.iterateOverMagnetModel(updateFittedValues) 1762 self._magnet_model. blockSignals(False)1786 self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 1763 1787 1764 1788 if self.has_magnet_error_column: … … 1770 1794 1771 1795 # switch off reponse to model change 1772 self._magnet_model.blockSignals(True)1773 1796 self._magnet_model.insertColumn(2, error_column) 1774 self._magnet_model.blockSignals(False)1775 1797 FittingUtilities.addErrorHeadersToModel(self._magnet_model) 1776 1798 … … 1784 1806 self.cmdPlot.setText("Show Plot") 1785 1807 # Force data recalculation so existing charts are updated 1808 self.showPlot() 1786 1809 self.recalculatePlotData() 1787 self.showPlot()1788 1810 1789 1811 def onSmearingOptionsUpdate(self): … … 1950 1972 # Crete/overwrite model items 1951 1973 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: 1955 1986 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 1964 1989 # Allow the SF combobox visibility for the given sasmodel 1965 1990 self.enableStructureFactorControl(structure_factor) 1991 1992 # Add S(Q) 1966 1993 if self.cbStructureFactor.isEnabled(): 1967 1994 structure_factor = self.cbStructureFactor.currentText() 1968 1995 self.fromStructureFactorToQModel(structure_factor) 1969 1996 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() 1979 2003 1980 2004 # Adjust the table cells width … … 2049 2073 self.shell_names = self.shellNamesList() 2050 2074 2075 # Add heading row 2076 FittingUtilities.addHeadingRowToModel(self._model_model, model_name) 2077 2051 2078 # 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 display2057 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) 2058 2085 2059 2086 def fromStructureFactorToQModel(self, structure_factor): … … 2063 2090 if structure_factor is None or structure_factor=="None": 2064 2091 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) 2083 2136 2084 2137 def haveParamsToFit(self): … … 2106 2159 model_row = item.row() 2107 2160 name_index = self._model_model.index(model_row, 0) 2161 name_item = self._model_model.itemFromIndex(name_index) 2108 2162 2109 2163 # Extract changed value. … … 2114 2168 return 2115 2169 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)) 2117 2175 2118 2176 # Update the parameter value - note: this supports +/-inf as well … … 2237 2295 return self.completed1D if isinstance(self.data, Data1D) else self.completed2D 2238 2296 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 2239 2314 def calculateQGridForModelExt(self, data=None, model=None, completefn=None, use_threads=True): 2240 2315 """ … … 2244 2319 data = self.data 2245 2320 if model is None: 2246 model = self.kernel_module 2321 model = copy.deepcopy(self.kernel_module) 2322 self.updateKernelModelWithExtraParams(model) 2323 2247 2324 if completefn is None: 2248 2325 completefn = self.methodCompleteForData() … … 2329 2406 new_plots.append(sq_data) 2330 2407 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 2331 2422 # Update/generate plots 2332 2423 for plot in new_plots: 2333 2424 self.communicate.plotUpdateSignal.emit([plot]) 2334 2335 def complete2D(self, return_data):2336 """2337 Plot the current 2D data2338 """2339 fitted_data = self.logic.new2DPlot(return_data)2340 self.calculateResiduals(fitted_data)2341 self.model_data = fitted_data2342 2425 2343 2426 def calculateResiduals(self, fitted_data): … … 2470 2553 _, min, max = self.kernel_module.details[param_name] 2471 2554 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 2472 2560 # Construct a row with polydisp. related variable. 2473 2561 # This will get added to the polydisp. model … … 2517 2605 def updateFunctionCaption(row): 2518 2606 # 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) 2519 2610 param_name = str(self._model_model.item(row, 0).text()) 2611 self._model_model.blockSignals(False) 2520 2612 if param_name != param.name: 2521 2613 return 2522 2614 # Modify the param value 2615 self._model_model.blockSignals(True) 2523 2616 if self.has_error_column: 2524 2617 # err column changes the indexing … … 2526 2619 else: 2527 2620 self._model_model.item(row, 0).child(0).child(0,4).setText(combo_string) 2621 self._model_model.blockSignals(False) 2528 2622 2529 2623 if combo_string == 'array': … … 2644 2738 param.units] 2645 2739 2740 self.magnet_params[param.name] = param.default 2741 2646 2742 FittingUtilities.addCheckedListToModel(model, checked_list) 2647 2743 … … 2683 2779 2684 2780 self.lstParams.setIndexWidget(shell_index, func) 2685 self._ last_model_row = self._model_model.rowCount()2781 self._n_shells_row = shell_row - 1 2686 2782 2687 2783 # Set the index to the state-kept value … … 2694 2790 """ 2695 2791 # Find row location of the combobox 2696 last_row = self._last_model_row2697 remove_rows = self._ model_model.rowCount() - last_row2792 first_row = self._n_shells_row + 1 2793 remove_rows = self._num_shell_params 2698 2794 2699 2795 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) 2703 2806 self.current_shell_displayed = index 2704 2807 -
src/sas/qtgui/Perspectives/Fitting/ModelThread.py
r2df558e rdcabba7 101 101 elapsed = time.time() - self.starttime 102 102 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 103 111 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) 135 115 136 116 class Calc1D(CalcThread): … … 236 216 elapsed = time.time() - self.starttime 237 217 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 238 227 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) 264 231 265 232 def results(self): -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
r605d944 r4ea8020 256 256 self.widget.cbStructureFactor.setCurrentIndex(structure_index) 257 257 258 # We have 4 more rows now258 # We have 3 more param rows now (radius_effective is removed), and a new heading 259 259 self.assertEqual(self.widget._model_model.rowCount(), rowcount+4) 260 260 … … 276 276 last_index = self.widget.cbStructureFactor.count() 277 277 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) 280 280 281 281 # Are the command buttons properly enabled? … … 445 445 self.assertEqual(self.widget.kernel_module.details['radius_bell'][1], 1.0) 446 446 447 #self.widget.show() 448 #QtWidgets.QApplication.exec_() 449 447 450 # 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) 449 452 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) 451 454 # try something stupid 452 455 self.widget._poly_model.item(0,4).setText("butt") 453 456 # 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) 455 458 456 459 # 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) 458 461 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) 460 463 # try something stupid again 461 464 self.widget._poly_model.item(0,4).setText("beer") 462 465 # 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) 464 467 465 468 def testOnPolyComboIndexChange(self): … … 482 485 self.widget.onPolyComboIndexChange('rectangle', 0) 483 486 # 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) 486 489 # Change the index 487 490 self.widget.onPolyComboIndexChange('lognormal', 0) 488 491 # 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) 491 494 # Change the index 492 495 self.widget.onPolyComboIndexChange('schulz', 0) 493 496 # 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) 496 499 497 500 # mock up file load … … 506 509 Test opening of the load file dialog for 'array' polydisp. function 507 510 """ 511 512 # open a non-existent file 508 513 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) 509 516 QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 510 517 self.widget.show() … … 522 529 523 530 # 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 524 534 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") 525 539 QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 526 540 … … 588 602 589 603 # Assure we have the combobox available 590 last_row = self.widget._last_model_row591 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) 592 606 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() 593 610 594 611 # Change the combo box index … … 1024 1041 1025 1042 # Check the model 1026 self.assertEqual(self.widget._model_model.rowCount(), 6)1043 self.assertEqual(self.widget._model_model.rowCount(), 7) 1027 1044 self.assertEqual(self.widget._model_model.columnCount(), 5) 1028 1045 … … 1140 1157 # two rows selected 1141 1158 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()) 1143 1160 selection_model = self.widget.lstParams.selectionModel() 1144 1161 selection_model.select(index1, selection_model.Select | selection_model.Rows) … … 1176 1193 # several random parameters 1177 1194 self.assertEqual(self.widget.getRowFromName('scale'), 0) 1178 self.assertEqual(self.widget.getRowFromName('length'), 5)1195 self.assertEqual(self.widget.getRowFromName('length'), 6) 1179 1196 1180 1197 def testGetParamNames(self): … … 1213 1230 # Create a constraint object 1214 1231 const = Constraint(parent=None, value=7.0) 1215 row = 21232 row = 3 1216 1233 1217 1234 spy = QtSignalSpy(self.widget, self.widget.constraintAddedSignal) … … 1232 1249 # assign complex constraint now 1233 1250 const = Constraint(parent=None, param='radius', func='5*sld') 1234 row = 41251 row = 5 1235 1252 # call the method tested 1236 1253 self.widget.addConstraintToRow(constraint=const, row=row) … … 1291 1308 self.widget.cbModel.setCurrentIndex(model_index) 1292 1309 1310 row1 = 1 1311 row2 = 5 1312 1313 param1 = "background" 1314 param2 = "radius" 1315 1316 #default_value1 = "0.001" 1317 default_value2 = "20" 1318 1293 1319 # select two rows 1294 row1 = 11295 row2 = 41296 1320 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1297 1321 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1310 1334 1311 1335 # delete one of the constraints 1312 self.widget.deleteConstraintOnParameter(param= 'background')1336 self.widget.deleteConstraintOnParameter(param=param1) 1313 1337 1314 1338 # see that the other constraint is still present 1315 cons = self.widget.getConstraintForRow( 4) # 4 = radius1316 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) 1318 1342 1319 1343 # kill the other constraint … … 1321 1345 1322 1346 # see that the other constraint is still present 1323 self.assertEqual(self.widget.getConstraintsForModel(), [( 'radius', None)])1347 self.assertEqual(self.widget.getConstraintsForModel(), [(param2, None)]) 1324 1348 1325 1349 def testGetConstraintForRow(self): … … 1341 1365 self.widget.cbModel.setCurrentIndex(model_index) 1342 1366 1367 row1 = 1 1368 row2 = 5 1369 1343 1370 # select two rows 1344 row1 = 11345 row2 = 41346 1371 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1347 1372 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1353 1378 self.widget.addSimpleConstraint() 1354 1379 1355 con_list = [False, True, False, False, True, False]1380 con_list = [False, True, False, False, False, True, False] 1356 1381 new_list = [] 1357 1382 for row in range(self.widget._model_model.rowCount()): … … 1371 1396 self.widget.cbModel.setCurrentIndex(model_index) 1372 1397 1398 row1 = 1 1399 row2 = 5 1400 1373 1401 # select two rows 1374 row1 = 11375 row2 = 41376 1402 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1377 1403 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1387 1413 constraint_objects[0].active = False 1388 1414 1389 con_list = [False, False, False, False, True, False]1415 con_list = [False, False, False, False, False, True, False] 1390 1416 new_list = [] 1391 1417 for row in range(self.widget._model_model.rowCount()): … … 1408 1434 self.assertEqual(self.widget.getConstraintsForModel(),[]) 1409 1435 1436 row1 = 1 1437 row2 = 5 1438 1439 param1 = "background" 1440 param2 = "radius" 1441 1442 default_value1 = "0.001" 1443 default_value2 = "20" 1444 1410 1445 # select two rows 1411 row1 = 11412 row2 = 41413 1446 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1414 1447 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1422 1455 # simple constraints 1423 1456 # self.assertEqual(self.widget.getConstraintsForModel(), [('background', '0.001'), ('radius', '20')]) 1424 cons = self.widget.getConstraintForRow( 1) # 1 - background1425 self.assertEqual(cons.param, "background")1426 self.assertEqual(cons.value, "0.001")1427 cons = self.widget.getConstraintForRow( 4) # 4 = radius1428 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) 1430 1463 1431 1464 objects = self.widget.getConstraintObjectsForModel() 1432 1465 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" 1435 1472 1436 1473 # 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) 1439 1475 self.widget.addConstraintToRow(constraint=const, row=row) 1440 1476 #self.assertEqual(self.widget.getConstraintsForModel(),[('scale', '5*sld'), ('background', '0.001'), ('radius', None)]) 1441 cons = self.widget.getConstraintForRow( 4) # 4 = radius1442 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) 1444 1480 1445 1481 objects = self.widget.getConstraintObjectsForModel() 1446 1482 self.assertEqual(len(objects), 3) 1447 self.assertEqual(objects[0].func, '5*sld')1483 self.assertEqual(objects[0].func, func) 1448 1484 1449 1485 def testReplaceConstraintName(self): -
src/sas/qtgui/Plotting/Plotter.py
rb764ae5 rc2f3ca2 30 30 # Dictionary of {plot_id:Data1d} 31 31 self.plot_dict = {} 32 32 # Dictionaty of {plot_id:line} 33 34 self.plot_lines = {} 33 35 # Window for text add 34 36 self.addText = AddText(self) … … 182 184 self.plot_dict[self._data.id] = self.data 183 185 186 self.plot_lines[self._data.id] = line 187 184 188 # Now add the legend with some customizations. 185 189 … … 196 200 197 201 # refresh canvas 198 self.canvas.draw _idle()202 self.canvas.draw() 199 203 # This is an important processEvent. 200 204 # This allows charts to be properly updated in order … … 416 420 This effectlvely refreshes the chart with changes to one of its plots 417 421 """ 422 import logging 418 423 self.removePlot(id) 419 424 self.plot(data=new_plot) … … 470 475 """ 471 476 selected_plot = self.plot_dict[id] 472 477 selected_line = self.plot_lines[id] 473 478 # Old style color - single integer for enum color 474 479 # New style color - #hhhhhh -
src/sas/qtgui/MainWindow/GuiManager.py
rf84d793 r339e22b 422 422 self._workspace.actionExcel.triggered.connect(self.actionExcel) 423 423 self._workspace.actionLatex.triggered.connect(self.actionLatex) 424 425 424 # View 426 425 self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window) … … 452 451 self._workspace.actionManage_Custom_Models.triggered.connect(self.actionManage_Custom_Models) 453 452 self._workspace.actionAddMult_Models.triggered.connect(self.actionAddMult_Models) 453 self._workspace.actionEditMask.triggered.connect(self.actionEditMask) 454 454 455 # Window 455 456 self._workspace.actionCascade.triggered.connect(self.actionCascade) … … 781 782 self.add_mult_editor.show() 782 783 784 def actionEditMask(self): 785 786 self.communicate.extMaskEditorSignal.emit() 787 783 788 #============ ANALYSIS ================= 784 789 def actionFitting(self): -
src/sas/qtgui/MainWindow/UI/MainWindowUI.ui
rdda8f16 r339e22b 113 113 <addaction name="actionManage_Custom_Models"/> 114 114 <addaction name="actionAddMult_Models"/> 115 <addaction name="separator"/> 116 <addaction name="EditMask"/> 115 117 </widget> 116 118 <widget class="QMenu" name="menuWindow"> … … 413 415 </property> 414 416 </action> 417 <action name="EditMask"> 418 <property name="text"> 419 <string>Edit Mask</string> 420 </property> 421 </action> 415 422 <action name="actionCascade"> 416 423 <property name="text"> -
src/sas/qtgui/Utilities/GuiUtils.py
r6da3e3d r339e22b 265 265 # Mask Editor requested 266 266 maskEditorSignal = QtCore.pyqtSignal(Data2D) 267 268 #second Mask Editor for external 269 extMaskEditorSignal = QtCore.pyqtSignal() 267 270 268 271 # Fitting parameter copy to clipboard
Note: See TracChangeset
for help on using the changeset viewer.