From f1c6fd72bf2b61b4ad7db3783e66e8120acf8e18 Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Tue, 24 Oct 2023 17:18:59 +0100 Subject: [PATCH 1/8] Spectrum viewer: change default_roi_list to special_roi_list --- .../gui/windows/spectrum_viewer/model.py | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 26852b30d24..2d224d259e3 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -20,6 +20,8 @@ LOG = getLogger(__name__) +ROI_ALL = "all" + class SpecType(Enum): SAMPLE = 1 @@ -44,7 +46,7 @@ def __init__(self, presenter: 'SpectrumViewerWindowPresenter'): self.presenter = presenter self._roi_id_counter = 0 self._roi_ranges = {} - self.default_roi_list = ["all"] + self.special_roi_list = [ROI_ALL] def roi_name_generator(self) -> str: """ @@ -77,7 +79,7 @@ def set_stack(self, stack: Optional[ImageStack]) -> None: return self._roi_id_counter = 0 self.tof_range = (0, stack.data.shape[0] - 1) - self.set_new_roi(self.default_roi_list[0]) + self.set_new_roi(ROI_ALL) def set_new_roi(self, name: str) -> None: """ @@ -198,9 +200,6 @@ def save_rits(self, path: Path, normalized: bool) -> None: if self._stack is None: raise ValueError("No stack selected") - # Default_roi will likely need updating once UI is implemented - default_roi = self.default_roi_list[0] - tof = self.get_stack_time_of_flight() if tof is None: raise ValueError("No Time of Flights for sample. Make sure spectra log has been loaded") @@ -212,7 +211,7 @@ def save_rits(self, path: Path, normalized: bool) -> None: if normalized: if self._normalise_stack is None: raise RuntimeError("No normalisation stack selected") - transmission = self.get_spectrum(default_roi, SpecType.SAMPLE_NORMED) + transmission = self.get_spectrum(ROI_ALL, SpecType.SAMPLE_NORMED) self.export_spectrum_to_rits(path, tof, transmission, transmission_error) else: LOG.error("Data is not normalised to open beam. This will not export to a valid RITS format") @@ -266,8 +265,8 @@ def remove_roi(self, roi_name) -> None: @param roi_name: The name of the ROI to remove """ if roi_name in self._roi_ranges.keys(): - if roi_name in self.default_roi_list: - raise RuntimeError("Cannot remove the 'all' or 'roi' ROIs") + if roi_name in self.special_roi_list: + raise RuntimeError(f"Cannot remove ROI: {roi_name}") del self._roi_ranges[roi_name] else: raise KeyError( @@ -283,8 +282,8 @@ def rename_roi(self, old_name: str, new_name: str) -> None: @raises RuntimeError: If the ROI is 'all' """ if old_name in self._roi_ranges.keys() and new_name not in self._roi_ranges.keys(): - if old_name == self.default_roi_list[0]: - raise RuntimeError("Cannot rename the 'all' ROI") + if old_name in self.special_roi_list: + raise RuntimeError(f"Cannot remove ROI: {old_name}") self._roi_ranges[new_name] = self._roi_ranges.pop(old_name) else: raise KeyError(f"Cannot rename {old_name} to {new_name} Available:{self._roi_ranges.keys()}") @@ -293,4 +292,4 @@ def remove_all_roi(self) -> None: """ Remove all ROIs from the model excluding default ROI 'all' """ - self._roi_ranges = {key: value for key, value in self._roi_ranges.items() if key in self.default_roi_list} + self._roi_ranges = {key: value for key, value in self._roi_ranges.items() if key in self.special_roi_list} From 95bca2751f7f665fd0236450af555692ab089b2e Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Tue, 24 Oct 2023 17:27:40 +0100 Subject: [PATCH 2/8] SpectrumViewerWindowModel: simplify remove_all_roi() --- mantidimaging/gui/windows/spectrum_viewer/model.py | 4 ++-- mantidimaging/gui/windows/spectrum_viewer/presenter.py | 2 +- mantidimaging/gui/windows/spectrum_viewer/test/model_test.py | 2 +- .../gui/windows/spectrum_viewer/test/presenter_test.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 2d224d259e3..6d593c15fc0 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -290,6 +290,6 @@ def rename_roi(self, old_name: str, new_name: str) -> None: def remove_all_roi(self) -> None: """ - Remove all ROIs from the model excluding default ROI 'all' + Remove all ROIs from the model """ - self._roi_ranges = {key: value for key, value in self._roi_ranges.items() if key in self.special_roi_list} + self._roi_ranges = {} diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 3796921f4d3..98adfcd597a 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -224,7 +224,7 @@ def rename_roi(self, old_name: str, new_name: str) -> None: self.view.spectrum.rename_roi(old_name, new_name) self.model.rename_roi(old_name, new_name) - def do_remove_roi(self, roi_name=None) -> None: + def do_remove_roi(self, roi_name: str | None = None) -> None: """ Remove a given ROI from the table by ROI name or all ROIs from the table if no name is passed as an argument diff --git a/mantidimaging/gui/windows/spectrum_viewer/test/model_test.py b/mantidimaging/gui/windows/spectrum_viewer/test/model_test.py index 3e02f037681..5c9d8bcc585 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/test/model_test.py +++ b/mantidimaging/gui/windows/spectrum_viewer/test/model_test.py @@ -283,7 +283,7 @@ def test_WHEN_remove_all_rois_called_THEN_all_but_default_rois_removed(self): self.model.set_new_roi("new_roi_2") self.assertListEqual(self.model.get_list_of_roi_names(), ["all", "new_roi", "new_roi_2"]) self.model.remove_all_roi() - self.assertListEqual(self.model.get_list_of_roi_names(), ["all"]) + self.assertListEqual(self.model.get_list_of_roi_names(), []) def test_WHEN_roi_renamed_THEN_roi_name_changed_in_list_of_roi_names(self): self.model.set_stack(generate_images()) diff --git a/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py b/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py index 5dbaf9137ad..6dab80a7e69 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py +++ b/mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py @@ -256,4 +256,4 @@ def test_WHEN_do_remove_roi_called_with_no_arguments_THEN_all_rois_removed(self) self.presenter.do_add_roi() self.assertEqual(["all", "roi", "roi_1", "roi_2"], self.presenter.model.get_list_of_roi_names()) self.presenter.do_remove_roi() - self.assertEqual(["all"], self.presenter.model.get_list_of_roi_names()) + self.assertEqual([], self.presenter.model.get_list_of_roi_names()) From a8c4880e5d5bfea101edeecd72c58a97158ae618 Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Wed, 25 Oct 2023 10:27:53 +0100 Subject: [PATCH 3/8] Make ROI TableModel iterable --- mantidimaging/gui/windows/spectrum_viewer/roi_table_model.py | 3 +++ mantidimaging/gui/windows/spectrum_viewer/view.py | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/roi_table_model.py b/mantidimaging/gui/windows/spectrum_viewer/roi_table_model.py index 95fe83d9b08..abbb2dd5dc3 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/roi_table_model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/roi_table_model.py @@ -91,6 +91,9 @@ def row_data(self, row: int) -> list: """ return self._data[row] + def __getitem__(self, item: int) -> list: + return self.row_data(item) + def column_data(self, column: int) -> list: """ Return data from selected column diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index 9a1aa45dd39..b3601d814fd 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -142,9 +142,8 @@ def on_visibility_change(self) -> None: """ When the visibility of an ROI is changed, update the visibility of the ROI in the spectrum widget """ - for roi_item in range(self.roi_table_model.rowCount()): + for roi_name, _, roi_visible in self.roi_table_model: if self.presenter.export_mode == ExportMode.ROI_MODE: - roi_name, _, roi_visible = self.roi_table_model.row_data(roi_item) if roi_visible is False: self.set_roi_alpha(0, roi_name) else: @@ -154,8 +153,6 @@ def on_visibility_change(self) -> None: roi_name, _, _ = self.roi_table_model.row_data(roi_item) self.set_roi_alpha(0, roi_name) - return - @property def roi_table_model(self) -> TableModel: if self.tableView.model() is None: From bb9bc3e74b4d93ebd7f1a2bb31a602e7e7eb99ec Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Wed, 25 Oct 2023 15:20:36 +0100 Subject: [PATCH 4/8] Spectrum viewer: add an ROI for RITS export Add adjust ROI visibility on tab change --- .../gui/windows/spectrum_viewer/model.py | 1 + .../gui/windows/spectrum_viewer/presenter.py | 10 +++++++++- mantidimaging/gui/windows/spectrum_viewer/view.py | 15 +++++++++++---- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 6d593c15fc0..e1e9d7b95d9 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -21,6 +21,7 @@ LOG = getLogger(__name__) ROI_ALL = "all" +ROI_RITS = "rits_roi" class SpecType(Enum): diff --git a/mantidimaging/gui/windows/spectrum_viewer/presenter.py b/mantidimaging/gui/windows/spectrum_viewer/presenter.py index 98adfcd597a..a8096f6c9e0 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/presenter.py +++ b/mantidimaging/gui/windows/spectrum_viewer/presenter.py @@ -8,7 +8,7 @@ from logging import getLogger from mantidimaging.core.data.dataset import StrictDataset from mantidimaging.gui.mvp_base import BasePresenter -from mantidimaging.gui.windows.spectrum_viewer.model import SpectrumViewerWindowModel, SpecType +from mantidimaging.gui.windows.spectrum_viewer.model import SpectrumViewerWindowModel, SpecType, ROI_RITS if TYPE_CHECKING: from mantidimaging.gui.windows.spectrum_viewer.view import SpectrumViewerWindowView # pragma: no cover @@ -75,6 +75,7 @@ def handle_sample_change(self, uuid: Optional['UUID']) -> None: self.model.set_normalise_stack(norm_stack) self.do_add_roi() + self.add_rits_roi() self.view.set_normalise_error(self.model.normalise_issue()) self.show_new_sample() @@ -205,6 +206,13 @@ def do_add_roi(self) -> None: self.view.auto_range_image() self.do_add_roi_to_table(roi_name) + def add_rits_roi(self) -> None: + roi_name = ROI_RITS + self.model.set_new_roi(roi_name) + self.view.spectrum.add_roi(self.model.get_roi(roi_name), roi_name) + self.view.set_spectrum(roi_name, self.model.get_spectrum(roi_name, self.spectrum_mode)) + self.view.set_roi_alpha(0, ROI_RITS) + def do_add_roi_to_table(self, roi_name: str) -> None: """ Add a given ROI to the table by ROI name diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index b3601d814fd..778ed0d3cf0 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -11,6 +11,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 .presenter import SpectrumViewerWindowPresenter, ExportMode from mantidimaging.gui.widgets import RemovableRowTableView from .spectrum_widget import SpectrumWidget @@ -142,17 +143,23 @@ def on_visibility_change(self) -> None: """ When the visibility of an ROI is changed, update the visibility of the ROI in the spectrum widget """ - for roi_name, _, roi_visible in self.roi_table_model: - if self.presenter.export_mode == ExportMode.ROI_MODE: + if self.presenter.export_mode == ExportMode.ROI_MODE: + for roi_name, _, roi_visible in self.roi_table_model: if roi_visible is False: self.set_roi_alpha(0, roi_name) else: self.set_roi_alpha(255, roi_name) self.presenter.redraw_spectrum(roi_name) - else: - roi_name, _, _ = self.roi_table_model.row_data(roi_item) + else: + for roi_name, _, _ in self.roi_table_model: self.set_roi_alpha(0, roi_name) + if self.presenter.export_mode == ExportMode.IMAGE_MODE: + self.set_roi_alpha(255, ROI_RITS) + self.presenter.redraw_spectrum(ROI_RITS) + else: + self.set_roi_alpha(0, ROI_RITS) + @property def roi_table_model(self) -> TableModel: if self.tableView.model() is None: From 309f894394498549ea1d945b04e8cb79ce427d8a Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Wed, 25 Oct 2023 15:38:35 +0100 Subject: [PATCH 5/8] Use RITS ROI when exporting to RITS --- mantidimaging/gui/windows/spectrum_viewer/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index e1e9d7b95d9..912b92b1e8e 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -212,7 +212,7 @@ def save_rits(self, path: Path, normalized: bool) -> None: if normalized: if self._normalise_stack is None: raise RuntimeError("No normalisation stack selected") - transmission = self.get_spectrum(ROI_ALL, SpecType.SAMPLE_NORMED) + transmission = self.get_spectrum(ROI_RITS, SpecType.SAMPLE_NORMED) self.export_spectrum_to_rits(path, tof, transmission, transmission_error) else: LOG.error("Data is not normalised to open beam. This will not export to a valid RITS format") From 3b18581cb9d5c0be5047e59dfc96c64e018a4278 Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Wed, 25 Oct 2023 15:42:26 +0100 Subject: [PATCH 6/8] Release notes --- docs/release_notes/next/feature-1957-rits-roi | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/release_notes/next/feature-1957-rits-roi diff --git a/docs/release_notes/next/feature-1957-rits-roi b/docs/release_notes/next/feature-1957-rits-roi new file mode 100644 index 00000000000..bdcc93f94df --- /dev/null +++ b/docs/release_notes/next/feature-1957-rits-roi @@ -0,0 +1,2 @@ +#1957 : ROI support for RITS export + From 37fcd86e1370bf20cb21a220422b15478ca9226d Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Fri, 27 Oct 2023 13:00:03 +0100 Subject: [PATCH 7/8] Spectrum Viewer: for hidden ROIs set spectrum to None instead of Zero Avoid the spectrum plot range being scaled to show zero --- .../gui/windows/spectrum_viewer/spectrum_widget.py | 2 +- mantidimaging/gui/windows/spectrum_viewer/view.py | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py index e9d0da14331..f7ff2cd6cf4 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py +++ b/mantidimaging/gui/windows/spectrum_viewer/spectrum_widget.py @@ -87,7 +87,7 @@ def __init__(self) -> None: self.nextRow() self.spectrum = self.addPlot() - self.spectrum_data_dict: dict[str, np.ndarray] = {} + self.spectrum_data_dict: dict[str, np.ndarray | None] = {} self.nextRow() self._tof_range_label = self.addLabel() diff --git a/mantidimaging/gui/windows/spectrum_viewer/view.py b/mantidimaging/gui/windows/spectrum_viewer/view.py index 778ed0d3cf0..cc34f436dc3 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/view.py +++ b/mantidimaging/gui/windows/spectrum_viewer/view.py @@ -213,9 +213,7 @@ def set_spectrum(self, name: str, spectrum_data: 'np.ndarray'): self.spectrum.spectrum_data_dict[name] = spectrum_data self.spectrum.spectrum.clearPlots() - for key, value in self.spectrum.spectrum_data_dict.items(): - if key in self.spectrum.roi_dict: - self.spectrum.spectrum.plot(value, name=key, pen=self.spectrum.roi_dict[key].colour) + self.show_visible_spectrums() def clear(self) -> None: self.spectrum.spectrum_data_dict = {} @@ -256,14 +254,15 @@ def set_roi_alpha(self, alpha: float, roi_name: str) -> None: """ self.spectrum.set_roi_alpha(roi_name, alpha) if alpha == 0: - self.spectrum.spectrum_data_dict[roi_name] = np.zeros(self.spectrum.spectrum_data_dict[roi_name].shape) - else: - self.spectrum.spectrum_data_dict[roi_name] = self.spectrum.spectrum_data_dict[roi_name] + self.spectrum.spectrum_data_dict[roi_name] = None self.spectrum.spectrum.clearPlots() self.spectrum.spectrum.update() + self.show_visible_spectrums() + + def show_visible_spectrums(self): for key, value in self.spectrum.spectrum_data_dict.items(): - if key in self.spectrum.roi_dict: + if value is not None and key in self.spectrum.roi_dict: self.spectrum.spectrum.plot(value, name=key, pen=self.spectrum.roi_dict[key].colour) def add_roi_table_row(self, name: str, colour: tuple[int, int, int]): From ab79dcf2d9bc37e66dcf4a64f69c584083b60bc4 Mon Sep 17 00:00:00 2001 From: Sam Tygier Date: Wed, 22 Nov 2023 12:16:29 +0000 Subject: [PATCH 8/8] Rits export. Use 0.1 as placeholder for transmission errors --- mantidimaging/gui/windows/spectrum_viewer/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mantidimaging/gui/windows/spectrum_viewer/model.py b/mantidimaging/gui/windows/spectrum_viewer/model.py index 912b92b1e8e..583b220c1b2 100644 --- a/mantidimaging/gui/windows/spectrum_viewer/model.py +++ b/mantidimaging/gui/windows/spectrum_viewer/model.py @@ -208,7 +208,7 @@ def save_rits(self, path: Path, normalized: bool) -> None: # RITS expects ToF in μs tof *= 1e6 - transmission_error = np.zeros_like(tof) + transmission_error = np.full_like(tof, 0.1) if normalized: if self._normalise_stack is None: raise RuntimeError("No normalisation stack selected")