junifer 0.0.3.dev188__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.dev188.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.dev188.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.dev188.dist-info/RECORD +0 -199
  175. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/AUTHORS.rst +0 -0
  176. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/LICENSE.md +0 -0
  177. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/entry_points.txt +0 -0
  178. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/top_level.txt +0 -0
junifer/_version.py CHANGED
@@ -1,4 +1,16 @@
1
1
  # file generated by setuptools_scm
2
2
  # don't change, don't track in version control
3
- __version__ = version = '0.0.3.dev188'
4
- __version_tuple__ = version_tuple = (0, 0, 3, 'dev188')
3
+ TYPE_CHECKING = False
4
+ if TYPE_CHECKING:
5
+ from typing import Tuple, Union
6
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
7
+ else:
8
+ VERSION_TUPLE = object
9
+
10
+ version: str
11
+ __version__: str
12
+ __version_tuple__: VERSION_TUPLE
13
+ version_tuple: VERSION_TUPLE
14
+
15
+ __version__ = version = '0.0.4'
16
+ __version_tuple__ = version_tuple = (0, 0, 4)
junifer/api/cli.py CHANGED
@@ -8,9 +8,10 @@ import pathlib
8
8
  import subprocess
9
9
  import sys
10
10
  from pathlib import Path
11
- from typing import Dict, List, Union
11
+ from typing import Dict, List, Tuple, Union
12
12
 
13
13
  import click
14
+ import pandas as pd
14
15
 
