junifer 0.0.3.dev131__py3-none-any.whl → 0.0.3.dev148__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/__init__.py CHANGED
@@ -17,5 +17,6 @@ from . import (
17
17
  storage,
18
18
  utils,
19
19
  external,
20
+ onthefly,
20
21
  )
21
22
  from ._version import __version__
junifer/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # file generated by setuptools_scm
2
2
  # don't change, don't track in version control
3
- __version__ = version = '0.0.3.dev131'
4
- __version_tuple__ = version_tuple = (0, 0, 3, 'dev131')
3
+ __version__ = version = '0.0.3.dev148'
4
+ __version_tuple__ = version_tuple = (0, 0, 3, 'dev148')
@@ -103,6 +103,21 @@ for year in (2013, 2015, 2019):
103
103
  "year": 2019,
104
104
  "n_rois": 368,
105
105
  }
106
+ # Add Yan parcellation info
107
+ for n_rois in range(100, 1001, 100):
108
+ # Add Yeo networks
109
+ for yeo_network in [7, 17]:
110
+ _available_parcellations[f"Yan{n_rois}xYeo{yeo_network}"] = {
111
+ "family": "Yan",
112
+ "n_rois": n_rois,
113
+ "yeo_networks": yeo_network,
114
+ }
115
+ # Add Kong networks
116
+ _available_parcellations[f"Yan{n_rois}xKong17"] = {
117
+ "family": "Yan",
118
+ "n_rois": n_rois,
119
+ "kong_networks": 17,
120
+ }
106
121
 
107
122
 
