Skip to content

Commit

Permalink
add two simple additional validation functions (#261)
Browse files Browse the repository at this point in the history
* add two simple additional validation functions

* add tests for reference/annotation comparison

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* improve error message

Co-authored-by: Vasco Schiavo <[email protected]>

* make linter happy

* adapt test accordingly

* revert to assertion error

for consistency with other validation functions.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* add tests for additional reference validation

* fix test failure due to typo

* document tests

* Apply suggestions from code review

Co-authored-by: Will Graham <[email protected]>

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Vasco Schiavo <[email protected]>
Co-authored-by: Will Graham <[email protected]>
  • Loading branch information
4 people authored Apr 8, 2024
1 parent b59b534 commit 53795e2
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 4 deletions.
36 changes: 32 additions & 4 deletions brainglobe_atlasapi/atlas_generation/validate_atlases.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,36 @@ def validate_checksum(atlas: BrainGlobeAtlas):
pass


def check_additional_references(atlas: BrainGlobeAtlas):
# check additional references are different, but have same dimensions
pass
def validate_image_dimensions(atlas: BrainGlobeAtlas):
"""
Check that annotation and reference image have the same dimensions.
"""
assert atlas.annotation.shape == atlas.reference.shape, (
"Annotation and reference image have different dimensions. \n"
f"Annotation image has dimension: {atlas.annotation.shape}, "
f"while reference image has dimension {atlas.reference.shape}."
)
return True


def validate_additional_references(atlas: BrainGlobeAtlas):
"""
Check that additional references are different, but have same dimensions.
"""
for (
additional_reference_name
) in atlas.additional_references.references_list:
additional_reference = atlas.additional_references[
additional_reference_name
]
assert additional_reference.shape == atlas.reference.shape, (
f"Additional reference {additional_reference} "
"has unexpected dimension."
)
assert not np.all(
additional_reference == atlas.reference
), "Additional reference is not different to main reference."
return True


def catch_missing_mesh_files(atlas: BrainGlobeAtlas):
Expand Down Expand Up @@ -211,7 +238,8 @@ def validate_atlas(atlas_name, version, validation_functions):
validate_mesh_matches_image_extents,
open_for_visual_check,
validate_checksum,
check_additional_references,
validate_image_dimensions,
validate_additional_references,
catch_missing_mesh_files,
catch_missing_structures,
]
Expand Down
112 changes: 112 additions & 0 deletions tests/atlasgen/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

import numpy as np
import pytest
import tifffile

from brainglobe_atlasapi import BrainGlobeAtlas
from brainglobe_atlasapi.atlas_generation.validate_atlases import (
_assert_close,
catch_missing_mesh_files,
catch_missing_structures,
validate_additional_references,
validate_atlas_files,
validate_image_dimensions,
validate_mesh_matches_image_extents,
)
from brainglobe_atlasapi.config import get_brainglobe_dir
from brainglobe_atlasapi.core import AdditionalRefDict


@pytest.fixture
Expand All @@ -36,6 +40,27 @@ def atlas_with_bad_reference_file():
os.rename(bad_name, good_name)


@pytest.fixture
def atlas_with_bad_reference_tiff_content():
"""A fixture providing an invalid version of Allen Mouse atlas for testing.
The atlas will have a misnamed template file that won't be found by the API
This fixture cleans up the invalid atlas after the test has run.
"""
BrainGlobeAtlas("allen_mouse_100um") # ensure atlas is locally downloaded
actual_name = (
get_brainglobe_dir() / "allen_mouse_100um_v1.2/reference.tiff"
)
backup_name = (
get_brainglobe_dir() / "allen_mouse_100um_v1.2/reference_backup.tiff"
)
os.rename(actual_name, backup_name)
too_small_reference = np.ones((3, 3, 3), dtype=np.uint16)
tifffile.imwrite(actual_name, too_small_reference)
yield BrainGlobeAtlas("allen_mouse_100um")
os.remove(actual_name)
os.rename(backup_name, actual_name)


@pytest.fixture
def atlas_with_missing_structure():
atlas = BrainGlobeAtlas("osten_mouse_100um")
Expand All @@ -47,6 +72,54 @@ def atlas_with_missing_structure():
return modified_atlas


@pytest.fixture
def atlas_with_valid_additional_reference():
"""A fixture providing a testing-only version of the Allen Mouse atlas.
The instance of the atlas returned has an additional reference
consisting of an array of 1, of the correct size.
This fixture cleans up the invalid atlas after the test has run.
"""
allen_100 = BrainGlobeAtlas(
"allen_mouse_100um"
) # ensure atlas is locally downloaded
additional_reference_name = (
get_brainglobe_dir()
/ "allen_mouse_100um_v1.2/mock_additional_reference.tiff"
)
additional_reference = np.ones(allen_100.reference.shape, dtype=np.uint16)
allen_100.additional_references = AdditionalRefDict(
["mock_additional_reference"],
data_path=get_brainglobe_dir() / "allen_mouse_100um_v1.2",
)
tifffile.imwrite(additional_reference_name, additional_reference)
yield allen_100
os.remove(additional_reference_name)


@pytest.fixture
def atlas_with_reference_matching_additional_reference():
"""A fixture providing an invalid version of Allen Mouse atlas for testing.
It provides the atlas, with an additional reference containing
the same data as the main reference image.
This fixture cleans up the invalid atlas after the test has run.
"""
allen_100 = BrainGlobeAtlas(
"allen_mouse_100um"
) # ensure atlas is locally downloaded
additional_reference_name = (
get_brainglobe_dir()
/ "allen_mouse_100um_v1.2/mock_additional_reference.tiff"
)
additional_reference = allen_100.reference
allen_100.additional_references = AdditionalRefDict(
["mock_additional_reference"],
data_path=get_brainglobe_dir() / "allen_mouse_100um_v1.2",
)
tifffile.imwrite(additional_reference_name, additional_reference)
yield allen_100
os.remove(additional_reference_name)


def test_validate_mesh_matches_image_extents(atlas):
assert validate_mesh_matches_image_extents(atlas)

Expand Down Expand Up @@ -121,3 +194,42 @@ def test_catch_missing_structures(atlas_with_missing_structure):
"but are not accessible through the atlas.",
):
catch_missing_structures(atlas_with_missing_structure)


def test_atlas_image_dimensions_match(atlas):
"""Check the atlas passes the annotation-reference dimension validation"""
assert validate_image_dimensions(atlas)


def test_atlas_image_dimensions_match_negative(
atlas_with_bad_reference_tiff_content,
):
"""Checks that an atlas with different annotation and reference
dimensions is flagged by the validation."""
with pytest.raises(
AssertionError,
match=r"Annotation and reference image have different dimensions.*",
):
validate_image_dimensions(atlas_with_bad_reference_tiff_content)


def test_atlas_additional_reference_different(
atlas_with_valid_additional_reference,
):
"""Checks that an atlas with a reasonably sized additional reference
passes its validation."""
validate_additional_references(atlas_with_valid_additional_reference)


def test_atlas_additional_reference_same(
atlas_with_reference_matching_additional_reference,
):
"""Checks that an atlas with a rduplicate additional reference
fails the validation for this case."""
with pytest.raises(
AssertionError,
match=r"Additional reference is not different to main reference.",
):
validate_additional_references(
atlas_with_reference_matching_additional_reference
)

0 comments on commit 53795e2

Please sign in to comment.