Coverage for nilearn/maskers/multi_nifti_maps_masker.py: 28%
51 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-20 10:58 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-20 10:58 +0200
1"""Transformer for computing ROI signals of multiple 4D images."""
3import itertools
5from joblib import Parallel, delayed
6from sklearn.utils.estimator_checks import check_is_fitted
8from nilearn._utils import fill_doc
9from nilearn._utils.niimg_conversions import iter_check_niimg
10from nilearn._utils.tags import SKLEARN_LT_1_6
11from nilearn.maskers.base_masker import prepare_confounds_multimaskers
12from nilearn.maskers.nifti_maps_masker import NiftiMapsMasker
13from nilearn.typing import NiimgLike
16@fill_doc
17class MultiNiftiMapsMasker(NiftiMapsMasker):
18 """Class for extracting data from multiple Niimg-like objects \
19 using maps of potentially overlapping brain regions.
21 MultiNiftiMapsMasker is useful when data from overlapping volumes
22 and from different subjects should be extracted (contrary to
23 :class:`nilearn.maskers.NiftiMapsMasker`).
25 Use case:
26 summarize brain signals from several subjects
27 from large-scale networks obtained by prior PCA or :term:`ICA`.
29 .. note::
30 Inf or NaN present in the given input images are automatically
31 put to zero rather than considered as missing data.
33 For more details on the definitions of maps in Nilearn,
34 see the :ref:`region` section.
36 Parameters
37 ----------
38 maps_img : 4D niimg-like object or None, default=None
39 See :ref:`extracting_data`.
40 Set of continuous maps. One representative time course per map is
41 extracted using least square regression.
43 mask_img : 3D niimg-like object, optional
44 See :ref:`extracting_data`.
45 Mask to apply to regions before extracting signals.
47 allow_overlap : :obj:`bool`, default=True
48 If False, an error is raised if the maps overlaps (ie at least two
49 maps have a non-zero value for the same voxel).
50 %(smoothing_fwhm)s
51 %(standardize_maskers)s
52 %(standardize_confounds)s
53 high_variance_confounds : :obj:`bool`, default=False
54 If True, high variance confounds are computed on provided image with
55 :func:`nilearn.image.high_variance_confounds` and default parameters
56 and regressed out.
57 %(detrend)s
58 %(low_pass)s
59 %(high_pass)s
60 %(t_r)s
62 %(dtype)s
64 resampling_target : {"data", "mask", "maps", None}, default="data"
65 Gives which image gives the final shape/size:
67 - "data" means the atlas is resampled to the shape of the data if
68 needed
69 - "mask" means the maps_img and images provided to fit() are
70 resampled to the shape and affine of mask_img
71 - "maps" means the mask_img and images provided to fit() are
72 resampled to the shape and affine of maps_img
73 - None means no resampling: if shapes and affines do not match,
74 a ValueError is raised.
77 %(memory)s
79 %(memory_level)s
81 %(n_jobs)s
83 %(verbose0)s
85 reports : :obj:`bool`, default=True
86 If set to True, data is saved in order to produce a report.
88 %(cmap)s
89 default="CMRmap_r"
90 Only relevant for the report figures.
92 %(clean_args)s
94 %(masker_kwargs)s
96 Attributes
97 ----------
98 maps_img_ : :obj:`nibabel.nifti1.Nifti1Image`
99 The maps mask of the data.
101 %(nifti_mask_img_)s
103 n_elements_ : :obj:`int`
104 The number of overlapping maps in the mask.
105 This is equivalent to the number of volumes in the mask image.
107 .. versionadded:: 0.9.2
109 Notes
110 -----
111 If resampling_target is set to "maps", every 3D image processed by
112 transform() will be resampled to the shape of maps_img. It may lead to a
113 very large memory consumption if the voxel number in maps_img is large.
115 See Also
116 --------
117 nilearn.maskers.NiftiMasker
118 nilearn.maskers.NiftiLabelsMasker
119 nilearn.maskers.NiftiMapsMasker
121 """
123 # memory and memory_level are used by CacheMixin.
125 def __init__(
126 self,
127 maps_img=None,
128 mask_img=None,
129 allow_overlap=True,
130 smoothing_fwhm=None,
131 standardize=False,
132 standardize_confounds=True,
133 high_variance_confounds=False,
134 detrend=False,
135 low_pass=None,
136 high_pass=None,
137 t_r=None,
138 dtype=None,
139 resampling_target="data",
140 memory=None,
141 memory_level=0,
142 verbose=0,
143 reports=True,
144 cmap="CMRmap_r",
145 n_jobs=1,
146 clean_args=None,
147 **kwargs,
148 ):
149 self.n_jobs = n_jobs
150 super().__init__(
151 maps_img,
152 mask_img=mask_img,
153 allow_overlap=allow_overlap,
154 smoothing_fwhm=smoothing_fwhm,
155 standardize=standardize,
156 standardize_confounds=standardize_confounds,
157 high_variance_confounds=high_variance_confounds,
158 detrend=detrend,
159 low_pass=low_pass,
160 high_pass=high_pass,
161 t_r=t_r,
162 dtype=dtype,
163 resampling_target=resampling_target,
164 memory=memory,
165 memory_level=memory_level,
166 verbose=verbose,
167 reports=reports,
168 cmap=cmap,
169 clean_args=clean_args,
170 **kwargs,
171 )
173 def __sklearn_tags__(self):
174 """Return estimator tags.
176 See the sklearn documentation for more details on tags
177 https://scikit-learn.org/1.6/developers/develop.html#estimator-tags
178 """
179 # TODO
180 # get rid of if block
181 # bumping sklearn_version > 1.5
182 if SKLEARN_LT_1_6:
183 from nilearn._utils.tags import tags
185 return tags(masker=True, multi_masker=True)
187 from nilearn._utils.tags import InputTags
189 tags = super().__sklearn_tags__()
190 tags.input_tags = InputTags(masker=True, multi_masker=True)
191 return tags
193 @fill_doc
194 def transform_imgs(
195 self, imgs_list, confounds=None, n_jobs=1, sample_mask=None
196 ):
197 """Extract signals from a list of 4D niimgs.
199 Parameters
200 ----------
201 %(imgs)s
202 Images to process.
204 %(confounds_multi)s
206 %(n_jobs)s
208 %(sample_mask_multi)s
210 Returns
211 -------
212 %(signals_transform_imgs_multi_nifti)s
214 """
215 # We handle the resampling of maps and mask separately because the
216 # affine of the maps and mask images should not impact the extraction
217 # of the signal.
219 check_is_fitted(self)
221 niimg_iter = iter_check_niimg(
222 imgs_list,
223 ensure_ndim=None,
224 atleast_4d=False,
225 memory=self.memory,
226 memory_level=self.memory_level,
227 )
229 confounds = prepare_confounds_multimaskers(self, imgs_list, confounds)
231 if sample_mask is None:
232 sample_mask = itertools.repeat(None, len(imgs_list))
233 elif len(sample_mask) != len(imgs_list):
234 raise ValueError(
235 f"number of sample_mask ({len(sample_mask)}) unequal to "
236 f"number of images ({len(imgs_list)})."
237 )
239 func = self._cache(self.transform_single_imgs)
241 region_signals = Parallel(n_jobs=n_jobs)(
242 delayed(func)(imgs=imgs, confounds=cfs, sample_mask=sms)
243 for imgs, cfs, sms in zip(niimg_iter, confounds, sample_mask)
244 )
245 return region_signals
247 @fill_doc
248 def transform(self, imgs, confounds=None, sample_mask=None):
249 """Apply mask, spatial and temporal preprocessing.
251 Parameters
252 ----------
253 imgs : Niimg-like object, or a :obj:`list` of Niimg-like objects
254 See :ref:`extracting_data`.
255 Data to be preprocessed
257 %(confounds_multi)s
259 %(sample_mask_multi)s
261 Returns
262 -------
263 %(signals_transform_multi_nifti)s
265 """
266 check_is_fitted(self)
268 if not (confounds is None or isinstance(confounds, list)):
269 raise TypeError(
270 "'confounds' must be a None or a list. "
271 f"Got {confounds.__class__.__name__}."
272 )
273 if not (sample_mask is None or isinstance(sample_mask, list)):
274 raise TypeError(
275 "'sample_mask' must be a None or a list. "
276 f"Got {sample_mask.__class__.__name__}."
277 )
278 if isinstance(imgs, NiimgLike):
279 if isinstance(confounds, list):
280 confounds = confounds[0]
281 if isinstance(sample_mask, list):
282 sample_mask = sample_mask[0]
283 return super().transform(
284 imgs, confounds=confounds, sample_mask=sample_mask
285 )
287 return self.transform_imgs(
288 imgs,
289 confounds=confounds,
290 sample_mask=sample_mask,
291 n_jobs=self.n_jobs,
292 )
294 @fill_doc
295 def fit_transform(self, imgs, y=None, confounds=None, sample_mask=None):
296 """
297 Fit to data, then transform it.
299 Parameters
300 ----------
301 imgs : Niimg-like object, or a :obj:`list` of Niimg-like objects
302 See :ref:`extracting_data`.
303 Data to be preprocessed
305 y : None
306 This parameter is unused. It is solely included for scikit-learn
307 compatibility.
309 %(confounds_multi)s
311 %(sample_mask_multi)s
313 .. versionadded:: 0.8.0
315 Returns
316 -------
317 %(signals_transform_multi_nifti)s
318 """
319 return self.fit(imgs, y=y).transform(
320 imgs, confounds=confounds, sample_mask=sample_mask
321 )