From 3ea397c5d323fafc7ca28d3cd408168ef92df8a5 Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Thu, 27 Oct 2022 18:56:47 +0200 Subject: [PATCH 1/9] WIP Add on-send-to-fitting plot --- src/sas/qtgui/MainWindow/DataExplorer.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sas/qtgui/MainWindow/DataExplorer.py b/src/sas/qtgui/MainWindow/DataExplorer.py index 653e630344..2e7c017f9c 100644 --- a/src/sas/qtgui/MainWindow/DataExplorer.py +++ b/src/sas/qtgui/MainWindow/DataExplorer.py @@ -778,8 +778,13 @@ def isItemReady(index): try: if self.chkSwap.isChecked(): self._perspective().swapData(selected_items[0]) + if self._perspective().name == 'Fitting': + self._perspective().tabs[0].onPlot() #todo sort out where the plot should go. else: self._perspective().setData(data_item=selected_items, is_batch=self.chkBatch.isChecked()) + if self._perspective().name == 'Fitting': + self._perspective().tabs[0].onPlot() + except Exception as ex: msg = "%s perspective returned the following message: \n%s\n" % (self._perspective().name, str(ex)) logging.error(ex, exc_info=True) From 68818440302ad0cfa1a0c13bf2cd4359e1917f3d Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Fri, 28 Oct 2022 12:29:21 +0200 Subject: [PATCH 2/9] Add auto-plot option and a flag to disable it --- src/sas/qtgui/MainWindow/DataExplorer.py | 6 ++++-- src/sas/system/config/config.py | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sas/qtgui/MainWindow/DataExplorer.py b/src/sas/qtgui/MainWindow/DataExplorer.py index 2e7c017f9c..a8c1b25a8e 100644 --- a/src/sas/qtgui/MainWindow/DataExplorer.py +++ b/src/sas/qtgui/MainWindow/DataExplorer.py @@ -779,11 +779,13 @@ def isItemReady(index): if self.chkSwap.isChecked(): self._perspective().swapData(selected_items[0]) if self._perspective().name == 'Fitting': - self._perspective().tabs[0].onPlot() #todo sort out where the plot should go. + if config.FITTING_PLOT_ON_SEND_DATA: + self.newPlot() #todo sort out where the plot should go. else: self._perspective().setData(data_item=selected_items, is_batch=self.chkBatch.isChecked()) if self._perspective().name == 'Fitting': - self._perspective().tabs[0].onPlot() + if config.FITTING_PLOT_ON_SEND_DATA: + self.newPlot() except Exception as ex: msg = "%s perspective returned the following message: \n%s\n" % (self._perspective().name, str(ex)) diff --git a/src/sas/system/config/config.py b/src/sas/system/config/config.py index 93a0a69bac..1c560749aa 100644 --- a/src/sas/system/config/config.py +++ b/src/sas/system/config/config.py @@ -181,6 +181,8 @@ def __init__(self): # Time out for updating sasview self.UPDATE_TIMEOUT = 2 + # Auto-plot when sending data to Fitting + self.FITTING_PLOT_ON_SEND_DATA = True # # Lock the class down, this is necessary both for From 0d747ab9a683d5c6960ecd8df8d12cbf0a8867f0 Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Fri, 28 Oct 2022 12:33:23 +0200 Subject: [PATCH 3/9] Add basic preferences widget for auto-plot --- .../Utilities/Preferences/FittingPreferencesWidget.py | 11 +++++++++++ .../Preferences/PlottingPreferencesWidget.py | 2 +- .../qtgui/Utilities/Preferences/PreferencesPanel.py | 1 + src/sas/system/config/config.py | 6 +++--- 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 src/sas/qtgui/Utilities/Preferences/FittingPreferencesWidget.py diff --git a/src/sas/qtgui/Utilities/Preferences/FittingPreferencesWidget.py b/src/sas/qtgui/Utilities/Preferences/FittingPreferencesWidget.py new file mode 100644 index 0000000000..481a167aac --- /dev/null +++ b/src/sas/qtgui/Utilities/Preferences/FittingPreferencesWidget.py @@ -0,0 +1,11 @@ +from sas.system import config + +from .PreferencesWidget import PreferencesWidget, config_value_setter_generator + + +class FittingPreferencesWidget(PreferencesWidget): + def __init__(self): + super(FittingPreferencesWidget, self).__init__("Fitting Settings") + self.addCheckBox(title="Auto-plot data when sent to fitting perspective", + callback=config_value_setter_generator('FITTING_PLOT_ON_SEND_DATA', dtype=bool), + checked=config.FITTING_PLOT_ON_SEND_DATA) \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/Preferences/PlottingPreferencesWidget.py b/src/sas/qtgui/Utilities/Preferences/PlottingPreferencesWidget.py index 6c500a2ab6..72291d72b1 100644 --- a/src/sas/qtgui/Utilities/Preferences/PlottingPreferencesWidget.py +++ b/src/sas/qtgui/Utilities/Preferences/PlottingPreferencesWidget.py @@ -5,7 +5,7 @@ class PlottingPreferencesWidget(PreferencesWidget): def __init__(self): - super(PlottingPreferencesWidget, self).__init__("Plotting Options") + super(PlottingPreferencesWidget, self).__init__("Plotting Settings") self.addCheckBox(title="Use full-width plot legends (most compatible)?", callback=config_value_setter_generator('FITTING_PLOT_FULL_WIDTH_LEGENDS', dtype=bool), checked=config.FITTING_PLOT_FULL_WIDTH_LEGENDS) diff --git a/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py b/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py index 69220c0399..519f59e9ad 100644 --- a/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py +++ b/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py @@ -18,6 +18,7 @@ BASE_PANELS = {"Plotting Settings":PlottingPreferencesWidget, "Display Settings":DisplayPreferencesWidget, + "Fitting Settings":FittingPreferencesWidget, } # Type: Dict[str, Union[Type[PreferencesWidget], Callable[[],QWidget]] logger = logging.getLogger(__name__) diff --git a/src/sas/system/config/config.py b/src/sas/system/config/config.py index 299b4f510a..3d3963144c 100644 --- a/src/sas/system/config/config.py +++ b/src/sas/system/config/config.py @@ -180,13 +180,13 @@ def __init__(self): # Time out for updating sasview self.UPDATE_TIMEOUT = 2 - # Auto-plot when sending data to Fitting - self.FITTING_PLOT_ON_SEND_DATA = True - # Window scaling values self.QT_SCALE_FACTOR = 1.0 self.QT_AUTO_SCREEN_SCALE_FACTOR = False + # Auto-plot when sending data to Fitting + self.FITTING_PLOT_ON_SEND_DATA = True + # If True, use an ugly but more robust legend plotting method in Fitting that results in full- # width legends. self.FITTING_PLOT_FULL_WIDTH_LEGENDS = False From 56d703bd7a9e1ae335b117c06acdb043d7560ed4 Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Fri, 28 Oct 2022 12:37:18 +0200 Subject: [PATCH 4/9] Small essentially typo fixes in fitting preferences widget --- src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py b/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py index 519f59e9ad..6483c958e7 100644 --- a/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py +++ b/src/sas/qtgui/Utilities/Preferences/PreferencesPanel.py @@ -7,13 +7,14 @@ from sas.qtgui.Utilities.Preferences.UI.PreferencesUI import Ui_preferencesUI from sas.qtgui.Utilities.Preferences.PreferencesWidget import PreferencesWidget from sas.qtgui.Utilities.Preferences.DisplayPreferencesWidget import DisplayPreferencesWidget - +from sas.qtgui.Utilities.Preferences.PlottingPreferencesWidget import PlottingPreferencesWidget +from sas.qtgui.Utilities.Preferences.FittingPreferencesWidget import FittingPreferencesWidget # The PreferencesPanel object will instantiate all widgets during its instantiation. # e.g: # `from foo.bar import BarWidget # BarWidget is a child of PreferencesWidget` # `BASE_PANELS = {"Bar Widget Options": BarWidget}` # PreferenceWidget Imports go here and then are added to the BASE_PANELS, but not instantiated. -from .PlottingPreferencesWidget import PlottingPreferencesWidget + # Pre-made option widgets BASE_PANELS = {"Plotting Settings":PlottingPreferencesWidget, From f31f226646289fb4a3d7c665d0b0b8a757831a57 Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Sat, 29 Oct 2022 11:57:04 +0200 Subject: [PATCH 5/9] Add flag for experimental data and gate plotting on it --- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py | 2 +- src/sas/qtgui/Perspectives/Fitting/ModelThread.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py index b1ac8089f3..97164e5efd 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @@ -2238,7 +2238,7 @@ def _requestPlots(self, item_name, item_model): data_shown = False item = None for item, plot in plots.items(): - if fitpage_name in plot.name: + if not hasattr(plot,'isExpData') and fitpage_name in plot.name: data_shown = True self.communicate.plotRequestedSignal.emit([item, plot], self.tab_id) # return the last data item seen, if nothing was plotted; supposed to be just data) diff --git a/src/sas/qtgui/Perspectives/Fitting/ModelThread.py b/src/sas/qtgui/Perspectives/Fitting/ModelThread.py index dd992d4ea5..6ed2b66c46 100644 --- a/src/sas/qtgui/Perspectives/Fitting/ModelThread.py +++ b/src/sas/qtgui/Perspectives/Fitting/ModelThread.py @@ -100,6 +100,8 @@ def compute(self): output[index_model] = value elapsed = time.time() - self.starttime + setattr(self.data,'isExpData',True) + res = dict(image = output, data = self.data, page_id = self.page_id, model = self.model, state = self.state, toggle_mode_on = self.toggle_mode_on, elapsed = elapsed, @@ -254,6 +256,8 @@ def compute(self): elapsed = time.time() - self.starttime + setattr(self.data,'isExpData',True) + res = dict(x = self.data.x[index], y = output[index], page_id = self.page_id, state = self.state, weight = self.weight, fid = self.fid, toggle_mode_on = self.toggle_mode_on, From 0b9189d08e10f6ff2d7c663ec2cf3997d5fd5d01 Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Sat, 29 Oct 2022 15:58:02 +0200 Subject: [PATCH 6/9] Remove flag and replace with plot data --- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py | 2 +- src/sas/qtgui/Perspectives/Fitting/ModelThread.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py index 97164e5efd..cf2b30aa55 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @@ -2238,7 +2238,7 @@ def _requestPlots(self, item_name, item_model): data_shown = False item = None for item, plot in plots.items(): - if not hasattr(plot,'isExpData') and fitpage_name in plot.name: + if plot.plot_role != Data1D.ROLE_DATA and fitpage_name in plot.name: data_shown = True self.communicate.plotRequestedSignal.emit([item, plot], self.tab_id) # return the last data item seen, if nothing was plotted; supposed to be just data) diff --git a/src/sas/qtgui/Perspectives/Fitting/ModelThread.py b/src/sas/qtgui/Perspectives/Fitting/ModelThread.py index 6ed2b66c46..3e34ad59d6 100644 --- a/src/sas/qtgui/Perspectives/Fitting/ModelThread.py +++ b/src/sas/qtgui/Perspectives/Fitting/ModelThread.py @@ -100,8 +100,6 @@ def compute(self): output[index_model] = value elapsed = time.time() - self.starttime - setattr(self.data,'isExpData',True) - res = dict(image = output, data = self.data, page_id = self.page_id, model = self.model, state = self.state, toggle_mode_on = self.toggle_mode_on, elapsed = elapsed, From 3b2b4ed286a4ae3abee1f1d457d7229b689fe8c3 Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Sat, 29 Oct 2022 18:02:35 +0200 Subject: [PATCH 7/9] Auto-plot on submit option --- src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py | 9 +++++++++ src/sas/qtgui/Perspectives/Fitting/FittingWidget.py | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py b/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py index 9208469f45..ae109994cb 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py @@ -22,6 +22,8 @@ from sas.qtgui.Utilities.Reports.reportdata import ReportData +from sas import config + class FittingWindow(QtWidgets.QTabWidget, Perspective): """ """ @@ -263,6 +265,13 @@ def addFit(self, data, is_batch=False, tab_index=None): self.addTab(tab, icon, tab_name) # Show the new tab self.setCurrentWidget(tab) + # If configured, plot the current data + if config.FITTING_PLOT_ON_SEND_DATA: + #First, create model and residuals inside this data. + tab.calculateQGridForModel() + #then simply push plot + tab.onPlot() + # Notify listeners self.tabsModifiedSignal.emit() diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py index cf2b30aa55..b9a4516db6 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @@ -2917,8 +2917,11 @@ def calculateQGridForModel(self): Prepare the fitting data object, based on current ModelModel """ if self.kernel_module is None: - return - self.calculateQGridForModelExt() + if self.data_is_loaded: + self.SASModelToQModel('porod') + self.calculateQGridForModelExt() + else: + self.calculateQGridForModelExt() def calculateDataFailed(self, reason): """ From 2c9e18cb586fb621df821d108c13c53c04856202 Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Sun, 30 Oct 2022 16:11:09 +0100 Subject: [PATCH 8/9] Switch to backend which quickly sets up a model. --- src/sas/qtgui/MainWindow/DataExplorer.py | 6 ----- .../Fitting/FittingPerspective.py | 23 +++++++++++++++---- .../Perspectives/Fitting/FittingWidget.py | 7 ++---- .../qtgui/Perspectives/Fitting/ModelThread.py | 2 -- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/sas/qtgui/MainWindow/DataExplorer.py b/src/sas/qtgui/MainWindow/DataExplorer.py index 73325f5f69..a74f854d61 100644 --- a/src/sas/qtgui/MainWindow/DataExplorer.py +++ b/src/sas/qtgui/MainWindow/DataExplorer.py @@ -778,14 +778,8 @@ def isItemReady(index): try: if self.chkSwap.isChecked(): self._perspective().swapData(selected_items[0]) - if self._perspective().name == 'Fitting': - if config.FITTING_PLOT_ON_SEND_DATA: - self.newPlot() #todo sort out where the plot should go. else: self._perspective().setData(data_item=selected_items, is_batch=self.chkBatch.isChecked()) - if self._perspective().name == 'Fitting': - if config.FITTING_PLOT_ON_SEND_DATA: - self.newPlot() except Exception as ex: msg = "%s perspective returned the following message: \n%s\n" % (self._perspective().name, str(ex)) diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py b/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py index ae109994cb..f0f7482889 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py @@ -23,6 +23,10 @@ from sas.qtgui.Utilities.Reports.reportdata import ReportData from sas import config +import time + +import logging +logger = logging.getLogger(__name__) class FittingWindow(QtWidgets.QTabWidget, Perspective): """ @@ -266,15 +270,23 @@ def addFit(self, data, is_batch=False, tab_index=None): # Show the new tab self.setCurrentWidget(tab) # If configured, plot the current data - if config.FITTING_PLOT_ON_SEND_DATA: - #First, create model and residuals inside this data. - tab.calculateQGridForModel() - #then simply push plot - tab.onPlot() + self.maybePlotOnLoad(tab) # Notify listeners self.tabsModifiedSignal.emit() + def maybePlotOnLoad(self,tab): + if tab.data_is_loaded and config.FITTING_PLOT_ON_SEND_DATA: + #First, create model and residuals inside this data. + def tidyup(self): + logger.info(msg='calculation complete, running tidy-up function') + time.sleep(2) + tab.onPlot() + time.sleep(2) + tab._model_model.clear() + tab.cmdPlot.setEnabled(False) + tab.SASModelToQModel('porod') + tab.calculateQGridForModelExt(completefn= tidyup) def addConstraintTab(self): """ Add a new C&S fitting tab @@ -440,6 +452,7 @@ def setData(self, data_item=None, is_batch=False, tab_index=None): self.tabs[first_good_tab].data = data tab_name = str(self.tabText(first_good_tab)) self.updateFitDict(data, tab_name) + self.maybePlotOnLoad(self.tabs[first_good_tab]) else: self.addFit(data, is_batch=is_batch) diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py index b9a4516db6..cf2b30aa55 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @@ -2917,11 +2917,8 @@ def calculateQGridForModel(self): Prepare the fitting data object, based on current ModelModel """ if self.kernel_module is None: - if self.data_is_loaded: - self.SASModelToQModel('porod') - self.calculateQGridForModelExt() - else: - self.calculateQGridForModelExt() + return + self.calculateQGridForModelExt() def calculateDataFailed(self, reason): """ diff --git a/src/sas/qtgui/Perspectives/Fitting/ModelThread.py b/src/sas/qtgui/Perspectives/Fitting/ModelThread.py index 3e34ad59d6..dd992d4ea5 100644 --- a/src/sas/qtgui/Perspectives/Fitting/ModelThread.py +++ b/src/sas/qtgui/Perspectives/Fitting/ModelThread.py @@ -254,8 +254,6 @@ def compute(self): elapsed = time.time() - self.starttime - setattr(self.data,'isExpData',True) - res = dict(x = self.data.x[index], y = output[index], page_id = self.page_id, state = self.state, weight = self.weight, fid = self.fid, toggle_mode_on = self.toggle_mode_on, From 7499b79618da595e0820723471575bf7c2346a5a Mon Sep 17 00:00:00 2001 From: Peter Beaucage Date: Sun, 30 Oct 2022 20:21:54 +0100 Subject: [PATCH 9/9] re-add timing things --- src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py b/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py index f0f7482889..fc7f4ad08b 100644 --- a/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py +++ b/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py @@ -280,9 +280,12 @@ def maybePlotOnLoad(self,tab): #First, create model and residuals inside this data. def tidyup(self): logger.info(msg='calculation complete, running tidy-up function') - time.sleep(2) - tab.onPlot() - time.sleep(2) + #time.sleep(2) + #tab.onPlot() + #QtWidgets.QApplication.processEvents() + tab.showPlot() + #QtWidgets.QApplication.processEvents() + #time.sleep(2) tab._model_model.clear() tab.cmdPlot.setEnabled(False) tab.SASModelToQModel('porod')