15
16
  from ..utils.logging import (
16
17
  configure_logging,
@@ -20,6 +21,7 @@ from ..utils.logging import (
20
21
  )
21
22
  from .functions import collect as api_collect
22
23
  from .functions import queue as api_queue
24
+ from .functions import reset as api_reset
23
25
  from .functions import run as api_run
24
26
  from .parser import parse_yaml
25
27
  from .utils import (
@@ -32,27 +34,45 @@ from .utils import (
32
34
  )
33
35
 
34
36
 
35
- def _parse_elements(element: str, config: Dict) -> Union[List, None]:
37
+ def _parse_elements(element: Tuple[str], config: Dict) -> Union[List, None]:
36
38
  """Parse elements from cli.
37
39
 
38
40
  Parameters
39
41
  ----------
40
- element : str
41
- The element to operate on.
42
+ element : tuple of str
43
+ The element(s) to operate on.
42
44
  config : dict
43
45
  The configuration to operate using.
44
46
 
45
47
  Returns
46
48
  -------
47
- list
48
- The element(s) as list.
49
+ list or None
50
+ The element(s) as list or None.
51
+
52
+ Raises
53
+ ------
54
+ ValueError
55
+ If no element is found either in the command-line options or
56
+ the configuration file.
57
+
58
+ Warns
59
+ -----
60
+ RuntimeWarning
61
+ If elements are specified both via the command-line options and
62
+ the configuration file.
49
63
 
50
64
  """
51
65
  logger.debug(f"Parsing elements: {element}")
66
+ # Early return None to continue with all elements
52
67
  if len(element) == 0:
53
68
  return None
54
- # TODO: If len == 1, check if its a file, then parse elements from file
55
- elements = [tuple(x.split(",")) if "," in x else x for x in element]
69
+ # Check if the element is a file for single element;
70
+ # if yes, then parse elements from it
71
+ if len(element) == 1 and Path(element[0]).resolve().is_file():
72
+ elements = _parse_elements_file(Path(element[0]).resolve())
73
+ else:
74
+ # Process multi-keyed elements
75
+ elements = [tuple(x.split(",")) if "," in x else x for x in element]
56
76
  logger.debug(f"Parsed elements: {elements}")
57
77
  if elements is not None and "elements" in config:
58
78
  warn_with_log(
@@ -61,19 +81,48 @@ def _parse_elements(element: str, config: Dict) -> Union[List, None]:
61
81
  "over the configuration file. That is, the elements specified "
62
82
  "in the command line will be used. The elements specified in "
63
83
  "the configuration file will be ignored. To remove this warning, "
64
- 'please remove the "elements" item from the configuration file.'
84
+ "please remove the `elements` item from the configuration file."
65
85
  )
66
86
  elif elements is None:
87
+ # Check in config
67
88
  elements = config.get("elements", None)
68
89
  if elements is None:
69
90
  raise_error(
70
- "The 'elements' key is set in the configuration, but its value"
71
- " is 'None'. It is likely that there is an empty 'elements' "
91
+ "The `elements` key is set in the configuration, but its value"
92
+ " is `None`. It is likely that there is an empty `elements` "
72
93
  "section in the yaml configuration file."
73
94
  )
74
95
  return elements
75
96
 
76
97
 
98
+ def _parse_elements_file(filepath: Path) -> List[Tuple[str, ...]]:
99
+ """Parse elements from file.
100
+
101
+ Parameters
102
+ ----------
103
+ filepath : pathlib.Path
104
+ The path to the element file.
105
+
106
+ Returns
107
+ -------
108
+ list of tuple of str
109
+ The element(s) as list.
110
+
111
+ """
112
+ # Read CSV into dataframe
113
+ csv_df = pd.read_csv(
114
+ filepath,
115
+ header=None, # no header # type: ignore
116
+ index_col=False, # no index column
117
+ dtype=str,
118
+ skipinitialspace=True, # no leading space after delimiter
119
+ )
120
+ # Remove trailing whitespace in cell entries
121
+ csv_df_trimmed = csv_df.apply(lambda x: x.str.strip())
122
+ # Convert to list of tuple of str
123
+ return list(map(tuple, csv_df_trimmed.to_numpy()))
124
+
125
+
77
126
  def _validate_verbose(
78
127
  ctx: click.Context, param: str, value: str
79
128
  ) -> Union[str, int]:
@@ -92,6 +141,7 @@ def _validate_verbose(
92
141
  -------
93
142
  str or int
94
143
  The validated value.
144
+
95
145
  """
96
146
  if isinstance(value, int):
97
147
  return value
@@ -133,7 +183,9 @@ def cli() -> None: # pragma: no cover
133
183
  callback=_validate_verbose,
134
184
  default="info",
135
185
  )
136
- def run(filepath: click.Path, element: str, verbose: Union[str, int]) -> None:
186
+ def run(
187
+ filepath: click.Path, element: Tuple[str], verbose: Union[str, int]
188
+ ) -> None:
137
189
  """Run command for CLI.
138
190
 
139
191
  \f
@@ -142,20 +194,30 @@ def run(filepath: click.Path, element: str, verbose: Union[str, int]) -> None:
142
194
  ----------
143
195
  filepath : click.Path
144
196
  The filepath to the configuration file.
145
- element : str
146
- The element to operate using.
197
+ element : tuple of str
198
+ The element to operate on.
147
199
  verbose : click.Choice
148
200
  The verbosity level: warning, info or debug (default "info").
149
201
 
150
202
  """
151
203
  configure_logging(level=verbose)
152
- # TODO: add validation
204
+ # TODO(synchon): add validation
205
+ # Parse YAML
153
206
  config = parse_yaml(filepath) # type: ignore
207
+ # Retrieve working directory
154
208
  workdir = config["workdir"]
209
+ # Fetch datagrabber
155
210
  datagrabber = config["datagrabber"]
211
+ # Fetch markers
156
212
  markers = config["markers"]
213
+ # Fetch storage
157
214
  storage = config["storage"]
158
- preprocessor = config.get("preprocess")
215
+ # Fetch preprocessors
216
+ preprocessors = config.get("preprocess")
217
+ # Convert to list if single preprocessor
218
+ if preprocessors is not None and not isinstance(preprocessors, list):
219
+ preprocessors = [preprocessors]
220
+ # Parse elements
159
221
  elements = _parse_elements(element, config)
160
222
  # Perform operation
161
223
  api_run(
@@ -163,7 +225,7 @@ def run(filepath: click.Path, element: str, verbose: Union[str, int]) -> None:
163
225
  datagrabber=datagrabber,
164
226
  markers=markers,
165
227
  storage=storage,
166
- preprocessor=preprocessor,
228
+ preprocessors=preprocessors,
167
229
  elements=elements,
168
230
  )
169
231
 
@@ -352,6 +414,43 @@ def selftest(subpkg: str) -> None:
352
414
  click.secho("Failure.", fg="red")
353
415
 
354
416
 
417
+ @cli.command()
418
+ @click.argument(
419
+ "filepath",
420
+ type=click.Path(
421
+ exists=True, readable=True, dir_okay=False, path_type=pathlib.Path
422
+ ),
423
+ )
424
+ @click.option(
425
+ "-v",
426
+ "--verbose",
427
+ type=click.UNPROCESSED,
428
+ callback=_validate_verbose,
429
+ default="info",
430
+ )
431
+ def reset(
432
+ filepath: click.Path,
433
+ verbose: Union[str, int],
434
+ ) -> None:
435
+ """Reset command for CLI.
436
+
437
+ \f
438
+
439
+ Parameters
440
+ ----------
441
+ filepath : click.Path
442
+ The filepath to the configuration file.
443
+ verbose : click.Choice
444
+ The verbosity level: warning, info or debug (default "info").
445
+
446
+ """
447
+ configure_logging(level=verbose)
448
+ # Parse YAML
449
+ config = parse_yaml(filepath)
450
+ # Perform operation
451
+ api_reset(config)
452
+
453
+
355
454
  @cli.group()
356
455
  def setup() -> None: # pragma: no cover
357
456
  """Configure commands for Junifer."""
@@ -379,3 +478,49 @@ def afni_docker() -> None: # pragma: no cover
379
478
  export PATH="$PATH:{afni_wrappers_path}"
380
479
  """
381
480
  click.secho(msg, fg="blue")
481
+
482
+
483
+ @setup.command("fsl-docker")
484
+ def fsl_docker() -> None: # pragma: no cover
485
+ """Configure FSL-Docker wrappers."""
486
+ import junifer
487
+
488
+ pkg_path = Path(junifer.__path__[0]) # type: ignore
489
+ fsl_wrappers_path = pkg_path / "api" / "res" / "fsl"
490
+ msg = f"""
491
+ Installation instructions for FSL-Docker wrappers:
492
+
493
+ 1. Install Docker: https://docs.docker.com/get-docker/
494
+
495
+ 2. Get the FSL-Docker image by running this on the command line:
496
+
497
+ docker pull brainlife/fsl
498
+
499
+ 3. Add this line to the ~/.bashrc or ~/.zshrc file:
500
+
501
+ export PATH="$PATH:{fsl_wrappers_path}"
502
+ """
503
+ click.secho(msg, fg="blue")
504
+
505
+
506
+ @setup.command("ants-docker")
507
+ def ants_docker() -> None: # pragma: no cover
508
+ """Configure ANTs-Docker wrappers."""
509
+ import junifer
510
+
511
+ pkg_path = Path(junifer.__path__[0]) # type: ignore
512
+ ants_wrappers_path = pkg_path / "api" / "res" / "ants"
513
+ msg = f"""
514
+ Installation instructions for ANTs-Docker wrappers:
515
+
516
+ 1. Install Docker: https://docs.docker.com/get-docker/
517
+
518
+ 2. Get the ANTs-Docker image by running this on the command line:
519
+
520
+ docker pull antsx/ants
521
+
522
+ 3. Add this line to the ~/.bashrc or ~/.zshrc file:
523
+
524
+ export PATH="$PATH:{ants_wrappers_path}"
525
+ """
526
+ click.secho(msg, fg="blue")