108
123
  def register_parcellation(
@@ -273,7 +288,7 @@ def _retrieve_parcellation(
273
288
 
274
289
  Parameters
275
290
  ----------
276
- family : {"Schaefer", "SUIT", "Tian", "AICHA", "Shen"}
291
+ family : {"Schaefer", "SUIT", "Tian", "AICHA", "Shen", "Yan"}
277
292
  The name of the parcellation family.
278
293
  parcellations_dir : str or pathlib.Path, optional
279
294
  Path where the retrieved parcellations file are stored. The default
@@ -316,6 +331,13 @@ def _retrieve_parcellation(
316
331
  Number of ROIs to use. Can be ``50, 100, or 150`` for
317
332
  ``year = 2013`` but is fixed at ``268`` for ``year = 2015`` and at
318
333
  ``368`` for ``year = 2019``.
334
+ * Yan :
335
+ ``n_rois`` : {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}
336
+ Granularity of the parcellation to be used.
337
+ ``yeo_networks`` : {7, 17}, optional
338
+ Number of Yeo networks to use (default None).
339
+ ``kong_networks`` : {17}, optional
340
+ Number of Kong networks to use (default None).
319
341
 
320
342
  Returns
321
343
  -------
@@ -373,6 +395,12 @@ def _retrieve_parcellation(
373
395
  resolution=resolution,
374
396
  **kwargs,
375
397
  )
398
+ elif family == "Yan":
399
+ parcellation_fname, parcellation_labels = _retrieve_yan(
400
+ parcellations_dir=parcellations_dir,
401
+ resolution=resolution,
402
+ **kwargs,
403
+ )
376
404
  else:
377
405
  raise_error(
378
406
  f"The provided parcellation name {family} cannot be retrieved."
@@ -1089,6 +1117,188 @@ def _retrieve_shen( # noqa: C901
1089
1117
  return parcellation_fname, labels
1090
1118
 
1091
1119
 
1120
+ def _retrieve_yan(
1121
+ parcellations_dir: Path,
1122
+ resolution: Optional[float] = None,
1123
+ n_rois: Optional[int] = None,
1124
+ yeo_networks: Optional[int] = None,
1125
+ kong_networks: Optional[int] = None,
1126
+ ) -> Tuple[Path, List[str]]:
1127
+ """Retrieve Yan parcellation.
1128
+
1129
+ Parameters
1130
+ ----------
1131
+ parcellations_dir : pathlib.Path
1132
+ The path to the parcellation data directory.
1133
+ resolution : float, optional
1134
+ The desired resolution of the parcellation to load. If it is not
1135
+ available, the closest resolution will be loaded. Preferably, use a
1136
+ resolution higher than the desired one. By default, will load the
1137
+ highest one (default None). Available resolutions for this
1138
+ parcellation are 1mm and 2mm.
1139
+ n_rois : {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}, optional
1140
+ Granularity of the parcellation to be used (default None).
1141
+ yeo_networks : {7, 17}, optional
1142
+ Number of Yeo networks to use (default None).
1143
+ kong_networks : {17}, optional
1144
+ Number of Kong networks to use (default None).
1145
+
1146
+ Returns
1147
+ -------
1148
+ pathlib.Path
1149
+ File path to the parcellation image.
1150
+ list of str
1151
+ Parcellation labels.
1152
+
1153
+ Raises
1154
+ ------
1155
+ ValueError
1156
+ If invalid value is provided for ``n_rois``, ``yeo_networks`` or
1157
+ ``kong_networks`` or if there is a problem fetching the parcellation.
1158
+
1159
+ """
1160
+ logger.info("Parcellation parameters:")
1161
+ logger.info(f"\tresolution: {resolution}")
1162
+ logger.info(f"\tn_rois: {n_rois}")
1163
+ logger.info(f"\tyeo_networks: {yeo_networks}")
1164
+ logger.info(f"\tkong_networks: {kong_networks}")
1165
+
1166
+ # Allow single network type
1167
+ if (not yeo_networks and not kong_networks) or (
1168
+ yeo_networks and kong_networks
1169
+ ):
1170
+ raise_error(
1171
+ "Either one of `yeo_networks` or `kong_networks` need to be "
1172
+ "specified."
1173
+ )
1174
+
1175
+ # Check resolution
1176
+ _valid_resolutions = [1, 2]
1177
+ resolution = closest_resolution(resolution, _valid_resolutions)
1178
+
1179
+ # Check n_rois value
1180
+ _valid_n_rois = list(range(100, 1001, 100))
1181
+ if n_rois not in _valid_n_rois:
1182
+ raise_error(
1183
+ f"The parameter `n_rois` ({n_rois}) needs to be one of the "
1184
+ f"following: {_valid_n_rois}"
1185
+ )
1186
+
1187
+ if yeo_networks:
1188
+ # Check yeo_networks value
1189
+ _valid_yeo_networks = [7, 17]
1190
+ if yeo_networks not in _valid_yeo_networks:
1191
+ raise_error(
1192
+ f"The parameter `yeo_networks` ({yeo_networks}) needs to be "
1193
+ f"one of the following: {_valid_yeo_networks}"
1194
+ )
1195
+ # Define image and label file according to network
1196
+ parcellation_fname = (
1197
+ parcellations_dir
1198
+ / "Yan_2023"
1199
+ / (
1200
+ f"{n_rois}Parcels_Yeo2011_{yeo_networks}Networks_FSLMNI152_"
1201
+ f"{resolution}mm.nii.gz"
1202
+ )
1203
+ )
1204
+ parcellation_lname = (
1205
+ parcellations_dir
1206
+ / "Yan_2023"
1207
+ / f"{n_rois}Parcels_Yeo2011_{yeo_networks}Networks_LUT.txt"
1208
+ )
1209
+ elif kong_networks:
1210
+ # Check kong_networks value
1211
+ _valid_kong_networks = [17]
1212
+ if kong_networks not in _valid_kong_networks:
1213
+ raise_error(
1214
+ f"The parameter `kong_networks` ({kong_networks}) needs to be "
1215
+ f"one of the following: {_valid_kong_networks}"
1216
+ )
1217
+ # Define image and label file according to network
1218
+ parcellation_fname = (
1219
+ parcellations_dir
1220
+ / "Yan_2023"
1221
+ / (
1222
+ f"{n_rois}Parcels_Kong2022_{kong_networks}Networks_FSLMNI152_"
1223
+ f"{resolution}mm.nii.gz"
1224
+ )
1225
+ )
1226
+ parcellation_lname = (
1227
+ parcellations_dir
1228
+ / "Yan_2023"
1229
+ / f"{n_rois}Parcels_Kong2022_{kong_networks}Networks_LUT.txt"
1230
+ )
1231
+
1232
+ # Check for existence of parcellation:
1233
+ if not parcellation_fname.exists() and not parcellation_lname.exists():
1234
+ logger.info(
1235
+ "At least one of the parcellation files are missing, fetching."
1236
+ )
1237
+
1238
+ # Set URL based on network
1239
+ if yeo_networks:
1240
+ img_url = (
1241
+ "https://raw.githubusercontent.com/ThomasYeoLab/CBIG/"
1242
+ "master/stable_projects/brain_parcellation/Yan2023_homotopic/"
1243
+ f"parcellations/MNI/yeo{yeo_networks}/{n_rois}Parcels_Yeo2011"
1244
+ f"_{yeo_networks}Networks_FSLMNI152_{resolution}mm.nii.gz"
1245
+ )
1246
+ label_url = (
1247
+ "https://raw.githubusercontent.com/ThomasYeoLab/CBIG/"
1248
+ "master/stable_projects/brain_parcellation/Yan2023_homotopic/"
1249
+ f"parcellations/MNI/yeo{yeo_networks}/freeview_lut/{n_rois}"
1250
+ f"Parcels_Yeo2011_{yeo_networks}Networks_LUT.txt"
1251
+ )
1252
+ elif kong_networks:
1253
+ img_url = (
1254
+ "https://raw.githubusercontent.com/ThomasYeoLab/CBIG/"
1255
+ "master/stable_projects/brain_parcellation/Yan2023_homotopic/"
1256
+ f"parcellations/MNI/kong17/{n_rois}Parcels_Kong2022"
1257
+ f"_17Networks_FSLMNI152_{resolution}mm.nii.gz"
1258
+ )
1259
+ label_url = (
1260
+ "https://raw.githubusercontent.com/ThomasYeoLab/CBIG/"
1261
+ "master/stable_projects/brain_parcellation/Yan2023_homotopic/"
1262
+ f"parcellations/MNI/kong17/freeview_lut/{n_rois}Parcels_"
1263
+ "Kong2022_17Networks_LUT.txt"
1264
+ )
1265
+
1266
+ # Initiate a session and make HTTP requests
1267
+ session = requests.Session()
1268
+ # Download parcellation file
1269
+ logger.info(f"Downloading Yan 2023 parcellation from {img_url}")
1270
+ try:
1271
+ img_resp = session.get(img_url)
1272
+ img_resp.raise_for_status()
1273
+ except (ConnectionError, ReadTimeout, HTTPError) as err:
1274
+ raise_error(
1275
+ f"Failed to download Yan 2023 parcellation due to: {err}"
1276
+ )
1277
+ else:
1278
+ parcellation_img_path = Path(parcellation_fname)
1279
+ parcellation_img_path.parent.mkdir(parents=True, exist_ok=True)
1280
+ parcellation_img_path.touch(exist_ok=True)
1281
+ with open(parcellation_img_path, "wb") as f:
1282
+ f.write(img_resp.content)
1283
+ # Download label file
1284
+ logger.info(f"Downloading Yan 2023 labels from {label_url}")
1285
+ try:
1286
+ label_resp = session.get(label_url)
1287
+ label_resp.raise_for_status()
1288
+ except (ConnectionError, ReadTimeout, HTTPError) as err:
1289
+ raise_error(f"Failed to download Yan 2023 labels due to: {err}")
1290
+ else:
1291
+ parcellation_labels_path = Path(parcellation_lname)
1292
+ parcellation_labels_path.touch(exist_ok=True)
1293
+ with open(parcellation_labels_path, "wb") as f:
1294
+ f.write(label_resp.content)
1295
+
1296
+ # Load label file
1297
+ labels = pd.read_csv(parcellation_lname, sep=" ", header=None)[1].to_list()
1298
+
1299
+ return parcellation_fname, labels
1300
+
1301
+
1092
1302
  def merge_parcellations(
1093
1303
  parcellations_list: List["Nifti1Image"],
1094
1304
  parcellations_names: List[str],
@@ -21,6 +21,7 @@ from junifer.data.parcellations import (
21
21
  _retrieve_shen,
22
22
  _retrieve_suit,
23
23
  _retrieve_tian,
24
+ _retrieve_yan,
24
25
  list_parcellations,
25
26
  load_parcellation,
26
27
  merge_parcellations,
@@ -728,6 +729,204 @@ def test_retrieve_shen_incorrect_param_combo(
728
729
  )
729
730
 
730
731
 
732
+ @pytest.mark.parametrize(
733
+ "resolution, n_rois, yeo_networks, kong_networks",
734
+ [
735
+ (1.0, 100, 7, None),
736
+ (1.0, 200, 7, None),
737
+ (1.0, 300, 7, None),
738
+ (1.0, 400, 7, None),
739
+ (1.0, 500, 7, None),
740
+ (1.0, 600, 7, None),
741
+ (1.0, 700, 7, None),
742
+ (1.0, 800, 7, None),
743
+ (1.0, 900, 7, None),
744
+ (1.0, 1000, 7, None),
745
+ (2.0, 100, 7, None),
746
+ (2.0, 200, 7, None),
747
+ (2.0, 300, 7, None),
748
+ (2.0, 400, 7, None),
749
+ (2.0, 500, 7, None),
750
+ (2.0, 600, 7, None),
751
+ (2.0, 700, 7, None),
752
+ (2.0, 800, 7, None),
753
+ (2.0, 900, 7, None),
754
+ (2.0, 1000, 7, None),
755
+ (1.0, 100, 17, None),
756
+ (1.0, 200, 17, None),
757
+ (1.0, 300, 17, None),
758
+ (1.0, 400, 17, None),
759
+ (1.0, 500, 17, None),
760
+ (1.0, 600, 17, None),
761
+ (1.0, 700, 17, None),
762
+ (1.0, 800, 17, None),
763
+ (1.0, 900, 17, None),
764
+ (1.0, 1000, 17, None),
765
+ (2.0, 100, 17, None),
766
+ (2.0, 200, 17, None),
767
+ (2.0, 300, 17, None),
768
+ (2.0, 400, 17, None),
769
+ (2.0, 500, 17, None),
770
+ (2.0, 600, 17, None),
771
+ (2.0, 700, 17, None),
772
+ (2.0, 800, 17, None),
773
+ (2.0, 900, 17, None),
774
+ (2.0, 1000, 17, None),
775
+ (1.0, 100, None, 17),
776
+ (1.0, 200, None, 17),
777
+ (1.0, 300, None, 17),
778
+ (1.0, 400, None, 17),
779
+ (1.0, 500, None, 17),
780
+ (1.0, 600, None, 17),
781
+ (1.0, 700, None, 17),
782
+ (1.0, 800, None, 17),
783
+ (1.0, 900, None, 17),
784
+ (1.0, 1000, None, 17),
785
+ (2.0, 100, None, 17),
786
+ (2.0, 200, None, 17),
787
+ (2.0, 300, None, 17),
788
+ (2.0, 400, None, 17),
789
+ (2.0, 500, None, 17),
790
+ (2.0, 600, None, 17),
791
+ (2.0, 700, None, 17),
792
+ (2.0, 800, None, 17),
793
+ (2.0, 900, None, 17),
794
+ (2.0, 1000, None, 17),
795
+ ],
796
+ )
797
+ def test_yan(
798
+ tmp_path: Path,
799
+ resolution: float,
800
+ n_rois: int,
801
+ yeo_networks: int,
802
+ kong_networks: int,
803
+ ) -> None:
804
+ """Test Yan parcellation.
805
+
806
+ Parameters
807
+ ----------
808
+ tmp_path : pathlib.Path
809
+ The path to the test directory.
810
+ resolution : float
811
+ The parametrized resolution values.
812
+ n_rois : int
813
+ The parametrized ROI count values.
814
+ yeo_networks : int
815
+ The parametrized Yeo networks values.
816
+ kong_networks : int
817
+ The parametrized Kong networks values.
818
+
819
+ """
820
+ parcellations = list_parcellations()
821
+ if yeo_networks:
822
+ parcellation_name = f"Yan{n_rois}xYeo{yeo_networks}"
823
+ assert parcellation_name in parcellations
824
+ parcellation_file = (
825
+ f"{n_rois}Parcels_Yeo2011_{yeo_networks}Networks_FSLMNI152_"
826
+ f"{int(resolution)}mm.nii.gz"
827
+ )
828
+ elif kong_networks:
829
+ parcellation_name = f"Yan{n_rois}xKong{kong_networks}"
830
+ assert parcellation_name in parcellations
831
+ parcellation_file = (
832
+ f"{n_rois}Parcels_Kong2022_{kong_networks}Networks_FSLMNI152_"
833
+ f"{int(resolution)}mm.nii.gz"
834
+ )
835
+ # Load parcellation
836
+ img, label, img_path = load_parcellation(
837
+ name=parcellation_name, # type: ignore
838
+ parcellations_dir=tmp_path,
839
+ resolution=resolution,
840
+ )
841
+ assert img is not None
842
+ assert img_path.name == parcellation_file # type: ignore
843
+ assert len(label) == n_rois
844
+ assert_array_equal(
845
+ img.header["pixdim"][1:4], 3 * [resolution] # type: ignore
846
+ )
847
+
848
+
849
+ def test_retrieve_yan_incorrect_networks(tmp_path: Path) -> None:
850
+ """Test retrieve Yan with incorrect networks.
851
+
852
+ Parameters
853
+ ----------
854
+ tmp_path : pathlib.Path
855
+ The path to the test directory.
856
+
857
+ """
858
+ with pytest.raises(
859
+ ValueError, match="Either one of `yeo_networks` or `kong_networks`"
860
+ ):
861
+ _retrieve_yan(
862
+ parcellations_dir=tmp_path,
863
+ n_rois=31418,
864
+ yeo_networks=100,
865
+ kong_networks=100,
866
+ )
867
+
868
+ with pytest.raises(
869
+ ValueError, match="Either one of `yeo_networks` or `kong_networks`"
870
+ ):
871
+ _retrieve_yan(
872
+ parcellations_dir=tmp_path,
873
+ n_rois=31418,
874
+ yeo_networks=None,
875
+ kong_networks=None,
876
+ )
877
+
878
+
879
+ def test_retrieve_yan_incorrect_n_rois(tmp_path: Path) -> None:
880
+ """Test retrieve Yan with incorrect ROIs.
881
+
882
+ Parameters
883
+ ----------
884
+ tmp_path : pathlib.Path
885
+ The path to the test directory.
886
+
887
+ """
888
+ with pytest.raises(ValueError, match="The parameter `n_rois`"):
889
+ _retrieve_yan(
890
+ parcellations_dir=tmp_path,
891
+ n_rois=31418,
892
+ yeo_networks=7,
893
+ )
894
+
895
+
896
+ def test_retrieve_yan_incorrect_yeo_networks(tmp_path: Path) -> None:
897
+ """Test retrieve Yan with incorrect Yeo networks.
898
+
899
+ Parameters
900
+ ----------
901
+ tmp_path : pathlib.Path
902
+ The path to the test directory.
903
+
904
+ """
905
+ with pytest.raises(ValueError, match="The parameter `yeo_networks`"):
906
+ _retrieve_yan(
907
+ parcellations_dir=tmp_path,
908
+ n_rois=100,
909
+ yeo_networks=27,
910
+ )
911
+
912
+
913
+ def test_retrieve_yan_incorrect_kong_networks(tmp_path: Path) -> None:
914
+ """Test retrieve Yan with incorrect Kong networks.
915
+
916
+ Parameters
917
+ ----------
918
+ tmp_path : pathlib.Path
919
+ The path to the test directory.
920
+
921
+ """
922
+ with pytest.raises(ValueError, match="The parameter `kong_networks`"):
923
+ _retrieve_yan(
924
+ parcellations_dir=tmp_path,
925
+ n_rois=100,
926
+ kong_networks=27,
927
+ )
928
+
929
+
731
930
  def test_merge_parcellations() -> None:
732
931
  """Test merging parcellations."""
733
932
  # load some parcellations for testing
@@ -0,0 +1,6 @@
1
+ """Provide imports for onthefly sub-package."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from .read_transform import read_transform
@@ -0,0 +1,134 @@
1
+ """Provide implementation for read-and-transform function."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+
7
+ from typing import TYPE_CHECKING, Dict, Optional, Tuple, Type
8
+
9
+ import pandas as pd
10
+
11
+ from ..utils import logger, raise_error, warn_with_log
12
+
13
+
14
+ if TYPE_CHECKING:
15
+ from junifer.storage import BaseFeatureStorage
16
+
17
+
18
+ def read_transform(
19
+ storage: Type["BaseFeatureStorage"],
20
+ feature_name: str,
21
+ transform: str,
22
+ transform_args: Optional[Tuple] = None,
23
+ transform_kw_args: Optional[Dict] = None,
24
+ ) -> pd.DataFrame:
25
+ """Read stored feature and transform to specific statistical output.
26
+
27
+ Parameters
28
+ ----------
29
+ storage : storage-like
30
+ The storage class, for example, SQLiteFeatureStorage.
31
+ feature_name : str
32
+ Name of the feature to read.
33
+ transform : str
34
+ The kind of transform formatted as ``<package>_<function>``,
35
+ for example, ``bctpy_degrees_und``.
36
+ transform_args : tuple, optional
37
+ The positional arguments for the callable of ``transform``
38
+ (default None).
39
+ transform_kw_args : dict, optional
40
+ The keyword arguments for the callable of ``transform``
41
+ (default None).
42
+
43
+ Returns
44
+ -------
45
+ pandas.DataFrame
46
+ The transformed feature as a dataframe.
47
+
48
+ Notes
49
+ -----
50
+ This function has been only tested for:
51
+
52
+ * ``bct.degrees_und``
53
+ * ``bct.strengths_und``
54
+ * ``bct.clustering_coef_wu``
55
+ * ``bct.eigenvector_centrality_und``
56
+
57
+ Using other functions may fail and require tweaking.
58
+
59
+ """
60
+ # Set default values for args and kwargs
61
+ transform_args = transform_args or ()
62
+ transform_kw_args = transform_kw_args or {}
63
+
64
+ # Read storage
65
+ stored_data = storage.read(feature_name=feature_name) # type: ignore
66
+ # Retrieve package and function
67
+ package, func_str = transform.split("_", 1)
68
+ # Condition for package
69
+ if package == "bctpy":
70
+ # Check that "matrix" is the feature data kind
71
+ if stored_data["kind"] != "matrix":
72
+ raise_error(
73
+ msg=(
74
+ f"'{stored_data['kind']}' is not valid data kind for "
75
+ f"'{package}'"
76
+ ),
77
+ klass=RuntimeError,
78
+ )
79
+
80
+ # Check bctpy import
81
+ try:
82
+ import bct
83
+ except ImportError as err:
84
+ raise_error(msg=str(err), klass=ImportError)
85
+
86
+ # Warning about function usage
87
+ if func_str not in [
88
+ "degrees_und",
89
+ "strengths_und",
90
+ "clustering_coef_wu",
91
+ "eigenvector_centrality_und",
92
+ ]:
93
+ warn_with_log(
94
+ f"You are about to use '{package}.{func_str}' which has not "
95
+ "been tested to run. In case it fails, you will need to tweak"
96
+ " the code yourself."
97
+ )
98
+
99
+ # Retrieve callable object
100
+ try:
101
+ func = getattr(bct, func_str)
102
+ except AttributeError as err:
103
+ raise_error(msg=str(err), klass=AttributeError)
104
+
105
+ # Apply function and store subject-wise
106
+ output_list = []
107
+ logger.debug(
108
+ f"Computing '{package}.{func_str}' for feature {feature_name} ..."
109
+ )
110
+ for subject in range(stored_data["data"].shape[2]):
111
+ output = func(
112
+ stored_data["data"][:, :, subject],
113
+ *transform_args,
114
+ **transform_kw_args,
115
+ )
116
+ output_list.append(output)
117
+
118
+ # Create dataframe for index
119
+ idx_df = pd.DataFrame(data=stored_data["element"])
120
+ # Create multiindex from dataframe
121
+ logger.debug(
122
+ f"Generating pandas.MultiIndex for feature {feature_name} ..."
123
+ )
124
+ data_idx = pd.MultiIndex.from_frame(df=idx_df)
125
+
126
+ # Create dataframe
127
+ df = pd.DataFrame(
128
+ data=output_list,
129
+ index=data_idx,
130
+ columns=stored_data["row_headers"],
131
+ )
132
+ return df
133
+ else:
134
+ raise_error(f"Unknown package: {package}")
@@ -0,0 +1,179 @@
1
+ """Provide tests for read-and-transform."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+
7
+ import logging
8
+ from pathlib import Path
9
+
10
+ import numpy as np
11
+ import pytest
12
+
13
+ from junifer.onthefly import read_transform
14
+ from junifer.storage.hdf5 import HDF5FeatureStorage
15
+
16
+
17
+ @pytest.fixture
18
+ def vector_storage(tmp_path: Path) -> HDF5FeatureStorage:
19
+ """Return a HDF5FeatureStorage with vector data.
20
+
21
+ Parameters
22
+ ----------
23
+ tmp_path : pathlib.Path
24
+ The path to the test directory.
25
+
26
+ """
27
+ storage = HDF5FeatureStorage(tmp_path / "vector_store.hdf5")
28
+ storage.store(
29
+ kind="vector",
30
+ meta={
31
+ "element": {"subject": "test"},
32
+ "dependencies": [],
33
+ "marker": {"name": "vector"},
34
+ "type": "BOLD",
35
+ },
36
+ data=np.arange(2).reshape(1, 2),
37
+ col_names=["f1", "f2"],
38
+ )
39
+ return storage
40
+
41
+
42
+ @pytest.fixture
43
+ def matrix_storage(tmp_path: Path) -> HDF5FeatureStorage:
44
+ """Return a HDF5FeatureStorage with matrix data.
45
+
46
+ Parameters
47
+ ----------
48
+ tmp_path : pathlib.Path
49
+ The path to the test directory.
50
+
51
+ """
52
+ storage = HDF5FeatureStorage(tmp_path / "matrix_store.hdf5")
53
+ storage.store(
54
+ kind="matrix",
55
+ meta={
56
+ "element": {"subject": "test"},
57
+ "dependencies": [],
58
+ "marker": {"name": "matrix"},
59
+ "type": "BOLD",
60
+ },
61
+ data=np.arange(4).reshape(2, 2),
62
+ col_names=["f1", "f2"],
63
+ row_names=["g1", "g2"],
64
+ )
65
+ return storage
66
+
67
+
68
+ def test_incorrect_package(matrix_storage: HDF5FeatureStorage) -> None:
69
+ """Test error check for incorrect package name.
70
+
71
+ Parameters
72
+ ----------
73
+ matrix_storage : HDF5FeatureStorage
74
+ The HDF5FeatureStorage with matrix data, as fixture.
75
+
76
+ """
77
+ with pytest.raises(ValueError, match="Unknown package"):
78
+ read_transform(
79
+ storage=matrix_storage, # type: ignore
80
+ feature_name="BOLD_matrix",
81
+ transform="godspeed_makemake",
82
+ )
83
+
84
+
85
+ def test_incorrect_data_kind(vector_storage: HDF5FeatureStorage) -> None:
86
+ """Test error check for incorrect data kind.
87
+
88
+ Parameters
89
+ ----------
90
+ vector_storage : HDF5FeatureStorage
91
+ The HDF5FeatureStorage with vector data, as fixture.
92
+
93
+ """
94
+ with pytest.raises(RuntimeError, match="not valid data kind"):
95
+ read_transform(
96
+ storage=vector_storage, # type: ignore
97
+ feature_name="BOLD_vector",
98
+ transform="bctpy_gonggong",
99
+ )
100
+
101
+
102
+ def test_untested_bctpy_function(matrix_storage: HDF5FeatureStorage) -> None:
103
+ """Test warning check for untested function of bctpy.
104
+
105
+ Parameters
106
+ ----------
107
+ matrix_storage : HDF5FeatureStorage
108
+ The HDF5FeatureStorage with matrix data, as fixture.
109
+
110
+ """
111
+ # Skip test if import fails
112
+ pytest.importorskip("bct")
113
+
114
+ with pytest.raises(ValueError):
115
+ with pytest.warns(RuntimeWarning, match="You are about to use"):
116
+ read_transform(
117
+ storage=matrix_storage, # type: ignore
118
+ feature_name="BOLD_matrix",
119
+ transform="bctpy_distance_bin",
120
+ )
121
+
122
+
123
+ def test_incorrect_bctpy_function(matrix_storage: HDF5FeatureStorage) -> None:
124
+ """Test error check for incorrect function of bctpy.
125
+
126
+ Parameters
127
+ ----------
128
+ matrix_storage : HDF5FeatureStorage
129
+ The HDF5FeatureStorage with matrix data, as fixture.
130
+
131
+ """
132
+ # Skip test if import fails
133
+ pytest.importorskip("bct")
134
+
135
+ with pytest.raises(AttributeError, match="has no attribute"):
136
+ read_transform(
137
+ storage=matrix_storage, # type: ignore
138
+ feature_name="BOLD_matrix",
139
+ transform="bctpy_haumea",
140
+ )
141
+
142
+
143
+ @pytest.mark.parametrize(
144
+ "func",
145
+ (
146
+ "degrees_und",
147
+ "strengths_und",
148
+ "clustering_coef_wu",
149
+ "eigenvector_centrality_und",
150
+ ),
151
+ )
152
+ def test_bctpy_function(
153
+ matrix_storage: HDF5FeatureStorage,
154
+ caplog: pytest.LogCaptureFixture,
155
+ func: str,
156
+ ) -> None:
157
+ """Test working function of bctpy.
158
+
159
+ Parameters
160
+ ----------
161
+ matrix_storage : HDF5FeatureStorage
162
+ The HDF5FeatureStorage with matrix data, as fixture.
163
+ caplog : pytest.LogCaptureFixture
164
+ The pytest.LogCaptureFixture object.
165
+ func : str
166
+ The function to test.
167
+
168
+ """
169
+ # Skip test if import fails
170
+ pytest.importorskip("bct")
171
+
172
+ with caplog.at_level(logging.DEBUG):
173
+ read_transform(
174
+ storage=matrix_storage, # type: ignore
175
+ feature_name="BOLD_matrix",
176
+ transform=f"bctpy_{func}",
177
+ )
178
+ assert "Computing" in caplog.text
179
+ assert "Generating" in caplog.text
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: junifer
3
- Version: 0.0.3.dev131
3
+ Version: 0.0.3.dev148
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>
@@ -49,6 +49,8 @@ Requires-Dist: julearn (==0.2.5) ; extra == 'docs'
49
49
  Requires-Dist: sphinx-copybutton (==0.5.1) ; extra == 'docs'
50
50
  Requires-Dist: towncrier (==22.12.0) ; extra == 'docs'
51
51
  Requires-Dist: sphinxcontrib-mermaid (==0.8.1) ; extra == 'docs'
52
+ Provides-Extra: onthefly
53
+ Requires-Dist: bctpy (==0.6.0) ; extra == 'onthefly'
52
54
 
53
55
  ![Junifer logo](docs/images/junifer_logo.png "junifer logo")
54
56
 
@@ -82,7 +84,9 @@ The documentation is available at [https://juaml.github.io/junifer](https://juam
82
84
  * `data`: Module that handles data required for the library to work (e.g. parcels, coordinates).
83
85
  * `datagrabber`: DataGrabber module.
84
86
  * `datareader`: DataReader module.
87
+ * `external`: Module for external libraries and tools.
85
88
  * `markers`: Markers module.
89
+ * `onthefly`: Transformation components (on-the-fly) module.
86
90
  * `pipeline`: Pipeline module.
87
91
  * `preprocess`: Preprocessing module.
88
92
  * `storage`: Storage module.
@@ -1,5 +1,5 @@
1
- junifer/__init__.py,sha256=rJgTGeR-SOntQoLSGo36zKDTE8IMRBn2-YwC0JSNUpU,377
2
- junifer/_version.py,sha256=zrdxBHOLnzo6P7aJ99_k1bAOp-M3BvSj7nVMG0zeZzU,177
1
+ junifer/__init__.py,sha256=x1UR2jUcrUdm2HNl-3Qvyi4UUrU6ms5qm2qcmNY7zZk,391
2
+ junifer/_version.py,sha256=kvDO67P7RJ0LLRcQBePW7yJNV-eCAWLFpxAl-oBTn60,177
3
3
  junifer/stats.py,sha256=KUX4jJcLWnlE34coet8EkdFypFd-td4Vtpx5LvlomVs,5879
4
4
  junifer/api/__init__.py,sha256=YILu9M7SC0Ri4CVd90fELH2OnK_gvCYAXCoqBNCFE8E,257
5
5
  junifer/api/cli.py,sha256=epPGiMU9szF0Dbv-_ty3hxxWPUd8KM-gqQI10TJEl2Y,9843
@@ -35,7 +35,7 @@ junifer/configs/juseless/datagrabbers/tests/test_ukb_vbm.py,sha256=b9hjc1mgO--PS
35
35
  junifer/data/__init__.py,sha256=UKoiW2DfuNgWlpdqSVPWAED1tSMl9ygUHMsCnFXPp2A,507
36
36
  junifer/data/coordinates.py,sha256=mPiaOdw3HY5c_5geGiQbHjKCTvj2YVTXie0Y6HLFk_I,4896
37
37
  junifer/data/masks.py,sha256=oRvKzbm4Z4q3Dz1PdnsuS4t08x70s1fpbEgPeFKuy2Y,11277
38
- junifer/data/parcellations.py,sha256=r73CeNpGLYH6AGPvL_Zz2iLqXpZvoLkJZkNFz6bdMjM,40638
38
+ junifer/data/parcellations.py,sha256=8br_1uc1iV_fOXjiX1q6Hh39nS2wdApzU4P09MZZBA4,48676
39
39
  junifer/data/utils.py,sha256=K9quLIoWRmm2QFM8Rdy_5bYsWb_XhL0l5Uq_1Sie0kA,1274
40
40
  junifer/data/VOIs/meta/CogAC_VOIs.txt,sha256=Sr5_E712OLdeQRyUcDNM0wLBvZIyO6gc9Q7KkyJHX1A,398
41
41
  junifer/data/VOIs/meta/CogAR_VOIs.txt,sha256=t3NLwEVUZTPP34p15SaB3UInLrQyK-7Qc4iLBuQlZu8,189
@@ -60,7 +60,7 @@ junifer/data/masks/vickery-patil/GMprob0.2_cortex_3mm_NA_rm.nii.gz,sha256=jfMe_4
60
60
  junifer/data/tests/test_coordinates.py,sha256=RCYOuaAjs2wqPeFHX-l9Bryt5Zw5mOIV0WpsH891RwA,3240
61
61
  junifer/data/tests/test_data_utils.py,sha256=Vy7x8zaHws5hmn92PKSv3H38hU2kamOpyaH6nG_NNpw,1086
62
62
  junifer/data/tests/test_masks.py,sha256=sJ_rXAPddQ_2SAGvew1FEEMcLwy0NEfQv8TsCvgA2pA,13266
63
- junifer/data/tests/test_parcellations.py,sha256=2diYT-a6cgXjEaK8iBZl6YUBcpb-VuhEpKmRtbsFSak,26923
63
+ junifer/data/tests/test_parcellations.py,sha256=zAhIl2f1w6BEocSGujwZ-zveSFg8EBeQniRm_hoTxHs,32445
64
64
  junifer/datagrabber/__init__.py,sha256=xKMQMjqoWul13YluGTLLMBgKahUg5jJKi4phPih3XJU,634
65
65
  junifer/datagrabber/base.py,sha256=6JoIDBCWXCIQdjSg6OIbdrqbQKzV6_zBTk0Zs1Wj6_Y,4622
66
66
  junifer/datagrabber/datalad_base.py,sha256=dDaBiIePPP6-G4ycgBMxTcXxs4vkg-yDS3OBURK4VGs,10731
@@ -146,6 +146,9 @@ junifer/markers/tests/test_marker_utils.py,sha256=SR3ADWI3uGv4ozYqVu-rMZnJVqP6Jn
146
146
  junifer/markers/tests/test_markers_base.py,sha256=cbuCeMmjyFMP1ea6J6XRsBQo8CivQ41ooABiT1Snj2k,3076
147
147
  junifer/markers/tests/test_parcel_aggregation.py,sha256=RW2EKRokmavMZB7e8WghYc6fLm6UOHzOm6xKdvBsoo0,21501
148
148
  junifer/markers/tests/test_sphere_aggregation.py,sha256=1uOfnLQJ5hVCz7jcX9QG3M6htLSJSEOflKV6fXNtSZI,7652
149
+ junifer/onthefly/__init__.py,sha256=GG_Z5NgnVNph6CLPtGFI2HE_OIuVTZ874BOq72mA-ps,160
150
+ junifer/onthefly/read_transform.py,sha256=2yLlFscCZDS3z80ffD36_vF1GeKxSFfK0xNB-xsqOTM,4040
151
+ junifer/onthefly/tests/test_read_transform.py,sha256=D2C3IpXQHdsJSF07v8rEwGntLGXjZOserlRhebJUAVM,4719
149
152
  junifer/pipeline/__init__.py,sha256=gOOrLf_C3oe9RdmLLjKMhs2gqtrr5Tzfi_cyTFEp8HM,238
150
153
  junifer/pipeline/pipeline_step_mixin.py,sha256=fZtJa5NJ2_9r6dD_UOkXA5fOPtRjuPUbh4lnF-ILB4c,5019
151
154
  junifer/pipeline/registry.py,sha256=PQq8D6DiHhSeh0tdHs9J6jv9L1WsfEUqJxzhlzAQDbE,3956
@@ -187,10 +190,10 @@ junifer/utils/fs.py,sha256=Jd9AoV2fIF7pT7KhXsn8T1O1fJ1_SFZgaFuOBAM7DG8,460
187
190
  junifer/utils/logging.py,sha256=phBwOFaK6ejqbSjkCSAkZhhdo4sr01GdVZmJIL8t-Lw,8994
188
191
  junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
189
192
  junifer/utils/tests/test_logging.py,sha256=l8oo-AiBV7H6_IzlsNcj__cLeZBUvgIGoaMszD9VaJg,7754
190
- junifer-0.0.3.dev131.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
191
- junifer-0.0.3.dev131.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
192
- junifer-0.0.3.dev131.dist-info/METADATA,sha256=4WeSR9NPBNwBkJ6BQ3uulmidIWkTNFJeE4kTp0MyJAA,6508
193
- junifer-0.0.3.dev131.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
194
- junifer-0.0.3.dev131.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
195
- junifer-0.0.3.dev131.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
196
- junifer-0.0.3.dev131.dist-info/RECORD,,
193
+ junifer-0.0.3.dev148.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
194
+ junifer-0.0.3.dev148.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
195
+ junifer-0.0.3.dev148.dist-info/METADATA,sha256=1P5_ZElKDMxF97PWTlPrNpGvCCv26szrvETPaIgy5UI,6706
196
+ junifer-0.0.3.dev148.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
197
+ junifer-0.0.3.dev148.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
198
+ junifer-0.0.3.dev148.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
199
+ junifer-0.0.3.dev148.dist-info/RECORD,,