From 5914a5eef01ae0951ba5a7c0e2be04bc3d6cfdeb Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Wed, 20 Mar 2024 17:22:07 +0000 Subject: [PATCH 01/12] Tof Unit conversion formulas and setting TofUnitMode --- .../gui/windows/spectrum_viewer/model.py | 35 +++++++++++++++++++ .../gui/windows/spectrum_viewer/view.py | 13 +++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 8749f266eb6..43bfbbb8563 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -32,6 +32,13 @@ class SpecType(Enum): SAMPLE_NORMED = 3 +class ToFUnitMode(Enum): + IMAGE_NUMBER = 1 + TOF_US = 2 + WAVELENGTH = 3 + ENERGY = 4 + + class ErrorMode(Enum): STANDARD_DEVIATION = "Standard Deviation" PROPAGATED = "Propagated" @@ -175,6 +182,7 @@ def get_spectrum(self, roi: str | SensibleROI, mode: SpecType) -> np.ndarray: roi = self.get_roi(roi) if mode == SpecType.SAMPLE: + print(f"TOF Spectrum: {self.get_stack_spectrum(self._stack, roi)}, Length: {len(self.get_stack_spectrum(self._stack, roi))}") return self.get_stack_spectrum(self._stack, roi) if self._normalise_stack is None: @@ -441,3 +449,30 @@ def remove_all_roi(self) -> None: Remove all ROIs from the model """ self._roi_ranges = {} + + def get_stack_time_of_flight_wavelength(self, target_to_camera_dist: float = 56) -> np.ndarray | None: + # target_to_camera_dist = 56 m taken from https://scripts.iucr.org/cgi-bin/paper?S1600576719001730 + tof = self.get_stack_time_of_flight() + if tof is not None: + velocity = target_to_camera_dist / tof + planck_h = 6.62606896e-34 # [JHz-1] + neutron_mass = 1.674927211e-27 # [kg] + angstrom = 1e-10 #[m] + wavelength = planck_h / (neutron_mass * velocity) + wavelength_angstroms = wavelength / angstrom + return wavelength_angstroms + else: + return None + + def get_stack_time_of_flight_energy(self, target_to_camera_dist: float = 56) -> np.ndarray | None: + tof = self.get_stack_time_of_flight() + # target_to_camera_dist = 56 m taken from https://scripts.iucr.org/cgi-bin/paper?S1600576719001730 + if tof is not None: + velocity = target_to_camera_dist / tof + neutron_mass = 1.674927211e-27 # [kg] + energy = neutron_mass * velocity / 2 + mega_electro_volt = 1.60217662e-13 + energy_evs = energy / mega_electro_volt + return energy_evs + else: + return None diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index a1519d7772d..71b0b030c2b 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -13,7 +13,7 @@ from mantidimaging.core.utility import finder from mantidimaging.gui.mvp_base import BaseMainWindowView from mantidimaging.gui.widgets.dataset_selector import DatasetSelectorWidgetView -from .model import ROI_RITS +from .model import ROI_RITS, ToFUnitMode from .presenter import SpectrumViewerWindowPresenter, ExportMode from mantidimaging.gui.widgets import RemovableRowTableView from .spectrum_widget import SpectrumWidget @@ -161,6 +161,10 @@ def __init__(self, main_window: MainWindowView): self.current_roi = self.last_clicked_roi = self.roi_table_model.roi_names()[0] self.set_roi_properties() + print(f"{self.presenter.model.get_stack_time_of_flight()=}") + print(f"{self.presenter.model.get_stack_time_of_flight_wavelength()=}") + print(f"{self.presenter.model.get_stack_time_of_flight_energy()=}") + def on_row_change(item, _) -> None: """ Handle cell change in table view and update selected ROI and @@ -397,10 +401,13 @@ def set_roi_alpha(self, alpha: float, roi_name: str) -> None: self.spectrum_widget.spectrum.update() self.show_visible_spectrums() - def show_visible_spectrums(self): + def show_visible_spectrums(self, mode: ToFUnitMode = ToFUnitMode.WAVELENGTH): + if mode == ToFUnitMode.WAVELENGTH: + tof_data = self.presenter.model.get_stack_time_of_flight_wavelength() for key, value in self.spectrum_widget.spectrum_data_dict.items(): if value is not None and key in self.spectrum_widget.roi_dict: - self.spectrum_widget.spectrum.plot(value, name=key, pen=self.spectrum_widget.roi_dict[key].colour) + self.spectrum_widget.spectrum.plot(tof_data, value, name=key, pen=self.spectrum_widget.roi_dict[key].colour) + def add_roi_table_row(self, name: str, colour: tuple[int, int, int]): """ From f10a24721a67a4087bea6f35d8a1320dde7db556 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Thu, 21 Mar 2024 17:35:57 +0000 Subject: [PATCH 02/12] Backend unit switching implemented --- .../gui/windows/spectrum_viewer/model.py | 23 ++++++++++++++++++- .../gui/windows/spectrum_viewer/presenter.py | 18 +++++++++++++-- .../spectrum_viewer/spectrum_widget.py | 8 ++++--- .../gui/windows/spectrum_viewer/view.py | 12 ++++++---- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 43bfbbb8563..66bacf7b73a 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -62,7 +62,11 @@ class SpectrumViewerWindowModel: _stack: ImageStack | None = None _normalise_stack: ImageStack | None = None tof_range: tuple[int, int] = (0, 0) + tof_plot_range: tuple[float, float] | tuple[int, int] = (0, 0) _roi_ranges: dict[str, SensibleROI] + tof_mode: ToFUnitMode = ToFUnitMode.WAVELENGTH + tof_data: np.ndarray | None = None + tof_range_full: tuple[int, int] = (0, 0) def __init__(self, presenter: SpectrumViewerWindowPresenter): self.presenter = presenter @@ -101,6 +105,7 @@ def set_stack(self, stack: ImageStack | None) -> None: return self._roi_id_counter = 0 self.tof_range = (0, stack.data.shape[0] - 1) + self.tof_range_full = self.tof_range self.set_new_roi(ROI_ALL) def set_new_roi(self, name: str) -> None: @@ -453,6 +458,7 @@ def remove_all_roi(self) -> None: def get_stack_time_of_flight_wavelength(self, target_to_camera_dist: float = 56) -> np.ndarray | None: # target_to_camera_dist = 56 m taken from https://scripts.iucr.org/cgi-bin/paper?S1600576719001730 tof = self.get_stack_time_of_flight() + print("tof", tof) if tof is not None: velocity = target_to_camera_dist / tof planck_h = 6.62606896e-34 # [JHz-1] @@ -471,8 +477,23 @@ def get_stack_time_of_flight_energy(self, target_to_camera_dist: float = 56) -> velocity = target_to_camera_dist / tof neutron_mass = 1.674927211e-27 # [kg] energy = neutron_mass * velocity / 2 - mega_electro_volt = 1.60217662e-13 + mega_electro_volt = 1.60217662e-19 / 1e6 energy_evs = energy / mega_electro_volt return energy_evs else: return None + + def set_relevant_tof_units(self) -> None: + print(f"{self.tof_mode=}") + if self.tof_mode == ToFUnitMode.IMAGE_NUMBER: + self.tof_data = None + self.tof_plot_range = (0, self._stack.data.shape[0] - 1) + else: + if self.tof_mode == ToFUnitMode.TOF_US: + self.tof_data = self.get_stack_time_of_flight() + elif self.tof_mode == ToFUnitMode.WAVELENGTH: + self.tof_data = self.get_stack_time_of_flight_wavelength() + print(f"{self.tof_data=}") + elif self.tof_mode == ToFUnitMode.ENERGY: + self.tof_data = self.get_stack_time_of_flight_energy() + self.tof_plot_range = (self.tof_data.min(), self.tof_data.max()) diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 8384294c6f5..b05e34f3840 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -7,6 +7,9 @@ from typing import TYPE_CHECKING from logging import getLogger + +import numpy as np + from mantidimaging.core.data.dataset import StrictDataset from mantidimaging.gui.dialogs.async_task import start_async_task_view, TaskWorkerThread from mantidimaging.gui.mvp_base import BasePresenter @@ -84,6 +87,7 @@ def handle_sample_change(self, uuid: UUID | None) -> None: return self.model.set_stack(self.main_window.get_stack(uuid)) + self.model.set_relevant_tof_units() normalise_uuid = self.view.get_normalise_stack() if normalise_uuid is not None: try: @@ -135,13 +139,16 @@ def show_new_sample(self) -> None: averaged_image = self.model.get_averaged_image() assert averaged_image is not None self.view.set_image(averaged_image) - self.view.spectrum_widget.spectrum_plot_widget.add_range(*self.model.tof_range) + self.view.spectrum_widget.spectrum_plot_widget.add_range(*self.model.tof_plot_range) self.view.auto_range_image() if self.view.get_roi_properties_spinboxes(): self.view.set_roi_properties() def handle_range_slide_moved(self, tof_range) -> None: - self.model.tof_range = tof_range + tof_range_min_rescaled = int(np.interp(tof_range[0], (self.model.tof_data.min(), self.model.tof_data.max()), (self.model.tof_range_full[0], self.model.tof_range_full[1]))) + tof_range_max_rescaled = int(np.interp(tof_range[1], (self.model.tof_data.min(), self.model.tof_data.max()), (self.model.tof_range_full[0], self.model.tof_range_full[1]))) + self.model.tof_range = (tof_range_min_rescaled, tof_range_max_rescaled) + print(f"{self.model.tof_range=}") averaged_image = self.model.get_averaged_image() assert averaged_image is not None self.view.set_image(averaged_image, autoLevels=False) @@ -312,3 +319,10 @@ def do_remove_roi(self, roi_name: str | None = None) -> None: def handle_export_tab_change(self, index: int) -> None: self.export_mode = ExportMode(index) self.view.on_visibility_change() + + def handle_tof_unit_change(self) -> None: + print("handle_tof_unit_change") + self.model.set_relevant_tof_units() + + + diff --git a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py index c3b84e7c792..486269f9c3e 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py +++ b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py @@ -279,9 +279,10 @@ def __init__(self) -> None: self.range_control.sigRegionChanged.connect(self._handle_tof_range_changed) self.ci.layout.setRowStretchFactor(0, 1) - def get_tof_range(self) -> tuple[int, int]: + def get_tof_range(self) -> tuple[float, float]: r_min, r_max = self.range_control.getRegion() - return int(r_min), int(r_max) + print(f"{(r_min, r_max)=}") + return r_min, r_max def _handle_tof_range_changed(self) -> None: tof_range = self.get_tof_range() @@ -295,8 +296,9 @@ def add_range(self, range_min: int, range_max: int) -> None: self.spectrum.addItem(self.range_control) self._set_tof_range_label(range_min, range_max) - def _set_tof_range_label(self, range_min: int, range_max: int) -> None: + def _set_tof_range_label(self, range_min: float, range_max: float) -> None: self._tof_range_label.setText(f'ToF range: {range_min} - {range_max}') + # Need to add the range of image numbers to the label class SpectrumProjectionWidget(GraphicsLayoutWidget): diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index 71b0b030c2b..1151499f18d 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -103,6 +103,7 @@ def __init__(self, main_window: MainWindowView): self.sampleStackSelector.select_eligible_stack() self.try_to_select_relevant_normalise_stack("Flat") + self.presenter.handle_tof_unit_change() self.exportButton.clicked.connect(self.presenter.handle_export_csv) self.exportButtonRITS.clicked.connect(self.presenter.handle_rits_export) @@ -401,12 +402,15 @@ def set_roi_alpha(self, alpha: float, roi_name: str) -> None: self.spectrum_widget.spectrum.update() self.show_visible_spectrums() - def show_visible_spectrums(self, mode: ToFUnitMode = ToFUnitMode.WAVELENGTH): - if mode == ToFUnitMode.WAVELENGTH: - tof_data = self.presenter.model.get_stack_time_of_flight_wavelength() + def show_visible_spectrums(self): for key, value in self.spectrum_widget.spectrum_data_dict.items(): if value is not None and key in self.spectrum_widget.roi_dict: - self.spectrum_widget.spectrum.plot(tof_data, value, name=key, pen=self.spectrum_widget.roi_dict[key].colour) + if self.presenter.model.tof_mode == ToFUnitMode.IMAGE_NUMBER: + self.spectrum_widget.spectrum.plot(value, name=key, pen=self.spectrum_widget.roi_dict[key].colour) + else: + self.spectrum_widget.spectrum.plot(self.presenter.model.tof_data, value, name=key, pen=self.spectrum_widget.roi_dict[key].colour) + + def add_roi_table_row(self, name: str, colour: tuple[int, int, int]): From e7abe569cc8d30b4e6c142ec88797a21446d8638 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Fri, 22 Mar 2024 16:27:07 +0000 Subject: [PATCH 03/12] Mostly working - switching to Image Number units needs fixing --- mantidimaging/core/utility/unit_conversion.py | 30 +++++++++++ .../gui/windows/spectrum_viewer/model.py | 53 +++++++------------ .../gui/windows/spectrum_viewer/presenter.py | 48 ++++++++++++++--- .../spectrum_viewer/spectrum_widget.py | 37 ++++++++++--- .../gui/windows/spectrum_viewer/view.py | 22 ++++++-- 5 files changed, 135 insertions(+), 55 deletions(-) create mode 100644 mantidimaging/core/utility/unit_conversion.py diff --git a/mantidimaging/core/utility/unit_conversion.py b/mantidimaging/core/utility/unit_conversion.py new file mode 100644 index 00000000000..909d2d29b87 --- /dev/null +++ b/mantidimaging/core/utility/unit_conversion.py @@ -0,0 +1,30 @@ +# Copyright (C) 2024 ISIS Rutherford Appleton Laboratory UKRI +# SPDX - License - Identifier: GPL-3.0-or-later +from __future__ import annotations + +import numpy as np +from typing import TYPE_CHECKING + + +class UnitConversion: + # target_to_camera_dist = 56 m taken from https://scripts.iucr.org/cgi-bin/paper?S1600576719001730 + neutron_mass = 1.674927211e-27 # [kg] + planck_h = 6.62606896e-34 # [JHz-1] + angstrom = 1e-10 # [m] + mega_electro_volt = 1.60217662e-19 / 1e6 + + def __init__(self, data_to_convert: np.ndarray, target_to_camera_dist: float = 56) -> None: + self.tof_data_to_convert = data_to_convert + self.target_to_camera_dist = target_to_camera_dist + self.velocity = self.target_to_camera_dist / self.tof_data_to_convert + + def tof_seconds_to_wavelength(self) -> np.ndarray: + wavelength = self.planck_h / (self.neutron_mass * self.velocity) + wavelength_angstroms = wavelength / self.angstrom + return wavelength_angstroms + + def tof_seconds_to_energy(self) -> np.ndarray: + energy = self.neutron_mass * self.velocity / 2 + energy_evs = energy / self.mega_electro_volt + return energy_evs + diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 66bacf7b73a..6987dd6a8d9 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -16,6 +16,7 @@ from mantidimaging.core.io.instrument_log import LogColumn from mantidimaging.core.utility.sensible_roi import SensibleROI from mantidimaging.core.utility.progress_reporting import Progress +from mantidimaging.core.utility.unit_conversion import UnitConversion if TYPE_CHECKING: from mantidimaging.gui.windows.spectrum_viewer.presenter import SpectrumViewerWindowPresenter @@ -64,7 +65,7 @@ class SpectrumViewerWindowModel: tof_range: tuple[int, int] = (0, 0) tof_plot_range: tuple[float, float] | tuple[int, int] = (0, 0) _roi_ranges: dict[str, SensibleROI] - tof_mode: ToFUnitMode = ToFUnitMode.WAVELENGTH + tof_mode: ToFUnitMode tof_data: np.ndarray | None = None tof_range_full: tuple[int, int] = (0, 0) @@ -74,6 +75,13 @@ def __init__(self, presenter: SpectrumViewerWindowPresenter): self._roi_ranges = {} self.special_roi_list = [ROI_ALL] + self.tof_data = self.get_stack_time_of_flight() + if self.tof_data is None: + self.tof_mode = ToFUnitMode.IMAGE_NUMBER + #self.presenter.view.units_menu.setEnabled(False) + else: + self.tof_mode = ToFUnitMode.WAVELENGTH + def roi_name_generator(self) -> str: """ Returns a new Unique ID for newly created ROIs @@ -106,6 +114,7 @@ def set_stack(self, stack: ImageStack | None) -> None: self._roi_id_counter = 0 self.tof_range = (0, stack.data.shape[0] - 1) self.tof_range_full = self.tof_range + self.tof_data = self.get_stack_time_of_flight() self.set_new_roi(ROI_ALL) def set_new_roi(self, name: str) -> None: @@ -140,6 +149,7 @@ def get_averaged_image(self) -> np.ndarray | None: or None if it does not """ if self._stack is not None: + print(f"{self.tof_range=}") tof_slice = slice(self.tof_range[0], self.tof_range[1] + 1) return self._stack.data[tof_slice].mean(axis=0) return None @@ -455,45 +465,18 @@ def remove_all_roi(self) -> None: """ self._roi_ranges = {} - def get_stack_time_of_flight_wavelength(self, target_to_camera_dist: float = 56) -> np.ndarray | None: - # target_to_camera_dist = 56 m taken from https://scripts.iucr.org/cgi-bin/paper?S1600576719001730 - tof = self.get_stack_time_of_flight() - print("tof", tof) - if tof is not None: - velocity = target_to_camera_dist / tof - planck_h = 6.62606896e-34 # [JHz-1] - neutron_mass = 1.674927211e-27 # [kg] - angstrom = 1e-10 #[m] - wavelength = planck_h / (neutron_mass * velocity) - wavelength_angstroms = wavelength / angstrom - return wavelength_angstroms - else: - return None - - def get_stack_time_of_flight_energy(self, target_to_camera_dist: float = 56) -> np.ndarray | None: - tof = self.get_stack_time_of_flight() - # target_to_camera_dist = 56 m taken from https://scripts.iucr.org/cgi-bin/paper?S1600576719001730 - if tof is not None: - velocity = target_to_camera_dist / tof - neutron_mass = 1.674927211e-27 # [kg] - energy = neutron_mass * velocity / 2 - mega_electro_volt = 1.60217662e-19 / 1e6 - energy_evs = energy / mega_electro_volt - return energy_evs - else: - return None - def set_relevant_tof_units(self) -> None: - print(f"{self.tof_mode=}") - if self.tof_mode == ToFUnitMode.IMAGE_NUMBER: + self.tof_data = self.get_stack_time_of_flight() + if self.tof_mode == ToFUnitMode.IMAGE_NUMBER or self.tof_data is None: self.tof_data = None self.tof_plot_range = (0, self._stack.data.shape[0] - 1) + self.tof_range = (0, self._stack.data.shape[0] - 1) else: + units = UnitConversion(self.tof_data) if self.tof_mode == ToFUnitMode.TOF_US: - self.tof_data = self.get_stack_time_of_flight() + self.tof_data = self.get_stack_time_of_flight() * 1e6 elif self.tof_mode == ToFUnitMode.WAVELENGTH: - self.tof_data = self.get_stack_time_of_flight_wavelength() - print(f"{self.tof_data=}") + self.tof_data = units.tof_seconds_to_wavelength() elif self.tof_mode == ToFUnitMode.ENERGY: - self.tof_data = self.get_stack_time_of_flight_energy() + self.tof_data = units.tof_seconds_to_energy() self.tof_plot_range = (self.tof_data.min(), self.tof_data.max()) diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index b05e34f3840..12652c89d22 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -13,7 +13,8 @@ from mantidimaging.core.data.dataset import StrictDataset from mantidimaging.gui.dialogs.async_task import start_async_task_view, TaskWorkerThread from mantidimaging.gui.mvp_base import BasePresenter -from mantidimaging.gui.windows.spectrum_viewer.model import SpectrumViewerWindowModel, SpecType, ROI_RITS, ErrorMode +from mantidimaging.gui.windows.spectrum_viewer.model import SpectrumViewerWindowModel, SpecType, ROI_RITS, ErrorMode, \ + ToFUnitMode if TYPE_CHECKING: from mantidimaging.gui.windows.spectrum_viewer.view import SpectrumViewerWindowView # pragma: no cover @@ -65,6 +66,12 @@ def handle_stack_changed(self) -> None: except RuntimeError: norm_stack = None self.model.set_normalise_stack(norm_stack) + print(f"handle_stack_changed: {self.model.tof_data}") + if self.model.tof_data is None: + self.view.tof_mode_select_group.setEnabled(False) + else: + self.view.tof_mode_select_group.setEnabled(True) + self.model.set_relevant_tof_units() self.show_new_sample() self.redraw_all_rois() @@ -87,6 +94,11 @@ def handle_sample_change(self, uuid: UUID | None) -> None: return self.model.set_stack(self.main_window.get_stack(uuid)) + print(f"handle_sample_changed: {self.model.tof_data}") + if self.model.tof_data is None: + self.view.tof_mode_select_group.setEnabled(False) + else: + self.view.tof_mode_select_group.setEnabled(True) self.model.set_relevant_tof_units() normalise_uuid = self.view.get_normalise_stack() if normalise_uuid is not None: @@ -140,15 +152,19 @@ def show_new_sample(self) -> None: assert averaged_image is not None self.view.set_image(averaged_image) self.view.spectrum_widget.spectrum_plot_widget.add_range(*self.model.tof_plot_range) + self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(*self.model.tof_range) self.view.auto_range_image() if self.view.get_roi_properties_spinboxes(): self.view.set_roi_properties() def handle_range_slide_moved(self, tof_range) -> None: - tof_range_min_rescaled = int(np.interp(tof_range[0], (self.model.tof_data.min(), self.model.tof_data.max()), (self.model.tof_range_full[0], self.model.tof_range_full[1]))) - tof_range_max_rescaled = int(np.interp(tof_range[1], (self.model.tof_data.min(), self.model.tof_data.max()), (self.model.tof_range_full[0], self.model.tof_range_full[1]))) - self.model.tof_range = (tof_range_min_rescaled, tof_range_max_rescaled) - print(f"{self.model.tof_range=}") + if self.model.tof_mode == ToFUnitMode.IMAGE_NUMBER: + self.model.tof_range = tof_range + else: + image_index_min = np.abs(self.model.tof_data - tof_range[0]).argmin() + image_index_max = np.abs(self.model.tof_data - tof_range[1]).argmin() + self.model.tof_range = (image_index_min, image_index_max) + self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(*self.model.tof_range) averaged_image = self.model.get_averaged_image() assert averaged_image is not None self.view.set_image(averaged_image, autoLevels=False) @@ -321,8 +337,26 @@ def handle_export_tab_change(self, index: int) -> None: self.view.on_visibility_change() def handle_tof_unit_change(self) -> None: - print("handle_tof_unit_change") + selected_mode = self.view.tof_mode_select_group.checkedAction().text() + print(f"{selected_mode=}") + self.model.tof_mode = self.view.allowed_modes[selected_mode] + print(f"{self.model.tof_mode=}") + print(f"1: {self.model.tof_data=}") self.model.set_relevant_tof_units() - + print(f"2: {self.model.tof_data=}") + tof_mode = self.model.tof_mode + if tof_mode == ToFUnitMode.IMAGE_NUMBER: + return + tof_axis_label = "" + if tof_mode == ToFUnitMode.TOF_US: + tof_axis_label = "Time of Flight (\u03BC s)" + if tof_mode == ToFUnitMode.WAVELENGTH: + tof_axis_label = "Neutron Wavelength (\u212B)" + if tof_mode == ToFUnitMode.ENERGY: + tof_axis_label = "Neutron Energy (MeV)" + self.view.spectrum_widget.spectrum_plot_widget.set_tof_axis_label(tof_axis_label) + self.view.spectrum_widget.spectrum.clearPlots() + self.view.spectrum_widget.spectrum.update() + self.view.show_visible_spectrums() diff --git a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py index 486269f9c3e..185c32d8bb3 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py +++ b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py @@ -6,8 +6,8 @@ from PyQt5.QtCore import pyqtSignal, Qt, QSignalBlocker from PyQt5.QtGui import QColor -from PyQt5.QtWidgets import QColorDialog, QAction, QMenu, QSplitter, QWidget, QVBoxLayout -from pyqtgraph import ROI, GraphicsLayoutWidget, LinearRegionItem, PlotItem, mkPen +from PyQt5.QtWidgets import QColorDialog, QAction, QMenu, QSplitter, QWidget, QVBoxLayout, QActionGroup +from pyqtgraph import ROI, GraphicsLayoutWidget, LinearRegionItem, PlotItem, mkPen, ViewBox from mantidimaging.core.utility.close_enough_point import CloseEnoughPoint from mantidimaging.core.utility.sensible_roi import SensibleROI @@ -121,7 +121,6 @@ def __init__(self) -> None: self.image = self.image_widget.image self.spectrum_plot_widget = SpectrumPlotWidget() self.spectrum = self.spectrum_plot_widget.spectrum - self.splitter = QSplitter(Qt.Vertical) self.splitter.addWidget(self.image_widget) self.splitter.addWidget(self.spectrum_plot_widget) @@ -272,17 +271,33 @@ class SpectrumPlotWidget(GraphicsLayoutWidget): def __init__(self) -> None: super().__init__() - self.spectrum = self.addPlot() + self.vb = ViewBox() + self.spectrum = self.addPlot(viewbox=self.vb) self.nextRow() self._tof_range_label = self.addLabel() + self.nextRow() + self._image_index_range_label = self.addLabel() self.range_control = LinearRegionItem() self.range_control.sigRegionChanged.connect(self._handle_tof_range_changed) self.ci.layout.setRowStretchFactor(0, 1) - def get_tof_range(self) -> tuple[float, float]: + """print(f"{self.spectrum.getMenu()=}") + self.spectrum_right_click_menu = self.spectrum.vb.menu + self.units_menu = self.spectrum_right_click_menu.addMenu("Units") + self.tof_mode_select_group = QActionGroup(self) + + allowed_modes = ["Image Index", "Wavelength", "Energy", "us"] + for mode in allowed_modes: + action = QAction(mode, self.tof_mode_select_group) + action.setCheckable(True) + self.units_menu.addAction(action) + action.triggered.connect(self.set_tof_unit_mode) + if mode == "Image Index": + action.setChecked(True)""" + + def get_tof_range(self) -> tuple[int, int]: r_min, r_max = self.range_control.getRegion() - print(f"{(r_min, r_max)=}") - return r_min, r_max + return int(r_min), int(r_max) def _handle_tof_range_changed(self) -> None: tof_range = self.get_tof_range() @@ -298,7 +313,13 @@ def add_range(self, range_min: int, range_max: int) -> None: def _set_tof_range_label(self, range_min: float, range_max: float) -> None: self._tof_range_label.setText(f'ToF range: {range_min} - {range_max}') - # Need to add the range of image numbers to the label + + def set_image_index_range_label(self, range_min: int, range_max: int) -> None: + self._image_index_range_label.setText(f'Image index range: {range_min} - {range_max}') + + def set_tof_axis_label(self, tof_axis_label: str) -> None: + self.spectrum.setLabel('bottom', text=tof_axis_label) + class SpectrumProjectionWidget(GraphicsLayoutWidget): diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index 1151499f18d..beec25f1527 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -7,7 +7,7 @@ from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QCheckBox, QVBoxLayout, QFileDialog, QPushButton, QLabel, QAbstractItemView, QHeaderView, \ - QTabWidget, QComboBox, QSpinBox, QTableWidget, QTableWidgetItem, QGroupBox + QTabWidget, QComboBox, QSpinBox, QTableWidget, QTableWidgetItem, QGroupBox, QActionGroup, QAction from PyQt5.QtCore import QSignalBlocker, Qt from mantidimaging.core.utility import finder @@ -81,6 +81,22 @@ def __init__(self, main_window: MainWindowView): self.spectrum_widget.roi_changed.connect(self.presenter.handle_roi_moved) self.spectrum_widget.roiColorChangeRequested.connect(self.presenter.change_roi_colour) + self.spectrum_right_click_menu = self.spectrum_widget.spectrum_plot_widget.spectrum.vb.menu + self.units_menu = self.spectrum_right_click_menu.addMenu("Units") + self.tof_mode_select_group = QActionGroup(self) + + self.allowed_modes = {"Image Index": ToFUnitMode.IMAGE_NUMBER, "Wavelength": ToFUnitMode.WAVELENGTH, + "Energy": ToFUnitMode.ENERGY, "us": ToFUnitMode.TOF_US} + for mode in self.allowed_modes.keys(): + action = QAction(mode, self.tof_mode_select_group) + action.setCheckable(True) + self.units_menu.addAction(action) + action.triggered.connect(self.presenter.handle_tof_unit_change) + if mode == "Image Index": + action.setChecked(True) + if self.presenter.model.tof_data is None: + self.tof_mode_select_group.setEnabled(False) + self._current_dataset_id = None self.sampleStackSelector.stack_selected_uuid.connect(self.presenter.handle_sample_change) self.sampleStackSelector.stack_selected_uuid.connect(self.presenter.handle_button_enabled) @@ -162,10 +178,6 @@ def __init__(self, main_window: MainWindowView): self.current_roi = self.last_clicked_roi = self.roi_table_model.roi_names()[0] self.set_roi_properties() - print(f"{self.presenter.model.get_stack_time_of_flight()=}") - print(f"{self.presenter.model.get_stack_time_of_flight_wavelength()=}") - print(f"{self.presenter.model.get_stack_time_of_flight_energy()=}") - def on_row_change(item, _) -> None: """ Handle cell change in table view and update selected ROI and From bb6f8466de50ecc6b3e4e7fbf97d3b6d203bb3b3 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Tue, 26 Mar 2024 12:53:19 +0000 Subject: [PATCH 04/12] full functionality --- mantidimaging/core/utility/unit_conversion.py | 10 +++--- .../gui/windows/spectrum_viewer/model.py | 3 +- .../gui/windows/spectrum_viewer/presenter.py | 17 ++++++---- .../spectrum_viewer/spectrum_widget.py | 31 +++++-------------- .../gui/windows/spectrum_viewer/view.py | 19 ++++++------ 5 files changed, 34 insertions(+), 46 deletions(-) diff --git a/mantidimaging/core/utility/unit_conversion.py b/mantidimaging/core/utility/unit_conversion.py index 909d2d29b87..7c657be7048 100644 --- a/mantidimaging/core/utility/unit_conversion.py +++ b/mantidimaging/core/utility/unit_conversion.py @@ -3,15 +3,14 @@ from __future__ import annotations import numpy as np -from typing import TYPE_CHECKING class UnitConversion: # target_to_camera_dist = 56 m taken from https://scripts.iucr.org/cgi-bin/paper?S1600576719001730 - neutron_mass = 1.674927211e-27 # [kg] - planck_h = 6.62606896e-34 # [JHz-1] - angstrom = 1e-10 # [m] - mega_electro_volt = 1.60217662e-19 / 1e6 + neutron_mass: float = 1.674927211e-27 # [kg] + planck_h: float = 6.62606896e-34 # [JHz-1] + angstrom: float = 1e-10 # [m] + mega_electro_volt: float = 1.60217662e-19 / 1e6 def __init__(self, data_to_convert: np.ndarray, target_to_camera_dist: float = 56) -> None: self.tof_data_to_convert = data_to_convert @@ -27,4 +26,3 @@ def tof_seconds_to_energy(self) -> np.ndarray: energy = self.neutron_mass * self.velocity / 2 energy_evs = energy / self.mega_electro_volt return energy_evs - diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 6987dd6a8d9..3ff9bcc31a6 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -197,7 +197,6 @@ def get_spectrum(self, roi: str | SensibleROI, mode: SpecType) -> np.ndarray: roi = self.get_roi(roi) if mode == SpecType.SAMPLE: - print(f"TOF Spectrum: {self.get_stack_spectrum(self._stack, roi)}, Length: {len(self.get_stack_spectrum(self._stack, roi))}") return self.get_stack_spectrum(self._stack, roi) if self._normalise_stack is None: @@ -468,9 +467,9 @@ def remove_all_roi(self) -> None: def set_relevant_tof_units(self) -> None: self.tof_data = self.get_stack_time_of_flight() if self.tof_mode == ToFUnitMode.IMAGE_NUMBER or self.tof_data is None: - self.tof_data = None self.tof_plot_range = (0, self._stack.data.shape[0] - 1) self.tof_range = (0, self._stack.data.shape[0] - 1) + self.tof_data = np.arange(self.tof_range[0], self.tof_range[1] + 1) else: units = UnitConversion(self.tof_data) if self.tof_mode == ToFUnitMode.TOF_US: diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 12652c89d22..77eaf60f9cf 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -158,13 +158,17 @@ def show_new_sample(self) -> None: self.view.set_roi_properties() def handle_range_slide_moved(self, tof_range) -> None: + print(f"handle_range_slide_moved: tof_range={tof_range}") + self.model.tof_plot_range = tof_range if self.model.tof_mode == ToFUnitMode.IMAGE_NUMBER: - self.model.tof_range = tof_range + self.model.tof_range = (int(tof_range[0]), int(tof_range[1])) else: image_index_min = np.abs(self.model.tof_data - tof_range[0]).argmin() image_index_max = np.abs(self.model.tof_data - tof_range[1]).argmin() - self.model.tof_range = (image_index_min, image_index_max) + print(f"{(image_index_min, image_index_max)=}") + self.model.tof_range = sorted((image_index_min, image_index_max)) self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(*self.model.tof_range) + self.view.spectrum_widget.spectrum_plot_widget.set_tof_range_label(*self.model.tof_plot_range) averaged_image = self.model.get_averaged_image() assert averaged_image is not None self.view.set_image(averaged_image, autoLevels=False) @@ -345,9 +349,9 @@ def handle_tof_unit_change(self) -> None: self.model.set_relevant_tof_units() print(f"2: {self.model.tof_data=}") tof_mode = self.model.tof_mode - if tof_mode == ToFUnitMode.IMAGE_NUMBER: - return tof_axis_label = "" + if tof_mode == ToFUnitMode.IMAGE_NUMBER: + tof_axis_label = "Image index" if tof_mode == ToFUnitMode.TOF_US: tof_axis_label = "Time of Flight (\u03BC s)" if tof_mode == ToFUnitMode.WAVELENGTH: @@ -358,5 +362,6 @@ def handle_tof_unit_change(self) -> None: self.view.spectrum_widget.spectrum.clearPlots() self.view.spectrum_widget.spectrum.update() self.view.show_visible_spectrums() - - + self.view.spectrum_widget.spectrum_plot_widget.add_range(*self.model.tof_plot_range) + self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(0, len(self.model.tof_data) - 1) + self.view.auto_range_image() diff --git a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py index 185c32d8bb3..a51fb13466b 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py +++ b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py @@ -6,7 +6,7 @@ from PyQt5.QtCore import pyqtSignal, Qt, QSignalBlocker from PyQt5.QtGui import QColor -from PyQt5.QtWidgets import QColorDialog, QAction, QMenu, QSplitter, QWidget, QVBoxLayout, QActionGroup +from PyQt5.QtWidgets import QColorDialog, QAction, QMenu, QSplitter, QWidget, QVBoxLayout from pyqtgraph import ROI, GraphicsLayoutWidget, LinearRegionItem, PlotItem, mkPen, ViewBox from mantidimaging.core.utility.close_enough_point import CloseEnoughPoint @@ -281,38 +281,24 @@ def __init__(self) -> None: self.range_control.sigRegionChanged.connect(self._handle_tof_range_changed) self.ci.layout.setRowStretchFactor(0, 1) - """print(f"{self.spectrum.getMenu()=}") - self.spectrum_right_click_menu = self.spectrum.vb.menu - self.units_menu = self.spectrum_right_click_menu.addMenu("Units") - self.tof_mode_select_group = QActionGroup(self) - - allowed_modes = ["Image Index", "Wavelength", "Energy", "us"] - for mode in allowed_modes: - action = QAction(mode, self.tof_mode_select_group) - action.setCheckable(True) - self.units_menu.addAction(action) - action.triggered.connect(self.set_tof_unit_mode) - if mode == "Image Index": - action.setChecked(True)""" - - def get_tof_range(self) -> tuple[int, int]: + def get_tof_range(self) -> tuple[float, float]: r_min, r_max = self.range_control.getRegion() - return int(r_min), int(r_max) + return r_min, r_max def _handle_tof_range_changed(self) -> None: tof_range = self.get_tof_range() - self._set_tof_range_label(tof_range[0], tof_range[1]) + self.set_tof_range_label(tof_range[0], tof_range[1]) self.range_changed.emit(tof_range) - def add_range(self, range_min: int, range_max: int) -> None: + def add_range(self, range_min: int | float, range_max: int | float) -> None: with QSignalBlocker(self.range_control): self.range_control.setBounds((range_min, range_max)) self.range_control.setRegion((range_min, range_max)) self.spectrum.addItem(self.range_control) - self._set_tof_range_label(range_min, range_max) + self.set_tof_range_label(range_min, range_max) - def _set_tof_range_label(self, range_min: float, range_max: float) -> None: - self._tof_range_label.setText(f'ToF range: {range_min} - {range_max}') + def set_tof_range_label(self, range_min: float, range_max: float) -> None: + self._tof_range_label.setText(f'ToF range: {round(range_min, 3)} - {round(range_max, 3)}') def set_image_index_range_label(self, range_min: int, range_max: int) -> None: self._image_index_range_label.setText(f'Image index range: {range_min} - {range_max}') @@ -321,7 +307,6 @@ def set_tof_axis_label(self, tof_axis_label: str) -> None: self.spectrum.setLabel('bottom', text=tof_axis_label) - class SpectrumProjectionWidget(GraphicsLayoutWidget): image: MIMiniImageView diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index beec25f1527..20687fe1535 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -85,8 +85,12 @@ def __init__(self, main_window: MainWindowView): self.units_menu = self.spectrum_right_click_menu.addMenu("Units") self.tof_mode_select_group = QActionGroup(self) - self.allowed_modes = {"Image Index": ToFUnitMode.IMAGE_NUMBER, "Wavelength": ToFUnitMode.WAVELENGTH, - "Energy": ToFUnitMode.ENERGY, "us": ToFUnitMode.TOF_US} + self.allowed_modes = { + "Image Index": ToFUnitMode.IMAGE_NUMBER, + "Wavelength": ToFUnitMode.WAVELENGTH, + "Energy": ToFUnitMode.ENERGY, + "us": ToFUnitMode.TOF_US + } for mode in self.allowed_modes.keys(): action = QAction(mode, self.tof_mode_select_group) action.setCheckable(True) @@ -417,13 +421,10 @@ def set_roi_alpha(self, alpha: float, roi_name: str) -> None: def show_visible_spectrums(self): for key, value in self.spectrum_widget.spectrum_data_dict.items(): if value is not None and key in self.spectrum_widget.roi_dict: - if self.presenter.model.tof_mode == ToFUnitMode.IMAGE_NUMBER: - self.spectrum_widget.spectrum.plot(value, name=key, pen=self.spectrum_widget.roi_dict[key].colour) - else: - self.spectrum_widget.spectrum.plot(self.presenter.model.tof_data, value, name=key, pen=self.spectrum_widget.roi_dict[key].colour) - - - + self.spectrum_widget.spectrum.plot(self.presenter.model.tof_data, + value, + name=key, + pen=self.spectrum_widget.roi_dict[key].colour) def add_roi_table_row(self, name: str, colour: tuple[int, int, int]): """ From ac71a368519d71c2a160dba20ba3039fed9ec94d Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Tue, 26 Mar 2024 16:22:56 +0000 Subject: [PATCH 05/12] fixed issue with switching to stack with no spectra file --- .../gui/windows/spectrum_viewer/model.py | 29 ++++++++++--------- .../gui/windows/spectrum_viewer/presenter.py | 16 ++++++++++ .../gui/windows/spectrum_viewer/view.py | 4 +++ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 3ff9bcc31a6..3bbdb68ddfd 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -465,17 +465,18 @@ def remove_all_roi(self) -> None: self._roi_ranges = {} def set_relevant_tof_units(self) -> None: - self.tof_data = self.get_stack_time_of_flight() - if self.tof_mode == ToFUnitMode.IMAGE_NUMBER or self.tof_data is None: - self.tof_plot_range = (0, self._stack.data.shape[0] - 1) - self.tof_range = (0, self._stack.data.shape[0] - 1) - self.tof_data = np.arange(self.tof_range[0], self.tof_range[1] + 1) - else: - units = UnitConversion(self.tof_data) - if self.tof_mode == ToFUnitMode.TOF_US: - self.tof_data = self.get_stack_time_of_flight() * 1e6 - elif self.tof_mode == ToFUnitMode.WAVELENGTH: - self.tof_data = units.tof_seconds_to_wavelength() - elif self.tof_mode == ToFUnitMode.ENERGY: - self.tof_data = units.tof_seconds_to_energy() - self.tof_plot_range = (self.tof_data.min(), self.tof_data.max()) + if self._stack is not None: + self.tof_data = self.get_stack_time_of_flight() + if self.tof_mode == ToFUnitMode.IMAGE_NUMBER: + self.tof_plot_range = (0, self._stack.data.shape[0] - 1) + self.tof_range = (0, self._stack.data.shape[0] - 1) + self.tof_data = np.arange(self.tof_range[0], self.tof_range[1] + 1) + else: + units = UnitConversion(self.tof_data) + if self.tof_mode == ToFUnitMode.TOF_US: + self.tof_data = self.get_stack_time_of_flight() * 1e6 + elif self.tof_mode == ToFUnitMode.WAVELENGTH: + self.tof_data = units.tof_seconds_to_wavelength() + elif self.tof_mode == ToFUnitMode.ENERGY: + self.tof_data = units.tof_seconds_to_energy() + self.tof_plot_range = (self.tof_data.min(), self.tof_data.max()) diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 77eaf60f9cf..5fa0270411c 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -9,6 +9,7 @@ from logging import getLogger import numpy as np +from PyQt5.QtCore import QSignalBlocker from mantidimaging.core.data.dataset import StrictDataset from mantidimaging.gui.dialogs.async_task import start_async_task_view, TaskWorkerThread @@ -71,6 +72,13 @@ def handle_stack_changed(self) -> None: self.view.tof_mode_select_group.setEnabled(False) else: self.view.tof_mode_select_group.setEnabled(True) + self.model.tof_mode = ToFUnitMode.IMAGE_NUMBER + for action in self.view.tof_mode_select_group.actions(): + with QSignalBlocker(action): + if action.objectName() == 'Image Index': + action.setChecked(True) + else: + action.setChecked(False) self.model.set_relevant_tof_units() self.show_new_sample() self.redraw_all_rois() @@ -91,6 +99,7 @@ def handle_sample_change(self, uuid: UUID | None) -> None: if uuid is None: self.model.set_stack(None) self.view.clear() + self.view.tof_mode_select_group.setEnabled(False) return self.model.set_stack(self.main_window.get_stack(uuid)) @@ -99,6 +108,13 @@ def handle_sample_change(self, uuid: UUID | None) -> None: self.view.tof_mode_select_group.setEnabled(False) else: self.view.tof_mode_select_group.setEnabled(True) + self.model.tof_mode = ToFUnitMode.IMAGE_NUMBER + for action in self.view.tof_mode_select_group.actions(): + with QSignalBlocker(action): + if action.objectName() == 'Image Index': + action.setChecked(True) + else: + action.setChecked(False) self.model.set_relevant_tof_units() normalise_uuid = self.view.get_normalise_stack() if normalise_uuid is not None: diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index 20687fe1535..32eba1a662d 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -94,6 +94,7 @@ def __init__(self, main_window: MainWindowView): for mode in self.allowed_modes.keys(): action = QAction(mode, self.tof_mode_select_group) action.setCheckable(True) + action.setObjectName(mode) self.units_menu.addAction(action) action.triggered.connect(self.presenter.handle_tof_unit_change) if mode == "Image Index": @@ -101,6 +102,9 @@ def __init__(self, main_window: MainWindowView): if self.presenter.model.tof_data is None: self.tof_mode_select_group.setEnabled(False) + print(f"{self.tof_mode_select_group.actions()=}") + print(f"{self.tof_mode_select_group.actions()[0].objectName()=}") + self._current_dataset_id = None self.sampleStackSelector.stack_selected_uuid.connect(self.presenter.handle_sample_change) self.sampleStackSelector.stack_selected_uuid.connect(self.presenter.handle_button_enabled) From d91e5309c0ed13c6088e06dd785bc04430cfabfe Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Tue, 26 Mar 2024 16:57:39 +0000 Subject: [PATCH 06/12] fixed new mypy errors --- mantidimaging/gui/windows/spectrum_viewer/model.py | 5 +++-- mantidimaging/gui/windows/spectrum_viewer/presenter.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 3bbdb68ddfd..ba4f61afca5 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -467,16 +467,17 @@ def remove_all_roi(self) -> None: def set_relevant_tof_units(self) -> None: if self._stack is not None: self.tof_data = self.get_stack_time_of_flight() - if self.tof_mode == ToFUnitMode.IMAGE_NUMBER: + if self.tof_mode == ToFUnitMode.IMAGE_NUMBER or self.tof_data is None: self.tof_plot_range = (0, self._stack.data.shape[0] - 1) self.tof_range = (0, self._stack.data.shape[0] - 1) self.tof_data = np.arange(self.tof_range[0], self.tof_range[1] + 1) else: units = UnitConversion(self.tof_data) if self.tof_mode == ToFUnitMode.TOF_US: - self.tof_data = self.get_stack_time_of_flight() * 1e6 + self.tof_data = self.tof_data * 1e6 elif self.tof_mode == ToFUnitMode.WAVELENGTH: self.tof_data = units.tof_seconds_to_wavelength() elif self.tof_mode == ToFUnitMode.ENERGY: self.tof_data = units.tof_seconds_to_energy() self.tof_plot_range = (self.tof_data.min(), self.tof_data.max()) + self.tof_range = (0, self.tof_data.size) diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 5fa0270411c..c80bceb1ac9 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -182,7 +182,7 @@ def handle_range_slide_moved(self, tof_range) -> None: image_index_min = np.abs(self.model.tof_data - tof_range[0]).argmin() image_index_max = np.abs(self.model.tof_data - tof_range[1]).argmin() print(f"{(image_index_min, image_index_max)=}") - self.model.tof_range = sorted((image_index_min, image_index_max)) + self.model.tof_range = tuple(sorted((image_index_min, image_index_max))) self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(*self.model.tof_range) self.view.spectrum_widget.spectrum_plot_widget.set_tof_range_label(*self.model.tof_plot_range) averaged_image = self.model.get_averaged_image() @@ -379,5 +379,5 @@ def handle_tof_unit_change(self) -> None: self.view.spectrum_widget.spectrum.update() self.view.show_visible_spectrums() self.view.spectrum_widget.spectrum_plot_widget.add_range(*self.model.tof_plot_range) - self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(0, len(self.model.tof_data) - 1) + self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(*self.model.tof_range) self.view.auto_range_image() From dcaa1bf7a6405019bb99f6741826d8e8f7edaed3 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Tue, 26 Mar 2024 17:38:12 +0000 Subject: [PATCH 07/12] SV and presenter tests fixes --- .../gui/windows/spectrum_viewer/test/presenter_test.py | 5 +++-- .../gui/windows/spectrum_viewer/test/spectrum_test.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py b/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py index b5e501a38d2..72f821dafe2 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py +++ b/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py @@ -6,7 +6,7 @@ from pathlib import Path from unittest import mock -from PyQt5.QtWidgets import QPushButton +from PyQt5.QtWidgets import QPushButton, QActionGroup from parameterized import parameterized from mantidimaging.core.data.dataset import StrictDataset, MixedDataset @@ -34,6 +34,7 @@ def setUp(self) -> None: self.view.exportButton = mock.create_autospec(QPushButton) self.view.exportButtonRITS = mock.create_autospec(QPushButton) self.view.addBtn = mock.create_autospec(QPushButton) + self.view.tof_mode_select_group = mock.create_autospec(QActionGroup) self.presenter = SpectrumViewerWindowPresenter(self.view, self.main_window) def test_get_dataset_id_for_stack_no_stack_id(self): @@ -158,7 +159,7 @@ def test_WHEN_has_stack_has_bad_norm_THEN_buttons_set(self, normalise_issue, has def test_WHEN_show_sample_call_THEN_add_range_set(self): self.presenter.model.set_stack(generate_images([10, 5, 5])) - self.presenter.model.tof_range = (0, 9) + self.presenter.model.tof_plot_range = (0, 9) self.presenter.show_new_sample() self.view.spectrum_widget.spectrum_plot_widget.add_range.assert_called_once_with(0, 9) diff --git a/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py b/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py index 3a103fa5fab..4724faa7438 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py +++ b/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py @@ -136,7 +136,7 @@ def test_WHEN_remove_roi_called_THEN_roi_removed_from_roi_dict(self): self.assertNotIn(spectrum_roi, self.spectrum_widget.image.vb.addedItems) def test_WHEN_set_tof_range_called_THEN_range_control_set_correctly(self): - self.spectrum_plot_widget._set_tof_range_label(0, 100) + self.spectrum_plot_widget.set_tof_range_label(0, 100) self.assertEqual(self.spectrum_plot_widget._tof_range_label.text, "ToF range: 0 - 100") def test_WHEN_rename_roi_called_THEN_roi_renamed(self): From 838b18d5d9b8533b5b36847b3d2cada5b1ef489d Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Wed, 27 Mar 2024 09:17:47 +0000 Subject: [PATCH 08/12] prints removed and minor refactoring --- .../gui/windows/spectrum_viewer/model.py | 1 - .../gui/windows/spectrum_viewer/presenter.py | 45 +++++++------------ .../gui/windows/spectrum_viewer/view.py | 3 -- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index ba4f61afca5..24ef162f05a 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -149,7 +149,6 @@ def get_averaged_image(self) -> np.ndarray | None: or None if it does not """ if self._stack is not None: - print(f"{self.tof_range=}") tof_slice = slice(self.tof_range[0], self.tof_range[1] + 1) return self._stack.data[tof_slice].mean(axis=0) return None diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index c80bceb1ac9..2e6fbff926b 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -67,18 +67,7 @@ def handle_stack_changed(self) -> None: except RuntimeError: norm_stack = None self.model.set_normalise_stack(norm_stack) - print(f"handle_stack_changed: {self.model.tof_data}") - if self.model.tof_data is None: - self.view.tof_mode_select_group.setEnabled(False) - else: - self.view.tof_mode_select_group.setEnabled(True) - self.model.tof_mode = ToFUnitMode.IMAGE_NUMBER - for action in self.view.tof_mode_select_group.actions(): - with QSignalBlocker(action): - if action.objectName() == 'Image Index': - action.setChecked(True) - else: - action.setChecked(False) + self.reset_units_menu() self.model.set_relevant_tof_units() self.show_new_sample() self.redraw_all_rois() @@ -103,18 +92,7 @@ def handle_sample_change(self, uuid: UUID | None) -> None: return self.model.set_stack(self.main_window.get_stack(uuid)) - print(f"handle_sample_changed: {self.model.tof_data}") - if self.model.tof_data is None: - self.view.tof_mode_select_group.setEnabled(False) - else: - self.view.tof_mode_select_group.setEnabled(True) - self.model.tof_mode = ToFUnitMode.IMAGE_NUMBER - for action in self.view.tof_mode_select_group.actions(): - with QSignalBlocker(action): - if action.objectName() == 'Image Index': - action.setChecked(True) - else: - action.setChecked(False) + self.reset_units_menu() self.model.set_relevant_tof_units() normalise_uuid = self.view.get_normalise_stack() if normalise_uuid is not None: @@ -130,6 +108,19 @@ def handle_sample_change(self, uuid: UUID | None) -> None: self.show_new_sample() self.view.on_visibility_change() + def reset_units_menu(self): + if self.model.tof_data is None: + self.view.tof_mode_select_group.setEnabled(False) + else: + self.view.tof_mode_select_group.setEnabled(True) + self.model.tof_mode = ToFUnitMode.IMAGE_NUMBER + for action in self.view.tof_mode_select_group.actions(): + with QSignalBlocker(action): + if action.objectName() == 'Image Index': + action.setChecked(True) + else: + action.setChecked(False) + def handle_normalise_stack_change(self, normalise_uuid: UUID | None) -> None: if normalise_uuid == self.current_norm_stack_uuid: return @@ -174,14 +165,12 @@ def show_new_sample(self) -> None: self.view.set_roi_properties() def handle_range_slide_moved(self, tof_range) -> None: - print(f"handle_range_slide_moved: tof_range={tof_range}") self.model.tof_plot_range = tof_range if self.model.tof_mode == ToFUnitMode.IMAGE_NUMBER: self.model.tof_range = (int(tof_range[0]), int(tof_range[1])) else: image_index_min = np.abs(self.model.tof_data - tof_range[0]).argmin() image_index_max = np.abs(self.model.tof_data - tof_range[1]).argmin() - print(f"{(image_index_min, image_index_max)=}") self.model.tof_range = tuple(sorted((image_index_min, image_index_max))) self.view.spectrum_widget.spectrum_plot_widget.set_image_index_range_label(*self.model.tof_range) self.view.spectrum_widget.spectrum_plot_widget.set_tof_range_label(*self.model.tof_plot_range) @@ -358,12 +347,8 @@ def handle_export_tab_change(self, index: int) -> None: def handle_tof_unit_change(self) -> None: selected_mode = self.view.tof_mode_select_group.checkedAction().text() - print(f"{selected_mode=}") self.model.tof_mode = self.view.allowed_modes[selected_mode] - print(f"{self.model.tof_mode=}") - print(f"1: {self.model.tof_data=}") self.model.set_relevant_tof_units() - print(f"2: {self.model.tof_data=}") tof_mode = self.model.tof_mode tof_axis_label = "" if tof_mode == ToFUnitMode.IMAGE_NUMBER: diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index 32eba1a662d..7dc22763708 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -102,9 +102,6 @@ def __init__(self, main_window: MainWindowView): if self.presenter.model.tof_data is None: self.tof_mode_select_group.setEnabled(False) - print(f"{self.tof_mode_select_group.actions()=}") - print(f"{self.tof_mode_select_group.actions()[0].objectName()=}") - self._current_dataset_id = None self.sampleStackSelector.stack_selected_uuid.connect(self.presenter.handle_sample_change) self.sampleStackSelector.stack_selected_uuid.connect(self.presenter.handle_button_enabled) From 28def4b7c06345e6dc43978346d9f7edd0d98475 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Wed, 27 Mar 2024 09:22:16 +0000 Subject: [PATCH 09/12] release note --- docs/release_notes/next/feature-2151-spectrum-viewer-ToF-units | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/release_notes/next/feature-2151-spectrum-viewer-ToF-units diff --git a/docs/release_notes/next/feature-2151-spectrum-viewer-ToF-units b/docs/release_notes/next/feature-2151-spectrum-viewer-ToF-units new file mode 100644 index 00000000000..d4045f15bbb --- /dev/null +++ b/docs/release_notes/next/feature-2151-spectrum-viewer-ToF-units @@ -0,0 +1 @@ +#2151: Neutron wavelength, energy and tof units can be selected in the Spectrum Viewer \ No newline at end of file From a26b5773aec9bf9ebe678fac13efbe6a9d426cfd Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Mon, 8 Apr 2024 13:54:29 +0100 Subject: [PATCH 10/12] requested changes made --- .../gui/windows/spectrum_viewer/model.py | 1 - .../gui/windows/spectrum_viewer/presenter.py | 15 ++-------- .../spectrum_viewer/spectrum_widget.py | 2 +- .../gui/windows/spectrum_viewer/view.py | 29 +++++++++++++++---- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 24ef162f05a..3498286b22b 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -78,7 +78,6 @@ def __init__(self, presenter: SpectrumViewerWindowPresenter): self.tof_data = self.get_stack_time_of_flight() if self.tof_data is None: self.tof_mode = ToFUnitMode.IMAGE_NUMBER - #self.presenter.view.units_menu.setEnabled(False) else: self.tof_mode = ToFUnitMode.WAVELENGTH diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 2e6fbff926b..088f49dbc13 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -347,19 +347,10 @@ def handle_export_tab_change(self, index: int) -> None: def handle_tof_unit_change(self) -> None: selected_mode = self.view.tof_mode_select_group.checkedAction().text() - self.model.tof_mode = self.view.allowed_modes[selected_mode] + self.model.tof_mode = self.view.allowed_modes[selected_mode]["mode"] self.model.set_relevant_tof_units() - tof_mode = self.model.tof_mode - tof_axis_label = "" - if tof_mode == ToFUnitMode.IMAGE_NUMBER: - tof_axis_label = "Image index" - if tof_mode == ToFUnitMode.TOF_US: - tof_axis_label = "Time of Flight (\u03BC s)" - if tof_mode == ToFUnitMode.WAVELENGTH: - tof_axis_label = "Neutron Wavelength (\u212B)" - if tof_mode == ToFUnitMode.ENERGY: - tof_axis_label = "Neutron Energy (MeV)" - self.view.spectrum_widget.spectrum_plot_widget.set_tof_axis_label(tof_axis_label) + self.view.spectrum_widget.spectrum_plot_widget.set_tof_axis_label( + self.view.allowed_modes[selected_mode]["label"]) self.view.spectrum_widget.spectrum.clearPlots() self.view.spectrum_widget.spectrum.update() self.view.show_visible_spectrums() diff --git a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py index a51fb13466b..6338af2d0a9 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py +++ b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py @@ -298,7 +298,7 @@ def add_range(self, range_min: int | float, range_max: int | float) -> None: self.set_tof_range_label(range_min, range_max) def set_tof_range_label(self, range_min: float, range_max: float) -> None: - self._tof_range_label.setText(f'ToF range: {round(range_min, 3)} - {round(range_max, 3)}') + self._tof_range_label.setText(f'ToF range: {range_min:.3f} - {range_max:.3f}') def set_image_index_range_label(self, range_min: int, range_max: int) -> None: self._image_index_range_label.setText(f'Image index range: {range_min} - {range_max}') diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index 7dc22763708..329fc8a2d58 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -3,7 +3,7 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypedDict from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QCheckBox, QVBoxLayout, QFileDialog, QPushButton, QLabel, QAbstractItemView, QHeaderView, \ @@ -27,6 +27,11 @@ from uuid import UUID +class AllowedModesTypedDict(TypedDict): + mode: ToFUnitMode + label: str + + class SpectrumViewerWindowView(BaseMainWindowView): tableView: RemovableRowTableView sampleStackSelector: DatasetSelectorWidgetView @@ -85,11 +90,23 @@ def __init__(self, main_window: MainWindowView): self.units_menu = self.spectrum_right_click_menu.addMenu("Units") self.tof_mode_select_group = QActionGroup(self) - self.allowed_modes = { - "Image Index": ToFUnitMode.IMAGE_NUMBER, - "Wavelength": ToFUnitMode.WAVELENGTH, - "Energy": ToFUnitMode.ENERGY, - "us": ToFUnitMode.TOF_US + self.allowed_modes: dict[str, AllowedModesTypedDict] = { + "Image Index": { + "mode": ToFUnitMode.IMAGE_NUMBER, + "label": "Image index" + }, + "Wavelength": { + "mode": ToFUnitMode.WAVELENGTH, + "label": "Neutron Wavelength (\u212B)" + }, + "Energy": { + "mode": ToFUnitMode.ENERGY, + "label": "Neutron Energy (MeV)" + }, + "Time of Flight (\u03BCs)": { + "mode": ToFUnitMode.TOF_US, + "label": "Time of Flight (\u03BCs)" + } } for mode in self.allowed_modes.keys(): action = QAction(mode, self.tof_mode_select_group) From 84e9a4c2280edaed612b8236b2b8e68a354372d0 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Mon, 8 Apr 2024 13:55:35 +0100 Subject: [PATCH 11/12] Spectrum test fixes --- .../gui/windows/spectrum_viewer/test/spectrum_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py b/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py index 4724faa7438..20ff64f7d12 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py +++ b/mantidimaging/gui/windows/spectrum_viewer/test/spectrum_test.py @@ -104,7 +104,8 @@ def test_WHEN_set_roi_alpha_called_THEN_set_roi_visibility_flags_called(self, _, def test_WHEN_add_range_called_THEN_region_and_label_set_correctly(self, _, range_min, range_max): self.spectrum_plot_widget.add_range(range_min, range_max) self.assertEqual(self.spectrum_plot_widget.range_control.getRegion(), (range_min, range_max)) - self.assertEqual(self.spectrum_plot_widget._tof_range_label.text, f"ToF range: {range_min} - {range_max}") + self.assertEqual(self.spectrum_plot_widget._tof_range_label.text, + f"ToF range: {range_min:.3f} - {range_max:.3f}") def test_WHEN_get_roi_called_THEN_SensibleROI_returned(self): spectrum_roi = SpectrumROI("roi", @@ -137,7 +138,7 @@ def test_WHEN_remove_roi_called_THEN_roi_removed_from_roi_dict(self): def test_WHEN_set_tof_range_called_THEN_range_control_set_correctly(self): self.spectrum_plot_widget.set_tof_range_label(0, 100) - self.assertEqual(self.spectrum_plot_widget._tof_range_label.text, "ToF range: 0 - 100") + self.assertEqual(self.spectrum_plot_widget._tof_range_label.text, "ToF range: 0.000 - 100.000") def test_WHEN_rename_roi_called_THEN_roi_renamed(self): spectrum_roi = SpectrumROI("roi_1", From 4eb97a0d4e3a2bbf0533b171bfb7e8c1fb78e496 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Tue, 9 Apr 2024 17:03:59 +0100 Subject: [PATCH 12/12] fixed issue with spectrum label not resetting on stack change --- .../gui/windows/spectrum_viewer/presenter.py | 12 ++++++------ .../windows/spectrum_viewer/test/presenter_test.py | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 088f49dbc13..fc7bf405d67 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -68,7 +68,7 @@ def handle_stack_changed(self) -> None: norm_stack = None self.model.set_normalise_stack(norm_stack) self.reset_units_menu() - self.model.set_relevant_tof_units() + self.handle_tof_unit_change() self.show_new_sample() self.redraw_all_rois() @@ -93,7 +93,7 @@ def handle_sample_change(self, uuid: UUID | None) -> None: self.model.set_stack(self.main_window.get_stack(uuid)) self.reset_units_menu() - self.model.set_relevant_tof_units() + self.handle_tof_unit_change() normalise_uuid = self.view.get_normalise_stack() if normalise_uuid is not None: try: @@ -109,10 +109,6 @@ def handle_sample_change(self, uuid: UUID | None) -> None: self.view.on_visibility_change() def reset_units_menu(self): - if self.model.tof_data is None: - self.view.tof_mode_select_group.setEnabled(False) - else: - self.view.tof_mode_select_group.setEnabled(True) self.model.tof_mode = ToFUnitMode.IMAGE_NUMBER for action in self.view.tof_mode_select_group.actions(): with QSignalBlocker(action): @@ -120,6 +116,10 @@ def reset_units_menu(self): action.setChecked(True) else: action.setChecked(False) + if self.model.tof_data is None: + self.view.tof_mode_select_group.setEnabled(False) + else: + self.view.tof_mode_select_group.setEnabled(True) def handle_normalise_stack_change(self, normalise_uuid: UUID | None) -> None: if normalise_uuid == self.current_norm_stack_uuid: diff --git a/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py b/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py index 72f821dafe2..970c279c69a 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py +++ b/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py @@ -35,6 +35,7 @@ def setUp(self) -> None: self.view.exportButtonRITS = mock.create_autospec(QPushButton) self.view.addBtn = mock.create_autospec(QPushButton) self.view.tof_mode_select_group = mock.create_autospec(QActionGroup) + self.view.allowed_modes = mock.create_autospec(dict) self.presenter = SpectrumViewerWindowPresenter(self.view, self.main_window) def test_get_dataset_id_for_stack_no_stack_id(self): @@ -54,6 +55,7 @@ def test_handle_sample_change_has_flat_before(self): self.presenter.main_window.get_stack = mock.Mock(return_value=generate_images()) self.presenter.show_new_sample = mock.Mock() self.view.try_to_select_relevant_normalise_stack = mock.Mock() + self.presenter.handle_tof_unit_change = mock.Mock() self.presenter.handle_sample_change(uuid.uuid4()) self.view.try_to_select_relevant_normalise_stack.assert_called_once_with('Flat_before') @@ -68,6 +70,7 @@ def test_handle_sample_change_has_flat_after(self): self.presenter.show_new_sample = mock.Mock() self.view.try_to_select_relevant_normalise_stack = mock.Mock() + self.presenter.handle_tof_unit_change = mock.Mock() self.presenter.handle_sample_change(uuid.uuid4()) self.view.try_to_select_relevant_normalise_stack.assert_called_once_with('Flat_after') self.presenter.show_new_sample.assert_called_once() @@ -89,6 +92,7 @@ def test_handle_sample_change_dataset_unchanged(self): self.presenter.main_window.get_dataset = mock.Mock() self.presenter.main_window.get_stack = mock.Mock(return_value=generate_images()) self.presenter.show_new_sample = mock.Mock() + self.presenter.handle_tof_unit_change = mock.Mock() self.presenter.handle_sample_change(uuid.uuid4()) self.presenter.main_window.get_dataset.assert_not_called() @@ -101,6 +105,7 @@ def test_handle_sample_change_to_MixedDataset(self): self.presenter.main_window.get_stack = mock.Mock(return_value=generate_images()) self.presenter.show_new_sample = mock.Mock() self.view.try_to_select_relevant_normalise_stack = mock.Mock() + self.presenter.handle_tof_unit_change = mock.Mock() self.presenter.handle_sample_change(uuid.uuid4()) self.presenter.main_window.get_dataset.assert_called_once() @@ -113,6 +118,7 @@ def test_handle_sample_change_no_flat(self): self.presenter.main_window.get_stack = mock.Mock(return_value=generate_images()) self.presenter.show_new_sample = mock.Mock() self.view.try_to_select_relevant_normalise_stack = mock.Mock() + self.presenter.handle_tof_unit_change = mock.Mock() self.presenter.handle_sample_change(uuid.uuid4()) self.presenter.main_window.get_dataset.assert_called_once()