Skip to content

Commit

Permalink
Merge 32e1cfb into aa73fc2
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeSullivan7 committed May 8, 2024
2 parents aa73fc2 + 32e1cfb commit af62971
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 51 deletions.
1 change: 1 addition & 0 deletions docs/release_notes/next/dev-2177-spectrum-viewer-ToF-tests
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#2177: Added unit tests for the Time of Flight user properties in the Spectrum Viewer
45 changes: 38 additions & 7 deletions mantidimaging/gui/windows/spectrum_viewer/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import csv
from enum import Enum
from pathlib import Path
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, TypedDict

import numpy as np
from math import ceil
Expand Down Expand Up @@ -52,6 +52,31 @@ def get_by_value(cls, value: str) -> ErrorMode:
raise ValueError(f"Unknown error mode: {value}")


class AllowedModesTypedDict(TypedDict):
mode: ToFUnitMode
label: str


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)"
}
}


class SpectrumViewerWindowModel:
"""
The model for the spectrum viewer window.
Expand All @@ -75,12 +100,6 @@ 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
else:
self.tof_mode = ToFUnitMode.WAVELENGTH

self.units = UnitConversion()

def roi_name_generator(self) -> str:
Expand Down Expand Up @@ -481,3 +500,15 @@ def set_relevant_tof_units(self) -> None:
self.tof_data = self.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)

def set_tof_unit_mode_for_stack(self) -> None:
if self.get_stack_time_of_flight() is None or self.tof_data is None:
self.tof_mode = ToFUnitMode.IMAGE_NUMBER
self.presenter.change_selected_menu_option("Image Index")
elif self.tof_mode == ToFUnitMode.ENERGY:
self.presenter.change_selected_menu_option("Energy")
elif self.tof_mode == ToFUnitMode.TOF_US:
self.presenter.change_selected_menu_option("Time of Flight (\u03BCs)")
else:
self.tof_mode = ToFUnitMode.WAVELENGTH
self.presenter.change_selected_menu_option("Wavelength")
38 changes: 22 additions & 16 deletions mantidimaging/gui/windows/spectrum_viewer/presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
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, \
ToFUnitMode
ToFUnitMode, allowed_modes

if TYPE_CHECKING:
from mantidimaging.gui.windows.spectrum_viewer.view import SpectrumViewerWindowView # pragma: no cover
Expand Down Expand Up @@ -67,7 +67,10 @@ def handle_stack_changed(self) -> None:
except RuntimeError:
norm_stack = None
self.model.set_normalise_stack(norm_stack)

self.model.set_tof_unit_mode_for_stack()
self.reset_units_menu()

self.handle_tof_unit_change()
self.show_new_sample()
self.redraw_all_rois()
Expand All @@ -92,7 +95,9 @@ def handle_sample_change(self, uuid: UUID | None) -> None:
return

self.model.set_stack(self.main_window.get_stack(uuid))
self.model.set_tof_unit_mode_for_stack()
self.reset_units_menu()

self.handle_tof_unit_change()
normalise_uuid = self.view.get_normalise_stack()
if normalise_uuid is not None:
Expand All @@ -112,20 +117,12 @@ def reset_units_menu(self):
if self.model.tof_data is None:
self.view.tof_mode_select_group.setEnabled(False)
self.view.tofPropertiesGroupBox.setEnabled(False)
else:
self.view.tof_mode_select_group.setEnabled(True)
self.view.tofPropertiesGroupBox.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)
if self.model.tof_data is None:
self.model.tof_mode = ToFUnitMode.IMAGE_NUMBER
self.change_selected_menu_option("Image Index")
self.view.tof_mode_select_group.setEnabled(False)
else:
self.view.tof_mode_select_group.setEnabled(True)
self.view.tofPropertiesGroupBox.setEnabled(True)

def handle_normalise_stack_change(self, normalise_uuid: UUID | None) -> None:
if normalise_uuid == self.current_norm_stack_uuid:
Expand Down Expand Up @@ -352,13 +349,15 @@ def handle_export_tab_change(self, index: int) -> None:
self.view.on_visibility_change()

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]["mode"]
self.model.set_relevant_tof_units()
tof_axis_label = self.view.allowed_modes[selected_mode]["label"]
tof_axis_label = allowed_modes[self.view.tof_units_mode]["label"]
self.view.spectrum_widget.spectrum_plot_widget.set_tof_axis_label(tof_axis_label)
self.refresh_spectrum_plot()

def handle_tof_unit_change_via_menu(self) -> None:
self.model.tof_mode = allowed_modes[self.view.tof_units_mode]["mode"]
self.handle_tof_unit_change()

def refresh_spectrum_plot(self) -> None:
self.view.spectrum_widget.spectrum.clearPlots()
self.view.spectrum_widget.spectrum.update()
Expand All @@ -373,7 +372,14 @@ def handle_flight_path_change(self) -> None:
self.refresh_spectrum_plot()

def handle_time_delay_change(self) -> None:
self.model.tof_data = self.model.get_stack_time_of_flight()
self.model.units.data_offset = self.view.timeDelaySpinBox.value() * 1e-6
self.model.set_relevant_tof_units()
self.refresh_spectrum_plot()

def change_selected_menu_option(self, opt):
for action in self.view.tof_mode_select_group.actions():
with QSignalBlocker(action):
if action.objectName() == opt:
action.setChecked(True)
else:
action.setChecked(False)
36 changes: 35 additions & 1 deletion mantidimaging/gui/windows/spectrum_viewer/test/presenter_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from mantidimaging.core.data.dataset import StrictDataset, MixedDataset
from mantidimaging.gui.windows.main import MainWindowView
from mantidimaging.gui.windows.spectrum_viewer import SpectrumViewerWindowView, SpectrumViewerWindowPresenter
from mantidimaging.gui.windows.spectrum_viewer.model import ErrorMode
from mantidimaging.gui.windows.spectrum_viewer.model import ErrorMode, ToFUnitMode
from mantidimaging.gui.windows.spectrum_viewer.spectrum_widget import SpectrumWidget, SpectrumPlotWidget
from mantidimaging.test_helpers import mock_versions, start_qapplication
from mantidimaging.test_helpers.unit_test_helper import generate_images
Expand Down Expand Up @@ -173,6 +173,7 @@ def test_gui_changes_tof_range(self):
image_stack = generate_images([30, 11, 12])
new_tof_range = (10, 20)
self.presenter.model.set_stack(image_stack)
self.presenter.model.tof_mode = ToFUnitMode.IMAGE_NUMBER
self.presenter.handle_range_slide_moved(new_tof_range)

self.assertEqual(self.presenter.model.tof_range, new_tof_range)
Expand Down Expand Up @@ -271,3 +272,36 @@ def test_WHEN_do_remove_roi_called_with_no_arguments_THEN_all_rois_removed(self)
self.assertEqual(["all", "roi", "roi_1", "roi_2"], self.presenter.model.get_list_of_roi_names())
self.presenter.do_remove_roi()
self.assertEqual([], self.presenter.model.get_list_of_roi_names())

@parameterized.expand([("Image Index", ToFUnitMode.IMAGE_NUMBER), ("Wavelength", ToFUnitMode.WAVELENGTH),
("Energy", ToFUnitMode.ENERGY), ("Time of Flight (\u03BCs)", ToFUnitMode.TOF_US)])
def test_WHEN_tof_unit_selected_THEN_model_mode_changes(self, mode_text, expected_mode):
self.view.tof_units_mode = mode_text
self.presenter.refresh_spectrum_plot = mock.Mock()
self.presenter.handle_tof_unit_change_via_menu()
self.assertEqual(self.presenter.model.tof_mode, expected_mode)

@mock.patch("mantidimaging.gui.windows.spectrum_viewer.model.SpectrumViewerWindowModel.get_stack_time_of_flight")
def test_WHEN_no_spectrum_data_THEN_mode_is_image_index(self, get_stack_time_of_flight):
self.presenter.model.set_stack(generate_images())
self.presenter.get_dataset_id_for_stack = mock.Mock(return_value=uuid.uuid4())
self.presenter.main_window.get_stack = mock.Mock(return_value=generate_images())
get_stack_time_of_flight.return_value = None
self.view.tof_units_mode = "Wavelength"
self.presenter.refresh_spectrum_plot = mock.Mock()
self.presenter.handle_sample_change(uuid.uuid4())
self.assertEqual(self.presenter.model.tof_mode, ToFUnitMode.IMAGE_NUMBER)

def test_WHEN_tof_flight_path_changed_THEN_unit_conversion_flight_path_set(self):
self.view.flightPathSpinBox = mock.Mock()
self.view.flightPathSpinBox.value.return_value = 10
self.presenter.refresh_spectrum_plot = mock.Mock()
self.presenter.handle_flight_path_change()
self.assertEqual(self.presenter.model.units.target_to_camera_dist, 10)

def test_WHEN_tof_delay_changed_THEN_unit_conversion_delay_set(self):
self.view.timeDelaySpinBox = mock.Mock()
self.view.timeDelaySpinBox.value.return_value = 400
self.presenter.refresh_spectrum_plot = mock.Mock()
self.presenter.handle_time_delay_change()
self.assertEqual(self.presenter.model.units.data_offset, 400 * 1e-6)
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,7 @@ def test_WHEN_rename_roi_called_with_default_roi_THEN_roi_name_not_changed(self)
self.assertIn("roi_1", self.spectrum_widget.roi_dict.keys())
self.spectrum_widget.rename_roi("roi_1", "roi")
self.assertIn("roi_1", self.spectrum_widget.roi_dict)

def test_WHEN_tof_axis_label_changed_THEN_axis_label_set(self):
self.spectrum_plot_widget.set_tof_axis_label("test")
self.assertEqual(self.spectrum_plot_widget.spectrum.getAxis('bottom').labelText, "test")
35 changes: 8 additions & 27 deletions mantidimaging/gui/windows/spectrum_viewer/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, TypedDict
from typing import TYPE_CHECKING

from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QCheckBox, QVBoxLayout, QFileDialog, QPushButton, QLabel, QAbstractItemView, QHeaderView, \
Expand All @@ -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, ToFUnitMode
from .model import ROI_RITS, allowed_modes
from .presenter import SpectrumViewerWindowPresenter, ExportMode
from mantidimaging.gui.widgets import RemovableRowTableView
from .spectrum_widget import SpectrumWidget
Expand All @@ -27,11 +27,6 @@
from uuid import UUID


class AllowedModesTypedDict(TypedDict):
mode: ToFUnitMode
label: str


class SpectrumViewerWindowView(BaseMainWindowView):
tableView: RemovableRowTableView
sampleStackSelector: DatasetSelectorWidgetView
Expand Down Expand Up @@ -94,30 +89,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: 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():
for mode in 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)
action.triggered.connect(self.presenter.handle_tof_unit_change_via_menu)
if mode == "Image Index":
action.setChecked(True)
if self.presenter.model.tof_data is None:
Expand Down Expand Up @@ -527,6 +504,10 @@ def set_binning_visibility(self) -> None:
self.bin_step_label.setHidden(hide_binning)
self.bin_step_spinBox.setHidden(hide_binning)

@property
def tof_units_mode(self) -> str:
return self.tof_mode_select_group.checkedAction().text()

def set_roi_properties(self) -> None:
if self.presenter.export_mode == ExportMode.IMAGE_MODE:
self.current_roi = ROI_RITS
Expand Down

0 comments on commit af62971

Please sign in to comment.