junifer 0.0.3.dev186__py3-none-any.whl → 0.0.4__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.
Files changed (178) hide show
  1. junifer/_version.py +14 -2
  2. junifer/api/cli.py +162 -17
  3. junifer/api/functions.py +87 -419
  4. junifer/api/parser.py +24 -0
  5. junifer/api/queue_context/__init__.py +8 -0
  6. junifer/api/queue_context/gnu_parallel_local_adapter.py +258 -0
  7. junifer/api/queue_context/htcondor_adapter.py +365 -0
  8. junifer/api/queue_context/queue_context_adapter.py +60 -0
  9. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +192 -0
  10. junifer/api/queue_context/tests/test_htcondor_adapter.py +257 -0
  11. junifer/api/res/afni/run_afni_docker.sh +6 -6
  12. junifer/api/res/ants/ResampleImage +3 -0
  13. junifer/api/res/ants/antsApplyTransforms +3 -0
  14. junifer/api/res/ants/antsApplyTransformsToPoints +3 -0
  15. junifer/api/res/ants/run_ants_docker.sh +39 -0
  16. junifer/api/res/fsl/applywarp +3 -0
  17. junifer/api/res/fsl/flirt +3 -0
  18. junifer/api/res/fsl/img2imgcoord +3 -0
  19. junifer/api/res/fsl/run_fsl_docker.sh +39 -0
  20. junifer/api/res/fsl/std2imgcoord +3 -0
  21. junifer/api/res/run_conda.sh +4 -4
  22. junifer/api/res/run_venv.sh +22 -0
  23. junifer/api/tests/data/partly_cloudy_agg_mean_tian.yml +16 -0
  24. junifer/api/tests/test_api_utils.py +21 -3
  25. junifer/api/tests/test_cli.py +232 -9
  26. junifer/api/tests/test_functions.py +211 -439
  27. junifer/api/tests/test_parser.py +1 -1
  28. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +6 -1
  29. junifer/configs/juseless/datagrabbers/camcan_vbm.py +6 -1
  30. junifer/configs/juseless/datagrabbers/ixi_vbm.py +6 -1
  31. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +8 -8
  32. junifer/configs/juseless/datagrabbers/ucla.py +44 -26
  33. junifer/configs/juseless/datagrabbers/ukb_vbm.py +6 -1
  34. junifer/data/VOIs/meta/AutobiographicalMemory_VOIs.txt +23 -0
  35. junifer/data/VOIs/meta/Power2013_MNI_VOIs.tsv +264 -0
  36. junifer/data/__init__.py +4 -0
  37. junifer/data/coordinates.py +298 -31
  38. junifer/data/masks.py +360 -28
  39. junifer/data/parcellations.py +621 -188
  40. junifer/data/template_spaces.py +190 -0
  41. junifer/data/tests/test_coordinates.py +34 -3
  42. junifer/data/tests/test_data_utils.py +1 -0
  43. junifer/data/tests/test_masks.py +202 -86
  44. junifer/data/tests/test_parcellations.py +266 -55
  45. junifer/data/tests/test_template_spaces.py +104 -0
  46. junifer/data/utils.py +4 -2
  47. junifer/datagrabber/__init__.py +1 -0
  48. junifer/datagrabber/aomic/id1000.py +111 -70
  49. junifer/datagrabber/aomic/piop1.py +116 -53
  50. junifer/datagrabber/aomic/piop2.py +116 -53
  51. junifer/datagrabber/aomic/tests/test_id1000.py +27 -27
  52. junifer/datagrabber/aomic/tests/test_piop1.py +27 -27
  53. junifer/datagrabber/aomic/tests/test_piop2.py +27 -27
  54. junifer/datagrabber/base.py +62 -10
  55. junifer/datagrabber/datalad_base.py +0 -2
  56. junifer/datagrabber/dmcc13_benchmark.py +372 -0
  57. junifer/datagrabber/hcp1200/datalad_hcp1200.py +5 -0
  58. junifer/datagrabber/hcp1200/hcp1200.py +30 -13
  59. junifer/datagrabber/pattern.py +133 -27
  60. junifer/datagrabber/pattern_datalad.py +111 -13
  61. junifer/datagrabber/tests/test_base.py +57 -6
  62. junifer/datagrabber/tests/test_datagrabber_utils.py +204 -76
  63. junifer/datagrabber/tests/test_datalad_base.py +0 -6
  64. junifer/datagrabber/tests/test_dmcc13_benchmark.py +256 -0
  65. junifer/datagrabber/tests/test_multiple.py +43 -10
  66. junifer/datagrabber/tests/test_pattern.py +125 -178
  67. junifer/datagrabber/tests/test_pattern_datalad.py +44 -25
  68. junifer/datagrabber/utils.py +151 -16
  69. junifer/datareader/default.py +36 -10
  70. junifer/external/nilearn/junifer_nifti_spheres_masker.py +6 -0
  71. junifer/markers/base.py +25 -16
  72. junifer/markers/collection.py +35 -16
  73. junifer/markers/complexity/__init__.py +27 -0
  74. junifer/markers/complexity/complexity_base.py +149 -0
  75. junifer/markers/complexity/hurst_exponent.py +136 -0
  76. junifer/markers/complexity/multiscale_entropy_auc.py +140 -0
  77. junifer/markers/complexity/perm_entropy.py +132 -0
  78. junifer/markers/complexity/range_entropy.py +136 -0
  79. junifer/markers/complexity/range_entropy_auc.py +145 -0
  80. junifer/markers/complexity/sample_entropy.py +134 -0
  81. junifer/markers/complexity/tests/test_complexity_base.py +19 -0
  82. junifer/markers/complexity/tests/test_hurst_exponent.py +69 -0
  83. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +68 -0
  84. junifer/markers/complexity/tests/test_perm_entropy.py +68 -0
  85. junifer/markers/complexity/tests/test_range_entropy.py +69 -0
  86. junifer/markers/complexity/tests/test_range_entropy_auc.py +69 -0
  87. junifer/markers/complexity/tests/test_sample_entropy.py +68 -0
  88. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +68 -0
  89. junifer/markers/complexity/weighted_perm_entropy.py +133 -0
  90. junifer/markers/falff/_afni_falff.py +153 -0
  91. junifer/markers/falff/_junifer_falff.py +142 -0
  92. junifer/markers/falff/falff_base.py +91 -84
  93. junifer/markers/falff/falff_parcels.py +61 -45
  94. junifer/markers/falff/falff_spheres.py +64 -48
  95. junifer/markers/falff/tests/test_falff_parcels.py +89 -121
  96. junifer/markers/falff/tests/test_falff_spheres.py +92 -127
  97. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +1 -0
  98. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +1 -0
  99. junifer/markers/functional_connectivity/functional_connectivity_base.py +1 -0
  100. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +46 -44
  101. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +34 -39
  102. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +40 -52
  103. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +62 -70
  104. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +99 -85
  105. junifer/markers/parcel_aggregation.py +60 -38
  106. junifer/markers/reho/_afni_reho.py +192 -0
  107. junifer/markers/reho/_junifer_reho.py +281 -0
  108. junifer/markers/reho/reho_base.py +69 -34
  109. junifer/markers/reho/reho_parcels.py +26 -16
  110. junifer/markers/reho/reho_spheres.py +23 -9
  111. junifer/markers/reho/tests/test_reho_parcels.py +93 -92
  112. junifer/markers/reho/tests/test_reho_spheres.py +88 -86
  113. junifer/markers/sphere_aggregation.py +54 -9
  114. junifer/markers/temporal_snr/temporal_snr_base.py +1 -0
  115. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +38 -37
  116. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +34 -38
  117. junifer/markers/tests/test_collection.py +43 -42
  118. junifer/markers/tests/test_ets_rss.py +29 -37
  119. junifer/markers/tests/test_parcel_aggregation.py +587 -468
  120. junifer/markers/tests/test_sphere_aggregation.py +209 -157
  121. junifer/markers/utils.py +2 -40
  122. junifer/onthefly/read_transform.py +13 -6
  123. junifer/pipeline/__init__.py +1 -0
  124. junifer/pipeline/pipeline_step_mixin.py +105 -41
  125. junifer/pipeline/registry.py +17 -0
  126. junifer/pipeline/singleton.py +45 -0
  127. junifer/pipeline/tests/test_pipeline_step_mixin.py +139 -51
  128. junifer/pipeline/tests/test_update_meta_mixin.py +1 -0
  129. junifer/pipeline/tests/test_workdir_manager.py +104 -0
  130. junifer/pipeline/update_meta_mixin.py +8 -2
  131. junifer/pipeline/utils.py +154 -15
  132. junifer/pipeline/workdir_manager.py +246 -0
  133. junifer/preprocess/__init__.py +3 -0
  134. junifer/preprocess/ants/__init__.py +4 -0
  135. junifer/preprocess/ants/ants_apply_transforms_warper.py +185 -0
  136. junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +56 -0
  137. junifer/preprocess/base.py +96 -69
  138. junifer/preprocess/bold_warper.py +265 -0
  139. junifer/preprocess/confounds/fmriprep_confound_remover.py +91 -134
  140. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +106 -111
  141. junifer/preprocess/fsl/__init__.py +4 -0
  142. junifer/preprocess/fsl/apply_warper.py +179 -0
  143. junifer/preprocess/fsl/tests/test_apply_warper.py +45 -0
  144. junifer/preprocess/tests/test_bold_warper.py +159 -0
  145. junifer/preprocess/tests/test_preprocess_base.py +6 -6
  146. junifer/preprocess/warping/__init__.py +6 -0
  147. junifer/preprocess/warping/_ants_warper.py +167 -0
  148. junifer/preprocess/warping/_fsl_warper.py +109 -0
  149. junifer/preprocess/warping/space_warper.py +213 -0
  150. junifer/preprocess/warping/tests/test_space_warper.py +198 -0
  151. junifer/stats.py +18 -4
  152. junifer/storage/base.py +9 -1
  153. junifer/storage/hdf5.py +8 -3
  154. junifer/storage/pandas_base.py +2 -1
  155. junifer/storage/sqlite.py +1 -0
  156. junifer/storage/tests/test_hdf5.py +2 -1
  157. junifer/storage/tests/test_sqlite.py +8 -8
  158. junifer/storage/tests/test_utils.py +6 -6
  159. junifer/storage/utils.py +1 -0
  160. junifer/testing/datagrabbers.py +11 -7
  161. junifer/testing/utils.py +1 -0
  162. junifer/tests/test_stats.py +2 -0
  163. junifer/utils/__init__.py +1 -0
  164. junifer/utils/helpers.py +53 -0
  165. junifer/utils/logging.py +14 -3
  166. junifer/utils/tests/test_helpers.py +35 -0
  167. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/METADATA +59 -28
  168. junifer-0.0.4.dist-info/RECORD +257 -0
  169. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/WHEEL +1 -1
  170. junifer/markers/falff/falff_estimator.py +0 -334
  171. junifer/markers/falff/tests/test_falff_estimator.py +0 -238
  172. junifer/markers/reho/reho_estimator.py +0 -515
  173. junifer/markers/reho/tests/test_reho_estimator.py +0 -260
  174. junifer-0.0.3.dev186.dist-info/RECORD +0 -199
  175. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/AUTHORS.rst +0 -0
  176. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/LICENSE.md +0 -0
  177. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/entry_points.txt +0 -0
  178. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/top_level.txt +0 -0
