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

Add save option on analysis #114

Merged
merged 13 commits into from
Jul 11, 2023
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.
76 changes: 66 additions & 10 deletions tests/tests/test_integration/test_gui/test_regions.py
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(3)
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(3)
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(3)
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(3)
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