Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ROI support for RITS export #1958

Merged
merged 8 commits into from
Nov 22, 2023
2 changes: 2 additions & 0 deletions docs/release_notes/next/feature-1957-rits-roi
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#1957 : ROI support for RITS export

26 changes: 13 additions & 13 deletions mantidimaging/gui/windows/spectrum_viewer/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

LOG = getLogger(__name__)

ROI_ALL = "all"
ROI_RITS = "rits_roi"


class SpecType(Enum):
SAMPLE = 1
Expand All @@ -44,7 +47,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:
"""
Expand Down Expand Up @@ -77,7 +80,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:
"""
Expand Down Expand Up @@ -198,21 +201,18 @@ 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")

# RITS expects ToF in μs
tof *= 1e6

transmission_error = np.zeros_like(tof)
transmission_error = np.full_like(tof, 0.1)
if normalized:
samtygier-stfc marked this conversation as resolved.
Show resolved Hide resolved
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_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")
Expand Down Expand Up @@ -266,8 +266,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(
Expand All @@ -283,14 +283,14 @@ 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()}")

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.default_roi_list}
self._roi_ranges = {}
12 changes: 10 additions & 2 deletions mantidimaging/gui/windows/spectrum_viewer/presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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
Expand All @@ -224,7 +232,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
Expand Down
3 changes: 3 additions & 0 deletions mantidimaging/gui/windows/spectrum_viewer/roi_table_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
29 changes: 16 additions & 13 deletions mantidimaging/gui/windows/spectrum_viewer/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -142,19 +143,22 @@ 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()):
if self.presenter.export_mode == ExportMode.ROI_MODE:
roi_name, _, roi_visible = self.roi_table_model.row_data(roi_item)
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)

return
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:
Expand Down Expand Up @@ -209,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 = {}
Expand Down Expand Up @@ -252,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]):
Expand Down
Loading