@@ -4,11 +4,23 @@
4
4
  # License: AGPL
5
5
 
6
6
 
7
- from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Union
7
+ from pathlib import Path
8
+ from typing import (
9
+ TYPE_CHECKING,
10
+ Any,
11
+ ClassVar,
12
+ Dict,
13
+ List,
14
+ Optional,
15
+ Tuple,
16
+ Type,
17
+ Union,
18
+ )
8
19
 
9
20
  from ...utils import logger, raise_error
10
21
  from ..base import BaseMarker
11
- from .reho_estimator import ReHoEstimator
22
+ from ._afni_reho import AFNIReHo
23
+ from ._junifer_reho import JuniferReHo
12
24
 
13
25
 
14
26
  if TYPE_CHECKING:
@@ -20,32 +32,47 @@ class ReHoBase(BaseMarker):
20
32
 
21
33
  Parameters
22
34
  ----------
23
- use_afni : bool, optional
24
- Whether to use AFNI for computing. If None, will use AFNI only
25
- if available (default None).
35
+ using : {"junifer", "afni"}
36
+ Implementation to use for computing ReHo:
37
+
38
+ * "junifer" : Use ``junifer``'s own ReHo implementation
39
+ * "afni" : Use AFNI's ``3dReHo``
40
+
26
41
  name : str, optional
