Changes in src/sas/qtgui/Perspectives/Fitting/FittingWidget.py [e4c475b7:8b480d27] in sasview
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
re4c475b7 r8b480d27 24 24 import sas.qtgui.Utilities.GuiUtils as GuiUtils 25 25 import sas.qtgui.Utilities.LocalConfig as LocalConfig 26 from sas.qtgui.Utilities.GridPanel import BatchOutputPanel 26 27 from sas.qtgui.Utilities.CategoryInstaller import CategoryInstaller 27 28 from sas.qtgui.Plotting.PlotterData import Data1D … … 36 37 from sas.qtgui.Perspectives.Fitting.FittingLogic import FittingLogic 37 38 from sas.qtgui.Perspectives.Fitting import FittingUtilities 39 from sas.qtgui.Perspectives.Fitting import ModelUtilities 38 40 from sas.qtgui.Perspectives.Fitting.SmearingWidget import SmearingWidget 39 41 from sas.qtgui.Perspectives.Fitting.OptionsWidget import OptionsWidget … … 50 52 CATEGORY_DEFAULT = "Choose category..." 51 53 CATEGORY_STRUCTURE = "Structure Factor" 54 CATEGORY_CUSTOM = "Plugin Models" 52 55 STRUCTURE_DEFAULT = "None" 53 56 … … 83 86 constraintAddedSignal = QtCore.pyqtSignal(list) 84 87 newModelSignal = QtCore.pyqtSignal() 88 fittingFinishedSignal = QtCore.pyqtSignal(tuple) 89 batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 90 85 91 def __init__(self, parent=None, data=None, tab_id=1): 86 92 … … 211 217 self.page_stack = [] 212 218 self.all_data = [] 219 # custom plugin models 220 # {model.name:model} 221 self.custom_models = self.customModels() 213 222 # Polydisp widget table default index for function combobox 214 223 self.orig_poly_index = 3 … … 415 424 self.onSelectModel() 416 425 426 @classmethod 427 def customModels(cls): 428 """ Reads in file names in the custom plugin directory """ 429 return ModelUtilities._find_models() 430 417 431 def initializeControls(self): 418 432 """ … … 465 479 self._poly_model.itemChanged.connect(self.onPolyModelChange) 466 480 self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 481 self.lstParams.selectionModel().selectionChanged.connect(self.onSelectionChanged) 482 483 # Local signals 484 self.batchFittingFinishedSignal.connect(self.batchFitComplete) 485 self.fittingFinishedSignal.connect(self.fitComplete) 467 486 468 487 # Signals from separate tabs asking for replot 469 488 self.options_widget.plot_signal.connect(self.onOptionsUpdate) 489 490 # Signals from other widgets 491 self.communicate.customModelDirectoryChanged.connect(self.onCustomModelChange) 470 492 471 493 def modelName(self): … … 576 598 # widget.params[0] is the parameter we're constraining 577 599 constraint.param = mc_widget.params[0] 578 # Functionshould have the model name preamble600 # parameter should have the model name preamble 579 601 model_name = self.kernel_module.name 580 constraint.func = model_name + "." + c_text 602 # param_used is the parameter we're using in constraining function 603 param_used = mc_widget.params[1] 604 # Replace param_used with model_name.param_used 605 updated_param_used = model_name + "." + param_used 606 new_func = c_text.replace(param_used, updated_param_used) 607 constraint.func = new_func 581 608 # Which row is the constrained parameter in? 582 609 row = self.getRowFromName(constraint.param) … … 677 704 Delete constraints from selected parameters. 678 705 """ 679 self.deleteConstraintOnParameter(param=None) 706 params = [s.data() for s in self.lstParams.selectionModel().selectedRows() 707 if self.isCheckable(s.row())] 708 for param in params: 709 self.deleteConstraintOnParameter(param=param) 680 710 681 711 def deleteConstraintOnParameter(self, param=None): … … 686 716 max_col = self.lstParams.itemDelegate().param_max 687 717 for row in range(self._model_model.rowCount()): 718 if not self.rowHasConstraint(row): 719 continue 688 720 # Get the Constraint object from of the model item 689 721 item = self._model_model.item(row, 1) 690 if not item.hasChildren(): 691 continue 692 constraint = item.child(0).data() 722 constraint = self.getConstraintForRow(row) 693 723 if constraint is None: 694 724 continue … … 816 846 return constraints 817 847 848 def getConstraintsForFitting(self): 849 """ 850 Return a list of constraints in format ready for use in fiting 851 """ 852 # Get constraints 853 constraints = self.getComplexConstraintsForModel() 854 # See if there are any constraints across models 855 multi_constraints = [cons for cons in constraints if self.isConstraintMultimodel(cons[1])] 856 857 if multi_constraints: 858 # Let users choose what to do 859 msg = "The current fit contains constraints relying on other fit pages.\n" 860 msg += "Parameters with those constraints are:\n" +\ 861 '\n'.join([cons[0] for cons in multi_constraints]) 862 msg += "\n\nWould you like to remove these constraints or cancel fitting?" 863 msgbox = QtWidgets.QMessageBox(self) 864 msgbox.setIcon(QtWidgets.QMessageBox.Warning) 865 msgbox.setText(msg) 866 msgbox.setWindowTitle("Existing Constraints") 867 # custom buttons 868 button_remove = QtWidgets.QPushButton("Remove") 869 msgbox.addButton(button_remove, QtWidgets.QMessageBox.YesRole) 870 button_cancel = QtWidgets.QPushButton("Cancel") 871 msgbox.addButton(button_cancel, QtWidgets.QMessageBox.RejectRole) 872 retval = msgbox.exec_() 873 if retval == QtWidgets.QMessageBox.RejectRole: 874 # cancel fit 875 raise ValueError("Fitting cancelled") 876 else: 877 # remove constraint 878 for cons in multi_constraints: 879 self.deleteConstraintOnParameter(param=cons[0]) 880 # re-read the constraints 881 constraints = self.getComplexConstraintsForModel() 882 883 return constraints 884 818 885 def showModelDescription(self): 819 886 """ … … 874 941 self.respondToModelStructure(model=model, structure_factor=structure) 875 942 943 def onCustomModelChange(self): 944 """ 945 Reload the custom model combobox 946 """ 947 self.custom_models = self.customModels() 948 self.readCustomCategoryInfo() 949 # See if we need to update the combo in-place 950 if self.cbCategory.currentText() != CATEGORY_CUSTOM: return 951 952 current_text = self.cbModel.currentText() 953 self.cbModel.blockSignals(True) 954 self.cbModel.clear() 955 self.cbModel.blockSignals(False) 956 self.enableModelCombo() 957 self.disableStructureCombo() 958 # Retrieve the list of models 959 model_list = self.master_category_dict[CATEGORY_CUSTOM] 960 # Populate the models combobox 961 self.cbModel.addItems(sorted([model for (model, _) in model_list])) 962 new_index = self.cbModel.findText(current_text) 963 if new_index != -1: 964 self.cbModel.setCurrentIndex(self.cbModel.findText(current_text)) 965 966 def onSelectionChanged(self): 967 """ 968 React to parameter selection 969 """ 970 rows = self.lstParams.selectionModel().selectedRows() 971 # Clean previous messages 972 self.communicate.statusBarUpdateSignal.emit("") 973 if len(rows) == 1: 974 # Show constraint, if present 975 row = rows[0].row() 976 if self.rowHasConstraint(row): 977 func = self.getConstraintForRow(row).func 978 if func is not None: 979 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 980 876 981 def replaceConstraintName(self, old_name, new_name=""): 877 982 """ … … 886 991 new_func = func.replace(old_name, new_name) 887 992 self._model_model.item(row, 1).child(0).data().func = new_func 993 994 def isConstraintMultimodel(self, constraint): 995 """ 996 Check if the constraint function text contains current model name 997 """ 998 current_model_name = self.kernel_module.name 999 if current_model_name in constraint: 1000 return False 1001 else: 1002 return True 888 1003 889 1004 def updateData(self): … … 1105 1220 except ValueError as ex: 1106 1221 # This should not happen! GUI explicitly forbids this situation 1107 self.communicate.statusBarUpdateSignal.emit( 'Fitting attempt without parameters.')1222 self.communicate.statusBarUpdateSignal.emit(str(ex)) 1108 1223 return 1109 1224 1110 1225 # Create the fitting thread, based on the fitter 1111 completefn = self.batchFit Complete if self.is_batch_fitting else self.fitComplete1226 completefn = self.batchFittingCompleted if self.is_batch_fitting else self.fittingCompleted 1112 1227 1113 1228 calc_fit = FitThread(handler=handler, … … 1146 1261 pass 1147 1262 1263 def batchFittingCompleted(self, result): 1264 """ 1265 Send the finish message from calculate threads to main thread 1266 """ 1267 self.batchFittingFinishedSignal.emit(result) 1268 1148 1269 def batchFitComplete(self, result): 1149 1270 """ … … 1152 1273 #re-enable the Fit button 1153 1274 self.setFittingStopped() 1275 # Show the grid panel 1276 self.grid_window = BatchOutputPanel(parent=self, output_data=result[0]) 1277 self.grid_window.show() 1278 1279 def fittingCompleted(self, result): 1280 """ 1281 Send the finish message from calculate threads to main thread 1282 """ 1283 self.fittingFinishedSignal.emit(result) 1154 1284 1155 1285 def fitComplete(self, result): … … 1162 1292 1163 1293 if result is None: 1164 msg = "Fitting failed after: %s s.\n" % GuiUtils.formatNumber(elapsed)1294 msg = "Fitting failed." 1165 1295 self.communicate.statusBarUpdateSignal.emit(msg) 1166 1296 return … … 1228 1358 smearing, accuracy, smearing_min, smearing_max = self.smearing_widget.state() 1229 1359 1360 # Get the constraints. 1230 1361 constraints = self.getComplexConstraintsForModel() 1362 if fitter is None: 1363 # For single fits - check for inter-model constraints 1364 constraints = self.getConstraintsForFitting() 1365 1231 1366 smearer = None 1232 1367 handler = None … … 1242 1377 constraints=constraints) 1243 1378 except ValueError as ex: 1244 logging.error("Setting model parameters failed with: %s" % ex) 1245 return 1379 raise ValueError("Setting model parameters failed with: %s" % ex) 1246 1380 1247 1381 qmin, qmax, _ = self.logic.computeRangeFromData(data) … … 1409 1543 if not dict: 1410 1544 return 1411 if self._m odel_model.rowCount() == 0:1545 if self._magnet_model.rowCount() == 0: 1412 1546 return 1413 1547 … … 1555 1689 self.models[model.name] = model 1556 1690 1691 self.readCustomCategoryInfo() 1692 1693 def readCustomCategoryInfo(self): 1694 """ 1695 Reads the custom model category 1696 """ 1697 #Looking for plugins 1698 self.plugins = list(self.custom_models.values()) 1699 plugin_list = [] 1700 for name, plug in self.custom_models.items(): 1701 self.models[name] = plug 1702 plugin_list.append([name, True]) 1703 self.master_category_dict[CATEGORY_CUSTOM] = plugin_list 1704 1557 1705 def regenerateModelDict(self): 1558 1706 """ … … 1662 1810 Setting model parameters into QStandardItemModel based on selected _model_ 1663 1811 """ 1664 kernel_module = generate.load_kernel_module(model_name) 1812 name = model_name 1813 if self.cbCategory.currentText() == CATEGORY_CUSTOM: 1814 # custom kernel load requires full path 1815 name = os.path.join(ModelUtilities.find_plugins_dir(), model_name+".py") 1816 kernel_module = generate.load_kernel_module(name) 1665 1817 self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', [])) 1666 1818
Note: See TracChangeset
for help on using the changeset viewer.