[ENH]: Add test for JuniferNiftiSpheresMasker against nilearn's version #136

Merged
synchon merged 8 commits from update/junifer-nifti-spheres-masker into main 2024-06-18 16:16:35 +00:00
4 changed files with 96 additions and 3 deletions

View file

@ -0,0 +1 @@
Add test to be sure that :class:`.JuniferNiftiSpheresMasker` with mean aggregation function behaves exactly as :class:`nilearn.maskers.NiftiSpheresMasker` by `Synchon Mandal`_

View file

@ -4,3 +4,6 @@
# License: AGPL # License: AGPL
from .junifer_nifti_spheres_masker import JuniferNiftiSpheresMasker from .junifer_nifti_spheres_masker import JuniferNiftiSpheresMasker
__all__ = ["JuniferNiftiSpheresMasker"]

View file

@ -29,9 +29,12 @@ if TYPE_CHECKING:
from pandas import DataFrame from pandas import DataFrame
__all__ = ["JuniferNiftiSpheresMasker"]
# New BSD License # New BSD License
# Copyright (c) 2007 - 2022 The nilearn developers. # Copyright (c) The nilearn developers.
# All rights reserved. # All rights reserved.
@ -99,6 +102,17 @@ def _apply_mask_and_get_affinity(
Contains the boolean indices for each sphere. Contains the boolean indices for each sphere.
shape: (number of seeds, number of voxels) shape: (number of seeds, number of voxels)
Raises
------
ValueError
If ``niimg`` and ``mask_img`` are both provided or
if overlap is detected between spheres.
Warns
-----
RuntimeWarning
If the provided images contain NaN, they will be converted to zeroes.
""" """
seeds = list(seeds) seeds = list(seeds)
@ -210,7 +224,7 @@ def _iter_signals_from_spheres(
X, A = _apply_mask_and_get_affinity( X, A = _apply_mask_and_get_affinity(
seeds, niimg, radius, allow_overlap, mask_img=mask_img seeds, niimg, radius, allow_overlap, mask_img=mask_img
) )
for _, row in enumerate(A.rows): for row in A.rows:
yield X[:, row] yield X[:, row]

View file

@ -4,12 +4,14 @@
# License: AGPL # License: AGPL
import warnings import warnings
from typing import List, Tuple
import nibabel import nibabel
import numpy as np import numpy as np
import pytest import pytest
from nilearn._utils import data_gen from nilearn._utils import data_gen
from nilearn.image import get_data from nilearn.image import get_data
from nilearn.maskers import NiftiSpheresMasker
from numpy.testing import assert_array_equal from numpy.testing import assert_array_equal
from junifer.external.nilearn import JuniferNiftiSpheresMasker from junifer.external.nilearn import JuniferNiftiSpheresMasker
@ -17,7 +19,7 @@ from junifer.external.nilearn import JuniferNiftiSpheresMasker
# New BSD License # New BSD License
# Copyright (c) 2007 - 2022 The nilearn developers. # Copyright (c) The nilearn developers.
# All rights reserved. # All rights reserved.
@ -331,3 +333,76 @@ def test_nifti_spheres_masker_io_shapes() -> None:
) )
test_data = masker.transform(img_4d) test_data = masker.transform(img_4d)
assert test_data.shape == (n_volumes, n_regions) assert test_data.shape == (n_volumes, n_regions)
@pytest.mark.parametrize(
"shape",
[
(10, 11, 12),
(10, 11, 12, 5),
],
)
@pytest.mark.parametrize(
"radius, allow_overlap",
[
(2.0, True),
(2.0, False),
(3.0, True),
(4.0, True),
(5.0, True),
],
)
@pytest.mark.parametrize(
"coords",
[
[(1, 1, 1)],
[(1, 1, 1), (4, 4, 4)],
[(1, 1, 1), (4, 4, 4), (10, 10, 10)],
],
)
def test_junifer_and_nilearn_mean_agg_are_equal(
shape: Tuple[int, ...],
radius: float,
allow_overlap: bool,
coords: List[Tuple[int, int, int]],
) -> None:
"""Test junifer's masker behaves same as nilearn's when agg is mean.
Parameters
----------
shape : tuple of int
The parametrized shape of the input image.
radius : float
The parametrized radius of the spheres.
allow_overlap : bool
The parametrized option to overlap spheres or not.
coords : list of tuple of int, int and int
The parametrized seeds.
"""
# Set affine
affine = np.eye(4)
# Generate random image
input_img, mask_img = data_gen.generate_random_img(
shape=shape,
affine=affine,
)
# Compute junifer's version
junifer_masker = JuniferNiftiSpheresMasker(
seeds=coords,
radius=radius,
allow_overlap=allow_overlap,
mask_img=mask_img,
)
junifer_output = junifer_masker.fit_transform(input_img)
# Compute nilearn's version
nilearn_masker = NiftiSpheresMasker(
seeds=coords,
radius=radius,
allow_overlap=allow_overlap,
mask_img=mask_img,
)
nilearn_output = nilearn_masker.fit_transform(input_img)
# Checks
assert junifer_output.shape == nilearn_output.shape
np.testing.assert_almost_equal(junifer_output, nilearn_output)