27
42
  The name of the marker. If None, it will use the class name
28
43
  (default None).
29
44
 
45
+ Raises
46
+ ------
47
+ ValueError
48
+ If ``using`` is invalid.
49
+
30
50
  """
31
51
 
32
- _EXT_DEPENDENCIES: ClassVar[
33
- List[Dict[str, Union[str, bool, List[str]]]]
34
- ] = [
52
+ _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [
35
53
  {
36
- "name": "afni",
37
- "optional": True,
38
- "commands": ["3dReHo", "3dAFNItoNIFTI"],
54
+ "using": "afni",
55
+ "depends_on": AFNIReHo,
56
+ },
57
+ {
58
+ "using": "junifer",
59
+ "depends_on": JuniferReHo,
39
60
  },
40
61
  ]
41
62
 
42
63
  def __init__(
43
64
  self,
44
- use_afni: Optional[bool] = None,
65
+ using: str,
45
66
  name: Optional[str] = None,
46
67
  ) -> None:
68
+ # Validate `using` parameter
69
+ valid_using = [dep["using"] for dep in self._CONDITIONAL_DEPENDENCIES]
70
+ if using not in valid_using:
71
+ raise_error(
72
+ f"Invalid value for `using`, should be one of: {valid_using}"
73
+ )
74
+ self.using = using
47
75
  super().__init__(on="BOLD", name=name)
48
- self.use_afni = use_afni
49
76
 
50
77
  def get_valid_inputs(self) -> List[str]:
51
78
  """Get valid data types for input.
