Skip to content

Commit

Permalink
Merge pull request #733 from mantidproject/702_see_if_logs_loaded
Browse files Browse the repository at this point in the history
Adds source file path to IMATLogFile, shows it in metadata
  • Loading branch information
Pasarus committed Dec 2, 2020
2 parents 7dd011d + 620b6f9 commit 73ec280
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 18 deletions.
4 changes: 4 additions & 0 deletions mantidimaging/core/data/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ def log_file(self):

@log_file.setter
def log_file(self, value: IMATLogFile):
if value is not None:
self.metadata[const.LOG_FILE] = value.source_file
elif value is None:
del self.metadata[const.LOG_FILE]
self._log_file = value

def projection_angles(self, max_angle: float = 360.0):
Expand Down
2 changes: 1 addition & 1 deletion mantidimaging/core/data/test/fake_logfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ def generate_logfile() -> IMATLogFile:
"Monitor 3 after: 6078866"
]
]
return IMATLogFile(data)
return IMATLogFile(data, "/tmp/fake")
5 changes: 5 additions & 0 deletions mantidimaging/core/data/test/images_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,8 @@ def test_get_projection_angles_no_logfile(self):
actual = images.projection_angles(275.69)
self.assertEqual(10, len(actual.value))
self.assertAlmostEqual(np.deg2rad(275.69), actual.value[-1], places=4)

def test_metadata_gets_updated_with_logfile(self):
images = generate_images()
images.log_file = generate_logfile()
self.assertEqual(images.log_file.source_file, images.metadata[const.LOG_FILE])
4 changes: 2 additions & 2 deletions mantidimaging/core/io/loader/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ def read_in_file_information(input_path,
return fi


def load_log(log_file) -> IMATLogFile:
def load_log(log_file: str) -> IMATLogFile:
data = []
with open(log_file, 'r') as f:
for line in f:
data.append(line.strip().split(" "))

return IMATLogFile(data)
return IMATLogFile(data, log_file)


def load_p(parameters: ImageParameters, dtype, progress) -> Images:
Expand Down
1 change: 1 addition & 0 deletions mantidimaging/core/operation_history/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
OPERATION_KEYWORD_ARGS = 'kwargs'
OPERATION_DISPLAY_NAME = 'display_name'
PIXEL_SIZE = 'pixel_size'
LOG_FILE = 'log_file'

OPERATION_NAME_COR_TILT_FINDING = 'cor_tilt_finding'
COR_TILT_ROTATION_CENTRE = 'rotation_centre'
Expand Down
7 changes: 6 additions & 1 deletion mantidimaging/core/utility/imat_log_file_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class IMATLogColumn(Enum):


class IMATLogFile:
def __init__(self, data: List[List[str]]):
def __init__(self, data: List[List[str]], source_file: str):
self._source_file = source_file
self._data: Dict[IMATLogColumn, List] = {
IMATLogColumn.TIMESTAMP: [],
IMATLogColumn.IMAGE_TYPE_IMAGE_COUNTER: [],
Expand All @@ -46,6 +47,10 @@ def __init__(self, data: List[List[str]]):
self._data[IMATLogColumn.COUNTS_BEFORE].append(line[2])
self._data[IMATLogColumn.COUNTS_AFTER].append(line[3])

@property
def source_file(self) -> str:
return self._source_file

def projection_numbers(self):
proj_nums = numpy.zeros(len(self._data[IMATLogColumn.IMAGE_TYPE_IMAGE_COUNTER]), dtype=numpy.uint32)
for i, angle_str in enumerate(self._data[IMATLogColumn.IMAGE_TYPE_IMAGE_COUNTER]):
Expand Down
18 changes: 15 additions & 3 deletions mantidimaging/core/utility/test/imat_log_file_parser_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def test_parsing_log_file():
EXPECTED_HEADER_FOR_IMAT_LOG_FILE, ["ignored line"],
["timestamp", "Projection: 0 angle: 0.1", "counts before: 12345", "counts_after: 45678"]
]
logfile = IMATLogFile(test_input)
logfile = IMATLogFile(test_input, "/tmp/fake")
assert len(logfile.projection_angles().value) == 1
assert logfile.projection_angles().value[0] == np.deg2rad(0.1), f"Got: {logfile.projection_angles().value[0]}"
assert logfile.counts().value[0] == (45678 - 12345)
Expand All @@ -25,7 +25,7 @@ def test_counts():
["timestamp", "Projection: 1 angle: 0.1", "counts before: 45678", "counts_after: 84678"],
["timestamp", "Projection: 2 angle: 0.2", "counts before: 84678", "counts_after: 124333"],
]
logfile = IMATLogFile(test_input)
logfile = IMATLogFile(test_input, "/tmp/fake")
assert len(logfile.counts().value) == 3
assert logfile.counts().value[0] == 45678 - 12345
assert logfile.counts().value[1] == 84678 - 45678
Expand All @@ -50,7 +50,7 @@ def test_find_missing_projection_number():
["timestamp", "Projection: 1 angle: 0.1", "counts before: 12345", "counts_after: 45678"],
["timestamp", "Projection: 2 angle: 0.2", "counts before: 12345", "counts_after: 45678"],
]
logfile = IMATLogFile(test_input)
logfile = IMATLogFile(test_input, "/tmp/fake")
assert len(logfile.projection_numbers()) == 3
# nothing missing
logfile.raise_if_angle_missing(["file_000.tif", "file_001.tif", "file_002.tif"])
Expand All @@ -60,3 +60,15 @@ def test_find_missing_projection_number():
assert_raises(RuntimeError, logfile.raise_if_angle_missing, ["file_000.tif", "file_001.tif"])
assert_raises(RuntimeError, logfile.raise_if_angle_missing,
["file_000.tif", "file_001.tif", "file_002.tif", "file_003.tif"])


