Skip to content

Commit

Permalink
Add save option on analysis (#114)
Browse files Browse the repository at this point in the history
* Add save option on analysis

* Add (broken) save test

* Update tracks test

* update testing

* Add sleep to fix tests

* Update test data

* Add remaining save tests

* set layer editability later to prevent it being reset

* sleep for longer to see if tests pass on windows/macos

* rename tests

* increase sleep
  • Loading branch information
adamltyson authored Jul 11, 2023
1 parent ccd50ed commit 4b95042
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 46 deletions.
2 changes: 2 additions & 0 deletions brainreg_segment/layout/gui_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"left" # Alignment of text in pushbuttons in methods chooser panel
)

SAVE_DEFAULT = False

POINT_SIZE = 100
SPLINE_SIZE = 50
NUM_COLORS = 10
Expand Down
25 changes: 14 additions & 11 deletions brainreg_segment/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,9 @@ def initialise_loaded_data(self):
]
self.hemispheres_data = self.hemispheres_layer.data

self.prevent_layer_edit()

self.initialise_segmentation_interface()
self.status_label.setText("Ready")
self.prevent_layer_edit()

def collate_widget_layers(self):
"""
Expand Down Expand Up @@ -486,6 +485,7 @@ def collate_widget_layers(self):
]

def prevent_layer_edit(self):
print("Preventing layer edit")
self.collate_widget_layers()
for layer in self.non_editable_widget_layers:
layer.editable = False
Expand Down Expand Up @@ -568,18 +568,21 @@ def save(self, override=True):
else:
choice = True # for debugging
if choice:
print("Saving")
worker = save_all(
self.paths.regions_directory,
self.paths.tracks_directory,
self.label_layers,
self.track_layers,
track_file_extension=TRACK_FILE_EXT,
)
worker.start()
self.run_save()
else:
print('Not saving because user chose "Cancel" \n')

def run_save(self):
print("Saving")
worker = save_all(
self.paths.regions_directory,
self.paths.tracks_directory,
self.label_layers,
self.track_layers,
track_file_extension=TRACK_FILE_EXT,
)
worker.start()

def export_to_brainrender(self, override=False):
if not override:
choice = display_warning(
Expand Down
19 changes: 16 additions & 3 deletions brainreg_segment/segmentation_panels/regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
COLUMN_WIDTH,
IMAGE_FILE_EXT,
NUM_COLORS,
SAVE_DEFAULT,
SEGM_METHODS_PANEL_ALIGN,
SUMMARIZE_VOLUMES_DEFAULT,
)
Expand Down Expand Up @@ -34,6 +35,7 @@ def __init__(
parent,
calculate_volumes_default=CALCULATE_VOLUMES_DEFAULT,
summarise_volumes_default=SUMMARIZE_VOLUMES_DEFAULT,
save_default=SAVE_DEFAULT,
brush_size=BRUSH_SIZE,
image_file_extension=IMAGE_FILE_EXT,
num_colors=NUM_COLORS,
Expand All @@ -43,6 +45,7 @@ def __init__(

self.calculate_volumes_default = calculate_volumes_default
self.summarise_volumes_default = summarise_volumes_default
self.save_default = save_default

# Brushes / ...
self.brush_size_default = BRUSH_SIZE # Keep track of default
Expand All @@ -60,7 +63,7 @@ def add_region_panel(self, row):
"Add new region",
region_layout,
self.add_new_region,
row=2,
row=3,
column=0,
tooltip="Create a new empty segmentation layer "
"to manually segment a new region.",
Expand All @@ -70,7 +73,7 @@ def add_region_panel(self, row):
"Analyse regions",
region_layout,
self.run_region_analysis,
row=2,
row=3,
column=1,
tooltip="Analyse the spatial distribution of the "
"segmented regions.",
Expand All @@ -79,7 +82,7 @@ def add_region_panel(self, row):
"Add region from selected layer",
region_layout,
self.add_region_from_existing_layer,
row=3,
row=4,
column=0,
tooltip="Adds a region from a selected labels layer (e.g. "
"from another plugin). Make sure this region "
Expand All @@ -105,6 +108,13 @@ def add_region_panel(self, row):
tooltip="Summarise each segmented region "
"(e.g. center, volume etc.).",
)
self.save_checkbox = add_checkbox(
region_layout,
self.save_default,
"Save segmentation",
row=2,
tooltip="Save the segmentation layers during analysis.",
)

region_layout.setColumnMinimumWidth(1, COLUMN_WIDTH)
self.region_panel.setLayout(region_layout)
Expand Down Expand Up @@ -204,6 +214,9 @@ def run_region_analysis(self, override=False):
choice = True # for debugging

if choice:
if self.save_checkbox.isChecked():
self.parent.run_save()

print("Running region analysis")

if check_segmentation_in_correct_space(
Expand Down
29 changes: 21 additions & 8 deletions brainreg_segment/segmentation_panels/tracks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
COLUMN_WIDTH,
FIT_DEGREE_DEFAULT,
POINT_SIZE,
SAVE_DEFAULT,
SEGM_METHODS_PANEL_ALIGN,
SPLINE_POINTS_DEFAULT,
SPLINE_SIZE,
Expand Down Expand Up @@ -47,6 +48,7 @@ def __init__(
spline_smoothing_default=SPLINE_SMOOTHING_DEFAULT,
fit_degree_default=FIT_DEGREE_DEFAULT,
summarise_track_default=SUMMARISE_TRACK_DEFAULT,
save_default=SAVE_DEFAULT,
):
super(TrackSeg, self).__init__()
self.parent = parent
Expand All @@ -62,6 +64,7 @@ def __init__(
self.spline_size = spline_size # Initialise
self.spline_smoothing_default = spline_smoothing_default
self.fit_degree_default = fit_degree_default
self.save_default = save_default

# File formats
self.track_file_extension = track_file_extension
Expand All @@ -78,7 +81,7 @@ def add_track_panel(self, row):
"Add track",
track_layout,
self.add_track,
row=5,
row=6,
column=0,
tooltip="Create a new empty segmentation layer "
"to manually annotate a new track.",
Expand All @@ -88,7 +91,7 @@ def add_track_panel(self, row):
"Trace tracks",
track_layout,
self.run_track_analysis,
row=5,
row=6,
column=1,
tooltip="Join up the points using a spline fit "
"and save the distribution of the track in "
Expand All @@ -99,7 +102,7 @@ def add_track_panel(self, row):
"Add track from selected layer",
track_layout,
self.add_track_from_existing_layer,
row=6,
row=7,
column=0,
tooltip="Adds a track from a selected points layer (e.g. "
"from another plugin). Make sure this track "
Expand All @@ -111,7 +114,7 @@ def add_track_panel(self, row):
"Add surface points",
track_layout,
self.add_surface_points,
row=6,
row=7,
column=1,
tooltip="Add an additional first point at the surface of the "
"brain. Selecting this option will add an additional "
Expand All @@ -128,14 +131,21 @@ def add_track_panel(self, row):
"each part of the interpolated track "
"(determined by the number of spline points). ",
)
self.save_checkbox = add_checkbox(
track_layout,
self.save_default,
"Save tracing",
row=1,
tooltip="Save the traced layers during analysis.",
)

self.fit_degree = add_int_box(
track_layout,
self.fit_degree_default,
1,
2,
5,
"Fit degree",
row=1,
row=2,
tooltip="Degree of polynomial to fit to the track.",
)

Expand All @@ -146,7 +156,7 @@ def add_track_panel(self, row):
1,
"Spline smoothing",
0.1,
row=2,
row=3,
tooltip="How closely or not to fit the points "
"(lower numbers fit more closely, for "
"a less smooth interpolation).",
Expand All @@ -158,7 +168,7 @@ def add_track_panel(self, row):
1,
10000,
"Spline points",
row=3,
row=4,
tooltip="How many points are sampled from the "
"interpolation (used for the summary).",
)
Expand Down Expand Up @@ -294,6 +304,9 @@ def run_track_analysis(self, override=False):
choice = True # for debugging

if choice:
if self.save_checkbox.isChecked():
self.parent.run_save()

print("Running track analysis")
self.splines, self.spline_names = track_analysis(
self.parent.viewer,
Expand Down
11 changes: 10 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@ def segmentation_widget(make_napari_viewer):
return widget


@pytest.fixture
@pytest.fixture(scope="function")
def segmentation_widget_with_data_atlas_space(tmp_path, segmentation_widget):
"""
Fixture to load a brainreg directory into the segmentation widget.
Data is copied to tmpdir so that when it's loaded, so all the paths
are set correctly.
The manual segmentation data is then deleted so that saving/export
can be properly tested
"""
tmp_input_dir = tmp_path / "brainreg_output"
shutil.copytree(brainreg_dir, tmp_input_dir)
segmentation_widget.standard_space = True
Expand All @@ -37,4 +44,6 @@ def segmentation_widget_with_data_atlas_space(tmp_path, segmentation_widget):
)
segmentation_widget.directory = Path(tmp_input_dir)
segmentation_widget.load_brainreg_directory()
# delete manual segmentation data to ensure it's saved correctly in tests
shutil.rmtree(segmentation_widget.paths.main_directory)
return segmentation_widget
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
region,volume_mm3,axis_0_min_um,axis_1_min_um,axis_2_min_um,axis_0_max_um,axis_1_max_um,axis_2_max_um,axis_0_center_um,axis_1_center_um,axis_2_center_um
test_region,1.95,123,29,46,142,65,80,132,46,62
test_region,1.95,6150.0,1450.0,2300.0,7100.0,3250.0,4000.0,6600.0,2329.8173076923076,3141.2339743589746
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from filecmp import cmp
from pathlib import Path
from time import sleep

import numpy as np
import pandas as pd
import pytest
from tifffile import imread

brainreg_dir = Path.cwd() / "tests" / "data" / "brainreg_output"
validate_regions_dir = (
Expand All @@ -11,8 +14,8 @@


@pytest.fixture
def test_regions_dir(tmpdir):
tmp_input_dir = tmpdir / "brainreg_output"
def test_regions_dir(tmp_path):
tmp_input_dir = tmp_path / "brainreg_output"
test_regions_dir = (
tmp_input_dir / "manual_segmentation" / "standard_space" / "regions"
)
Expand Down Expand Up @@ -59,23 +62,57 @@ def test_add_existing_region(
assert len(segmentation_widget_with_data_atlas_space.label_layers) == 2


def test_region_analysis(
def test_region_analysis_without_save(
segmentation_widget_with_data_atlas_space, test_regions_dir
):
segmentation_widget_with_data_atlas_space.region_seg.calculate_volumes_checkbox.setChecked(
True
)
segmentation_widget_with_data_atlas_space.region_seg.summarise_volumes_checkbox.setChecked(
True
)
segmentation_widget_with_data_atlas_space.region_seg.run_region_analysis(
override=True
)
region_csv_validate = pd.read_csv(validate_regions_dir / "test_region.csv")
region_csv_test = pd.read_csv(test_regions_dir / "test_region.csv")
pd.testing.assert_frame_equal(region_csv_test, region_csv_validate)

summary_csv_validate = pd.read_csv(validate_regions_dir / "summary.csv")
summary_csv_test = pd.read_csv(test_regions_dir / "summary.csv")
pd.testing.assert_frame_equal(summary_csv_test, summary_csv_validate)
# ensure data is saved before it is loaded again
sleep(8)
check_analysis(test_regions_dir, validate_regions_dir)

# check saving didn't happen (default)
test_saved_region = Path(test_regions_dir / "test_region.tiff")
assert test_saved_region.exists() is False


def test_region_analysis_with_save(
segmentation_widget_with_data_atlas_space, test_regions_dir
):
segmentation_widget_with_data_atlas_space.region_seg.calculate_volumes_checkbox.setChecked(
True
)
segmentation_widget_with_data_atlas_space.region_seg.summarise_volumes_checkbox.setChecked(
True
)
segmentation_widget_with_data_atlas_space.region_seg.save_checkbox.setChecked(
True
)
segmentation_widget_with_data_atlas_space.region_seg.run_region_analysis(
override=True
)

# ensure data is saved before it is loaded again
sleep(8)
check_analysis(test_regions_dir, validate_regions_dir)
check_saving(test_regions_dir, validate_regions_dir)


def test_region_save(segmentation_widget_with_data_atlas_space):
def test_region_save(
segmentation_widget_with_data_atlas_space, test_regions_dir
):
segmentation_widget_with_data_atlas_space.save(override=True)
# ensure data is saved before it is loaded again
sleep(8)
check_saving(test_regions_dir, validate_regions_dir)


def test_region_export(
Expand All @@ -84,7 +121,26 @@ def test_region_export(
segmentation_widget_with_data_atlas_space.export_to_brainrender(
override=True
)

# ensure data is saved before it is loaded again
sleep(8)
cmp(
validate_regions_dir / "test_region.obj",
test_regions_dir / "test_region.obj",
)


def check_analysis(test_regions_dir, validate_regions_dir):
region_csv_validate = pd.read_csv(validate_regions_dir / "test_region.csv")
region_csv_test = pd.read_csv(test_regions_dir / "test_region.csv")
pd.testing.assert_frame_equal(region_csv_test, region_csv_validate)

summary_csv_validate = pd.read_csv(validate_regions_dir / "summary.csv")
summary_csv_test = pd.read_csv(test_regions_dir / "summary.csv")
pd.testing.assert_frame_equal(summary_csv_test, summary_csv_validate)


def check_saving(test_regions_dir, validate_regions_dir):
image_validate = imread(validate_regions_dir / "test_region.tiff")
image_test = imread(test_regions_dir / "test_region.tiff")
np.testing.assert_array_equal(image_test, image_validate)
Loading

0 comments on commit 4b95042

Please sign in to comment.