@@ -74,12 +101,12 @@ class ReHoBase(BaseMarker):
74
101
  """
75
102
  return "vector"
76
103
 
77
- def compute_reho_map(
104
+ def _compute(
78
105
  self,
79
- input: Dict[str, Any],
106
+ input_data: Dict[str, Any],
80
107
  **reho_params: Any,
81
- ) -> "Nifti1Image":
82
- """Compute.
108
+ ) -> Tuple["Nifti1Image", Path]:
109
+ """Compute voxel-wise ReHo.
83
110
 
84
111
  Calculates Kendall's W per voxel using neighborhood voxels.
85
112
  Instead of the time series values themselves, Kendall's W uses the
@@ -90,7 +117,7 @@ class ReHoBase(BaseMarker):
90
117
 
91
118
  Parameters
92
119
  ----------
93
- input : dict
120
+ input_data : dict
94
121
  The BOLD data as dictionary.
95
122
  **reho_params : dict
96
123
  Extra keyword arguments for ReHo.
@@ -98,6 +125,10 @@ class ReHoBase(BaseMarker):
98
125
  Returns
99
126
  -------
100
127
  Niimg-like object
128
+ The ReHo map as NIfTI.
129
+ pathlib.Path
130
+ The path to the ReHo map as NIfTI or the input data path if the
131
+ input data space is "native".
101
132
 
102
133
  References
103
134
  ----------
@@ -108,21 +139,25 @@ class ReHoBase(BaseMarker):
108
139
  https://doi.org/10.1177/1073858415595004
109
140
 
110
141
  """