def test_source_file():
test_input = [
EXPECTED_HEADER_FOR_IMAT_LOG_FILE,
["ignored line"],
["timestamp", "Projection: 0 angle: 0.0", "counts before: 12345", "counts_after: 45678"],
["timestamp", "Projection: 1 angle: 0.1", "counts before: 12345", "counts_after: 45678"],
["timestamp", "Projection: 2 angle: 0.2", "counts before: 12345", "counts_after: 45678"],
]
logfile = IMATLogFile(test_input, "/tmp/fake")
assert logfile.source_file == "/tmp/fake"
17 changes: 13 additions & 4 deletions mantidimaging/gui/windows/main/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,21 @@ def have_active_stacks(self) -> bool:
return len(self.active_stacks) > 0

def add_log_to_sample(self, stack_name: str, log_file: str):
stack = self.get_stack_by_name(stack_name).widget() # type: ignore
stack.presenter.images.log_file = loader.load_log(log_file)
stack.presenter.images.log_file.raise_if_angle_missing(stack.presenter.images.filenames)
stack_dock = self.get_stack_by_name(stack_name)
if stack_dock is None:
raise RuntimeError(f"Failed to get stack with name {stack_name}")

stack: StackVisualiserView = stack_dock.widget() # type: ignore
log = loader.load_log(log_file)
log.raise_if_angle_missing(stack.presenter.images.filenames)
stack.presenter.images.log_file = log

def add_180_deg_to_stack(self, stack_name, _180_deg_file):
stack = self.get_stack_by_name(stack_name).widget() # type: ignore
stack_dock = self.get_stack_by_name(stack_name)
if stack_dock is None:
raise RuntimeError(f"Failed to get stack with name {stack_name}")

stack: StackVisualiserView = stack_dock.widget() # type: ignore
_180_deg = loader.load(file_names=[_180_deg_file])
stack.presenter.images.proj180deg = _180_deg.sample
return _180_deg
29 changes: 29 additions & 0 deletions mantidimaging/gui/windows/main/test/model_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,21 @@ def test_add_log_to_sample(self, load_log: mock.Mock):
stack_mock.return_value.widget.return_value.presenter.images.log_file.raise_if_angle_missing \
.assert_called_once_with(stack_mock.return_value.widget.return_value.presenter.images.filenames)

