Changes in / [dd2c2a31:e0da307] in sasview
- Files:
-
- 1 deleted
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
r7cc38a7 rce1f491 16 16 *.pyproj 17 17 *.sln 18 .*.swp19 18 .DS_Store 20 19 /.settings -
src/sas/qtgui/MainWindow/DataExplorer.py
r0cd98a1 re0da307 42 42 # Main model for keeping loaded data 43 43 self.model = QtGui.QStandardItemModel(self) 44 44 45 # Secondary model for keeping frozen data sets 45 46 self.theory_model = QtGui.QStandardItemModel(self) … … 97 98 self.communicator.plotUpdateSignal.connect(self.updatePlot) 98 99 self.communicator.maskEditorSignal.connect(self.showEditDataMask) 99 self.communicator.extMaskEditorSignal.connect(self.extShowEditDataMask)100 100 101 101 self.cbgraph.editTextChanged.connect(self.enableGraphCombo) … … 598 598 plot2D.plot(plot_set) 599 599 self.addPlot(plot2D) 600 self.active_plots[plot2D.data. name] = plot2D600 self.active_plots[plot2D.data.id] = plot2D 601 601 #============================================ 602 602 # Experimental hook for silx charts … … 626 626 new_plot.plot(plot_set, transform=transform) 627 627 # active_plots may contain multiple charts 628 self.active_plots[plot_set. name] = new_plot628 self.active_plots[plot_set.id] = new_plot 629 629 elif isinstance(plot_set, Data2D): 630 630 self.addDataPlot2D(plot_set, item) … … 697 697 old_plot.plot() 698 698 # need this for lookup - otherwise this plot will never update 699 self.active_plots[plot_set. name] = old_plot699 self.active_plots[plot_set.id] = old_plot 700 700 701 701 def updatePlot(self, data): … … 711 711 712 712 ids_keys = list(self.active_plots.keys()) 713 ids_vals = [val.data. namefor val in self.active_plots.values()]714 715 data_id = data. name713 ids_vals = [val.data.id for val in self.active_plots.values()] 714 715 data_id = data.id 716 716 if data_id in ids_keys: 717 717 self.active_plots[data_id].replacePlot(data_id, data) … … 952 952 model = proxy.sourceModel() 953 953 954 if not index.isValid(): 955 return 956 model_item = model.itemFromIndex(proxy.mapToSource(index)) 957 # Find the mapped index 958 orig_index = model_item.isCheckable() 959 if not orig_index: 960 return 961 # Check the data to enable/disable actions 962 is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D) 963 self.actionQuick3DPlot.setEnabled(is_2D) 964 self.actionEditMask.setEnabled(is_2D) 965 # Fire up the menu 966 self.context_menu.exec_(self.current_view.mapToGlobal(position)) 954 if index.isValid(): 955 model_item = model.itemFromIndex(proxy.mapToSource(index)) 956 # Find the mapped index 957 orig_index = model_item.isCheckable() 958 if orig_index: 959 # Check the data to enable/disable actions 960 is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D) 961 self.actionQuick3DPlot.setEnabled(is_2D) 962 self.actionEditMask.setEnabled(is_2D) 963 # Fire up the menu 964 self.context_menu.exec_(self.current_view.mapToGlobal(position)) 967 965 968 966 def showDataInfo(self): … … 1061 1059 self.new_plot.show() 1062 1060 1063 def extShowEditDataMask(self):1064 self.showEditDataMask()1065 1066 1061 def showEditDataMask(self, data=None): 1067 1062 """ 1068 1063 Mask Editor for 2D plots 1069 1064 """ 1070 try: 1071 if data is None or not isinstance(data, Data2D): 1072 index = self.current_view.selectedIndexes()[0] 1073 proxy = self.current_view.model() 1074 model = proxy.sourceModel() 1075 model_item = model.itemFromIndex(proxy.mapToSource(index)) 1076 1077 data = GuiUtils.dataFromItem(model_item) 1078 1079 if data is None or not isinstance(data, Data2D): 1080 msg = QtWidgets.QMessageBox() 1081 msg.setIcon(QtWidgets.QMessageBox.Information) 1082 msg.setText("Error: cannot apply mask. \ 1083 Please select a 2D dataset.") 1084 msg.setStandardButtons(QtWidgets.QMessageBox.Cancel) 1085 msg.exec_() 1086 return 1087 except: 1088 msg = QtWidgets.QMessageBox() 1089 msg.setIcon(QtWidgets.QMessageBox.Information) 1090 msg.setText("Error: No dataset selected. \ 1091 Please select a 2D dataset.") 1092 msg.setStandardButtons(QtWidgets.QMessageBox.Cancel) 1093 msg.exec_() 1094 return 1065 if data is None or not isinstance(data, Data2D): 1066 index = self.current_view.selectedIndexes()[0] 1067 proxy = self.current_view.model() 1068 model = proxy.sourceModel() 1069 model_item = model.itemFromIndex(proxy.mapToSource(index)) 1070 1071 data = GuiUtils.dataFromItem(model_item) 1095 1072 1096 1073 mask_editor = MaskEditor(self, data) -
src/sas/qtgui/MainWindow/GuiManager.py
r339e22b rf84d793 422 422 self._workspace.actionExcel.triggered.connect(self.actionExcel) 423 423 self._workspace.actionLatex.triggered.connect(self.actionLatex) 424 424 425 # View 425 426 self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window) … … 451 452 self._workspace.actionManage_Custom_Models.triggered.connect(self.actionManage_Custom_Models) 452 453 self._workspace.actionAddMult_Models.triggered.connect(self.actionAddMult_Models) 453 self._workspace.actionEditMask.triggered.connect(self.actionEditMask)454 455 454 # Window 456 455 self._workspace.actionCascade.triggered.connect(self.actionCascade) … … 782 781 self.add_mult_editor.show() 783 782 784 def actionEditMask(self):785 786 self.communicate.extMaskEditorSignal.emit()787 788 783 #============ ANALYSIS ================= 789 784 def actionFitting(self): -
src/sas/qtgui/MainWindow/UI/MainWindowUI.ui
r2f14b5d rdda8f16 113 113 <addaction name="actionManage_Custom_Models"/> 114 114 <addaction name="actionAddMult_Models"/> 115 <addaction name="separator"/>116 <addaction name="actionEditMask"/>117 115 </widget> 118 116 <widget class="QMenu" name="menuWindow"> … … 415 413 </property> 416 414 </action> 417 <action name="actionEditMask">418 <property name="text">419 <string>Edit Mask</string>420 </property>421 </action>422 415 <action name="actionCascade"> 423 416 <property name="text"> -
src/sas/qtgui/Perspectives/Fitting/FittingLogic.py
rdcabba7 rb4d05bd 161 161 Create a new 1D data instance based on fitting results 162 162 """ 163 return self._create1DPlot(tab_id, return_data['x'], return_data['y'], 164 return_data['model'], return_data['data']) 163 # Unpack return data from Calc1D 164 x, y, page_id, state, weight,\ 165 fid, toggle_mode_on, \ 166 elapsed, index, model, \ 167 data, update_chisqr, source, \ 168 unsmeared_output, unsmeared_data, unsmeared_error, \ 169 pq_values, sq_values = return_data 170 171 return self._create1DPlot(tab_id, x, y, model, data) 165 172 166 173 def new2DPlot(self, return_data): … … 168 175 Create a new 2D data instance based on fitting results 169 176 """ 170 image = return_data['image']171 data = return_data['data']172 model = return_data['model']177 image, data, page_id, model, state, toggle_mode_on,\ 178 elapsed, index, fid, qmin, qmax, weight, \ 179 update_chisqr, source = return_data 173 180 174 181 np.nan_to_num(image) … … 176 183 new_plot.name = model.name + '2d' 177 184 new_plot.title = "Analytical model 2D " 178 new_plot.id = str( return_data['page_id']) + " " + data.name179 new_plot.group_id = str( return_data['page_id']) + " Model2D"185 new_plot.id = str(page_id) + " " + data.name 186 new_plot.group_id = str(page_id) + " Model2D" 180 187 new_plot.detector = data.detector 181 188 new_plot.source = data.source … … 211 218 (pq_plot, sq_plot). If either are unavailable, the corresponding plot is None. 212 219 """ 213 plots = [] 214 for name, result in return_data['intermediate_results'].items(): 215 plots.append(self._create1DPlot(tab_id, return_data['x'], result, 216 return_data['model'], return_data['data'], 217 component=name)) 218 return plots 220 # Unpack return data from Calc1D 221 x, y, page_id, state, weight, \ 222 fid, toggle_mode_on, \ 223 elapsed, index, model, \ 224 data, update_chisqr, source, \ 225 unsmeared_output, unsmeared_data, unsmeared_error, \ 226 pq_values, sq_values = return_data 227 228 pq_plot = None 229 sq_plot = None 230 231 if pq_values is not None: 232 pq_plot = self._create1DPlot(tab_id, x, pq_values, model, data, component="P(Q)") 233 if sq_values is not None: 234 sq_plot = self._create1DPlot(tab_id, x, sq_values, model, data, component="S(Q)") 235 236 return pq_plot, sq_plot 219 237 220 238 def computeDataRange(self): -
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
r70f4458 rb764ae5 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 AssociatedComboBox12 10 13 11 model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units'] … … 63 61 return (param_name, param_length) 64 62 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. 63 def addParametersToModel(parameters, kernel_module, is2D): 64 """ 65 Update local ModelModel with sasmodel parameters 98 66 """ 99 67 multishell_parameters = getIterParams(parameters) … … 104 72 else: 105 73 params = parameters.iq_parameters 106 107 rows = [] 74 item = [] 108 75 for param in params: 109 76 # don't include shell parameters 110 77 if param.name == multishell_param_name: 111 78 continue 112 113 79 # Modify parameter name from <param>[n] to <param>1 114 80 item_name = param.name 115 81 if param in multishell_parameters: 116 82 continue 83 # item_name = replaceShellName(param.name, 1) 117 84 118 85 item1 = QtGui.QStandardItem(item_name) 119 86 item1.setCheckable(True) 120 87 item1.setEditable(False) 121 88 # item_err = QtGui.QStandardItem() 122 89 # check for polydisp params 123 90 if param.polydisperse: … … 126 93 item1_1 = QtGui.QStandardItem("Distribution") 127 94 item1_1.setEditable(False) 128 129 95 # Find param in volume_params 130 96 for p in parameters.form_volume_parameters: … … 133 99 width = kernel_module.getParam(p.name+'.width') 134 100 ptype = kernel_module.getParam(p.name+'.type') 101 135 102 item1_2 = QtGui.QStandardItem(str(width)) 136 103 item1_2.setEditable(False) … … 143 110 poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 144 111 break 145 146 112 # Add the polydisp item as a child 147 113 item1.appendRow([poly_item]) 148 149 114 # Param values 150 115 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() 151 119 item3 = QtGui.QStandardItem(str(param.limits[0])) 152 120 item4 = QtGui.QStandardItem(str(param.limits[1])) 153 item5 = QtGui.QStandardItem( str(param.units))121 item5 = QtGui.QStandardItem(param.units) 154 122 item5.setEditable(False) 155 156 # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 157 row = [item1, item2, item3, item4, item5] 158 cbox = createFixedChoiceComboBox(param, row) 159 160 # Append to the model and use the combobox, if required 161 if None not in (model, view): 162 model.appendRow(row) 163 if cbox: 164 view.setIndexWidget(item2.index(), cbox) 165 rows.append(row) 166 167 return rows 168 169 def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None, row_num=None): 170 """ 171 Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic) 172 Actually appends to model, if model and view params are not None. 173 Always returns list of lists of QStandardItems. 174 175 parameters_original: list of parameters before any tagging on their IDs, e.g. for product model (so that those are 176 the display names; see below) 123 item.append([item1, item2, item3, item4, item5]) 124 return item 125 126 def addSimpleParametersToModel(parameters, is2D): 127 """ 128 Update local ModelModel with sasmodel parameters 177 129 """ 178 130 if is2D: … … 180 132 else: 181 133 params = parameters.iq_parameters 182 183 if parameters_original: 184 # 'parameters_original' contains the parameters as they are to be DISPLAYED, while 'parameters' 185 # contains the parameters as they were renamed; this is for handling name collisions in product model. 186 # The 'real name' of the parameter will be stored in the item's user data. 187 if is2D: 188 params_orig = [p for p in parameters_original.kernel_parameters if p.type != 'magnetic'] 189 else: 190 params_orig = parameters_original.iq_parameters 191 else: 192 # no difference in names anyway 193 params_orig = params 194 195 rows = [] 196 for param, param_orig in zip(params, params_orig): 134 item = [] 135 for param in params: 197 136 # Create the top level, checkable item 198 item_name = param _orig.name137 item_name = param.name 199 138 item1 = QtGui.QStandardItem(item_name) 200 item1.setData(param.name, QtCore.Qt.UserRole)201 139 item1.setCheckable(True) 202 140 item1.setEditable(False) 203 204 141 # Param values 205 142 # TODO: add delegate for validation of cells 206 143 item2 = QtGui.QStandardItem(str(param.default)) 207 item3 = QtGui.QStandardItem(str(param.limits[0])) 208 item4 = QtGui.QStandardItem(str(param.limits[1])) 209 item5 = QtGui.QStandardItem(str(param.units)) 210 item5.setEditable(False) 211 212 # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 213 row = [item1, item2, item3, item4, item5] 214 cbox = createFixedChoiceComboBox(param, row) 215 216 # Append to the model and use the combobox, if required 217 if None not in (model, view): 218 if row_num is None: 219 model.appendRow(row) 220 else: 221 model.insertRow(row_num, row) 222 row_num += 1 223 224 if cbox: 225 view.setIndexWidget(item2.index(), cbox) 226 227 rows.append(row) 228 229 return rows 144 item4 = QtGui.QStandardItem(str(param.limits[0])) 145 item5 = QtGui.QStandardItem(str(param.limits[1])) 146 item6 = QtGui.QStandardItem(param.units) 147 item6.setEditable(False) 148 item.append([item1, item2, item4, item5, item6]) 149 return item 230 150 231 151 def markParameterDisabled(model, row): … … 262 182 model.appendRow(item_list) 263 183 264 def addHeadingRowToModel(model, name):265 """adds a non-interactive top-level row to the model"""266 header_row = [QtGui.QStandardItem() for i in range(5)]267 header_row[0].setText(name)268 269 font = header_row[0].font()270 font.setBold(True)271 header_row[0].setFont(font)272 273 for item in header_row:274 item.setEditable(False)275 item.setCheckable(False)276 item.setSelectable(False)277 278 model.appendRow(header_row)279 280 184 def addHeadersToModel(model): 281 185 """ … … 323 227 model.header_tooltips = copy.copy(poly_header_error_tooltips) 324 228 325 def addShellsToModel(parameters, model, index, row_num=None, view=None): 326 """ 327 Find out multishell parameters and update the model with the requested number of them. 328 Inserts them after the row at row_num, if not None; otherwise, appends to end. 329 If view param is not None, supports fixed-choice params. 330 Returns a list of lists of QStandardItem objects. 229 def addShellsToModel(parameters, model, index): 230 """ 231 Find out multishell parameters and update the model with the requested number of them 331 232 """ 332 233 multishell_parameters = getIterParams(parameters) 333 234 334 rows = []335 235 for i in range(index): 336 236 for par in multishell_parameters: … … 350 250 item1_3 = QtGui.QStandardItem(str(p.limits[0])) 351 251 item1_4 = QtGui.QStandardItem(str(p.limits[1])) 352 item1_5 = QtGui.QStandardItem( str(p.units))252 item1_5 = QtGui.QStandardItem(p.units) 353 253 poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 354 254 break … … 358 258 item3 = QtGui.QStandardItem(str(par.limits[0])) 359 259 item4 = QtGui.QStandardItem(str(par.limits[1])) 360 item5 = QtGui.QStandardItem(str(par.units)) 361 item5.setEditable(False) 362 363 # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 364 row = [item1, item2, item3, item4, item5] 365 cbox = createFixedChoiceComboBox(par, row) 366 367 # Always add to the model 368 if row_num is None: 369 model.appendRow(row) 370 else: 371 model.insertRow(row_num, row) 372 row_num += 1 373 374 # Apply combobox if required 375 if None not in (view, cbox): 376 view.setIndexWidget(item2.index(), cbox) 377 378 rows.append(row) 379 380 return rows 260 item5 = QtGui.QStandardItem(par.units) 261 model.appendRow([item1, item2, item3, item4, item5]) 381 262 382 263 def calculateChi2(reference_data, current_data): -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
rd4ba565 rf84d793 48 48 from sas.qtgui.Perspectives.Fitting.ReportPageLogic import ReportPageLogic 49 49 50 50 51 TAB_MAGNETISM = 4 51 52 TAB_POLY = 3 … … 90 91 fittingFinishedSignal = QtCore.pyqtSignal(tuple) 91 92 batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 92 Calc1DFinishedSignal = QtCore.pyqtSignal( dict)93 Calc2DFinishedSignal = QtCore.pyqtSignal( dict)93 Calc1DFinishedSignal = QtCore.pyqtSignal(tuple) 94 Calc2DFinishedSignal = QtCore.pyqtSignal(tuple) 94 95 95 96 def __init__(self, parent=None, data=None, tab_id=1): … … 187 188 188 189 # Overwrite data type descriptor 189 190 190 self.is2D = True if isinstance(self.logic.data, Data2D) else False 191 191 … … 219 219 # Utility variable to enable unselectable option in category combobox 220 220 self._previous_category_index = 0 221 # Utility variables for multishell display 222 self._n_shells_row = 0 223 self._num_shell_params = 0 221 # Utility variable for multishell display 222 self._last_model_row = 0 224 223 # Dictionary of {model name: model class} for the current category 225 224 self.models = {} … … 248 247 # copy of current kernel model 249 248 self.kernel_module_copy = None 250 251 # dictionaries of current params252 self.poly_params = {}253 self.magnet_params = {}254 249 255 250 # Page id for fitting … … 563 558 When clicked on white space: model description 564 559 """ 565 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows() 566 if self.isCheckable(s.row())] 560 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()] 567 561 menu = self.showModelDescription() if not rows else self.modelContextMenu(rows) 568 562 try: … … 678 672 Return list of all parameters for the current model 679 673 """ 680 return [self._model_model.item(row).text() 681 for row in range(self._model_model.rowCount()) 682 if self.isCheckable(row)] 674 return [self._model_model.item(row).text() for row in range(self._model_model.rowCount())] 683 675 684 676 def modifyViewOnRow(self, row, font=None, brush=None): … … 708 700 assert isinstance(constraint, Constraint) 709 701 assert 0 <= row <= self._model_model.rowCount() 710 assert self.isCheckable(row)711 702 712 703 item = QtGui.QStandardItem() … … 729 720 max_col = self.lstParams.itemDelegate().param_max 730 721 for row in self.selectedParameters(): 731 assert(self.isCheckable(row))732 722 param = self._model_model.item(row, 0).text() 733 723 value = self._model_model.item(row, 1).text() … … 772 762 max_col = self.lstParams.itemDelegate().param_max 773 763 for row in range(self._model_model.rowCount()): 774 if not self.isCheckable(row):775 continue776 764 if not self.rowHasConstraint(row): 777 765 continue … … 800 788 def getConstraintForRow(self, row): 801 789 """ 802 For the given row, return its constraint, if any (otherwise None) 803 """ 804 if not self.isCheckable(row): 805 return None 806 item = self._model_model.item(row, 1) 790 For the given row, return its constraint, if any 791 """ 807 792 try: 793 item = self._model_model.item(row, 1) 808 794 return item.child(0).data() 809 795 except AttributeError: 796 # return none when no constraints 810 797 return None 811 798 … … 814 801 Finds out if row of the main model has a constraint child 815 802 """ 816 if not self.isCheckable(row):817 return False818 803 item = self._model_model.item(row, 1) 819 if not item.hasChildren(): 820 return False 821 c = item.child(0).data() 822 if isinstance(c, Constraint): 823 return True 804 if item.hasChildren(): 805 c = item.child(0).data() 806 if isinstance(c, Constraint): 807 return True 824 808 return False 825 809 … … 828 812 Finds out if row of the main model has an active constraint child 829 813 """ 830 if not self.isCheckable(row):831 return False832 814 item = self._model_model.item(row, 1) 833 if not item.hasChildren(): 834 return False 835 c = item.child(0).data() 836 if isinstance(c, Constraint) and c.active: 837 return True 815 if item.hasChildren(): 816 c = item.child(0).data() 817 if isinstance(c, Constraint) and c.active: 818 return True 838 819 return False 839 820 … … 842 823 Finds out if row of the main model has an active, nontrivial constraint child 843 824 """ 844 if not self.isCheckable(row):845 return False846 825 item = self._model_model.item(row, 1) 847 if not item.hasChildren(): 848 return False 849 c = item.child(0).data() 850 if isinstance(c, Constraint) and c.func and c.active: 851 return True 826 if item.hasChildren(): 827 c = item.child(0).data() 828 if isinstance(c, Constraint) and c.func and c.active: 829 return True 852 830 return False 853 831 … … 1059 1037 # Show constraint, if present 1060 1038 row = rows[0].row() 1061 if not self.rowHasConstraint(row): 1062 return 1063 func = self.getConstraintForRow(row).func 1064 if func is not None: 1065 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 1039 if self.rowHasConstraint(row): 1040 func = self.getConstraintForRow(row).func 1041 if func is not None: 1042 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 1066 1043 1067 1044 def replaceConstraintName(self, old_name, new_name=""): … … 1209 1186 # Update the sasmodel 1210 1187 # PD[ratio] -> width, npts -> npts, nsigs -> nsigmas 1211 #self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 1212 key = parameter_name + '.' + delegate.columnDict()[model_column] 1213 self.poly_params[key] = value 1188 self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 1214 1189 1215 1190 # Update plot … … 1220 1195 row = self.getRowFromName(parameter_name) 1221 1196 param_item = self._model_model.item(row) 1222 self._model_model.blockSignals(True)1223 1197 param_item.child(0).child(0, model_column).setText(item.text()) 1224 self._model_model.blockSignals(False)1225 1198 1226 1199 def onMagnetModelChange(self, item): … … 1251 1224 # Unparsable field 1252 1225 return 1253 delegate = self.lstMagnetic.itemDelegate() 1254 1255 if model_column > 1: 1256 if model_column == delegate.mag_min: 1257 pos = 1 1258 elif model_column == delegate.mag_max: 1259 pos = 2 1260 elif model_column == delegate.mag_unit: 1261 pos = 0 1262 else: 1263 raise AttributeError("Wrong column in magnetism table.") 1264 # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 1265 self.kernel_module.details[parameter_name][pos] = value 1266 else: 1267 self.magnet_params[parameter_name] = value 1268 #self.kernel_module.setParam(parameter_name) = value 1269 # Force the chart update when actual parameters changed 1226 1227 property_index = self._magnet_model.headerData(1, model_column)-1 # Value, min, max, etc. 1228 1229 # Update the parameter value - note: this supports +/-inf as well 1230 self.kernel_module.params[parameter_name] = value 1231 1232 # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 1233 self.kernel_module.details[parameter_name][property_index] = value 1234 1235 # Force the chart update when actual parameters changed 1236 if model_column == 1: 1270 1237 self.recalculatePlotData() 1271 1238 … … 1514 1481 # update charts 1515 1482 self.onPlot() 1516 #self.recalculatePlotData()1517 1518 1483 1519 1484 # Read only value - we can get away by just printing it here … … 1530 1495 # Data going in 1531 1496 data = self.logic.data 1532 model = copy.deepcopy(self.kernel_module)1497 model = self.kernel_module 1533 1498 qmin = self.q_range_min 1534 1499 qmax = self.q_range_max 1535 # add polydisperse/magnet parameters if asked1536 self.updateKernelModelWithExtraParams(model)1537 1500 1538 1501 params_to_fit = self.main_params_to_fit … … 1598 1561 # internal so can use closure for param_dict 1599 1562 param_name = str(self._model_model.item(row, 0).text()) 1600 if not self.isCheckable(row) orparam_name not in list(param_dict.keys()):1563 if param_name not in list(param_dict.keys()): 1601 1564 return 1602 1565 # modify the param value 1603 1566 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1604 1567 self._model_model.item(row, 1).setText(param_repr) 1605 self.kernel_module.setParam(param_name, param_dict[param_name][0])1606 1568 if self.has_error_column: 1607 1569 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1611 1573 # Utility function for updateof polydispersity part of the main model 1612 1574 param_name = str(self._model_model.item(row, 0).text())+'.width' 1613 if not self.isCheckable(row) orparam_name not in list(param_dict.keys()):1575 if param_name not in list(param_dict.keys()): 1614 1576 return 1615 1577 # modify the param value … … 1645 1607 poly_item.insertColumn(2, [QtGui.QStandardItem("")]) 1646 1608 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 1647 1613 if not self.has_error_column: 1648 1614 # create top-level error column … … 1651 1617 self.iterateOverModel(createErrorColumn) 1652 1618 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) 1653 1622 self._model_model.insertColumn(2, error_column) 1623 self._model_model.blockSignals(True) 1654 1624 1655 1625 FittingUtilities.addErrorHeadersToModel(self._model_model) … … 1660 1630 self.has_error_column = True 1661 1631 1662 # block signals temporarily, so we don't end up1663 # updating charts with every single model change on the end of fitting1664 self._model_model.itemChanged.disconnect()1665 1632 self.iterateOverModel(updateFittedValues) 1666 1633 self.iterateOverModel(updatePolyValues) 1667 self._model_model.itemChanged.connect(self.onMainParamsChange) 1634 1635 self._model_model.blockSignals(False) 1668 1636 1669 1637 # Adjust the table cells width. … … 1700 1668 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1701 1669 self._poly_model.item(row_i, 1).setText(param_repr) 1702 self.kernel_module.setParam(param_name, param_dict[param_name][0])1703 1670 if self.has_poly_error_column: 1704 1671 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 1705 1672 self._poly_model.item(row_i, 2).setText(error_repr) 1673 1706 1674 1707 1675 def createErrorColumn(row_i): … … 1724 1692 # block signals temporarily, so we don't end up 1725 1693 # updating charts with every single model change on the end of fitting 1726 self._poly_model. itemChanged.disconnect()1694 self._poly_model.blockSignals(True) 1727 1695 self.iterateOverPolyModel(updateFittedValues) 1728 self._poly_model. itemChanged.connect(self.onPolyModelChange)1696 self._poly_model.blockSignals(False) 1729 1697 1730 1698 if self.has_poly_error_column: … … 1736 1704 1737 1705 # switch off reponse to model change 1706 self._poly_model.blockSignals(True) 1738 1707 self._poly_model.insertColumn(2, error_column) 1708 self._poly_model.blockSignals(False) 1739 1709 FittingUtilities.addErrorPolyHeadersToModel(self._poly_model) 1740 1710 … … 1769 1739 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1770 1740 self._magnet_model.item(row, 1).setText(param_repr) 1771 self.kernel_module.setParam(param_name, param_dict[param_name][0])1772 1741 if self.has_magnet_error_column: 1773 1742 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1789 1758 # block signals temporarily, so we don't end up 1790 1759 # updating charts with every single model change on the end of fitting 1791 self._magnet_model. itemChanged.disconnect()1760 self._magnet_model.blockSignals(True) 1792 1761 self.iterateOverMagnetModel(updateFittedValues) 1793 self._magnet_model. itemChanged.connect(self.onMagnetModelChange)1762 self._magnet_model.blockSignals(False) 1794 1763 1795 1764 if self.has_magnet_error_column: … … 1801 1770 1802 1771 # switch off reponse to model change 1772 self._magnet_model.blockSignals(True) 1803 1773 self._magnet_model.insertColumn(2, error_column) 1774 self._magnet_model.blockSignals(False) 1804 1775 FittingUtilities.addErrorHeadersToModel(self._magnet_model) 1805 1776 … … 1813 1784 self.cmdPlot.setText("Show Plot") 1814 1785 # Force data recalculation so existing charts are updated 1786 self.recalculatePlotData() 1815 1787 self.showPlot() 1816 # This is an important processEvent.1817 # This allows charts to be properly updated in order1818 # of plots being applied.1819 QtWidgets.QApplication.processEvents()1820 self.recalculatePlotData()1821 1788 1822 1789 def onSmearingOptionsUpdate(self): … … 1983 1950 # Crete/overwrite model items 1984 1951 self._model_model.clear() 1985 self._poly_model.clear() 1986 self._magnet_model.clear()1987 1988 if model_name is None:1989 if structure_factor not in (None, "None"): 1990 # S(Q) on its own, treat the same as a form factor1991 self.kernel_module = None1992 self.fromStructureFactorToQModel(structure_factor)1993 else:1994 # No models selected1995 return1952 1953 # First, add parameters from the main model 1954 if model_name is not None: 1955 self.fromModelToQModel(model_name) 1956 1957 # Then, add structure factor derived parameters 1958 if structure_factor is not None and structure_factor != "None": 1959 if model_name is None: 1960 # Instantiate the current sasmodel for SF-only models 1961 self.kernel_module = self.models[structure_factor]() 1962 self.fromStructureFactorToQModel(structure_factor) 1996 1963 else: 1997 self.fromModelToQModel(model_name)1998 self.addExtraShells()1999 2000 1964 # Allow the SF combobox visibility for the given sasmodel 2001 1965 self.enableStructureFactorControl(structure_factor) 2002 2003 # Add S(Q)2004 1966 if self.cbStructureFactor.isEnabled(): 2005 1967 structure_factor = self.cbStructureFactor.currentText() 2006 1968 self.fromStructureFactorToQModel(structure_factor) 2007 1969 2008 # Add polydispersity to the model 2009 self.poly_params = {} 2010 self.setPolyModel() 2011 # Add magnetic parameters to the model 2012 self.magnet_params = {} 2013 self.setMagneticModel() 1970 # Then, add multishells 1971 if model_name is not None: 1972 # Multishell models need additional treatment 1973 self.addExtraShells() 1974 1975 # Add polydispersity to the model 1976 self.setPolyModel() 1977 # Add magnetic parameters to the model 1978 self.setMagneticModel() 2014 1979 2015 1980 # Adjust the table cells width … … 2084 2049 self.shell_names = self.shellNamesList() 2085 2050 2086 # Add heading row2087 FittingUtilities.addHeadingRowToModel(self._model_model, model_name)2088 2089 2051 # Update the QModel 2090 FittingUtilities.addParametersToModel(2091 self.model_parameters, 2092 self.kernel_module,2093 self.is2D,2094 self._model_model,2095 self.lstParams)2052 new_rows = FittingUtilities.addParametersToModel(self.model_parameters, self.kernel_module, self.is2D) 2053 2054 for row in new_rows: 2055 self._model_model.appendRow(row) 2056 # Update the counter used for multishell display 2057 self._last_model_row = self._model_model.rowCount() 2096 2058 2097 2059 def fromStructureFactorToQModel(self, structure_factor): … … 2101 2063 if structure_factor is None or structure_factor=="None": 2102 2064 return 2103 2104 product_params = None 2105 2106 if self.kernel_module is None: 2107 # Structure factor is the only selected model; build it and show all its params 2108 self.kernel_module = self.models[structure_factor]() 2109 s_params = self.kernel_module._model_info.parameters 2110 s_params_orig = s_params 2111 else: 2112 s_kernel = self.models[structure_factor]() 2113 p_kernel = self.kernel_module 2114 2115 p_pars_len = len(p_kernel._model_info.parameters.kernel_parameters) 2116 s_pars_len = len(s_kernel._model_info.parameters.kernel_parameters) 2117 2118 self.kernel_module = MultiplicationModel(p_kernel, s_kernel) 2119 all_params = self.kernel_module._model_info.parameters.kernel_parameters 2120 all_param_names = [param.name for param in all_params] 2121 2122 # S(Q) params from the product model are not necessarily the same as those from the S(Q) model; any 2123 # conflicting names with P(Q) params will cause a rename 2124 2125 if "radius_effective_mode" in all_param_names: 2126 # Show all parameters 2127 # In this case, radius_effective is NOT pruned by sasmodels.product 2128 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len]) 2129 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters) 2130 product_params = modelinfo.ParameterTable( 2131 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 2132 else: 2133 # Ensure radius_effective is not displayed 2134 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters[1:]) 2135 if "radius_effective" in all_param_names: 2136 # In this case, radius_effective is NOT pruned by sasmodels.product 2137 s_params = modelinfo.ParameterTable(all_params[p_pars_len+1:p_pars_len+s_pars_len]) 2138 product_params = modelinfo.ParameterTable( 2139 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 2140 else: 2141 # In this case, radius_effective is pruned by sasmodels.product 2142 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len-1]) 2143 product_params = modelinfo.ParameterTable( 2144 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len-1:]) 2145 2146 # Add heading row 2147 FittingUtilities.addHeadingRowToModel(self._model_model, structure_factor) 2148 2149 # Get new rows for QModel 2150 # Any renamed parameters are stored as data in the relevant item, for later handling 2151 FittingUtilities.addSimpleParametersToModel( 2152 parameters=s_params, 2153 is2D=self.is2D, 2154 parameters_original=s_params_orig, 2155 model=self._model_model, 2156 view=self.lstParams) 2157 2158 # Insert product-only params into QModel 2159 if product_params: 2160 prod_rows = FittingUtilities.addSimpleParametersToModel( 2161 parameters=product_params, 2162 is2D=self.is2D, 2163 parameters_original=None, 2164 model=self._model_model, 2165 view=self.lstParams, 2166 row_num=2) 2167 2168 # Since this all happens after shells are dealt with and we've inserted rows, fix this counter 2169 self._n_shells_row += len(prod_rows) 2065 structure_module = generate.load_kernel_module(structure_factor) 2066 structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', [])) 2067 2068 structure_kernel = self.models[structure_factor]() 2069 form_kernel = self.kernel_module 2070 2071 self.kernel_module = MultiplicationModel(form_kernel, structure_kernel) 2072 2073 new_rows = FittingUtilities.addSimpleParametersToModel(structure_parameters, self.is2D) 2074 for row in new_rows: 2075 self._model_model.appendRow(row) 2076 # disable fitting of parameters not listed in self.kernel_module (probably radius_effective) 2077 if row[0].text() not in self.kernel_module.params.keys(): 2078 row_num = self._model_model.rowCount() - 1 2079 FittingUtilities.markParameterDisabled(self._model_model, row_num) 2080 2081 # Update the counter used for multishell display 2082 self._last_model_row = self._model_model.rowCount() 2170 2083 2171 2084 def haveParamsToFit(self): … … 2193 2106 model_row = item.row() 2194 2107 name_index = self._model_model.index(model_row, 0) 2195 name_item = self._model_model.itemFromIndex(name_index)2196 2108 2197 2109 # Extract changed value. … … 2202 2114 return 2203 2115 2204 # if the item has user data, this is the actual parameter name (e.g. to handle duplicate names) 2205 if name_item.data(QtCore.Qt.UserRole): 2206 parameter_name = str(name_item.data(QtCore.Qt.UserRole)) 2207 else: 2208 parameter_name = str(self._model_model.data(name_index)) 2116 parameter_name = str(self._model_model.data(name_index)) # sld, background etc. 2209 2117 2210 2118 # Update the parameter value - note: this supports +/-inf as well … … 2329 2237 return self.completed1D if isinstance(self.data, Data1D) else self.completed2D 2330 2238 2331 def updateKernelModelWithExtraParams(self, model=None):2332 """2333 Updates kernel model 'model' with extra parameters from2334 the polydisp and magnetism tab, if the tabs are enabled2335 """2336 if model is None: return2337 if not hasattr(model, 'setParam'): return2338 2339 # add polydisperse parameters if asked2340 if self.chkPolydispersity.isChecked():2341 for key, value in self.poly_params.items():2342 model.setParam(key, value)2343 # add magnetic params if asked2344 if self.chkMagnetism.isChecked():2345 for key, value in self.magnet_params.items():2346 model.setParam(key, value)2347 2348 2239 def calculateQGridForModelExt(self, data=None, model=None, completefn=None, use_threads=True): 2349 2240 """ … … 2353 2244 data = self.data 2354 2245 if model is None: 2355 model = copy.deepcopy(self.kernel_module) 2356 self.updateKernelModelWithExtraParams(model) 2357 2246 model = self.kernel_module 2358 2247 if completefn is None: 2359 2248 completefn = self.methodCompleteForData() … … 2428 2317 2429 2318 # Create plots for intermediate product data 2430 plots = self.logic.new1DProductPlots(return_data, self.tab_id) 2431 for plot in plots: 2432 plot.symbol = "Line" 2433 self.createNewIndex(plot) 2434 new_plots.append(plot) 2435 2436 for plot in new_plots: 2437 self.communicate.plotUpdateSignal.emit([plot]) 2438 2439 def complete2D(self, return_data): 2440 """ 2441 Plot the current 2D data 2442 """ 2443 fitted_data = self.logic.new2DPlot(return_data) 2444 residuals = self.calculateResiduals(fitted_data) 2445 self.model_data = fitted_data 2446 new_plots = [fitted_data] 2447 if residuals is not None: 2448 new_plots.append(residuals) 2319 pq_data, sq_data = self.logic.new1DProductPlots(return_data, self.tab_id) 2320 if pq_data is not None: 2321 pq_data.symbol = "Line" 2322 self.createNewIndex(pq_data) 2323 # self.communicate.plotUpdateSignal.emit([pq_data]) 2324 new_plots.append(pq_data) 2325 if sq_data is not None: 2326 sq_data.symbol = "Line" 2327 self.createNewIndex(sq_data) 2328 # self.communicate.plotUpdateSignal.emit([sq_data]) 2329 new_plots.append(sq_data) 2449 2330 2450 2331 # Update/generate plots 2451 2332 for plot in new_plots: 2452 2333 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 2453 2342 2454 2343 def calculateResiduals(self, fitted_data): … … 2581 2470 _, min, max = self.kernel_module.details[param_name] 2582 2471 2583 # Update local param dict2584 self.poly_params[param_name + '.width'] = width2585 self.poly_params[param_name + '.npts'] = npts2586 self.poly_params[param_name + '.nsigmas'] = nsigs2587 2588 2472 # Construct a row with polydisp. related variable. 2589 2473 # This will get added to the polydisp. model … … 2633 2517 def updateFunctionCaption(row): 2634 2518 # Utility function for update of polydispersity function name in the main model 2635 if not self.isCheckable(row):2636 return2637 self._model_model.blockSignals(True)2638 2519 param_name = str(self._model_model.item(row, 0).text()) 2639 self._model_model.blockSignals(False)2640 2520 if param_name != param.name: 2641 2521 return 2642 2522 # Modify the param value 2643 self._model_model.blockSignals(True)2644 2523 if self.has_error_column: 2645 2524 # err column changes the indexing … … 2647 2526 else: 2648 2527 self._model_model.item(row, 0).child(0).child(0,4).setText(combo_string) 2649 self._model_model.blockSignals(False)2650 2528 2651 2529 if combo_string == 'array': … … 2766 2644 param.units] 2767 2645 2768 self.magnet_params[param.name] = param.default2769 2770 2646 FittingUtilities.addCheckedListToModel(model, checked_list) 2771 2647 … … 2807 2683 2808 2684 self.lstParams.setIndexWidget(shell_index, func) 2809 self._ n_shells_row = shell_row - 12685 self._last_model_row = self._model_model.rowCount() 2810 2686 2811 2687 # Set the index to the state-kept value … … 2818 2694 """ 2819 2695 # Find row location of the combobox 2820 first_row = self._n_shells_row + 12821 remove_rows = self._ num_shell_params2696 last_row = self._last_model_row 2697 remove_rows = self._model_model.rowCount() - last_row 2822 2698 2823 2699 if remove_rows > 1: 2824 self._model_model.removeRows(first_row, remove_rows) 2825 2826 new_rows = FittingUtilities.addShellsToModel( 2827 self.model_parameters, 2828 self._model_model, 2829 index, 2830 first_row, 2831 self.lstParams) 2832 2833 self._num_shell_params = len(new_rows) 2700 self._model_model.removeRows(last_row, remove_rows) 2701 2702 FittingUtilities.addShellsToModel(self.model_parameters, self._model_model, index) 2834 2703 self.current_shell_displayed = index 2835 2836 # Change 'n' in the parameter model, thereby updating the underlying model2837 self._model_model.item(self._n_shells_row, 1).setText(str(index))2838 2704 2839 2705 # Update relevant models … … 3180 3046 formatted_output = FittingUtilities.formatParameters(param_list) 3181 3047 elif format == "Excel": 3182 formatted_output = FittingUtilities.formatParametersExcel(param_list [1:])3048 formatted_output = FittingUtilities.formatParametersExcel(param_list) 3183 3049 elif format == "Latex": 3184 formatted_output = FittingUtilities.formatParametersLatex(param_list [1:])3050 formatted_output = FittingUtilities.formatParametersLatex(param_list) 3185 3051 else: 3186 3052 raise AttributeError("Bad format specifier.") … … 3347 3213 self._poly_model.blockSignals(False) 3348 3214 3349 3350 -
src/sas/qtgui/Perspectives/Fitting/ModelThread.py
r5181e9b r2df558e 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 111 103 if LocalConfig.USING_TWISTED: 112 return res 113 else: 114 self.completefn(res) 104 return (output, 105 self.data, 106 self.page_id, 107 self.model, 108 self.state, 109 self.toggle_mode_on, 110 elapsed, 111 index_model, 112 self.fid, 113 self.qmin, 114 self.qmax, 115 self.weight, 116 self.update_chisqr, 117 self.source) 118 else: 119 self.completefn((output, 120 self.data, 121 self.page_id, 122 self.model, 123 self.state, 124 self.toggle_mode_on, 125 elapsed, 126 index_model, 127 self.fid, 128 self.qmin, 129 self.qmax, 130 self.weight, 131 #qstep=self.qstep, 132 self.update_chisqr, 133 self.source)) 134 115 135 116 136 class Calc1D(CalcThread): … … 164 184 index = (self.qmin <= self.data.x) & (self.data.x <= self.qmax) 165 185 166 intermediate_results = None167 168 186 # If we use a smearer, also return the unsmeared model 169 187 unsmeared_output = None … … 176 194 mask = self.data.x[first_bin:last_bin+1] 177 195 unsmeared_output = numpy.zeros((len(self.data.x))) 178 179 return_data = self.model.calculate_Iq(mask) 180 if isinstance(return_data, tuple): 181 # see sasmodels beta_approx: SasviewModel.calculate_Iq 182 # TODO: implement intermediate results in smearers 183 return_data, _ = return_data 184 unsmeared_output[first_bin:last_bin+1] = return_data 196 unsmeared_output[first_bin:last_bin+1] = self.model.evalDistribution(mask) 185 197 output = self.smearer(unsmeared_output, first_bin, last_bin) 186 198 … … 201 213 unsmeared_error=unsmeared_error 202 214 else: 203 return_data = self.model.calculate_Iq(self.data.x[index]) 204 if isinstance(return_data, tuple): 205 # see sasmodels beta_approx: SasviewModel.calculate_Iq 206 return_data, intermediate_results = return_data 207 output[index] = return_data 208 209 if intermediate_results: 210 # the model returns a callable which is then used to retrieve the data 211 intermediate_results = intermediate_results() 212 else: 213 # TODO: this conditional branch needs refactoring 214 sq_values = None 215 pq_values = None 216 s_model = None 217 p_model = None 218 219 if isinstance(self.model, MultiplicationModel): 220 s_model = self.model.s_model 221 p_model = self.model.p_model 222 223 elif hasattr(self.model, "calc_composition_models"): 224 results = self.model.calc_composition_models(self.data.x[index]) 225 if results is not None: 226 pq_values, sq_values = results 227 228 if pq_values is None or sq_values is None: 229 if p_model is not None and s_model is not None: 230 sq_values = numpy.zeros((len(self.data.x))) 231 pq_values = numpy.zeros((len(self.data.x))) 232 sq_values[index] = s_model.evalDistribution(self.data.x[index]) 233 pq_values[index] = p_model.evalDistribution(self.data.x[index]) 234 235 if pq_values is not None and sq_values is not None: 236 intermediate_results = { 237 "P(Q)": pq_values, 238 "S(Q)": sq_values 239 } 240 else: 241 intermediate_results = {} 215 output[index] = self.model.evalDistribution(self.data.x[index]) 216 217 sq_values = None 218 pq_values = None 219 s_model = None 220 p_model = None 221 if isinstance(self.model, MultiplicationModel): 222 s_model = self.model.s_model 223 p_model = self.model.p_model 224 elif hasattr(self.model, "calc_composition_models"): 225 results = self.model.calc_composition_models(self.data.x[index]) 226 if results is not None: 227 pq_values, sq_values = results 228 229 if pq_values is None or sq_values is None: 230 if p_model is not None and s_model is not None: 231 sq_values = numpy.zeros((len(self.data.x))) 232 pq_values = numpy.zeros((len(self.data.x))) 233 sq_values[index] = s_model.evalDistribution(self.data.x[index]) 234 pq_values[index] = p_model.evalDistribution(self.data.x[index]) 242 235 243 236 elapsed = time.time() - self.starttime 244 237 245 res = dict(x = self.data.x[index], y = output[index],246 page_id = self.page_id, state = self.state, weight = self.weight,247 fid = self.fid, toggle_mode_on = self.toggle_mode_on,248 elapsed = elapsed, index = index, model = self.model,249 data = self.data, update_chisqr = self.update_chisqr,250 source = self.source, unsmeared_output = unsmeared_output,251 unsmeared_data = unsmeared_data, unsmeared_error = unsmeared_error,252 intermediate_results = intermediate_results)253 254 238 if LocalConfig.USING_TWISTED: 255 return res 256 else: 257 self.completefn(res) 239 return (self.data.x[index], output[index], 240 self.page_id, 241 self.state, 242 self.weight, 243 self.fid, 244 self.toggle_mode_on, 245 elapsed, index, self.model, 246 self.data, 247 self.update_chisqr, 248 self.source, 249 unsmeared_output, unsmeared_data, unsmeared_error, 250 pq_values, sq_values) 251 else: 252 self.completefn((self.data.x[index], output[index], 253 self.page_id, 254 self.state, 255 self.weight, 256 self.fid, 257 self.toggle_mode_on, 258 elapsed, index, self.model, 259 self.data, 260 self.update_chisqr, 261 self.source, 262 unsmeared_output, unsmeared_data, unsmeared_error, 263 pq_values, sq_values)) 258 264 259 265 def results(self): -
src/sas/qtgui/Perspectives/Fitting/UI/OptionsWidgetUI.ui
r309fa1b r79bd268 32 32 <item row="0" column="1"> 33 33 <widget class="QLineEdit" name="txtMinRange"> 34 <property name="minimumSize">35 <size>36 <width>80</width>37 <height>0</height>38 </size>39 </property>40 34 <property name="toolTip"> 41 35 <string><html><head/><body><p>Minimum value of Q.</p></body></html></string> … … 60 54 <item row="1" column="1"> 61 55 <widget class="QLineEdit" name="txtMaxRange"> 62 <property name="minimumSize">63 <size>64 <width>80</width>65 <height>0</height>66 </size>67 </property>68 56 <property name="toolTip"> 69 57 <string><html><head/><body><p>Maximum value of Q.</p></body></html></string> -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingLogicTest.py
rbfb5d9e re752ab8 99 99 data.name = "boop" 100 100 data.id = "poop" 101 # Condensed return data (new1DPlot only uses these fields) 102 return_data = dict(x = data.x, 103 y = data.y, 104 model = data, 105 data = data) 106 # return_data = (data.x,data.y, 7, None, None, 107 # 0, True, 0.0, 1, data, 108 # data, False, None, 109 # None, None, None, 110 # None, None) 101 return_data = (data.x,data.y, 7, None, None, 102 0, True, 0.0, 1, data, 103 data, False, None, 104 None, None, None, 105 None, None) 111 106 112 107 new_plot = self.logic.new1DPlot(return_data=return_data, tab_id=0) … … 144 139 qmin, qmax, npts = self.logic.computeDataRange() 145 140 146 # Condensed return data (new2DPlot only uses these fields) 147 return_data = dict(image = x_0, 148 data = data, 149 page_id = 7, 150 model = data) 151 # return_data = (x_0, data, 7, data, None, 152 # True, 0.0, 1, 0, qmin, qmax, 153 # 0.1, False, None) 141 return_data = (x_0, data, 7, data, None, 142 True, 0.0, 1, 0, qmin, qmax, 143 0.1, False, None) 154 144 155 145 new_plot = self.logic.new2DPlot(return_data=return_data) -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingOptionsTest.py
rbfb5d9e r725d9c06 38 38 # The combo box 39 39 self.assertIsInstance(self.widget.cbAlgorithm, QtWidgets.QComboBox) 40 self.assertEqual(self.widget.cbAlgorithm.count(), 6)40 self.assertEqual(self.widget.cbAlgorithm.count(), 5) 41 41 self.assertEqual(self.widget.cbAlgorithm.itemText(0), 'Nelder-Mead Simplex') 42 42 self.assertEqual(self.widget.cbAlgorithm.itemText(4), 'Levenberg-Marquardt') -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
r3fbd77b r605d944 256 256 self.widget.cbStructureFactor.setCurrentIndex(structure_index) 257 257 258 # We have 3 more param rows now (radius_effective is removed), and a new heading258 # We have 4 more rows now 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 (incl. radius_effective & heading row)?279 self.assertEqual(self.widget._model_model.rowCount(), 5)278 # Do we have all the rows? 279 self.assertEqual(self.widget._model_model.rowCount(), 4) 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 450 447 # Change the number of points 451 self.assertEqual(self.widget. poly_params['radius_bell.npts'], 35)448 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 452 449 self.widget._poly_model.item(0,4).setText("22") 453 self.assertEqual(self.widget. poly_params['radius_bell.npts'], 22)450 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 454 451 # try something stupid 455 452 self.widget._poly_model.item(0,4).setText("butt") 456 453 # see that this didn't annoy the control at all 457 self.assertEqual(self.widget. poly_params['radius_bell.npts'], 22)454 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 458 455 459 456 # Change the number of sigmas 460 self.assertEqual(self.widget. poly_params['radius_bell.nsigmas'], 3)457 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 3) 461 458 self.widget._poly_model.item(0,5).setText("222") 462 self.assertEqual(self.widget. poly_params['radius_bell.nsigmas'], 222)459 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 463 460 # try something stupid again 464 461 self.widget._poly_model.item(0,4).setText("beer") 465 462 # no efect 466 self.assertEqual(self.widget. poly_params['radius_bell.nsigmas'], 222)463 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 467 464 468 465 def testOnPolyComboIndexChange(self): … … 485 482 self.widget.onPolyComboIndexChange('rectangle', 0) 486 483 # check values 487 self.assertEqual(self.widget. poly_params['radius_bell.npts'], 35)488 self.assertAlmostEqual(self.widget. poly_params['radius_bell.nsigmas'], 1.73205, 5)484 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 485 self.assertAlmostEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 1.73205, 5) 489 486 # Change the index 490 487 self.widget.onPolyComboIndexChange('lognormal', 0) 491 488 # check values 492 self.assertEqual(self.widget. poly_params['radius_bell.npts'], 80)493 self.assertEqual(self.widget. poly_params['radius_bell.nsigmas'], 8)489 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 490 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 494 491 # Change the index 495 492 self.widget.onPolyComboIndexChange('schulz', 0) 496 493 # check values 497 self.assertEqual(self.widget. poly_params['radius_bell.npts'], 80)498 self.assertEqual(self.widget. poly_params['radius_bell.nsigmas'], 8)494 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 495 self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 499 496 500 497 # mock up file load … … 509 506 Test opening of the load file dialog for 'array' polydisp. function 510 507 """ 511 512 # open a non-existent file513 508 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)516 509 QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 517 510 self.widget.show() … … 529 522 530 523 # 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 suite533 # TODO: individually534 524 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")539 525 QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 540 526 … … 602 588 603 589 # Assure we have the combobox available 604 cbox_row = self.widget._n_shells_row605 func_index = self.widget._model_model.index( cbox_row, 1)590 last_row = self.widget._last_model_row 591 func_index = self.widget._model_model.index(last_row-1, 1) 606 592 self.assertIsInstance(self.widget.lstParams.indexWidget(func_index), QtWidgets.QComboBox) 607 608 # get number of rows before changing shell count609 last_row = self.widget._model_model.rowCount()610 593 611 594 # Change the combo box index … … 1041 1024 1042 1025 # Check the model 1043 self.assertEqual(self.widget._model_model.rowCount(), 7)1026 self.assertEqual(self.widget._model_model.rowCount(), 6) 1044 1027 self.assertEqual(self.widget._model_model.columnCount(), 5) 1045 1028 … … 1157 1140 # two rows selected 1158 1141 index1 = self.widget.lstParams.model().index(1, 0, QtCore.QModelIndex()) 1159 index2 = self.widget.lstParams.model().index( 3, 0, QtCore.QModelIndex())1142 index2 = self.widget.lstParams.model().index(2, 0, QtCore.QModelIndex()) 1160 1143 selection_model = self.widget.lstParams.selectionModel() 1161 1144 selection_model.select(index1, selection_model.Select | selection_model.Rows) … … 1193 1176 # several random parameters 1194 1177 self.assertEqual(self.widget.getRowFromName('scale'), 0) 1195 self.assertEqual(self.widget.getRowFromName('length'), 6)1178 self.assertEqual(self.widget.getRowFromName('length'), 5) 1196 1179 1197 1180 def testGetParamNames(self): … … 1230 1213 # Create a constraint object 1231 1214 const = Constraint(parent=None, value=7.0) 1232 row = 31215 row = 2 1233 1216 1234 1217 spy = QtSignalSpy(self.widget, self.widget.constraintAddedSignal) … … 1249 1232 # assign complex constraint now 1250 1233 const = Constraint(parent=None, param='radius', func='5*sld') 1251 row = 51234 row = 4 1252 1235 # call the method tested 1253 1236 self.widget.addConstraintToRow(constraint=const, row=row) … … 1308 1291 self.widget.cbModel.setCurrentIndex(model_index) 1309 1292 1293 # select two rows 1310 1294 row1 = 1 1311 row2 = 5 1312 1313 param1 = "background" 1314 param2 = "radius" 1315 1316 #default_value1 = "0.001" 1317 default_value2 = "20" 1318 1319 # select two rows 1295 row2 = 4 1320 1296 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1321 1297 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1334 1310 1335 1311 # delete one of the constraints 1336 self.widget.deleteConstraintOnParameter(param= param1)1312 self.widget.deleteConstraintOnParameter(param='background') 1337 1313 1338 1314 # see that the other constraint is still present 1339 cons = self.widget.getConstraintForRow( row2)1340 self.assertEqual(cons.param, param2)1341 self.assertEqual(cons.value, default_value2)1315 cons = self.widget.getConstraintForRow(4) # 4 = radius 1316 self.assertEqual(cons.param, "radius") 1317 self.assertEqual(cons.value, "20") 1342 1318 1343 1319 # kill the other constraint … … 1345 1321 1346 1322 # see that the other constraint is still present 1347 self.assertEqual(self.widget.getConstraintsForModel(), [( param2, None)])1323 self.assertEqual(self.widget.getConstraintsForModel(), [('radius', None)]) 1348 1324 1349 1325 def testGetConstraintForRow(self): … … 1365 1341 self.widget.cbModel.setCurrentIndex(model_index) 1366 1342 1343 # select two rows 1367 1344 row1 = 1 1368 row2 = 5 1369 1370 # select two rows 1345 row2 = 4 1371 1346 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1372 1347 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1378 1353 self.widget.addSimpleConstraint() 1379 1354 1380 con_list = [False, True, False, False, False,True, False]1355 con_list = [False, True, False, False, True, False] 1381 1356 new_list = [] 1382 1357 for row in range(self.widget._model_model.rowCount()): … … 1396 1371 self.widget.cbModel.setCurrentIndex(model_index) 1397 1372 1373 # select two rows 1398 1374 row1 = 1 1399 row2 = 5 1400 1401 # select two rows 1375 row2 = 4 1402 1376 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1403 1377 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1413 1387 constraint_objects[0].active = False 1414 1388 1415 con_list = [False, False, False, False, False,True, False]1389 con_list = [False, False, False, False, True, False] 1416 1390 new_list = [] 1417 1391 for row in range(self.widget._model_model.rowCount()): … … 1434 1408 self.assertEqual(self.widget.getConstraintsForModel(),[]) 1435 1409 1410 # select two rows 1436 1411 row1 = 1 1437 row2 = 5 1438 1439 param1 = "background" 1440 param2 = "radius" 1441 1442 default_value1 = "0.001" 1443 default_value2 = "20" 1444 1445 # select two rows 1412 row2 = 4 1446 1413 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1447 1414 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1455 1422 # simple constraints 1456 1423 # self.assertEqual(self.widget.getConstraintsForModel(), [('background', '0.001'), ('radius', '20')]) 1457 cons = self.widget.getConstraintForRow( row1)1458 self.assertEqual(cons.param, param1)1459 self.assertEqual(cons.value, default_value1)1460 cons = self.widget.getConstraintForRow( row2)1461 self.assertEqual(cons.param, param2)1462 self.assertEqual(cons.value, default_value2)1424 cons = self.widget.getConstraintForRow(1) # 1 - background 1425 self.assertEqual(cons.param, "background") 1426 self.assertEqual(cons.value, "0.001") 1427 cons = self.widget.getConstraintForRow(4) # 4 = radius 1428 self.assertEqual(cons.param, "radius") 1429 self.assertEqual(cons.value, "20") 1463 1430 1464 1431 objects = self.widget.getConstraintObjectsForModel() 1465 1432 self.assertEqual(len(objects), 2) 1466 self.assertEqual(objects[1].value, default_value2) 1467 self.assertEqual(objects[0].param, param1) 1468 1433 self.assertEqual(objects[1].value, '20') 1434 self.assertEqual(objects[0].param, 'background') 1435 1436 # add complex constraint 1437 const = Constraint(parent=None, param='scale', func='5*sld') 1469 1438 row = 0 1470 param = "scale"1471 func = "5*sld"1472 1473 # add complex constraint1474 const = Constraint(parent=None, param=param, func=func)1475 1439 self.widget.addConstraintToRow(constraint=const, row=row) 1476 1440 #self.assertEqual(self.widget.getConstraintsForModel(),[('scale', '5*sld'), ('background', '0.001'), ('radius', None)]) 1477 cons = self.widget.getConstraintForRow( row2)1478 self.assertEqual(cons.param, param2)1479 self.assertEqual(cons.value, default_value2)1441 cons = self.widget.getConstraintForRow(4) # 4 = radius 1442 self.assertEqual(cons.param, "radius") 1443 self.assertEqual(cons.value, "20") 1480 1444 1481 1445 objects = self.widget.getConstraintObjectsForModel() 1482 1446 self.assertEqual(len(objects), 3) 1483 self.assertEqual(objects[0].func, func)1447 self.assertEqual(objects[0].func, '5*sld') 1484 1448 1485 1449 def testReplaceConstraintName(self): -
src/sas/qtgui/Plotting/Plotter.py
r0cd98a1 rb764ae5 30 30 # Dictionary of {plot_id:Data1d} 31 31 self.plot_dict = {} 32 # Dictionaty of {plot_id:line} 33 34 self.plot_lines = {} 32 35 33 # Window for text add 36 34 self.addText = AddText(self) … … 182 180 183 181 # Update the list of data sets (plots) in chart 184 self.plot_dict[self._data.name] = self.data 185 186 self.plot_lines[self._data.name] = line 182 self.plot_dict[self._data.id] = self.data 187 183 188 184 # Now add the legend with some customizations. … … 200 196 201 197 # refresh canvas 202 self.canvas.draw() 198 self.canvas.draw_idle() 199 # This is an important processEvent. 200 # This allows charts to be properly updated in order 201 # of plots being applied. 202 QtWidgets.QApplication.processEvents() 203 203 204 204 def createContextMenu(self): … … 470 470 """ 471 471 selected_plot = self.plot_dict[id] 472 selected_line = self.plot_lines[id] 472 473 473 # Old style color - single integer for enum color 474 474 # New style color - #hhhhhh -
src/sas/qtgui/Utilities/GuiUtils.py
r339e22b r0eff615 265 265 # Mask Editor requested 266 266 maskEditorSignal = QtCore.pyqtSignal(Data2D) 267 268 #second Mask Editor for external269 extMaskEditorSignal = QtCore.pyqtSignal()270 267 271 268 # Fitting parameter copy to clipboard
Note: See TracChangeset
for help on using the changeset viewer.