From 81cb550cb936330573604e9beaf25192a6d41ddd Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Thu, 27 Jan 2022 15:43:23 +0000 Subject: [PATCH 01/22] Fixed save to workspace button --- docs/source/quickstart.rst | 1 + mslice/app/mainwindow.ui | 2 +- mslice/presenters/cut_plotter_presenter.py | 10 ++++++---- mslice/widgets/cut/cut.py | 12 ++++++++---- mslice/widgets/cut/cut.ui | 4 ++-- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst index 3176b9072..e5d02fe8c 100644 --- a/docs/source/quickstart.rst +++ b/docs/source/quickstart.rst @@ -105,6 +105,7 @@ rectangle by clicking outside the current rectangle and dragging. Once you have ``Interactive Cut`` again to leave interactive mode. If you leave a slice in interactive cut mode and plot another slice, another window will open. Making a cut (see below) whilst the interactive mode is active will overplot on the same window as the interactive cut and this cut will be removed when the interactive mode rectangle is moved again. +Only when you click ``Save Cut to Workspace`` an ``MD Histo`` type workspace is created. Plotting a Cut -------------- diff --git a/mslice/app/mainwindow.ui b/mslice/app/mainwindow.ui index 2ae14f2c6..e43d61292 100644 --- a/mslice/app/mainwindow.ui +++ b/mslice/app/mainwindow.ui @@ -250,7 +250,7 @@ - 110 + 130 16777215 diff --git a/mslice/presenters/cut_plotter_presenter.py b/mslice/presenters/cut_plotter_presenter.py index eb48d48c3..8524d7136 100644 --- a/mslice/presenters/cut_plotter_presenter.py +++ b/mslice/presenters/cut_plotter_presenter.py @@ -1,6 +1,7 @@ from mslice.views.cut_plotter import plot_cut_impl, draw_interactive_cut, cut_figure_exists from mslice.models.cut.cut_functions import compute_cut from mslice.models.labels import generate_legend, is_momentum, is_twotheta +from mslice.models.workspacemanager.workspace_algorithms import export_workspace_to_ads from mslice.models.workspacemanager.workspace_provider import get_workspace_handle import mslice.plotting.pyplot as plt from mslice.presenters.presenter_utility import PresenterUtility @@ -20,11 +21,11 @@ def __init__(self): def run_cut(self, workspace, cut, plot_over=False, save_only=False): workspace = get_workspace_handle(workspace) cut.workspace_name = workspace.name - + if save_only: + self.save_cut_to_workspace(workspace, cut) + return if cut.width is not None: self._plot_with_width(workspace, cut, plot_over) - elif save_only: - self.save_cut_to_workspace(workspace, cut) else: self._plot_cut(workspace, cut, plot_over) @@ -67,8 +68,9 @@ def get_cache(self, ax): return self._cut_cache_dict[ax] if ax in self._cut_cache_dict.keys() else None def save_cut_to_workspace(self, workspace, cut): - compute_cut(workspace, cut.cut_axis, cut.integration_axis, cut.norm_to_one, cut.algorithm) + cut_ws = compute_cut(workspace, cut.cut_axis, cut.integration_axis, cut.norm_to_one, cut.algorithm) self._main_presenter.update_displayed_workspaces() + export_workspace_to_ads(cut_ws) def plot_cut_from_selected_workspace(self, plot_over=False): selected_workspaces = self._main_presenter.get_selected_workspaces() diff --git a/mslice/widgets/cut/cut.py b/mslice/widgets/cut/cut.py index 1da7ad77c..21e920d18 100644 --- a/mslice/widgets/cut/cut.py +++ b/mslice/widgets/cut/cut.py @@ -9,6 +9,7 @@ from qtpy.QtWidgets import QWidget from mslice.util.qt import load_ui from mslice.util.qt.validator_helper import double_validator_without_separator +from mslice.util.mantid import in_mantid from mslice.presenters.cut_widget_presenter import CutWidgetPresenter @@ -32,7 +33,7 @@ def __init__(self, parent=None, *args, **kwargs): self._command_lookup = { self.btnCutPlot: Command.Plot, self.btnCutPlotOver: Command.PlotOver, - self.btnCutSaveToWorkspace: Command.SaveToWorkspace + self.btnCutSaveToWorkbench: Command.SaveToWorkspace } for button in self._command_lookup.keys(): button.clicked.connect(self._btn_clicked) @@ -263,11 +264,14 @@ def enable(self): self.lneCutIntensityEnd.setEnabled(True) self.rdoCutNormToOne.setEnabled(True) - self.btnCutSaveToWorkspace.setEnabled(False) + self.btnCutSaveToWorkbench.setEnabled(False) self.btnCutPlot.setEnabled(False) self.btnCutPlotOver.setEnabled(False) - self.btnCutSaveToWorkspace.setEnabled(True) + if in_mantid(): + self.btnCutSaveToWorkbench.setEnabled(True) + else: + self.btnCutSaveToWorkbench.hide() self.btnCutPlot.setEnabled(True) self.btnCutPlotOver.setEnabled(True) @@ -286,7 +290,7 @@ def disable(self): self.lneCutIntensityEnd.setEnabled(False) self.rdoCutNormToOne.setEnabled(False) - self.btnCutSaveToWorkspace.setEnabled(False) + self.btnCutSaveToWorkbench.setEnabled(False) self.btnCutPlot.setEnabled(False) self.btnCutPlotOver.setEnabled(False) diff --git a/mslice/widgets/cut/cut.ui b/mslice/widgets/cut/cut.ui index c07df9ef7..85b668dd5 100644 --- a/mslice/widgets/cut/cut.ui +++ b/mslice/widgets/cut/cut.ui @@ -173,12 +173,12 @@ - + true - Save to Workspace + Save to Workbench From b483e90690364de8edf87a219c82361c4e9cadb6 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Thu, 27 Jan 2022 15:51:33 +0000 Subject: [PATCH 02/22] Nose fix for environment --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index d51c26bf1..3cef5d614 100644 --- a/environment.yml +++ b/environment.yml @@ -6,7 +6,6 @@ dependencies: - ipython - matplotlib - mock - - nose - numpy - numpy-base - pip @@ -19,5 +18,6 @@ dependencies: - pip: - coverage - h5py + - nose - pre-commit - pyyaml From 8e22a386dd1633c60549050b17c545e7a458ac90 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Thu, 27 Jan 2022 16:04:42 +0000 Subject: [PATCH 03/22] updated unit test for save to workspace --- mslice/tests/cut_plotter_presenter_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mslice/tests/cut_plotter_presenter_test.py b/mslice/tests/cut_plotter_presenter_test.py index edda72132..8bdcfc33f 100644 --- a/mslice/tests/cut_plotter_presenter_test.py +++ b/mslice/tests/cut_plotter_presenter_test.py @@ -53,7 +53,8 @@ def test_multiple_cuts_with_width(self, plot_cut_impl_mock, compute_cut_mock, ge @mock.patch('mslice.presenters.cut_plotter_presenter.get_workspace_handle') @mock.patch('mslice.presenters.cut_plotter_presenter.compute_cut') @mock.patch('mslice.presenters.cut_plotter_presenter.plot_cut_impl') - def test_save_to_workspace_success(self, plot_cut_impl_mock, compute_cut_mock, get_ws_handle_mock): + @mock.patch('mslice.presenters.cut_plotter_presenter.export_workspace_to_ads') + def test_save_to_workspace_success(self, export_workspace_to_ads, plot_cut_impl_mock, compute_cut_mock, get_ws_handle_mock): mock_ws = mock.MagicMock() mock_ws.name = 'workspace' get_ws_handle_mock.return_value = mock_ws @@ -61,6 +62,7 @@ def test_save_to_workspace_success(self, plot_cut_impl_mock, compute_cut_mock, g self.cut_plotter_presenter.run_cut('workspace', cut_cache, save_only=True) self.assertEqual(1, compute_cut_mock.call_count) + self.assertEqual(1, export_workspace_to_ads.call_count) self.assertEqual(0, plot_cut_impl_mock.call_count) @mock.patch('mslice.presenters.cut_plotter_presenter.get_workspace_handle') From 3d886019e97e99711e36a92b974217e972c4f28d Mon Sep 17 00:00:00 2001 From: Silke Schomann <74243814+SilkeSchomann@users.noreply.github.com> Date: Fri, 28 Jan 2022 08:05:15 +0000 Subject: [PATCH 04/22] Update docs/source/quickstart.rst Co-authored-by: Duc Le --- docs/source/quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst index e5d02fe8c..709ad78a2 100644 --- a/docs/source/quickstart.rst +++ b/docs/source/quickstart.rst @@ -105,7 +105,7 @@ rectangle by clicking outside the current rectangle and dragging. Once you have ``Interactive Cut`` again to leave interactive mode. If you leave a slice in interactive cut mode and plot another slice, another window will open. Making a cut (see below) whilst the interactive mode is active will overplot on the same window as the interactive cut and this cut will be removed when the interactive mode rectangle is moved again. -Only when you click ``Save Cut to Workspace`` an ``MD Histo`` type workspace is created. +Only when you click ``Save Cut to Workspace`` is an ``MD Histo`` type workspace created. Plotting a Cut -------------- From 11aa11e7c98d53a68ba5e5dc3f1eeeb11233f103 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Fri, 28 Jan 2022 08:28:28 +0000 Subject: [PATCH 05/22] Changed button widths --- mslice/app/mainwindow.ui | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mslice/app/mainwindow.ui b/mslice/app/mainwindow.ui index e43d61292..be012b625 100644 --- a/mslice/app/mainwindow.ui +++ b/mslice/app/mainwindow.ui @@ -75,7 +75,7 @@ - 110 + 130 16777215 @@ -101,7 +101,7 @@ - 110 + 130 16777215 @@ -114,7 +114,7 @@ - 110 + 130 16777215 @@ -127,7 +127,7 @@ - 110 + 130 16777215 @@ -140,7 +140,7 @@ - 110 + 130 16777215 @@ -153,7 +153,7 @@ - 110 + 130 16777215 @@ -166,7 +166,7 @@ - 110 + 130 16777215 @@ -179,7 +179,7 @@ - 110 + 130 16777215 @@ -211,7 +211,7 @@ - 110 + 130 25 @@ -232,7 +232,7 @@ 0 0 - 110 + 130 25 @@ -244,7 +244,7 @@ - 110 + 130 25 @@ -264,7 +264,7 @@ - 110 + 130 16777215 From 4cf6e368d38535617a4059c06ff035a38372323f Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Fri, 28 Jan 2022 13:51:48 +0000 Subject: [PATCH 06/22] Changed default visibility for various menu items --- mslice/plotting/plot_window/cut_plot.py | 8 +++++- mslice/plotting/plot_window/plot_window.py | 32 ++++++++++++---------- mslice/plotting/plot_window/slice_plot.py | 9 ++++++ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/mslice/plotting/plot_window/cut_plot.py b/mslice/plotting/plot_window/cut_plot.py index 86af13c74..cbd1aa477 100644 --- a/mslice/plotting/plot_window/cut_plot.py +++ b/mslice/plotting/plot_window/cut_plot.py @@ -60,8 +60,14 @@ def save_default_options(self): def setup_connections(self, plot_window): plot_window.redraw.connect(self._canvas.draw) - plot_window.menu_intensity.setDisabled(True) + plot_window.menu_information.setDisabled(False) plot_window.menu_recoil_lines.setDisabled(True) + plot_window.menu_intensity.setDisabled(True) + plot_window.action_toggle_legends.setVisible(True) + plot_window.action_keep.setVisible(True) + plot_window.action_make_current.setVisible(True) + plot_window.action_save_image.setVisible(True) + plot_window.action_plot_options.setVisible(True) plot_window.action_interactive_cuts.setVisible(False) plot_window.action_save_cut.setVisible(False) plot_window.action_save_cut.triggered.connect(self.save_icut) diff --git a/mslice/plotting/plot_window/plot_window.py b/mslice/plotting/plot_window/plot_window.py index dc2b06359..94df5a407 100644 --- a/mslice/plotting/plot_window/plot_window.py +++ b/mslice/plotting/plot_window/plot_window.py @@ -86,6 +86,8 @@ def create_menus(self): self.add_intensity_actions(self.menu_intensity) self.setMenuBar(self.menubar) + self.menu_information.setDisabled(True) + self.menu_intensity.setDisabled(True) def add_file_actions(self, menu): self.action_gen_script = add_action(menu, self, "Generate Script File") @@ -93,28 +95,28 @@ def add_file_actions(self, menu): self.action_gen_script_clipboard = add_action(menu, self, "Generate Script to Clipboard") menu.addAction(self.action_gen_script_clipboard) - self.action_quit = add_action(menu, self, "Close") + self.action_quit = add_action(menu, self, "Close", visible=True) menu.addAction(self.action_quit) self.action_quit.triggered.connect(self.close) def add_information_actions(self, menu, items): for text in items: - action = add_action(menu, self, text, checkable=True) + action = add_action(menu, self, text, checkable=True, visible=True) setattr(self, create_attribute_name(text), action) menu.addAction(action) def add_intensity_actions(self, menu): - self.action_sqe = add_action(menu, self, "S(Q,E)", checkable=True, checked=True) + self.action_sqe = add_action(menu, self, "S(Q,E)", checkable=True, checked=True, visible=True) menu.addAction(self.action_sqe) - self.action_chi_qe = add_action(menu, self, "Chi''(Q,E)", checkable=True) + self.action_chi_qe = add_action(menu, self, "Chi''(Q,E)", checkable=True, visible=True) menu.addAction(self.action_chi_qe) - self.action_chi_qe_magnetic = add_action(menu, self, "Chi''(Q,E) magnetic", checkable=True) + self.action_chi_qe_magnetic = add_action(menu, self, "Chi''(Q,E) magnetic", checkable=True, visible=True) menu.addAction(self.action_chi_qe_magnetic) - self.action_d2sig_dw_de = add_action(menu, self, "d2sigma/dOmega.dE", checkable=True) + self.action_d2sig_dw_de = add_action(menu, self, "d2sigma/dOmega.dE", checkable=True, visible=True) menu.addAction(self.action_d2sig_dw_de) - self.action_symmetrised_sqe = add_action(menu, self, "Symmetrised S(Q,E)", checkable=True) + self.action_symmetrised_sqe = add_action(menu, self, "Symmetrised S(Q,E)", checkable=True, visible=True) menu.addAction(self.action_symmetrised_sqe) - self.action_gdos = add_action(menu, self, "GDOS", checkable=True) + self.action_gdos = add_action(menu, self, "GDOS", checkable=True, visible=True) menu.addAction(self.action_gdos) def create_toolbar(self): @@ -124,23 +126,23 @@ def create_toolbar(self): def add_toolbar_actions(self, toolbar): self.action_zoom_in = add_action(toolbar, self, "Zoom In", on_triggered=self.stock_toolbar.zoom, - icon_name='mdi.magnify-plus-outline', checkable=True) + icon_name='mdi.magnify-plus-outline', checkable=True, visible=True) self.action_zoom_out = add_action(toolbar, self, "Zoom Out", on_triggered=self.stock_toolbar.back, - icon_name='mdi.magnify-minus-outline', checkable=False) + icon_name='mdi.magnify-minus-outline', checkable=False, visible=True) self.action_toggle_legends = add_action(toolbar, self, "Legends", checkable=True, checked=True) toolbar.addSeparator() - self.action_keep = add_action(toolbar, self, "Keep", checkable=True) + self.action_keep = add_action(toolbar, self, "Keep", checkable=True, visible=True) self.action_make_current = add_action(toolbar, self, "Make Current", - checkable=True, checked=True) + checkable=True, checked=True, visible=True) self.keep_make_current_group = QtWidgets.QActionGroup(self) self.keep_make_current_group.addAction(self.action_keep) self.keep_make_current_group.addAction(self.action_make_current) self.keep_make_current_seperator = toolbar.addSeparator() self.action_save_image = add_action(toolbar, self, "Save Image", icon_name='mdi.content-save') - self.action_copy_image = add_action(toolbar, self, "Copy Image", icon_name='mdi.content-copy') - self.action_print_plot = add_action(toolbar, self, "Print", icon_name='mdi.printer') + self.action_copy_image = add_action(toolbar, self, "Copy Image", icon_name='mdi.content-copy', visible=True) + self.action_print_plot = add_action(toolbar, self, "Print", icon_name='mdi.printer', visible=True) self.action_plot_options = add_action(toolbar, self, "Plot Options", icon_name='mdi.settings') toolbar.addSeparator() @@ -249,7 +251,7 @@ def create_attribute_name(text): def add_action(holder, parent, text, on_triggered=None, icon_name=None, - checkable=False, checked=False, visible=True): + checkable=False, checked=False, visible=False): """Create a new action based on the given attributes and add it to the given holder""" action = QtWidgets.QAction(text, parent) diff --git a/mslice/plotting/plot_window/slice_plot.py b/mslice/plotting/plot_window/slice_plot.py index 55d075496..fa4190b3f 100644 --- a/mslice/plotting/plot_window/slice_plot.py +++ b/mslice/plotting/plot_window/slice_plot.py @@ -68,6 +68,15 @@ def save_default_options(self): def setup_connections(self, plot_window): plot_window.redraw.connect(self._canvas.draw) + plot_window.action_gen_script.setVisible(True) + plot_window.action_gen_script_clipboard.setVisible(True) + plot_window.menu_information.setDisabled(False) + plot_window.menu_intensity.setDisabled(False) + plot_window.action_toggle_legends.setVisible(True) + plot_window.action_keep.setVisible(True) + plot_window.action_make_current.setVisible(True) + plot_window.action_save_image.setVisible(True) + plot_window.action_plot_options.setVisible(True) plot_window.action_interactive_cuts.setVisible(True) plot_window.action_interactive_cuts.triggered.connect(self.toggle_interactive_cuts) plot_window.action_save_cut.setVisible(False) From b438d43b0d145cccbee4455a4024dec029a2f716 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Mon, 31 Jan 2022 09:06:48 +0000 Subject: [PATCH 07/22] Add conda forge channel --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 3cef5d614..2b79c3e35 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ name: mslice channels: - - defaults + - conda-forge dependencies: - flake8 - ipython From 3da1c6b9f092676d2e6a8b9113bb3d5236b21b77 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Mon, 31 Jan 2022 15:54:29 +0000 Subject: [PATCH 08/22] Change to flake8 --- .github/workflows/unittest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index c5d845cca..ff010a4dd 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -36,7 +36,7 @@ jobs: - name: Flake8 run: | - python setup.py flake8 + python -m flake8 - name: Nosetests run: | From 229f90488fcc7eb38e00a735b83d466771ed9968 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Mon, 31 Jan 2022 16:06:40 +0000 Subject: [PATCH 09/22] Use default channel --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 2b79c3e35..252f84b0e 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ name: mslice channels: - - conda-forge + - default dependencies: - flake8 - ipython From f0b4c62c0207772ce66a3f7ccac0522bb0f4fe12 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 08:43:17 +0000 Subject: [PATCH 10/22] Added code for cut alg selection --- mslice/app/mainwindow.py | 2 + mslice/app/mainwindow.ui | 4 +- mslice/presenters/cut_widget_presenter.py | 8 +++- .../presenters/interfaces/main_presenter.py | 4 ++ mslice/presenters/main_presenter.py | 10 +++++ mslice/presenters/presenter_utility.py | 1 + mslice/tests/cut_widget_presenter_test.py | 18 ++++---- mslice/views/interfaces/cut_view.py | 9 ++-- mslice/widgets/cut/cut.py | 33 +++++++++++---- mslice/widgets/cut/cut.ui | 41 ++++++++++--------- 10 files changed, 88 insertions(+), 42 deletions(-) diff --git a/mslice/app/mainwindow.py b/mslice/app/mainwindow.py index 7491f271a..109a6e840 100644 --- a/mslice/app/mainwindow.py +++ b/mslice/app/mainwindow.py @@ -261,8 +261,10 @@ def set_cut_algorithm(self, algo): for action in self._cut_algo_map.keys(): if algo not in action: self._cut_algo_map[action].setChecked(False) + self._presenter.set_cut_algorithm_default(self.get_cut_algorithm()) def get_cut_algorithm(self): for action in self._cut_algo_map.keys(): if self._cut_algo_map[action].isChecked(): + print(action) return action diff --git a/mslice/app/mainwindow.ui b/mslice/app/mainwindow.ui index be012b625..fc073f3c2 100644 --- a/mslice/app/mainwindow.ui +++ b/mslice/app/mainwindow.ui @@ -470,7 +470,7 @@ true - Rebin + Rebin (Averages Counts) @@ -478,7 +478,7 @@ true - Integration + Integration (Sum Counts) diff --git a/mslice/presenters/cut_widget_presenter.py b/mslice/presenters/cut_widget_presenter.py index daf0fe848..77cb51f04 100644 --- a/mslice/presenters/cut_widget_presenter.py +++ b/mslice/presenters/cut_widget_presenter.py @@ -95,7 +95,7 @@ def _parse_input(self): norm_to_one = bool(self._cut_view.get_intensity_is_norm_to_one()) width = self._cut_view.get_integration_width() - algo = self._main_presenter.get_cut_algorithm() if self._main_presenter is not None else 'Rebin' + algo = self._cut_view.get_cut_algorithm() return cut_axis, integration_axis, intensity_start, intensity_end, norm_to_one, width, algo def _set_minimum_step(self, workspace, axis): @@ -200,3 +200,9 @@ def set_energy_default(self, en_default): self._en_default = en_default self._cut_view.set_energy_units_default(en_default) self._cut_view.set_energy_units(en_default) + + def set_cut_algorithm_default(self, algo_default): + print("cut default") + print(algo_default) + self._cut_view.set_cut_alg_default(algo_default) + self._cut_view.set_cut_algorithm(algo_default) diff --git a/mslice/presenters/interfaces/main_presenter.py b/mslice/presenters/interfaces/main_presenter.py index e2f5f7579..b3a7cc16d 100644 --- a/mslice/presenters/interfaces/main_presenter.py +++ b/mslice/presenters/interfaces/main_presenter.py @@ -49,6 +49,10 @@ def show_tab_for_workspace(self, ws): def subscribe_to_energy_default_monitor(self, client): pass + @abc.abstractmethod + def subscribe_to_cut_algo_default_monitor(self, client): + pass + @abc.abstractmethod def is_energy_conversion_allowed(self): pass diff --git a/mslice/presenters/main_presenter.py b/mslice/presenters/main_presenter.py index 0ca839cb9..9e562522a 100644 --- a/mslice/presenters/main_presenter.py +++ b/mslice/presenters/main_presenter.py @@ -9,6 +9,7 @@ def __init__(self, main_view, *subpresenters): self._mainView = main_view self._selected_workspace_listener = [] self._energy_default_listener = [] + self._cut_algo_default_listener = [] for presenter in subpresenters: presenter.register_master(self) @@ -70,6 +71,15 @@ def set_energy_default(self, en_default): for listener in self._energy_default_listener: listener.set_energy_default(en_default) + def subscribe_to_cut_algo_default_monitor(self, client): + print("client") + if isinstance(getattr(client, "set_cut_algo_default", None), collections.Callable): + self._cut_algo_default_listener.append(client) + + def set_cut_algorithm_default(self, algo_default): + for listener in self._cut_algo_default_listener: + listener.set_cut_algorithm_default(algo_default) + def is_energy_conversion_allowed(self): return self._mainView.is_energy_conversion_allowed() diff --git a/mslice/presenters/presenter_utility.py b/mslice/presenters/presenter_utility.py index 729df47a3..f9660411a 100644 --- a/mslice/presenters/presenter_utility.py +++ b/mslice/presenters/presenter_utility.py @@ -8,6 +8,7 @@ def register_master(self, main_presenter): self._main_presenter = main_presenter self._main_presenter.subscribe_to_workspace_selection_monitor(self) self._main_presenter.subscribe_to_energy_default_monitor(self) + self._main_presenter.subscribe_to_cut_algo_default_monitor(self) def _to_float(self, x): return None if x == "" else float(x) diff --git a/mslice/tests/cut_widget_presenter_test.py b/mslice/tests/cut_widget_presenter_test.py index a8acea2d4..bfaaa9c7c 100644 --- a/mslice/tests/cut_widget_presenter_test.py +++ b/mslice/tests/cut_widget_presenter_test.py @@ -113,7 +113,7 @@ def _create_cut(self, *args): axis, processed_axis = tuple(args[0:2]) integration_start, integration_end, width = tuple(args[2:5]) intensity_start, intensity_end, is_norm = tuple(args[5:8]) - workspace, integrated_axis = tuple(args[8:10]) + workspace, integrated_axis, cut_algorithm = tuple(args[8:11]) if isinstance(workspace, string_types): workspace = [workspace] self.main_presenter.get_selected_workspaces = mock.Mock(return_value=workspace) @@ -129,6 +129,7 @@ def _create_cut(self, *args): self.view.get_intensity_is_norm_to_one = mock.Mock(return_value=is_norm) self.view.get_integration_width = mock.Mock(return_value=width) self.view.get_energy_units = mock.Mock(return_value=axis.e_unit) + self.view.get_cut_algorithm = mock.Mock(return_value=cut_algorithm) def test_cut_no_workspaces_selected_fail(self): cut_widget_presenter = CutWidgetPresenter(self.view) @@ -164,7 +165,6 @@ def test_change_axis(self, get_ws_handle_mock, get_ws_handle_mock2, is_cuttable_ fields1['cut_parameters'] = ['0', '10', '0.05'] fields1['integration_range'] = ['-1', '1'] fields1['integration_width'] = '2' - fields1['smoothing'] = '' fields1['normtounity'] = False self.view.get_input_fields = mock.Mock(return_value=fields1) self.view.get_cut_axis = mock.Mock(return_value='DeltaE') @@ -180,7 +180,6 @@ def test_change_axis(self, get_ws_handle_mock, get_ws_handle_mock2, is_cuttable_ fields2['cut_parameters'] = ['-5', '5', '0.1'] fields2['integration_range'] = ['2', '3'] fields2['integration_width'] = '1' - fields2['smoothing'] = '' fields2['normtounity'] = True self.view.get_input_fields = mock.Mock(return_value=fields2) self.view.get_cut_axis = mock.Mock(return_value='|Q|') @@ -226,8 +225,10 @@ def test_invalid_step(self): is_norm = True workspace = "workspace" integrated_axis = 'integrated axis' + cut_algorithm = 'Rebin' self._create_cut(axis, processed_axis, integration_start, integration_end, width, - intensity_start, intensity_end, is_norm, workspace, integrated_axis) + intensity_start, intensity_end, is_norm, workspace, integrated_axis, + cut_algorithm) self.view.get_cut_axis_step = mock.Mock(return_value="") self.view.get_minimum_step = mock.Mock(return_value=1) @@ -252,9 +253,11 @@ def test_plot_multiple_workspaces_cut(self): is_norm = True selected_workspaces = ["ws1", "ws2"] integrated_axis = 'integrated axis' + cut_algorithm = 'Rebin' integration_axis = Axis('integrated axis', integration_start, integration_end, 0) self._create_cut(axis, integration_axis, integration_start, integration_end, width, - intensity_start, intensity_end, is_norm, selected_workspaces, integrated_axis) + intensity_start, intensity_end, is_norm, selected_workspaces, integrated_axis, + cut_algorithm) cut_widget_presenter.notify(Command.Plot) call_list = [ call(selected_workspaces[0], mock.ANY, save_only=False, plot_over=False), @@ -279,9 +282,10 @@ def test_cut_integration_algorithm(self, mock_cut_obj): intensity_start, intensity_end, is_norm, workspace = (11, 30, True, 'ws1') axis = Axis("units", "0", "100", "1") integration_axis = Axis('integrated axis', integration_start, integration_end, 0) + cut_algorithm = 'Integration' self._create_cut(axis, integration_axis, integration_start, integration_end, width, - intensity_start, intensity_end, is_norm, workspace, integrated_axis) - self.main_presenter.get_cut_algorithm = mock.Mock(return_value='Integration') + intensity_start, intensity_end, is_norm, workspace, integrated_axis, + cut_algorithm) cut_widget_presenter.notify(Command.Plot) self.view.display_error.assert_not_called() mock_cut_obj.assert_called_once_with(axis, integration_axis, intensity_start, intensity_end, diff --git a/mslice/views/interfaces/cut_view.py b/mslice/views/interfaces/cut_view.py index 6aa0adc42..5b533edae 100644 --- a/mslice/views/interfaces/cut_view.py +++ b/mslice/views/interfaces/cut_view.py @@ -38,9 +38,6 @@ def get_intensity_end(self): def get_intensity_is_norm_to_one(self): pass - def get_smoothing(self): - pass - def get_presenter(self): pass @@ -62,6 +59,12 @@ def get_energy_units(self): def set_energy_units(self, unit): pass + def get_cut_algorithm(self): + pass + + def set_cut_algorithm(self, algo): + pass + def set_energy_units_default(self, unit): pass diff --git a/mslice/widgets/cut/cut.py b/mslice/widgets/cut/cut.py index e7970006c..3edff1b68 100644 --- a/mslice/widgets/cut/cut.py +++ b/mslice/widgets/cut/cut.py @@ -26,6 +26,7 @@ class CutWidget(CutView, QWidget): error_occurred = Signal('QString') busy = Signal(bool) + _name_to_index = {'Rebin':0, 'Integration':1} def __init__(self, parent=None, *args, **kwargs): QWidget.__init__(self, parent, *args, **kwargs) @@ -45,7 +46,10 @@ def __init__(self, parent=None, *args, **kwargs): self.set_validators() self._en = EnergyUnits('meV') self._en_default = 'meV' + self._cut_alg_default = 'Rebin' + self.set_cut_algorithm('Rebin') self.cmbCutEUnits.currentIndexChanged.connect(self._changed_unit) + self.cmbCutAlg.currentIndexChanged.connect(self.cut_algorithm_changed) def _btn_clicked(self): sender = self.sender() @@ -90,6 +94,9 @@ def _changed_unit(self): def display_error(self, error_string): self.error_occurred.emit(error_string) + def cut_algorithm_changed(self, _changed_index): + self.get_input_fields() + def axis_changed(self, _changed_index): self._presenter.notify(Command.AxisChanged) @@ -143,9 +150,6 @@ def get_intensity_end(self): def get_intensity_is_norm_to_one(self): return self.rdoCutNormToOne.isChecked() - def get_smoothing(self): - return str(self.lneCutSmoothing.text()) - def get_energy_units(self): return self.cmbCutEUnits.currentText() @@ -155,6 +159,15 @@ def set_energy_units(self, unit): def set_energy_units_default(self, unit): self._en_default = unit + def set_cut_alg_default(self, algo_default): + self._cut_alg_default = algo_default + + def get_cut_algorithm(self): + return self.cmbCutAlg.currentIndex() + + def set_cut_algorithm(self, algo): + self.cmbCutAlg.setCurrentIndex(self._name_to_index[algo]) + def set_cut_axis(self, axis_name): index = [ind for ind in range(self.cmbCutAxis.count()) if str(self.cmbCutAxis.itemText(ind)) == axis_name] if index: @@ -208,8 +221,8 @@ def clear_input_fields(self, **kwargs): self.populate_cut_params("", "", "") self.populate_integration_params("", "") self.lneCutIntegrationWidth.setText("") - self.lneCutSmoothing.setText("") self.rdoCutNormToOne.setChecked(0) + self.cmbCutAlg.setCurrentIndex(self._name_to_index[self._cut_alg_default]) self.cmbCutEUnits.setCurrentIndex(EnergyUnits.get_index(self._en_default)) def is_fields_cleared(self): @@ -217,20 +230,20 @@ def is_fields_cleared(self): cleared_fields = {'cut_parameters': ['', '', ''], 'integration_range': ['', ''], 'integration_width': '', - 'smoothing': '', - 'normtounity': False} + 'normtounity': False, + 'cut_algorithm_index': ''} for k in cleared_fields: if current_fields[k] != cleared_fields[k]: return False return True def populate_input_fields(self, saved_input): - self.cmbCutEUnits.blockSignals(True) self.populate_cut_params(*saved_input['cut_parameters']) self.populate_integration_params(*saved_input['integration_range']) self.lneCutIntegrationWidth.setText(saved_input['integration_width']) - self.lneCutSmoothing.setText(saved_input['smoothing']) self.rdoCutNormToOne.setChecked(saved_input['normtounity']) + self.cmbCutAlg.setCurrentIndex(saved_input['cut_algorithm_index']) + self.cmbCutEUnits.blockSignals(True) self.cmbCutEUnits.setCurrentIndex(EnergyUnits.get_index(saved_input['energy_unit'])) self._en = EnergyUnits(saved_input['energy_unit']) self.cmbCutEUnits.blockSignals(False) @@ -243,8 +256,8 @@ def get_input_fields(self): saved_input['cut_parameters'] = list(cut_params) saved_input['integration_range'] = list(int_params)[:2] saved_input['integration_width'] = list(int_params)[2] - saved_input['smoothing'] = self.get_smoothing() saved_input['normtounity'] = self.get_intensity_is_norm_to_one() + saved_input['cut_algorithm_index'] = self.get_cut_algorithm() saved_input['energy_unit'] = self.get_energy_units() return saved_input @@ -254,6 +267,7 @@ def enable(self): self.lneCutStep.setEnabled(True) self.cmbCutAxis.setEnabled(True) self.cmbCutEUnits.setEnabled(True) + self.cmbCutAlg.setEnabled(True) self.lneCutIntegrationStart.setEnabled(True) self.lneCutIntegrationEnd.setEnabled(True) @@ -280,6 +294,7 @@ def disable(self): self.lneCutStep.setEnabled(False) self.cmbCutAxis.setEnabled(False) self.cmbCutEUnits.setEnabled(False) + self.cmbCutAlg.setEnabled(False) self.lneCutIntegrationStart.setEnabled(False) self.lneCutIntegrationEnd.setEnabled(False) diff --git a/mslice/widgets/cut/cut.ui b/mslice/widgets/cut/cut.ui index 85b668dd5..e838bd97f 100644 --- a/mslice/widgets/cut/cut.ui +++ b/mslice/widgets/cut/cut.ui @@ -124,23 +124,13 @@ - - - - false - - - Smoothing - - - - + - false + true - - false + + Save to Workbench @@ -172,16 +162,27 @@ - - - - true - + + - Save to Workbench + Cut Algorithm + + + + + Rebin (Averages Counts) + + + + + Integration (Sum Counts) + + + + From 979230e8d253e2a87f298a50e8eec97e52642397 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 09:25:53 +0000 Subject: [PATCH 11/22] Last batch of changes and added test --- mslice/app/mainwindow.py | 18 ++++++------------ mslice/presenters/cut_widget_presenter.py | 2 -- mslice/presenters/main_presenter.py | 3 +-- mslice/tests/main_presenter_test.py | 18 ++++++++++++++++++ mslice/widgets/cut/cut.py | 2 +- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/mslice/app/mainwindow.py b/mslice/app/mainwindow.py index 109a6e840..ea867c07f 100644 --- a/mslice/app/mainwindow.py +++ b/mslice/app/mainwindow.py @@ -113,8 +113,8 @@ def __init__(self, in_mantid=False): self.actionEUnitConvEnabled.triggered.connect(partial(self.set_energy_conversion, True)) self.actionEUnitConvDisabled.triggered.connect(partial(self.set_energy_conversion, False)) self._cut_algo_map = {'Rebin': self.actionCutAlgoRebin, 'Integration': self.actionCutAlgoIntegration} - self.actionCutAlgoRebin.triggered.connect(partial(self.set_cut_algorithm, 'Rebin')) - self.actionCutAlgoIntegration.triggered.connect(partial(self.set_cut_algorithm, 'Integration')) + self.actionCutAlgoRebin.triggered.connect(partial(self.set_cut_algorithm_default, 'Rebin')) + self.actionCutAlgoIntegration.triggered.connect(partial(self.set_cut_algorithm_default, 'Integration')) def setup_save(self): menu = QMenu() @@ -254,17 +254,11 @@ def set_energy_conversion(self, EnabledClicked): else: self.actionEUnitConvEnabled.setChecked(not self.actionEUnitConvDisabled.isChecked()) - def is_energy_conversion_allowed(self): - return self.actionEUnitConvEnabled.isChecked() - - def set_cut_algorithm(self, algo): + def set_cut_algorithm_default(self, algo): for action in self._cut_algo_map.keys(): if algo not in action: self._cut_algo_map[action].setChecked(False) - self._presenter.set_cut_algorithm_default(self.get_cut_algorithm()) + self._presenter.set_cut_algorithm_default(algo) - def get_cut_algorithm(self): - for action in self._cut_algo_map.keys(): - if self._cut_algo_map[action].isChecked(): - print(action) - return action + def is_energy_conversion_allowed(self): + return self.actionEUnitConvEnabled.isChecked() diff --git a/mslice/presenters/cut_widget_presenter.py b/mslice/presenters/cut_widget_presenter.py index 77cb51f04..52814d213 100644 --- a/mslice/presenters/cut_widget_presenter.py +++ b/mslice/presenters/cut_widget_presenter.py @@ -202,7 +202,5 @@ def set_energy_default(self, en_default): self._cut_view.set_energy_units(en_default) def set_cut_algorithm_default(self, algo_default): - print("cut default") - print(algo_default) self._cut_view.set_cut_alg_default(algo_default) self._cut_view.set_cut_algorithm(algo_default) diff --git a/mslice/presenters/main_presenter.py b/mslice/presenters/main_presenter.py index 9e562522a..75df5a9a2 100644 --- a/mslice/presenters/main_presenter.py +++ b/mslice/presenters/main_presenter.py @@ -72,8 +72,7 @@ def set_energy_default(self, en_default): listener.set_energy_default(en_default) def subscribe_to_cut_algo_default_monitor(self, client): - print("client") - if isinstance(getattr(client, "set_cut_algo_default", None), collections.Callable): + if isinstance(getattr(client, "set_cut_algorithm_default", None), collections.Callable): self._cut_algo_default_listener.append(client) def set_cut_algorithm_default(self, algo_default): diff --git a/mslice/tests/main_presenter_test.py b/mslice/tests/main_presenter_test.py index 4bd5e5282..05813a593 100644 --- a/mslice/tests/main_presenter_test.py +++ b/mslice/tests/main_presenter_test.py @@ -83,3 +83,21 @@ def test_energy_conversion_options(self): main_presenter = MainPresenter(self.mainview) main_presenter.is_energy_conversion_allowed() self.mainview.is_energy_conversion_allowed.assert_called() + + def test_set_cut_algorithm_default(self): + main_presenter = MainPresenter(self.mainview) + clients = [[mock.Mock(), True], [mock.Mock(), False], [mock.Mock(), True]] + for client, enable in clients: + if not enable: + client.set_cut_algorithm_default = mock.NonCallableMagicMock() + main_presenter.subscribe_to_cut_algo_default_monitor(client) + + for client, enable in clients: + client.set_energy_default.assert_not_called() + + main_presenter.set_cut_algorithm_default('Rebin') + for client, enable in clients: + if enable: + client.set_cut_algorithm_default.assert_called_once() + else: + client.set_cut_algorithm_default.assert_not_called() diff --git a/mslice/widgets/cut/cut.py b/mslice/widgets/cut/cut.py index 3edff1b68..26bb19e01 100644 --- a/mslice/widgets/cut/cut.py +++ b/mslice/widgets/cut/cut.py @@ -238,12 +238,12 @@ def is_fields_cleared(self): return True def populate_input_fields(self, saved_input): + self.cmbCutEUnits.blockSignals(True) self.populate_cut_params(*saved_input['cut_parameters']) self.populate_integration_params(*saved_input['integration_range']) self.lneCutIntegrationWidth.setText(saved_input['integration_width']) self.rdoCutNormToOne.setChecked(saved_input['normtounity']) self.cmbCutAlg.setCurrentIndex(saved_input['cut_algorithm_index']) - self.cmbCutEUnits.blockSignals(True) self.cmbCutEUnits.setCurrentIndex(EnergyUnits.get_index(saved_input['energy_unit'])) self._en = EnergyUnits(saved_input['energy_unit']) self.cmbCutEUnits.blockSignals(False) From 0215003d160bbb136b3b027002f1d1d2845df6d5 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 09:44:52 +0000 Subject: [PATCH 12/22] Fixed flake8 problems --- tools/boilerplate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/boilerplate.py b/tools/boilerplate.py index d6c24f775..65e67e8d7 100644 --- a/tools/boilerplate.py +++ b/tools/boilerplate.py @@ -103,7 +103,7 @@ def {name}(): ''' -def boilerplate_gen(): +def boilerplate_gen():# noqa: C901 """Generator of lines for the automated part of pyplot.""" # these methods are all simple wrappers of Axes methods by the same @@ -208,8 +208,8 @@ def format_value(value): return '=mlab.' + value.__name__ if value.__name__ == 'mean': return '=np.' + value.__name__ - raise ValueError(('default value %s unknown to boilerplate.' + - 'formatvalue') % value) + raise ValueError(('default value %s unknown to boilerplate.' + + 'formatvalue') % value) return '=' + repr(value) text_wrapper = textwrap.TextWrapper(break_long_words=False) @@ -243,7 +243,7 @@ def format_value(value): def_edited = [] for val in defaults: if six.PY2: - if isinstance(val, unicode): + if isinstance(val, str): val = val.encode('ascii', 'ignore') def_edited.append(val) defaults = tuple(def_edited) From 7370d12312e1d65d2ae65c823a8fe53db5b55b8b Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 09:51:38 +0000 Subject: [PATCH 13/22] Added fix for nightly builds --- .github/workflows/conda.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index 13ce9e4a1..cafb512c2 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -36,7 +36,7 @@ jobs: - name: Flake8 run: | - python setup.py flake8 + python -m flake8 - name: Nosetests run: | From 9beff81954e03678289e34d720de6d5c17d7e5d8 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 10:03:23 +0000 Subject: [PATCH 14/22] Changed flake8 setting in git workflow --- .github/workflows/conda.yml | 2 +- .github/workflows/unittest.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index 13ce9e4a1..cafb512c2 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -36,7 +36,7 @@ jobs: - name: Flake8 run: | - python setup.py flake8 + python -m flake8 - name: Nosetests run: | diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index c5d845cca..ff010a4dd 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -36,7 +36,7 @@ jobs: - name: Flake8 run: | - python setup.py flake8 + python -m flake8 - name: Nosetests run: | From 4650af55e5a6b6cfe63e72bed71c14ac7826c854 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 10:04:29 +0000 Subject: [PATCH 15/22] Updated boilerplate --- tools/boilerplate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/boilerplate.py b/tools/boilerplate.py index d6c24f775..65e67e8d7 100644 --- a/tools/boilerplate.py +++ b/tools/boilerplate.py @@ -103,7 +103,7 @@ def {name}(): ''' -def boilerplate_gen(): +def boilerplate_gen():# noqa: C901 """Generator of lines for the automated part of pyplot.""" # these methods are all simple wrappers of Axes methods by the same @@ -208,8 +208,8 @@ def format_value(value): return '=mlab.' + value.__name__ if value.__name__ == 'mean': return '=np.' + value.__name__ - raise ValueError(('default value %s unknown to boilerplate.' + - 'formatvalue') % value) + raise ValueError(('default value %s unknown to boilerplate.' + + 'formatvalue') % value) return '=' + repr(value) text_wrapper = textwrap.TextWrapper(break_long_words=False) @@ -243,7 +243,7 @@ def format_value(value): def_edited = [] for val in defaults: if six.PY2: - if isinstance(val, unicode): + if isinstance(val, str): val = val.encode('ascii', 'ignore') def_edited.append(val) defaults = tuple(def_edited) From a10c057c32cd5c8f89540a5a8db6dbabf40af585 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 11:39:45 +0000 Subject: [PATCH 16/22] Reverted changes from integration scale bug fix --- mslice/models/cut/cut_algorithm.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mslice/models/cut/cut_algorithm.py b/mslice/models/cut/cut_algorithm.py index 6c20d162c..52cef5c20 100644 --- a/mslice/models/cut/cut_algorithm.py +++ b/mslice/models/cut/cut_algorithm.py @@ -2,7 +2,7 @@ from mantid.api import PythonAlgorithm, WorkspaceProperty from mantid.kernel import Direction, PropertyManagerProperty, StringMandatoryValidator, StringListValidator -from mantid.simpleapi import BinMD, ConvertSpectrumAxis, CreateMDHistoWorkspace, Rebin2D, SofQW3, TransformMD, Scale, \ +from mantid.simpleapi import BinMD, ConvertSpectrumAxis, CreateMDHistoWorkspace, Rebin2D, SofQW3, TransformMD, \ ConvertToMD, DeleteWorkspace, CreateSimulationWorkspace, AddSampleLog, CopyLogs, Integration, Rebin, Transpose from mslice.models.alg_workspace_ops import fill_in_missing_input, get_number_of_steps @@ -149,17 +149,15 @@ def _cut_nonPSD_momentum(q_binning, e_binning, emode, selected_workspace, algo): if 'Integration' in algo: qbins = [float(q) for q in q_binning.split(',')] ebins = [float(e) for e in e_binning.split(',')] - nstep = 100. if np.abs((qbins[2]-qbins[0]) - qbins[1]) < 0.0001: - qbinstr = ','.join(map(str, [qbins[0], (qbins[2]-qbins[0])/nstep, qbins[2]])) + qbinstr = ','.join(map(str, [qbins[0], (qbins[2]-qbins[0])/100., qbins[2]])) ws_out = _cut_indirect_or_direct(qbinstr, e_binning, emode, selected_workspace) ws_out = Transpose(InputWorkspace=ws_out, EnableLogging=False) ws_out = Integration(InputWorkspace=ws_out, RangeLower=qbins[0], RangeUpper=qbins[2], EnableLogging=False) else: - ebinstr = ','.join(map(str, [ebins[0], (ebins[2]-ebins[0])/nstep, ebins[2]])) + ebinstr = ','.join(map(str, [ebins[0], (ebins[2]-ebins[0])/100., ebins[2]])) ws_out = _cut_indirect_or_direct(q_binning, ebinstr, emode, selected_workspace) ws_out = Integration(InputWorkspace=ws_out, RangeLower=ebins[0], RangeUpper=ebins[2], EnableLogging=False) - ws_out = Scale(InputWorkspace=ws_out, Factor=nstep, EnableLogging=False) else: ws_out = _cut_indirect_or_direct(q_binning, e_binning, emode, selected_workspace) return ws_out From 73ed86ba3566c000ab881e0960f59c1ed670cf0c Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 12:28:49 +0000 Subject: [PATCH 17/22] Changes after review and unit test update --- mslice/presenters/cut_widget_presenter.py | 2 +- mslice/tests/cut_widget_presenter_test.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mslice/presenters/cut_widget_presenter.py b/mslice/presenters/cut_widget_presenter.py index 52814d213..79839b4f0 100644 --- a/mslice/presenters/cut_widget_presenter.py +++ b/mslice/presenters/cut_widget_presenter.py @@ -95,7 +95,7 @@ def _parse_input(self): norm_to_one = bool(self._cut_view.get_intensity_is_norm_to_one()) width = self._cut_view.get_integration_width() - algo = self._cut_view.get_cut_algorithm() + algo = ['Rebin', 'Integration'][self._cut_view.get_cut_algorithm()] return cut_axis, integration_axis, intensity_start, intensity_end, norm_to_one, width, algo def _set_minimum_step(self, workspace, axis): diff --git a/mslice/tests/cut_widget_presenter_test.py b/mslice/tests/cut_widget_presenter_test.py index bfaaa9c7c..3b4ed3593 100644 --- a/mslice/tests/cut_widget_presenter_test.py +++ b/mslice/tests/cut_widget_presenter_test.py @@ -225,7 +225,7 @@ def test_invalid_step(self): is_norm = True workspace = "workspace" integrated_axis = 'integrated axis' - cut_algorithm = 'Rebin' + cut_algorithm = 0 self._create_cut(axis, processed_axis, integration_start, integration_end, width, intensity_start, intensity_end, is_norm, workspace, integrated_axis, cut_algorithm) @@ -253,7 +253,7 @@ def test_plot_multiple_workspaces_cut(self): is_norm = True selected_workspaces = ["ws1", "ws2"] integrated_axis = 'integrated axis' - cut_algorithm = 'Rebin' + cut_algorithm = 0 integration_axis = Axis('integrated axis', integration_start, integration_end, 0) self._create_cut(axis, integration_axis, integration_start, integration_end, width, intensity_start, intensity_end, is_norm, selected_workspaces, integrated_axis, @@ -282,7 +282,7 @@ def test_cut_integration_algorithm(self, mock_cut_obj): intensity_start, intensity_end, is_norm, workspace = (11, 30, True, 'ws1') axis = Axis("units", "0", "100", "1") integration_axis = Axis('integrated axis', integration_start, integration_end, 0) - cut_algorithm = 'Integration' + cut_algorithm = 1 self._create_cut(axis, integration_axis, integration_start, integration_end, width, intensity_start, intensity_end, is_norm, workspace, integrated_axis, cut_algorithm) From df43baa365787c5e256b6b39754624a006942a97 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Tue, 1 Feb 2022 12:35:14 +0000 Subject: [PATCH 18/22] Changed menu text for cut algorithm default --- mslice/app/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mslice/app/mainwindow.ui b/mslice/app/mainwindow.ui index fc073f3c2..d6ff5025e 100644 --- a/mslice/app/mainwindow.ui +++ b/mslice/app/mainwindow.ui @@ -426,7 +426,7 @@ - Cut algorithm + Cut algorithm default From 5755d14ab4a87c89fe0ab01b4aefc8afbe97929b Mon Sep 17 00:00:00 2001 From: Duc Le Date: Tue, 1 Feb 2022 12:56:09 +0000 Subject: [PATCH 19/22] Update pyplot.py to be compatible with MPL3 #686 #693 --- mslice/plotting/pyplot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mslice/plotting/pyplot.py b/mslice/plotting/pyplot.py index 8d48413d2..50dfa431a 100644 --- a/mslice/plotting/pyplot.py +++ b/mslice/plotting/pyplot.py @@ -3199,6 +3199,8 @@ def plot(*args, **kwargs): ax = gca() # Deprecated: allow callers to override the hold state # by passing hold=True|False + if not hasattr(ax, '_hold'): + return ax.plot(*args, **kwargs) washold = ax._hold hold = kwargs.pop('hold', None) if hold is not None: From c5207fc3b15572db3ec60073ebea3ac240ae7350 Mon Sep 17 00:00:00 2001 From: Duc Le Date: Tue, 1 Feb 2022 16:50:02 +0000 Subject: [PATCH 20/22] Add 'Integration' option to Cut for PSD workspaces --- mslice/models/cut/cut_algorithm.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/mslice/models/cut/cut_algorithm.py b/mslice/models/cut/cut_algorithm.py index 52cef5c20..0f534b077 100644 --- a/mslice/models/cut/cut_algorithm.py +++ b/mslice/models/cut/cut_algorithm.py @@ -3,7 +3,8 @@ from mantid.api import PythonAlgorithm, WorkspaceProperty from mantid.kernel import Direction, PropertyManagerProperty, StringMandatoryValidator, StringListValidator from mantid.simpleapi import BinMD, ConvertSpectrumAxis, CreateMDHistoWorkspace, Rebin2D, SofQW3, TransformMD, \ - ConvertToMD, DeleteWorkspace, CreateSimulationWorkspace, AddSampleLog, CopyLogs, Integration, Rebin, Transpose + ConvertToMD, DeleteWorkspace, CreateSimulationWorkspace, AddSampleLog, CopyLogs, Integration, Rebin, Transpose, \ + IntegrateMDHistoWorkspace from mslice.models.alg_workspace_ops import fill_in_missing_input, get_number_of_steps from mslice.models.axis import Axis @@ -50,7 +51,7 @@ def category(self): def compute_cut(selected_workspace, cut_axis, integration_axis, e_mode, PSD, is_norm, algo): if PSD: - cut = _compute_cut_PSD(selected_workspace, cut_axis, integration_axis) + cut = _compute_cut_PSD(selected_workspace, cut_axis, integration_axis, algo) else: cut = _compute_cut_nonPSD(selected_workspace, cut_axis, integration_axis, e_mode, algo) if is_norm: @@ -58,17 +59,25 @@ def compute_cut(selected_workspace, cut_axis, integration_axis, e_mode, PSD, is_ return cut -def _compute_cut_PSD(selected_workspace, cut_axis, integration_axis): +def _compute_cut_PSD(selected_workspace, cut_axis, integration_axis, algo): cut_axis.units = cut_axis.units.replace('2Theta', 'Degrees') integration_axis.units = integration_axis.units.replace('2Theta', 'Degrees') fill_in_missing_input(cut_axis, selected_workspace) n_steps = get_number_of_steps(cut_axis) cut_binning = " ,".join(map(str, (cut_axis.units, cut_axis.start_meV, cut_axis.end_meV, n_steps))) integration_binning = integration_axis.units + "," + str(integration_axis.start_meV) + "," + \ - str(integration_axis.end_meV) + ",1" + str(integration_axis.end_meV) + (",1" if 'Rebin' in algo else ",100") - return BinMD(InputWorkspace=selected_workspace, AxisAligned="1", AlignedDim1=integration_binning, - AlignedDim0=cut_binning, StoreInADS=False) + ws = BinMD(InputWorkspace=selected_workspace, AxisAligned="1", AlignedDim0=integration_binning, + AlignedDim1=cut_binning, StoreInADS=False) + if 'Integration' in algo: + x0, x1 = (integration_axis.start_meV, integration_axis.end_meV) + # 100 step is hard coded into the `integration_binning` string above + norm_fac = (np.sum(ws.getNumEventsArray() != 0., axis=0) / 100) * (x1 - x0) + ws = IntegrateMDHistoWorkspace(ws, P1Bin=[x0, x1], P2Bin=[], StoreInADS=False) + ws.setSignalArray(ws.getSignalArray() * norm_fac) + ws.setErrorSquaredArray(ws.getErrorSquaredArray() * np.square(norm_fac)) + return ws def _compute_cut_nonPSD(selected_workspace, cut_axis, integration_axis, emode, algo): From c3b2300502a17f02b6605216ab9502008ed2354c Mon Sep 17 00:00:00 2001 From: Duc Le Date: Tue, 1 Feb 2022 18:49:56 +0000 Subject: [PATCH 21/22] Add/fix unit test --- mslice/tests/command_line_test.py | 6 ++++++ mslice/workspace/histo_mixin.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mslice/tests/command_line_test.py b/mslice/tests/command_line_test.py index a9125f48a..70216b1eb 100644 --- a/mslice/tests/command_line_test.py +++ b/mslice/tests/command_line_test.py @@ -173,6 +173,12 @@ def test_cut_psd(self, get_cpp, is_gui): self.assertEqual(128, signal[0]) self.assertEqual(192, signal[29]) self.assertEqual(429, signal[15]) + result = Cut(workspace, Algorithm='Integration') + signal = result.get_signal() + self.assertEqual(type(result), HistogramWorkspace) + self.assertAlmostEqual(64, signal[0], 2) + self.assertAlmostEqual(192, signal[29], 2) + self.assertAlmostEqual(1287, signal[15], 2) @mock.patch('mslice.app.presenters.get_slice_plotter_presenter') def test_slice_fail_workspace_type(self, get_spp): diff --git a/mslice/workspace/histo_mixin.py b/mslice/workspace/histo_mixin.py index 895302cb3..0916a057c 100644 --- a/mslice/workspace/histo_mixin.py +++ b/mslice/workspace/histo_mixin.py @@ -8,7 +8,7 @@ class HistoMixin(object): def get_signal(self): """Gets data values (Y axis) from the workspace as a numpy array.""" - return self._raw_ws.getSignalArray().copy() + return np.squeeze(self._raw_ws.getSignalArray().copy()) def get_error(self): """Gets error values (E) from the workspace as a numpy array.""" @@ -17,7 +17,7 @@ def get_error(self): def get_variance(self, copy=True): """Gets variance (error^2) from the workspace as a numpy array.""" variance = self._raw_ws.getErrorSquaredArray() - return variance.copy() if copy else variance + return np.squeeze(variance.copy() if copy else variance) def set_signal(self, signal): self._raw_ws.setSignalArray(signal) From 302cfd8be3e471983bed26404792c20935d83fe5 Mon Sep 17 00:00:00 2001 From: Silke Schomann <74243814+SilkeSchomann@users.noreply.github.com> Date: Wed, 2 Feb 2022 16:13:34 +0000 Subject: [PATCH 22/22] Update environment.yml --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 252f84b0e..3cef5d614 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ name: mslice channels: - - default + - defaults dependencies: - flake8 - ipython