@mock.patch('mantidimaging.core.io.loader.load_log')
def test_add_log_to_sample_no_stack(self, load_log: mock.Mock):
"""
Test in add_log_to_sample when get_stack_by_name returns None
"""
log_file = "Log file"
stack_name = "stack name"
stack_mock = mock.MagicMock()
self.model.get_stack_by_name = stack_mock
stack_mock.return_value = None

self.assertRaises(RuntimeError, self.model.add_log_to_sample, stack_name=stack_name, log_file=log_file)

stack_mock.assert_called_with(stack_name)

@mock.patch('mantidimaging.core.io.loader.load')
def test_add_180_deg_to_stack(self, load: mock.Mock):
_180_file = "180 file"
Expand All @@ -251,6 +266,20 @@ def test_add_180_deg_to_stack(self, load: mock.Mock):
stack_mock.assert_called_with(stack_name)
self.assertEqual(_180_stack, stack_mock.return_value.widget.return_value.presenter.images.proj180deg)

@mock.patch('mantidimaging.core.io.loader.load')
def test_add_180_deg_to_stack_no_stack(self, load: mock.Mock):
"""
Test in add_180_deg_to_stack when get_stack_by_name returns None
"""
_180_file = "180 file"
stack_name = "stack name"
stack_mock = mock.MagicMock()
self.model.get_stack_by_name = stack_mock
stack_mock.return_value = None

self.assertRaises(RuntimeError, self.model.add_180_deg_to_stack, stack_name=stack_name, _180_deg_file=_180_file)
stack_mock.assert_called_with(stack_name)


if __name__ == '__main__':
unittest.main()
1 change: 1 addition & 0 deletions mantidimaging/gui/windows/operations/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ def toggle_average_images(images_):
toggle_show_averaged_image = QAction("Toggle show averaged image", menu)
toggle_show_averaged_image.triggered.connect(lambda: toggle_average_images(images))
menu.addAction(toggle_show_averaged_image)
menu.addSeparator()
self.roi_view.imageItem.menu = menu

self.roi_view.setImage(images.data)
Expand Down
18 changes: 11 additions & 7 deletions mantidimaging/gui/windows/stack_visualiser/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,25 @@ def roi_changed_callback(self, roi: SensibleROI):
self.roi_updated.emit(roi)

def build_context_menu(self) -> QMenu:
actions = [("Set ROI", self.set_roi), ("Copy ROI to clipboard", self.copy_roi_to_clipboard),
("Toggle show averaged image", lambda: self.presenter.notify(SVNotification.TOGGLE_IMAGE_MODE)),
("Create sinograms from stack", lambda: self.presenter.notify(SVNotification.SWAP_AXES)),
actions = [("Show history and metadata", self.show_image_metadata),
("Duplicate whole data", lambda: self.presenter.notify(SVNotification.DUPE_STACK)),
("Duplicate current ROI of data", lambda: self.presenter.notify(SVNotification.DUPE_STACK_ROI)),
("Show history", self.show_image_metadata), ("Mark as projections/sinograms", self.mark_as_),
("Mark as projections/sinograms", self.mark_as_), ("", None),
("Toggle show averaged image", lambda: self.presenter.notify(SVNotification.TOGGLE_IMAGE_MODE)),
("Create sinograms from stack", lambda: self.presenter.notify(SVNotification.SWAP_AXES)),
("Set ROI", self.set_roi), ("Copy ROI to clipboard", self.copy_roi_to_clipboard), ("", None),
("Change window name", self.change_window_name_clicked), ("Goto projection", self.goto_projection),
("Goto angle", self.goto_angle)]

menu = QMenu(self)

for (menu_text, func) in actions:
action = QAction(menu_text, menu)
action.triggered.connect(func)
menu.addAction(action)
if func is None:
menu.addSeparator()
else:
action = QAction(menu_text, menu)
action.triggered.connect(func)
menu.addAction(action)

return menu

Expand Down

0 comments on commit 73ec280

Please sign in to comment.