junifer 0.0.7.dev95__py3-none-any.whl → 0.0.7.dev105__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
junifer/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.0.7.dev95'
21
- __version_tuple__ = version_tuple = (0, 0, 7, 'dev95')
20
+ __version__ = version = '0.0.7.dev105'
21
+ __version_tuple__ = version_tuple = (0, 0, 7, 'dev105')
@@ -76,6 +76,7 @@ class PipelineComponentRegistry(metaclass=Singleton):
76
76
  "SpaceWarper": "SpaceWarper",
77
77
  "fMRIPrepConfoundRemover": "fMRIPrepConfoundRemover",
78
78
  "TemporalSlicer": "TemporalSlicer",
79
+ "TemporalFilter": "TemporalFilter",
79
80
  },
80
81
  "marker": {
81
82
  "ALFFParcels": "ALFFParcels",
@@ -4,6 +4,7 @@ __all__ = [
4
4
  "SpaceWarper",
5
5
  "Smoothing",
6
6
  "TemporalSlicer",
7
+ "TemporalFilter",
7
8
  ]
8
9
 
9
10
  from .base import BasePreprocessor
@@ -11,3 +12,4 @@ from .confounds import fMRIPrepConfoundRemover
11
12
  from .warping import SpaceWarper
12
13
  from .smoothing import Smoothing
13
14
  from ._temporal_slicer import TemporalSlicer
15
+ from ._temporal_filter import TemporalFilter
@@ -0,0 +1,240 @@
1
+ """Provide class for temporal filtering."""
2
+
3
+ # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
+ # Leonard Sasse <l.sasse@fz-juelich.de>
5
+ # Synchon Mandal <s.mandal@fz-juelich.de>
6
+ # License: AGPL
7
+
8
+ from typing import (
9
+ Any,
10
+ ClassVar,
11
+ Optional,
12
+ Union,
13
+ )
14
+
15
+ import nibabel as nib
16
+ from nilearn import image as nimg
17
+ from nilearn._utils.niimg_conversions import check_niimg_4d
18
+
19
+ from ..api.decorators import register_preprocessor
20
+ from ..data import get_data
21
+ from ..pipeline import WorkDirManager
22
+ from ..typing import Dependencies
23
+ from ..utils import logger
24
+ from .base import BasePreprocessor
25
+
26
+
27
+ __all__ = ["TemporalFilter"]
28
+
29
+
30
+ @register_preprocessor
31
+ class TemporalFilter(BasePreprocessor):
32
+ """Class for temporal filtering.
33
+
34
+ Temporal filtering is based on :func:`nilearn.image.clean_img`.
35
+
36
+ Parameters
37
+ ----------
38
+ detrend : bool, optional
39
+ If True, detrending will be applied on timeseries (default True).
40
+ standardize : bool, optional
41
+ If True, returned signals are set to unit variance (default True).
42
+ low_pass : float, optional
43
+ Low cutoff frequencies, in Hertz. If None, no filtering is applied
44
+ (default None).
45
+ high_pass : float, optional
46
+ High cutoff frequencies, in Hertz. If None, no filtering is
47
+ applied (default None).
48
+ t_r : float, optional
49
+ Repetition time, in second (sampling period).
50
+ If None, it will use t_r from nifti header (default None).
51
+ masks : str, dict or list of dict or str, optional
52
+ The specification of the masks to apply to regions before extracting
53
+ signals. Check :ref:`Using Masks <using_masks>` for more details.
54
+ If None, will not apply any mask (default None).
55
+
56
+ """
57
+
58
+ _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nilearn"}
59
+
60
+ def __init__(
61
+ self,
62
+ detrend: bool = True,
63
+ standardize: bool = True,
64
+ low_pass: Optional[float] = None,
65
+ high_pass: Optional[float] = None,
66
+ t_r: Optional[float] = None,
67
+ masks: Union[str, dict, list[Union[dict, str]], None] = None,
68
+ ) -> None:
69
+ """Initialize the class."""
70
+ self.detrend = detrend
71
+ self.standardize = standardize
72
+ self.low_pass = low_pass
73
+ self.high_pass = high_pass
74
+ self.t_r = t_r
75
+ self.masks = masks
76
+
77
+ super().__init__(on="BOLD", required_data_types=["BOLD"])
78
+
79
+ def get_valid_inputs(self) -> list[str]:
80
+ """Get valid data types for input.
81
+
82
+ Returns
83
+ -------
84
+ list of str
85
+ The list of data types that can be used as input for this
86
+ preprocessor.
87
+
88
+ """
89
+ return ["BOLD"]
90
+
91
+ def get_output_type(self, input_type: str) -> str:
92
+ """Get output type.
93
+
94
+ Parameters
95
+ ----------
96
+ input_type : str
97
+ The input to the preprocessor.
98
+
99
+ Returns
100
+ -------
101
+ str
102
+ The data type output by the preprocessor.
103
+
104
+ """
105
+ # Does not add any new keys
106
+ return input_type
107
+
108
+ def _validate_data(
109
+ self,
110
+ input: dict[str, Any],
111
+ ) -> None:
112
+ """Validate input data.
113
+
114
+ Parameters
115
+ ----------
116
+ input : dict
117
+ Dictionary containing the ``BOLD`` data from the
118
+ Junifer Data object.
119
+
120
+ Raises
121
+ ------
122
+ ValueError
123
+ If ``"data"`` is not 4D
124
+
125
+ """
126
+ # BOLD must be 4D niimg
127
+ check_niimg_4d(input["data"])
128
+
129
+ def preprocess(
130
+ self,
131
+ input: dict[str, Any],
132
+ extra_input: Optional[dict[str, Any]] = None,
133
+ ) -> tuple[dict[str, Any], Optional[dict[str, dict[str, Any]]]]:
134
+ """Preprocess.
135
+
136
+ Parameters
137
+ ----------
138
+ input : dict
139
+ A single input from the Junifer Data object to preprocess.
140
+ extra_input : dict, optional
141
+ The other fields in the Junifer Data object.
142
+
143
+ Returns
144
+ -------
145
+ dict
146
+ The computed result as dictionary. If `self.masks` is not None,
147
+ then the target data computed mask is updated for further steps.
148
+ None
149
+ Extra "helper" data types as dictionary to add to the Junifer Data
150
+ object.
151
+
152
+ """
153
+ # Validate data
154
+ self._validate_data(input)
155
+
156
+ # Get BOLD data
157
+ bold_img = input["data"]
158
+ # Set t_r
159
+ t_r = self.t_r
160
+ if t_r is None:
161
+ logger.info("No `t_r` specified, using t_r from NIfTI header")
162
+ t_r = bold_img.header.get_zooms()[3] # type: ignore
163
+ logger.info(
164
+ f"Read t_r from NIfTI header: {t_r}",
165
+ )
166
+
167
+ # Create element-specific tempdir for storing generated data
168
+ # and / or mask
169
+ element_tempdir = WorkDirManager().get_element_tempdir(
170
+ prefix="temporal_filter"
171
+ )
172
+
173
+ # Set mask data
174
+ mask_img = None
175
+ if self.masks is not None:
176
+ # Generate mask
177
+ logger.debug(f"Masking with {self.masks}")
178
+ mask_img = get_data(
179
+ kind="mask",
180
+ names=self.masks,
181
+ target_data=input,
182
+ extra_input=extra_input,
183
+ )
184
+ # Save generated mask for use later
185
+ generated_mask_img_path = element_tempdir / "generated_mask.nii.gz"
186
+ nib.save(mask_img, generated_mask_img_path)
187
+
188
+ # Save BOLD mask and link it to the BOLD data type dict;
189
+ # this allows to use "inherit" down the pipeline
190
+ logger.debug("Setting `BOLD.mask`")
191
+ input.update(
192
+ {
193
+ "mask": {
194
+ # Update path to sync with "data"
195
+ "path": generated_mask_img_path,
196
+ # Update data
197
+ "data": mask_img,
198
+ # Should be in the same space as target data
199
+ "space": input["space"],
200
+ }
201
+ }
202
+ )
203
+
204
+ signal_clean_kwargs = {}
205
+
206
+ # Clean image
207
+ logger.info("Temporal filter image using nilearn")
208
+ logger.debug(f"\tdetrend: {self.detrend}")
209
+ logger.debug(f"\tstandardize: {self.standardize}")
210
+ logger.debug(f"\tlow_pass: {self.low_pass}")
211
+ logger.debug(f"\thigh_pass: {self.high_pass}")
212
+ logger.debug(f"\tt_r: {self.t_r}")
213
+
214
+ cleaned_img = nimg.clean_img(
215
+ imgs=bold_img,
216
+ detrend=self.detrend,
217
+ standardize=self.standardize,
218
+ low_pass=self.low_pass,
219
+ high_pass=self.high_pass,
220
+ t_r=t_r,
221
+ mask_img=mask_img,
222
+ **signal_clean_kwargs,
223
+ )
224
+ # Fix t_r as nilearn messes it up
225
+ cleaned_img.header["pixdim"][4] = t_r
226
+ # Save filtered data
227
+ filtered_data_path = element_tempdir / "filtered_data.nii.gz"
228
+ nib.save(cleaned_img, filtered_data_path)
229
+
230
+ logger.debug("Updating `BOLD`")
231
+ input.update(
232
+ {
233
+ # Update path to sync with "data"
234
+ "path": filtered_data_path,
235
+ # Update data
236
+ "data": cleaned_img,
237
+ }
238
+ )
239
+
240
+ return input, None
@@ -0,0 +1,99 @@
1
+ """Provide tests for TemporalFilter."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from typing import Optional
7
+
8
+ import pytest
9
+
10
+ from junifer.datareader import DefaultDataReader
11
+ from junifer.preprocess import TemporalFilter
12
+ from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
13
+
14
+
15
+ @pytest.mark.parametrize(
16
+ "detrend, standardize, low_pass, high_pass, t_r, masks",
17
+ (
18
+ [
19
+ True,
20
+ True,
21
+ None,
22
+ None,
23
+ None,
24
+ None,
25
+ ],
26
+ [
27
+ False,
28
+ True,
29
+ 0.1,
30
+ None,
31
+ None,
32
+ "compute_brain_mask",
33
+ ],
34
+ [
35
+ True,
36
+ False,
37
+ None,
38
+ 0.08,
39
+ None,
40
+ "compute_background_mask",
41
+ ],
42
+ [
43
+ False,
44
+ False,
45
+ None,
46
+ None,
47
+ 2,
48
+ None,
49
+ ],
50
+ [
51
+ True,
52
+ True,
53
+ 0.1,
54
+ 0.08,
55
+ 2,
56
+ "compute_brain_mask",
57
+ ],
58
+ ),
59
+ )
60
+ def test_TemporalFilter(
61
+ detrend: bool,
62
+ standardize: bool,
63
+ low_pass: Optional[float],
64
+ high_pass: Optional[float],
65
+ t_r: Optional[float],
66
+ masks: Optional[str],
67
+ ) -> None:
68
+ """Test TemporalFilter.
69
+
70
+ Parameters
71
+ ----------
72
+ detrend : bool
73
+ The parametrized detrending flag.
74
+ standardize : bool
75
+ The parametrized standardization flag.
76
+ low_pass : float or None
77
+ The parametrized low pass value.
78
+ high_pass : float or None
79
+ The parametrized high pass value.
80
+ t_r : float or None
81
+ The parametrized repetition time.
82
+ masks : str or None
83
+ The parametrized mask.
84
+
85
+ """
86
+ with PartlyCloudyTestingDataGrabber() as dg:
87
+ # Read data
88
+ element_data = DefaultDataReader().fit_transform(dg["sub-01"])
89
+ # Preprocess data
90
+ output = TemporalFilter(
91
+ detrend=detrend,
92
+ standardize=standardize,
93
+ low_pass=low_pass,
94
+ high_pass=high_pass,
95
+ t_r=t_r,
96
+ masks=masks,
97
+ ).fit_transform(element_data)
98
+
99
+ assert isinstance(output, dict)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: junifer
3
- Version: 0.0.7.dev95
3
+ Version: 0.0.7.dev105
4
4
  Summary: JUelich NeuroImaging FEature extractoR
5
5
  Author-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
6
6
  Maintainer-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
@@ -1,6 +1,6 @@
1
1
  junifer/__init__.py,sha256=2McgH1yNue6Z1V26-uN_mfMjbTcx4CLhym-DMBl5xA4,266
2
2
  junifer/__init__.pyi,sha256=SsTvgq2Dod6UqJN96GH1lCphH6hJQQurEJHGNhHjGUI,508
3
- junifer/_version.py,sha256=engVxAmzTt-PVcgI0gU2Xna6ChVkV4BLs_yEYh5R5MM,526
3
+ junifer/_version.py,sha256=jFH3nrzs5AspealBCIydRQVFvENTPE2XjxPHECcRoME,528
4
4
  junifer/conftest.py,sha256=PWYkkRDU8ly2lYwv7VBKMHje4et6HX7Yey3Md_I2KbA,613
5
5
  junifer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  junifer/stats.py,sha256=e9aaagMGtgpRfW3Wdpz9ocpnYld1IWylCDcjFUgX9Mk,6225
@@ -242,7 +242,7 @@ junifer/onthefly/tests/test_read_transform.py,sha256=Ed6gtj8bsD11fe0Y1AxG2JndtIT
242
242
  junifer/pipeline/__init__.py,sha256=rxKQGRwc6_sts1KhVIcVVpuXeiFABf11mQQ2h5jgA3U,194
243
243
  junifer/pipeline/__init__.pyi,sha256=hhcvNcABhtLaUQiZdTjo5sMWC3rtDkwVshL0sxD5JAE,399
244
244
  junifer/pipeline/marker_collection.py,sha256=1Kmf5f0E2MFhDpO9OBui046b_6h1u9U64AdEqrxso-o,5377
245
- junifer/pipeline/pipeline_component_registry.py,sha256=zSbIeubzvXFhv_CIQaAsGy_fFrGs43EJeerQUtr1TlA,9465
245
+ junifer/pipeline/pipeline_component_registry.py,sha256=N80XfOZB33tscuqUlrri0r8sMUGVkPL6Li01Of70qrA,9517
246
246
  junifer/pipeline/pipeline_step_mixin.py,sha256=oXfJh27yifHs1V3V_tMPCanRiHX1ggOVIbHTvMzq3cY,7853
247
247
  junifer/pipeline/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
248
248
  junifer/pipeline/update_meta_mixin.py,sha256=yzGCx8AUbc9mMnWKRu4qaIXTBBSIxtNlGH5zIQIUvzM,1812
@@ -254,7 +254,8 @@ junifer/pipeline/tests/test_pipeline_step_mixin.py,sha256=KCdhFdThm9TGkUvhGzQF3z
254
254
  junifer/pipeline/tests/test_update_meta_mixin.py,sha256=po7mWGmXCkZUi201zqgtTm7-A1HKjBgUgqMglMvedqc,1338
255
255
  junifer/pipeline/tests/test_workdir_manager.py,sha256=_rXlGb_PUQJBVgV1PWmwjFvTW971MkEbyDDY9dLfJAY,4051
256
256
  junifer/preprocess/__init__.py,sha256=91D43p254il88g-7sSN64M7HsCvwytYoiTS_GLEr37Y,342
257
- junifer/preprocess/__init__.pyi,sha256=77mlHjZXhHOsWd37deAq6d0PIdoCeme4cPGC8jk3Fmw,321
257
+ junifer/preprocess/__init__.pyi,sha256=TM84ia0HAOO9Tt7yTnZVRa1PTE6-F6pnHXcM0ijqVe4,388
258
+ junifer/preprocess/_temporal_filter.py,sha256=_tvoCvTBOD7WgeaoR9RqxltfKD_vLQBKPTFYxsFzf2s,7241
258
259
  junifer/preprocess/_temporal_slicer.py,sha256=clZdDwGZrw656JYuK5eVvml54WxNVCQ2EOTbnsHhwnQ,7160
259
260
  junifer/preprocess/base.py,sha256=hARO4Yq9sQ8m2tATeuBmPMbI4BSnwNxLf2prF8Iq_Tk,6662
260
261
  junifer/preprocess/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -272,6 +273,7 @@ junifer/preprocess/smoothing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
272
273
  junifer/preprocess/smoothing/smoothing.py,sha256=wdOnPi8XkEqzOQdUNJ0yOm_uWi3H4DnTQhOL8z7dZDs,5281
273
274
  junifer/preprocess/smoothing/tests/test_smoothing.py,sha256=IYL-IaRYIuhOU7jGixgNuT-ed_i6q9gmDhK-ZpXAGeU,2389
274
275
  junifer/preprocess/tests/test_preprocess_base.py,sha256=-0rpe8QjqYES36H6MHuDs3cv_6upHBdVHnFMgQsmEX4,2571
276
+ junifer/preprocess/tests/test_temporal_filter.py,sha256=ZgEDIGqpFX3dGGKOJAf1vhvg2Q4xWR1aP6MADuPUdro,2227
275
277
  junifer/preprocess/tests/test_temporal_slicer.py,sha256=bbt6kxOM-Bv_s9iPn4wrf2YxpA64xO2S0kgRYUEeBNo,4061
276
278
  junifer/preprocess/warping/__init__.py,sha256=rzUUP7-6H_nygQ7a7TBZ4_RY7p0ELacosYsWQbSdVZk,214
277
279
  junifer/preprocess/warping/__init__.pyi,sha256=Drbqp8N3uprvXcKSxqdfj90fesz9XYVLgivhPnKAYcc,65
@@ -322,10 +324,10 @@ junifer/utils/tests/test_config.py,sha256=7ltIXuwb_W4Mv_1dxQWyiyM10XgUAfsWKV6D_i
322
324
  junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
323
325
  junifer/utils/tests/test_helpers.py,sha256=k5qqfxK8dFyuewTJyR1Qn6-nFaYNuVr0ysc18bfPjyU,929
324
326
  junifer/utils/tests/test_logging.py,sha256=W4tFKmaf8_CxnWZ-o_-XxM7DQbhGG18RsLZJk8bZelI,8163
325
- junifer-0.0.7.dev95.dist-info/licenses/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
326
- junifer-0.0.7.dev95.dist-info/licenses/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
327
- junifer-0.0.7.dev95.dist-info/METADATA,sha256=ldts4m1p0zPk8UArf0VD6dxgbByhI6BIjddw_wkIU8c,8387
328
- junifer-0.0.7.dev95.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
329
- junifer-0.0.7.dev95.dist-info/entry_points.txt,sha256=6O8ru0BP-SP7YMUZiizFNoaZ2HvJpadO2G7nKk4PwjI,48
330
- junifer-0.0.7.dev95.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
331
- junifer-0.0.7.dev95.dist-info/RECORD,,
327
+ junifer-0.0.7.dev105.dist-info/licenses/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
328
+ junifer-0.0.7.dev105.dist-info/licenses/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
329
+ junifer-0.0.7.dev105.dist-info/METADATA,sha256=y9qwZWakS8Oc_XurJ3dN1hQ-ndxPyy5BdikbsZsaIG8,8388
330
+ junifer-0.0.7.dev105.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
331
+ junifer-0.0.7.dev105.dist-info/entry_points.txt,sha256=6O8ru0BP-SP7YMUZiizFNoaZ2HvJpadO2G7nKk4PwjI,48
332
+ junifer-0.0.7.dev105.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
333
+ junifer-0.0.7.dev105.dist-info/RECORD,,