Changes in src/sas/qtgui/Perspectives/Fitting/FittingWidget.py [daf7c9c:d8d81ea] in sasview
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
rdaf7c9c rd8d81ea 28 28 from sas.qtgui.Plotting.PlotterData import Data1D 29 29 from sas.qtgui.Plotting.PlotterData import Data2D 30 from sas.qtgui.Plotting.Plotter import PlotterWidget 30 31 31 32 from sas.qtgui.Perspectives.Fitting.UI.FittingWidgetUI import Ui_FittingWidgetUI … … 57 58 DEFAULT_POLYDISP_FUNCTION = 'gaussian' 58 59 60 # CRUFT: remove when new release of sasmodels is available 61 # https://github.com/SasView/sasview/pull/181#discussion_r218135162 62 from sasmodels.sasview_model import SasviewModel 63 if not hasattr(SasviewModel, 'get_weights'): 64 def get_weights(self, name): 65 """ 66 Returns the polydispersity distribution for parameter *name* as *value* and *weight* arrays. 67 """ 68 # type: (str) -> Tuple(np.ndarray, np.ndarray) 69 _, x, w = self._get_weights(self._model_info.parameters[name]) 70 return x, w 71 72 SasviewModel.get_weights = get_weights 59 73 60 74 logger = logging.getLogger(__name__) … … 273 287 self.theory_item = None 274 288 289 # list column widths 290 self.lstParamHeaderSizes = {} 291 275 292 # signal communicator 276 293 self.communicate = self.parent.communicate … … 361 378 self.lstParams.customContextMenuRequested.connect(self.showModelContextMenu) 362 379 self.lstParams.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False) 380 # Column resize signals 381 self.lstParams.header().sectionResized.connect(self.onColumnWidthUpdate) 382 363 383 # Poly model displayed in poly list 364 384 self.lstPoly.setModel(self._poly_model) … … 642 662 # Create and display the widget for param1 and param2 643 663 mc_widget = MultiConstraint(self, params=params_list) 664 # Check if any of the parameters are polydisperse 665 if not np.any([FittingUtilities.isParamPolydisperse(p, self.model_parameters, is2D=self.is2D) for p in params_list]): 666 # no parameters are pd - reset the text to not show the warning 667 mc_widget.lblWarning.setText("") 644 668 if mc_widget.exec_() != QtWidgets.QDialog.Accepted: 645 669 return … … 1108 1132 self.SASModelToQModel(model, structure_factor) 1109 1133 1134 for column, width in self.lstParamHeaderSizes.items(): 1135 self.lstParams.setColumnWidth(column, width) 1136 1110 1137 # Update plot 1111 1138 self.updateData() … … 1219 1246 if model_column in [delegate.poly_pd, delegate.poly_error, delegate.poly_min, delegate.poly_max]: 1220 1247 row = self.getRowFromName(parameter_name) 1221 param_item = self._model_model.item(row) 1248 param_item = self._model_model.item(row).child(0).child(0, model_column) 1249 if param_item is None: 1250 return 1222 1251 self._model_model.blockSignals(True) 1223 param_item. child(0).child(0, model_column).setText(item.text())1252 param_item.setText(item.text()) 1224 1253 self._model_model.blockSignals(False) 1225 1254 … … 1366 1395 self.communicate.statusBarUpdateSignal.emit('Fitting started...') 1367 1396 self.fit_started = True 1397 1368 1398 # Disable some elements 1369 self. setFittingStarted()1399 self.disableInteractiveElements() 1370 1400 1371 1401 def stopFit(self): … … 1376 1406 return 1377 1407 self.calc_fit.stop() 1378 #self.fit_started=False1379 1408 #re-enable the Fit button 1380 self. setFittingStopped()1409 self.enableInteractiveElements() 1381 1410 1382 1411 msg = "Fitting cancelled." … … 1392 1421 """ 1393 1422 """ 1394 self. setFittingStopped()1423 self.enableInteractiveElements() 1395 1424 msg = "Fitting failed with: "+ str(reason) 1396 1425 self.communicate.statusBarUpdateSignal.emit(msg) … … 1409 1438 """ 1410 1439 #re-enable the Fit button 1411 self. setFittingStopped()1440 self.enableInteractiveElements() 1412 1441 1413 1442 if len(result) == 0: … … 1481 1510 """ 1482 1511 #re-enable the Fit button 1483 self. setFittingStopped()1512 self.enableInteractiveElements() 1484 1513 1485 1514 if len(result) == 0: … … 1666 1695 self.iterateOverModel(updatePolyValues) 1667 1696 self._model_model.itemChanged.connect(self.onMainParamsChange) 1668 1669 # Adjust the table cells width.1670 # TODO: find a way to dynamically adjust column width while resized expanding1671 self.lstParams.resizeColumnToContents(0)1672 self.lstParams.resizeColumnToContents(4)1673 self.lstParams.resizeColumnToContents(5)1674 self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)1675 1697 1676 1698 def iterateOverPolyModel(self, func): … … 2012 2034 self.magnet_params = {} 2013 2035 self.setMagneticModel() 2014 2015 # Adjust the table cells width2016 self.lstParams.resizeColumnToContents(0)2017 self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)2018 2036 2019 2037 # Now we claim the model has been loaded … … 2340 2358 2341 2359 # add polydisperse parameters if asked 2342 if self.chkPolydispersity.isChecked() :2360 if self.chkPolydispersity.isChecked() and self._poly_model.rowCount() > 0: 2343 2361 for key, value in self.poly_params.items(): 2344 2362 model.setParam(key, value) 2345 2363 # add magnetic params if asked 2346 2364 if self.chkMagnetism.isChecked(): 2347 for key, value in self.magnet_params.items() :2365 for key, value in self.magnet_params.items() and self._magnet_model.rowCount() > 0: 2348 2366 model.setParam(key, value) 2349 2367 … … 2363 2381 weight = FittingUtilities.getWeight(data=data, is2d=self.is2D, flag=self.weighting) 2364 2382 2383 # Disable buttons/table 2384 self.disableInteractiveElements() 2365 2385 # Awful API to a backend method. 2366 2386 calc_thread = self.methodCalculateForData()(data=data, … … 2404 2424 Thread returned error 2405 2425 """ 2426 # Bring the GUI to normal state 2427 self.enableInteractiveElements() 2406 2428 print("Calculate Data failed with ", reason) 2407 2429 … … 2416 2438 Plot the current 1D data 2417 2439 """ 2440 # Bring the GUI to normal state 2441 self.enableInteractiveElements() 2442 2418 2443 fitted_data = self.logic.new1DPlot(return_data, self.tab_id) 2419 2444 residuals = self.calculateResiduals(fitted_data) … … 2424 2449 2425 2450 if self.data_is_loaded: 2426 # delete any plots associated with the data that were not updated (e.g. to remove beta(Q), S_eff(Q)) 2451 # delete any plots associated with the data that were not updated 2452 # (e.g. to remove beta(Q), S_eff(Q)) 2427 2453 GuiUtils.deleteRedundantPlots(self.all_data[self.data_index], new_plots) 2428 2454 pass 2429 2455 else: 2430 # delete theory items for the model, in order to get rid of any redundant items, e.g. beta(Q), S_eff(Q) 2456 # delete theory items for the model, in order to get rid of any 2457 # redundant items, e.g. beta(Q), S_eff(Q) 2431 2458 self.communicate.deleteIntermediateTheoryPlotsSignal.emit(self.kernel_module.id) 2459 2460 # Create plots for parameters with enabled polydispersity 2461 for plot in FittingUtilities.plotPolydispersities(return_data.get('model', None)): 2462 data_id = fitted_data.id.split() 2463 plot.id = "{} [{}] {}".format(data_id[0], plot.name, " ".join(data_id[1:])) 2464 data_name = fitted_data.name.split() 2465 plot.name = " ".join([data_name[0], plot.name] + data_name[1:]) 2466 self.createNewIndex(plot) 2467 new_plots.append(plot) 2432 2468 2433 2469 # Create plots for intermediate product data … … 2445 2481 Plot the current 2D data 2446 2482 """ 2483 # Bring the GUI to normal state 2484 self.enableInteractiveElements() 2485 2447 2486 fitted_data = self.logic.new2DPlot(return_data) 2448 2487 residuals = self.calculateResiduals(fitted_data) … … 2479 2518 residuals_plot = FittingUtilities.plotResiduals(self.data, weighted_data) 2480 2519 residuals_plot.id = "Residual " + residuals_plot.id 2520 residuals_plot.plot_role = Data1D.ROLE_RESIDUAL 2481 2521 self.createNewIndex(residuals_plot) 2482 2522 return residuals_plot … … 2514 2554 Thread threw an exception. 2515 2555 """ 2556 # Bring the GUI to normal state 2557 self.enableInteractiveElements() 2516 2558 # TODO: remimplement thread cancellation 2517 2559 logger.error("".join(traceback.format_exception(etype, value, tb))) … … 2725 2767 self._poly_model.setData(fname_index, fname) 2726 2768 2769 def onColumnWidthUpdate(self, index, old_size, new_size): 2770 """ 2771 Simple state update of the current column widths in the param list 2772 """ 2773 self.lstParamHeaderSizes[index] = new_size 2774 2727 2775 def setMagneticModel(self): 2728 2776 """ … … 2796 2844 2797 2845 func = QtWidgets.QComboBox() 2798 # Available range of shells displayed in the combobox2799 func.addItems([str(i) for i in range(param_length+1)])2800 2801 # Respond to index change2802 func.currentIndexChanged.connect(self.modifyShellsInList)2803 2846 2804 2847 # cell 2: combobox 2805 2848 item2 = QtGui.QStandardItem() 2806 self._model_model.appendRow([item1, item2]) 2849 2850 # cell 3: min value 2851 item3 = QtGui.QStandardItem() 2852 2853 # cell 4: max value 2854 item4 = QtGui.QStandardItem() 2855 2856 # cell 4: SLD button 2857 item5 = QtGui.QStandardItem() 2858 button = QtWidgets.QPushButton() 2859 button.setText("Show SLD Profile") 2860 2861 self._model_model.appendRow([item1, item2, item3, item4, item5]) 2807 2862 2808 2863 # Beautify the row: span columns 2-4 2809 2864 shell_row = self._model_model.rowCount() 2810 2865 shell_index = self._model_model.index(shell_row-1, 1) 2866 button_index = self._model_model.index(shell_row-1, 4) 2811 2867 2812 2868 self.lstParams.setIndexWidget(shell_index, func) 2869 self.lstParams.setIndexWidget(button_index, button) 2813 2870 self._n_shells_row = shell_row - 1 2814 2871 … … 2823 2880 logger.error("Could not find %s in kernel parameters.", param_name) 2824 2881 default_shell_count = shell_par.default 2882 shell_min = 0 2883 shell_max = 0 2884 try: 2885 shell_min = int(shell_par.limits[0]) 2886 shell_max = int(shell_par.limits[1]) 2887 except IndexError as ex: 2888 # no info about limits 2889 pass 2890 item3.setText(str(shell_min)) 2891 item4.setText(str(shell_max)) 2892 2893 # Respond to index change 2894 func.currentTextChanged.connect(self.modifyShellsInList) 2895 2896 # Respond to button press 2897 button.clicked.connect(self.onShowSLDProfile) 2898 2899 # Available range of shells displayed in the combobox 2900 func.addItems([str(i) for i in range(shell_min, shell_max+1)]) 2825 2901 2826 2902 # Add default number of shells to the model 2827 func.setCurrent Index(default_shell_count)2828 2829 def modifyShellsInList(self, index):2903 func.setCurrentText(str(default_shell_count)) 2904 2905 def modifyShellsInList(self, text): 2830 2906 """ 2831 2907 Add/remove additional multishell parameters … … 2834 2910 first_row = self._n_shells_row + 1 2835 2911 remove_rows = self._num_shell_params 2836 2912 try: 2913 index = int(text) 2914 except ValueError: 2915 # bad text on the control! 2916 index = 0 2917 logger.error("Multiplicity incorrect! Setting to 0") 2918 self.kernel_module.multiplicity = index 2837 2919 if remove_rows > 1: 2838 2920 self._model_model.removeRows(first_row, remove_rows) … … 2861 2943 self.setMagneticModel() 2862 2944 2863 def setFittingStarted(self): 2864 """ 2865 Set buttion caption on fitting start 2945 def onShowSLDProfile(self): 2946 """ 2947 Show a quick plot of SLD profile 2948 """ 2949 # get profile data 2950 x, y = self.kernel_module.getProfile() 2951 y *= 1.0e6 2952 profile_data = Data1D(x=x, y=y) 2953 profile_data.name = "SLD" 2954 profile_data.scale = 'linear' 2955 profile_data.symbol = 'Line' 2956 profile_data.hide_error = True 2957 profile_data._xaxis = "R(\AA)" 2958 profile_data._yaxis = "SLD(10^{-6}\AA^{-2})" 2959 2960 plotter = PlotterWidget(self, quickplot=True) 2961 plotter.data = profile_data 2962 plotter.showLegend = True 2963 plotter.plot(hide_error=True, marker='-') 2964 2965 self.plot_widget = QtWidgets.QWidget() 2966 self.plot_widget.setWindowTitle("Scattering Length Density Profile") 2967 layout = QtWidgets.QVBoxLayout() 2968 layout.addWidget(plotter) 2969 self.plot_widget.setLayout(layout) 2970 self.plot_widget.show() 2971 2972 def setInteractiveElements(self, enabled=True): 2973 """ 2974 Switch interactive GUI elements on/off 2975 """ 2976 assert isinstance(enabled, bool) 2977 2978 self.lstParams.setEnabled(enabled) 2979 self.lstPoly.setEnabled(enabled) 2980 self.lstMagnetic.setEnabled(enabled) 2981 2982 self.cbCategory.setEnabled(enabled) 2983 self.cbModel.setEnabled(enabled) 2984 self.cbStructureFactor.setEnabled(enabled) 2985 2986 self.chkPolydispersity.setEnabled(enabled) 2987 self.chkMagnetism.setEnabled(enabled) 2988 self.chk2DView.setEnabled(enabled) 2989 2990 def enableInteractiveElements(self): 2991 """ 2992 Set buttion caption on fitting/calculate finish 2993 Enable the param table(s) 2994 """ 2995 # Notify the user that fitting is available 2996 self.cmdFit.setStyleSheet('QPushButton {color: black;}') 2997 self.cmdFit.setText("Fit") 2998 self.fit_started = False 2999 self.setInteractiveElements(True) 3000 3001 def disableInteractiveElements(self): 3002 """ 3003 Set buttion caption on fitting/calculate start 3004 Disable the param table(s) 2866 3005 """ 2867 3006 # Notify the user that fitting is being run … … 2869 3008 self.cmdFit.setStyleSheet('QPushButton {color: red;}') 2870 3009 self.cmdFit.setText('Stop fit') 2871 2872 def setFittingStopped(self): 2873 """ 2874 Set button caption on fitting stop 2875 """ 2876 # Notify the user that fitting is available 2877 self.cmdFit.setStyleSheet('QPushButton {color: black;}') 2878 self.cmdFit.setText("Fit") 2879 self.fit_started = False 3010 self.setInteractiveElements(False) 2880 3011 2881 3012 def readFitPage(self, fp):
Note: See TracChangeset
for help on using the changeset viewer.