111
- if self.use_afni is None:
112
- raise_error(
113
- "Parameter `use_afni` must be set to True or False in order "
114
- "to compute this marker. It is currently set to None (default "
115
- "behaviour). This is intended to be for auto-detection. In "
116
- "order for that to happen, please call the `validate` method "
117
- "before calling the `compute` method."
118
- )
119
- logger.info("Calculating ReHO map.")
120
- # Initialize reho estimator
121
- reho_estimator = ReHoEstimator()
122
- # Fit-transform reho estimator
123
- reho_map = reho_estimator.fit_transform(
124
- use_afni=self.use_afni,
125
- input_data=input,
142
+ logger.debug("Calculating voxel-wise ReHo")
143
+
144
+ # Conditional estimator
145
+ if self.using == "afni":
146
+ estimator = AFNIReHo()
147
+ elif self.using == "junifer":
148
+ estimator = JuniferReHo()
149
+ # Compute reho
150
+ reho_map, reho_map_path = estimator.compute( # type: ignore
151
+ data=input_data["data"],
126
152
  **reho_params,
127
153
  )
128
- return reho_map
154
+
155
+ # If the input data space is native already, the original path should
156
+ # be propagated down as it might be required for transforming
157
+ # parcellation / coordinates to native space, else the reho map
158
+ # path should be passed for use later if required.
159
+ # TODO(synchon): will be taken care in #292
160
+ if input_data["space"] == "native":
161
+ return reho_map, input_data["path"]
162
+
163
+ return reho_map, reho_map_path
@@ -20,15 +20,18 @@ class ReHoParcels(ReHoBase):
20
20
 
21
21
  Parameters
22
22
  ----------
23
- parcellation : str
24
- The name of the parcellation. Check valid options by calling
23
+ parcellation : str or list of str
24
+ The name(s) of the parcellation(s). Check valid options by calling
25
25
  :func:`.list_parcellations`.
26
- use_afni : bool, optional
27
- Whether to use AFNI for computing. If None, will use AFNI only
28
- if available (default None).
26
+ using : {"junifer", "afni"}
27
+ Implementation to use for computing ReHo:
28
+
29
+ * "junifer" : Use ``junifer``'s own ReHo implementation
30
+ * "afni" : Use AFNI's ``3dReHo``
31
+
29
32
  reho_params : dict, optional
30
33
  Extra parameters for computing ReHo map as a dictionary (default None).
31
- If ``use_afni = True``, then the valid keys are:
34
+ If ``using="afni"``, then the valid keys are:
32
35
 
33
36
  * ``nneigh`` : {7, 19, 27}, optional (default 27)
34
37
  Number of voxels in the neighbourhood, inclusive. Can be:
@@ -58,7 +61,7 @@ class ReHoParcels(ReHoBase):
58
61
  The number of voxels for +/- z-axis of cuboidal volumes
59
62
  (default None).
60
63
 
61
- else if ``use_afni = False``, then the valid keys are:
64
+ else if ``using="junifer"``, then the valid keys are:
62
65
 
63
66
  * ``nneigh`` : {7, 19, 27, 125}, optional (default 27)
64
67
  Number of voxels in the neighbourhood, inclusive. Can be:
@@ -86,20 +89,21 @@ class ReHoParcels(ReHoBase):
86
89
 
87
90
  def __init__(
88
91
  self,
89
- parcellation: str,
90
- use_afni: Optional[bool] = None,
92
+ parcellation: Union[str, List[str]],
93
+ using: str,
91
94
  reho_params: Optional[Dict] = None,
92
95
  agg_method: str = "mean",
93
96
  agg_method_params: Optional[Dict] = None,
94
97
  masks: Union[str, Dict, List[Union[Dict, str]], None] = None,
95
98
  name: Optional[str] = None,
96
99
  ) -> None:
100
+ # Superclass init first to validate `using` parameter
101
+ super().__init__(using=using, name=name)
97
102
  self.parcellation = parcellation
98
103
  self.reho_params = reho_params
99
104
  self.agg_method = agg_method
100
105
  self.agg_method_params = agg_method_params
101
106
  self.masks = masks
102
- super().__init__(use_afni=use_afni, name=name)
103
107
 
104
108
  def compute(
105
109
  self,
@@ -125,12 +129,19 @@ class ReHoParcels(ReHoBase):
125
129
  * ``col_names`` : the column labels for the parcels as a list
126
130
 
127
131
  """
128
- logger.info("Calculating ReHo for parcels.")
129
- # Calculate reho map
132
+ logger.info("Calculating ReHo for parcels")
133
+
134
+ # Compute voxelwise reho
135
+ # If the input data space is "native", then reho_file_path points to
136
+ # the input data path as it might be required for parcellation
137
+ # transformation to native space.
130
138
  if self.reho_params is not None:
131
- reho_map = self.compute_reho_map(input=input, **self.reho_params)
139
+ reho_map, reho_file_path = self._compute(
140
+ input_data=input, **self.reho_params
141
+ )
132
142
  else:
133
- reho_map = self.compute_reho_map(input=input)
143
+ reho_map, reho_file_path = self._compute(input_data=input)
144
+
134
145
  # Initialize parcel aggregation
135
146
  parcel_aggregation = ParcelAggregation(
136
147
  parcellation=self.parcellation,
@@ -142,8 +153,7 @@ class ReHoParcels(ReHoBase):
142
153
  # Perform aggregation on reho map
143
154
  parcel_aggregation_input = dict(input.items())
144
155
  parcel_aggregation_input["data"] = reho_map
145
- parcel_aggregation_input["path"] = None
146
-
156
+ parcel_aggregation_input["path"] = reho_file_path
147
157
  output = parcel_aggregation.compute(
148
158
  input=parcel_aggregation_input,
149
159
  extra_input=extra_input,
@@ -23,6 +23,12 @@ class ReHoSpheres(ReHoBase):
23
23
  coords : str
24
24
  The name of the coordinates list to use. See
25
25
  :func:`.list_coordinates` for options.
26
+ using : {"junifer", "afni"}
27
+ Implementation to use for computing ReHo:
28
+
29
+ * "junifer" : Use ``junifer``'s own ReHo implementation
30
+ * "afni" : Use AFNI's ``3dReHo``
31
+
26
32
  radius : float, optional
27
33
  The radius of the sphere in millimeters. If None, the signal will be
28
34
  extracted from a single voxel. See
@@ -36,7 +42,7 @@ class ReHoSpheres(ReHoBase):
36
42
  if available (default None).
37
43
  reho_params : dict, optional
38
44
  Extra parameters for computing ReHo map as a dictionary (default None).
39
- If ``use_afni = True``, then the valid keys are:
45
+ If ``using="afni"``, then the valid keys are:
40
46
 
41
47
  * ``nneigh`` : {7, 19, 27}, optional (default 27)
42
48
  Number of voxels in the neighbourhood, inclusive. Can be:
@@ -66,7 +72,7 @@ class ReHoSpheres(ReHoBase):
66
72
  The number of voxels for +/- z-axis of cuboidal volumes
67
73
  (default None).
68
74
 
69
- else if ``use_afni = False``, then the valid keys are:
75
+ else if ``using="junifer"``, then the valid keys are:
70
76
 
71
77
  * ``nneigh`` : {7, 19, 27, 125}, optional (default 27)
72
78
  Number of voxels in the neighbourhood, inclusive. Can be:
@@ -95,15 +101,17 @@ class ReHoSpheres(ReHoBase):
95
101
  def __init__(
96
102
  self,
97
103
  coords: str,
104
+ using: str,
98
105
  radius: Optional[float] = None,
99
106
  allow_overlap: bool = False,
100
- use_afni: Optional[bool] = None,
101
107
  reho_params: Optional[Dict] = None,
102
108
  agg_method: str = "mean",
103
109
  agg_method_params: Optional[Dict] = None,
104
110
  masks: Union[str, Dict, List[Union[Dict, str]], None] = None,
105
111
  name: Optional[str] = None,
106
112
  ) -> None:
113
+ # Superclass init first to validate `using` parameter
114
+ super().__init__(using=using, name=name)
107
115
  self.coords = coords
108
116
  self.radius = radius
109
117
  self.allow_overlap = allow_overlap
@@ -111,7 +119,6 @@ class ReHoSpheres(ReHoBase):
111
119
  self.agg_method = agg_method
112
120
  self.agg_method_params = agg_method_params
113
121
  self.masks = masks
114
- super().__init__(use_afni=use_afni, name=name)
115
122
 
116
123
  def compute(
117
124
  self,
@@ -137,12 +144,19 @@ class ReHoSpheres(ReHoBase):
137
144
  * ``col_names`` : the column labels for the spheres as a list
138
145
 
139
146
  """
140
- logger.info("Calculating ReHo for spheres.")
141
- # Calculate reho map
147
+ logger.info("Calculating ReHo for spheres")
148
+
149
+ # Compute voxelwise reho
150
+ # If the input data space is "native", then reho_file_path points to
151
+ # the input data path as it might be required for coordinates
152
+ # transformation to native space.
142
153
  if self.reho_params is not None:
143
- reho_map = self.compute_reho_map(input=input, **self.reho_params)
154
+ reho_map, reho_file_path = self._compute(
155
+ input_data=input, **self.reho_params
156
+ )
144
157
  else:
145
- reho_map = self.compute_reho_map(input=input)
158
+ reho_map, reho_file_path = self._compute(input_data=input)
159
+
146
160
  # Initialize sphere aggregation
147
161
  sphere_aggregation = SphereAggregation(
148
162
  coords=self.coords,
@@ -156,7 +170,7 @@ class ReHoSpheres(ReHoBase):
156
170
  # Perform aggregation on reho map
157
171
  sphere_aggregation_input = dict(input.items())
158
172
  sphere_aggregation_input["data"] = reho_map
159
- sphere_aggregation_input["path"] = None
173
+ sphere_aggregation_input["path"] = reho_file_path
160
174
  output = sphere_aggregation.compute(
161
175
  input=sphere_aggregation_input, extra_input=extra_input
162
176
  )
@@ -1,94 +1,88 @@
1
- """Provide tests for ReHo on parcels."""
1
+ """Provide tests for ReHoParcels."""
2
2
 
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
+ import logging
6
7
  from pathlib import Path
7
8
 
8
9
  import pytest
9
- from nilearn import image as nimg
10
- from scipy.stats import pearsonr
11
-
12
- from junifer.markers.reho.reho_parcels import ReHoParcels
13
- from junifer.pipeline.utils import _check_afni
14
- from junifer.storage.sqlite import SQLiteFeatureStorage
15
- from junifer.testing.datagrabbers import SPMAuditoryTestingDataGrabber
16
-
10
+ import scipy as sp
11
+
12
+ from junifer.datareader import DefaultDataReader
13
+ from junifer.markers import ReHoParcels
14
+ from junifer.pipeline import WorkDirManager
15
+ from junifer.pipeline.utils import _check_afni, _check_ants
16
+ from junifer.storage import SQLiteFeatureStorage
17
+ from junifer.testing.datagrabbers import (
18
+ PartlyCloudyTestingDataGrabber,
19
+ SPMAuditoryTestingDataGrabber,
20
+ )
17
21
 
18
- PARCELLATION = "Schaefer100x7"
19
22
 
23
+ def test_ReHoParcels(caplog: pytest.LogCaptureFixture, tmp_path: Path) -> None:
24
+ """Test ReHoParcels.
20
25
 
21
- def test_reho_parcels_computation() -> None:
22
- """Test ReHoParcels fit-transform."""
23
- with SPMAuditoryTestingDataGrabber() as dg:
24
- # Use first subject
25
- subject_data = dg["sub001"]
26
- # Load image to memory
27
- fmri_img = nimg.load_img(subject_data["BOLD"]["path"])
28
- # Initialize marker
29
- reho_parcels_marker = ReHoParcels(parcellation=PARCELLATION)
30
- # Fit transform marker on data
31
- reho_parcels_output = reho_parcels_marker.fit_transform(
32
- {"BOLD": {"path": "/tmp", "data": fmri_img, "meta": {}}}
33
- )
34
- # Get BOLD output
35
- reho_parcels_output_bold = reho_parcels_output["BOLD"]
36
- # Assert BOLD output keys
37
- assert "data" in reho_parcels_output_bold
38
- assert "col_names" in reho_parcels_output_bold
26
+ Parameters
27
+ ----------
28
+ caplog : pytest.LogCaptureFixture
29
+ The pytest.LogCaptureFixture object.
30
+ tmp_path : pathlib.Path
31
+ The path to the test directory.
39
32
 
40
- reho_parcels_output_bold_data = reho_parcels_output_bold["data"]
41
- # Assert BOLD output data dimension
42
- assert reho_parcels_output_bold_data.ndim == 2
43
- # Assert BOLD output data is normalized
44
- assert (reho_parcels_output_bold_data > 0).all() and (
45
- reho_parcels_output_bold_data < 1
46
- ).all()
33
+ """
34
+ with caplog.at_level(logging.DEBUG):
35
+ with PartlyCloudyTestingDataGrabber() as dg:
36
+ element_data = DefaultDataReader().fit_transform(dg["sub-01"])
37
+ # Update workdir to current test's tmp_path
38
+ WorkDirManager().workdir = tmp_path
39
+
40
+ # Initialize marker
41
+ marker = ReHoParcels(
42
+ parcellation="TianxS1x3TxMNInonlinear2009cAsym",
43
+ using="junifer",
44
+ )
45
+ # Fit transform marker on data
46
+ output = marker.fit_transform(element_data)
47
+
48
+ assert "Creating cache" in caplog.text
49
+
50
+ # Get BOLD output
51
+ assert "BOLD" in output
52
+ output_bold = output["BOLD"]
53
+ # Assert BOLD output keys
54
+ assert "data" in output_bold
55
+ assert "col_names" in output_bold
56
+
57
+ output_bold_data = output_bold["data"]
58
+ # Assert BOLD output data dimension
59
+ assert output_bold_data.ndim == 2
60
+ # Assert BOLD output data is normalized
61
+ assert (output_bold_data > 0).all() and (
62
+ output_bold_data < 1
63
+ ).all()
64
+
65
+ # Reset log capture
66
+ caplog.clear()
67
+ # Initialize storage
68
+ storage = SQLiteFeatureStorage(tmp_path / "reho_parcels.sqlite")
69
+ # Fit transform marker on data with storage
70
+ marker.fit_transform(
71
+ input=element_data,
72
+ storage=storage,
73
+ )
74
+ # Cache working correctly
75
+ assert "Creating cache" not in caplog.text
47
76
 
48
77
 
49
78
  @pytest.mark.skipif(
50
- _check_afni() is False, reason="requires afni to be in PATH"
79
+ _check_ants() is False, reason="requires ANTs to be in PATH"
51
80
  )
52
- def test_reho_parcels_computation_comparison() -> None:
53
- """Test ReHoParcels fit-transform implementation comparison.."""
54
- with SPMAuditoryTestingDataGrabber() as dg:
55
- # Use first subject
56
- subject_data = dg["sub001"]
57
- # Load image to memory
58
- fmri_img = nimg.load_img(subject_data["BOLD"]["path"])
59
-
60
- # Initialize marker with use_afni=False
61
- reho_parcels_marker_python = ReHoParcels(
62
- parcellation=PARCELLATION, use_afni=False
63
- )
64
- # Fit transform marker on data
65
- reho_parcels_output_python = reho_parcels_marker_python.fit_transform(
66
- {"BOLD": {"path": "/tmp", "data": fmri_img, "meta": {}}}
67
- )
68
- # Get BOLD output
69
- reho_parcels_output_bold_python = reho_parcels_output_python["BOLD"]
70
-
71
- # Initialize marker with use_afni=True
72
- reho_parcels_marker_afni = ReHoParcels(
73
- parcellation=PARCELLATION, use_afni=True
74
- )
75
- # Fit transform marker on data
76
- reho_parcels_output_afni = reho_parcels_marker_afni.fit_transform(
77
- {"BOLD": {"path": "/tmp", "data": fmri_img, "meta": {}}}
78
- )
79
- # Get BOLD output
80
- reho_parcels_output_bold_afni = reho_parcels_output_afni["BOLD"]
81
-
82
- # Check for Pearson correlation coefficient
83
- r, _ = pearsonr(
84
- reho_parcels_output_bold_python["data"].flatten(),
85
- reho_parcels_output_bold_afni["data"].flatten(),
86
- )
87
- assert r >= 0.3 # this is very bad, but they differ...
88
-
89
-
90
- def test_reho_parcels_storage(tmp_path: Path) -> None:
91
- """Test ReHoParcels storage.
81
+ @pytest.mark.skipif(
82
+ _check_afni() is False, reason="requires AFNI to be in PATH"
83
+ )
84
+ def test_ReHoParcels_comparison(tmp_path: Path) -> None:
85
+ """Test ReHoParcels implementation comparison.
92
86
 
93
87
  Parameters
94
88
  ----------
@@ -97,22 +91,29 @@ def test_reho_parcels_storage(tmp_path: Path) -> None:
97
91
 
98
92
  """
99
93
  with SPMAuditoryTestingDataGrabber() as dg:
100
- # Use first subject
101
- subject_data = dg["sub001"]
102
- # Load image to memory
103
- fmri_img = nimg.load_img(subject_data["BOLD"]["path"])
94
+ element_data = DefaultDataReader().fit_transform(dg["sub001"])
95
+ # Update workdir to current test's tmp_path
96
+ WorkDirManager().workdir = tmp_path
97
+
104
98
  # Initialize marker
105
- reho_parcels_marker = ReHoParcels(parcellation=PARCELLATION)
106
- # Initialize storage
107
- reho_parcels_storage = SQLiteFeatureStorage(
108
- tmp_path / "reho_parcels.sqlite"
99
+ junifer_marker = ReHoParcels(
100
+ parcellation="Schaefer100x7", using="junifer"
109
101
  )
110
- # Generate meta
111
- meta = {
112
- "element": {"subject": "sub001"}
113
- } # only requires element key for storing
114
- # Fit transform marker on data with storage
115
- reho_parcels_marker.fit_transform(
116
- input={"BOLD": {"path": "/tmp", "data": fmri_img, "meta": meta}},
117
- storage=reho_parcels_storage,
102
+ # Fit transform marker on data
103
+ junifer_output = junifer_marker.fit_transform(element_data)
104
+ # Get BOLD output
105
+ junifer_output_bold = junifer_output["BOLD"]
106
+
107
+ # Initialize marker
108
+ afni_marker = ReHoParcels(parcellation="Schaefer100x7", using="afni")
109
+ # Fit transform marker on data
110
+ afni_output = afni_marker.fit_transform(element_data)
111
+ # Get BOLD output
112
+ afni_output_bold = afni_output["BOLD"]
113
+
114
+ # Check for Pearson correlation coefficient
115
+ r, _ = sp.stats.pearsonr(
116
+ junifer_output_bold["data"].flatten(),
117
+ afni_output_bold["data"].flatten(),
118
118
  )
119
+ assert r >= 0.2 # this is very bad, but they differ...