junifer 0.0.4.dev119__py3-none-any.whl → 0.0.4.dev133__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
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.0.4.dev119'
16
- __version_tuple__ = version_tuple = (0, 0, 4, 'dev119')
15
+ __version__ = version = '0.0.4.dev133'
16
+ __version_tuple__ = version_tuple = (0, 0, 4, 'dev133')
junifer/data/__init__.py CHANGED
@@ -8,6 +8,7 @@ from .coordinates import (
8
8
  list_coordinates,
9
9
  load_coordinates,
10
10
  register_coordinates,
11
+ get_coordinates,
11
12
  )
12
13
  from .parcellations import (
13
14
  list_parcellations,
@@ -1,11 +1,12 @@
1
1
  """Provide functions for list of coordinates."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
+ # Synchon Mandal <s.mandal@fz-juelich.de>
4
5
  # License: AGPL
5
6
 
6
7
  import typing
7
8
  from pathlib import Path
8
- from typing import Dict, List, Optional, Tuple, Union
9
+ from typing import Any, Dict, List, Optional, Tuple, Union
9
10
 
10
11
  import numpy as np
11
12
  import pandas as pd
@@ -57,7 +58,7 @@ def register_coordinates(
57
58
  voi_names: List[str],
58
59
  overwrite: Optional[bool] = False,
59
60
  ) -> None:
60
- """Register coordinates.
61
+ """Register a custom user coordinates.
61
62
 
62
63
  Parameters
63
64
  ----------
@@ -73,6 +74,18 @@ def register_coordinates(
73
74
  overwrite : bool, optional
74
75
  If True, overwrite an existing list of coordinates with the same name.
75
76
  Does not apply to built-in coordinates (default False).
77
+
78
+ Raises
79
+ ------
80
+ ValueError
81
+ If the coordinates name is already registered and overwrite is set to
82
+ False or if the coordinates name is a built-in coordinates or if the
83
+ ``coordinates`` is not a 2D array or if coordinate value does not have
84
+ 3 components or if the ``voi_names`` shape does not match the
85
+ ``coordinates`` shape.
86
+ TypeError
87
+ If ``coordinates`` is not a ``numpy.ndarray``.
88
+
76
89
  """
77
90
  if name in _available_coordinates:
78
91
  if isinstance(_available_coordinates[name], Path):
@@ -90,7 +103,8 @@ def register_coordinates(
90
103
 
91
104
  if not isinstance(coordinates, np.ndarray):
92
105
  raise_error(
93
- f"Coordinates must be a numpy.ndarray, not {type(coordinates)}."
106
+ f"Coordinates must be a `numpy.ndarray`, not {type(coordinates)}.",
107
+ klass=TypeError,
94
108
  )
95
109
  if coordinates.ndim != 2:
96
110
  raise_error(
@@ -102,8 +116,8 @@ def register_coordinates(
102
116
  )
103
117
  if len(voi_names) != coordinates.shape[0]:
104
118
  raise_error(
105
- f"Length of voi_names ({len(voi_names)}) does not match the "
106
- f"number of coordinates ({coordinates.shape[0]})."
119
+ f"Length of `voi_names` ({len(voi_names)}) does not match the "
120
+ f"number of `coordinates` ({coordinates.shape[0]})."
107
121
  )
108
122
  _available_coordinates[name] = {
109
123
  "coords": coordinates,
@@ -112,16 +126,55 @@ def register_coordinates(
112
126
 
113
127
 
114
128
  def list_coordinates() -> List[str]:
115
- """List all the available coordinates lists (VOIs).
129
+ """List all the available coordinates (VOIs).
116
130
 
117
131
  Returns
118
132
  -------
119
133
  list of str
120
134
  A list with all available coordinates names.
135
+
121
136
  """
122
137
  return sorted(_available_coordinates.keys())
123
138
 
124
139
 
140
+ def get_coordinates(
141
+ coords: str,
142
+ target_data: Dict[str, Any],
143
+ extra_input: Optional[Dict[str, Any]] = None,
144
+ ) -> Tuple[ArrayLike, List[str]]:
145
+ """Get coordinates, tailored for the target image.
146
+
147
+ Parameters
148
+ ----------
149
+ coords : str
150
+ The name of the coordinates.
151
+ target_data : dict
152
+ The corresponding item of the data object to which the coordinates
153
+ will be applied.
154
+ extra_input : dict, optional
155
+ The other fields in the data object. Useful for accessing other data
156
+ kinds that needs to be used in the computation of coordinates
157
+ (default None).
158
+
159
+ Returns
160
+ -------
161
+ numpy.ndarray
162
+ The coordinates.
163
+ list of str
164
+ The names of the VOIs.
165
+
166
+ Raises
167
+ ------
168
+ ValueError
169
+ If ``extra_input`` is None when ``target_data``'s space is not MNI.
170
+
171
+ """
172
+ # Load the coordinates
173
+ seeds, labels = load_coordinates(name=coords)
174
+
175
+ return seeds, labels
176
+
177
+
125
178
  def load_coordinates(name: str) -> Tuple[ArrayLike, List[str]]:
126
179
  """Load coordinates.
127
180
 
@@ -137,14 +190,23 @@ def load_coordinates(name: str) -> Tuple[ArrayLike, List[str]]:
137
190
  list of str
138
191
  The names of the VOIs.
139
192
 
193
+ Raises
194
+ ------
195
+ ValueError
196
+ If ``name`` is invalid.
197
+
140
198
  Warns
141
199
  -----
142
200
  DeprecationWarning
143
201
  If ``Power`` is provided as the ``name``.
144
202
 
145
203
  """
204
+ # Check for valid coordinates name
146
205
  if name not in _available_coordinates:
147
- raise_error(f"Coordinates {name} not found.")
206
+ raise_error(
207
+ f"Coordinates {name} not found. "
208
+ f"Valid options are: {list_coordinates()}"
209
+ )
148
210
 
149
211
  # Put up deprecation notice
150
212
  if name == "Power":
@@ -157,8 +219,10 @@ def load_coordinates(name: str) -> Tuple[ArrayLike, List[str]]:
157
219
  category=DeprecationWarning,
158
220
  )
159
221
 
222
+ # Load coordinates
160
223
  t_coord = _available_coordinates[name]
161
224
  if isinstance(t_coord, Path):
225
+ # Load via pandas
162
226
  df_coords = pd.read_csv(t_coord, sep="\t", header=None)
163
227
  coords = df_coords.iloc[:, [0, 1, 2]].to_numpy()
164
228
  names = list(df_coords.iloc[:, [3]].values[:, 0])
@@ -167,4 +231,5 @@ def load_coordinates(name: str) -> Tuple[ArrayLike, List[str]]:
167
231
  coords = typing.cast(ArrayLike, coords)
168
232
  names = t_coord["voi_names"]
169
233
  names = typing.cast(List[str], names)
234
+
170
235
  return coords, names
@@ -8,10 +8,13 @@ import pytest
8
8
  from numpy.testing import assert_array_equal
9
9
 
10
10
  from junifer.data.coordinates import (
11
+ get_coordinates,
11
12
  list_coordinates,
12
13
  load_coordinates,
13
14
  register_coordinates,
14
15
  )
16
+ from junifer.datareader import DefaultDataReader
17
+ from junifer.testing.datagrabbers import OasisVBMTestingDataGrabber
15
18
 
16
19
 
17
20
  def test_register_coordinates_built_in_check() -> None:
@@ -54,7 +57,7 @@ def test_register_coordinates_overwrite() -> None:
54
57
 
55
58
  def test_register_coordinates_valid_input() -> None:
56
59
  """Test coordinates registration check for valid input."""
57
- with pytest.raises(ValueError, match=r"numpy.ndarray"):
60
+ with pytest.raises(TypeError, match=r"numpy.ndarray"):
58
61
  register_coordinates(
59
62
  name="MyList",
60
63
  coordinates=[1, 2],
@@ -105,3 +108,21 @@ def test_load_coordinates_nonexisting() -> None:
105
108
  """Test loading coordinates that not exist."""
106
109
  with pytest.raises(ValueError, match=r"not found"):
107
110
  load_coordinates("NonExisting")
111
+
112
+
113
+ def test_get_coordinates() -> None:
114
+ """Test tailored coordinates fetch."""
115
+ reader = DefaultDataReader()
116
+ with OasisVBMTestingDataGrabber() as dg:
117
+ element = dg["sub-01"]
118
+ element_data = reader.fit_transform(element)
119
+ vbm_gm = element_data["VBM_GM"]
120
+ # Get tailored coordinates
121
+ tailored_coords, tailored_labels = get_coordinates(
122
+ coords="DMNBuckner", target_data=vbm_gm
123
+ )
124
+ # Get raw coordinates
125
+ raw_coords, raw_labels = load_coordinates("DMNBuckner")
126
+ # Both tailored and raw should be same for now
127
+ assert_array_equal(tailored_coords, raw_coords)
128
+ assert tailored_labels == raw_labels
@@ -7,7 +7,7 @@
7
7
  from typing import Any, ClassVar, Dict, List, Optional, Set, Union
8
8
 
9
9
  from ..api.decorators import register_marker
10
- from ..data import get_mask, load_coordinates
10
+ from ..data import get_coordinates, get_mask
11
11
  from ..external.nilearn import JuniferNiftiSpheresMasker
12
12
  from ..stats import get_aggfunc_by_name
13
13
  from ..utils import logger, raise_error, warn_with_log
@@ -55,6 +55,12 @@ class SphereAggregation(BaseMarker):
55
55
  The name of the marker. By default, it will use KIND_SphereAggregation
56
56
  where KIND is the kind of data it was applied to (default None).
57
57
 
58
+ Raises
59
+ ------
60
+ ValueError
61
+ If ``time_method`` is specified for non-BOLD data or if
62
+ ``time_method_params`` is not None when ``time_method`` is None.
63
+
58
64
  """
59
65
 
60
66
  _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn", "numpy"}
@@ -118,6 +124,11 @@ class SphereAggregation(BaseMarker):
118
124
  str
119
125
  The storage type output by the marker.
120
126
 
127
+ Raises
128
+ ------
129
+ ValueError
130
+ If the ``input_type`` is invalid.
131
+
121
132
  """
122
133
 
123
134
  if input_type in ["VBM_GM", "VBM_WM", "fALFF", "GCOR", "LCOR"]:
@@ -125,7 +136,7 @@ class SphereAggregation(BaseMarker):
125
136
  elif input_type == "BOLD":
126
137
  return "timeseries"
127
138
  else:
128
- raise ValueError(f"Unknown input kind for {input_type}")
139
+ raise_error(f"Unknown input kind for {input_type}")
129
140
 
130
141
  def compute(
131
142
  self,
@@ -155,6 +166,11 @@ class SphereAggregation(BaseMarker):
155
166
  * ``data`` : the actual computed values as a numpy.ndarray
156
167
  * ``col_names`` : the column labels for the computed values as list
157
168
 
169
+ Warns
170
+ -----
171
+ RuntimeWarning
172
+ If time aggregation is required but only time point is available.
173
+
158
174
  """
159
175
  t_input_img = input["data"]
160
176
  logger.debug(f"Sphere aggregation using {self.method}")
@@ -162,15 +178,25 @@ class SphereAggregation(BaseMarker):
162
178
  agg_func = get_aggfunc_by_name(
163
179
  self.method, func_params=self.method_params
164
180
  )
181
+
182
+ # Get seeds and labels tailored to target image
183
+ coords, labels = get_coordinates(
184
+ coords=self.coords,
185
+ target_data=input,
186
+ extra_input=extra_input,
187
+ )
188
+
165
189
  # Load mask
166
190
  mask_img = None
167
191
  if self.masks is not None:
168
192
  logger.debug(f"Masking with {self.masks}")
193
+ # Get tailored mask
169
194
  mask_img = get_mask(
170
195
  masks=self.masks, target_data=input, extra_input=extra_input
171
196
  )
172
- # Get seeds and labels
173
- coords, out_labels = load_coordinates(name=self.coords)
197
+
198
+ # Initialize masker
199
+ logger.debug("Masking")
174
200
  masker = JuniferNiftiSpheresMasker(
175
201
  seeds=coords,
176
202
  radius=self.radius,
@@ -180,6 +206,8 @@ class SphereAggregation(BaseMarker):
180
206
  )
181
207
  # Fit and transform the marker on the data
182
208
  out_values = masker.fit_transform(t_input_img)
209
+
210
+ # Apply time dimension aggregation if required
183
211
  if self.time_method is not None:
184
212
  if out_values.shape[0] > 1:
185
213
  logger.debug("Aggregating time dimension")
@@ -193,5 +221,5 @@ class SphereAggregation(BaseMarker):
193
221
  "available."
194
222
  )
195
223
  # Format the output
196
- out = {"data": out_values, "col_names": out_labels}
224
+ out = {"data": out_values, "col_names": labels}
197
225
  return out
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: junifer
3
- Version: 0.0.4.dev119
3
+ Version: 0.0.4.dev133
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,5 +1,5 @@
1
1
  junifer/__init__.py,sha256=x1UR2jUcrUdm2HNl-3Qvyi4UUrU6ms5qm2qcmNY7zZk,391
2
- junifer/_version.py,sha256=Q_-FZFzlsFgJsOYYiliNsv6V9_LUpEPKEWnwNMotXoQ,428
2
+ junifer/_version.py,sha256=H4AlzRmDL8gZspsFPWSrhtdTYzXK9ftnsDE7ckYan-c,428
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=mgqSeZbW9DvdztGL3DRXM4SQS7saJ-v18K6FL8LaDVs,11915
@@ -36,8 +36,8 @@ junifer/configs/juseless/datagrabbers/tests/test_camcan_vbm.py,sha256=o0dzptS97p
36
36
  junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py,sha256=8jxpNZelXwpJGvA5LOfpso2X8yt1chvERAYmv76hS_g,1252
37
37
  junifer/configs/juseless/datagrabbers/tests/test_ucla.py,sha256=e-jdvcZ9B0mka6_573JJU_cGwSaUV54U8X_n0UadtJY,3351
38
38
  junifer/configs/juseless/datagrabbers/tests/test_ukb_vbm.py,sha256=b9hjc1mgO--PSRC3id2EzzfE2yWNsuZ2UI47a6sfGZU,1025
39
- junifer/data/__init__.py,sha256=2H-kSQrc1w41m35SCzMBMcwTqauZ6wRDPhmqbl-iWo4,529
40
- junifer/data/coordinates.py,sha256=vals9pjwkEorw5rmvEOCOhkzz3biAfRKsNVQgJNRQWI,5485
39
+ junifer/data/__init__.py,sha256=oUjOs8_M6fitNb44izxpXf3su1e4pG_vCdjwVYkjZjQ,550
40
+ junifer/data/coordinates.py,sha256=8jwx3uN4rmmwTWfbwjtsXhTlWIBqXlGizKjwdPklNSk,7231
41
41
  junifer/data/masks.py,sha256=SYt2EJCUCw7KAl8nBK5fRFRonrfIVQn-DH6aQsnr7vE,11280
42
42
  junifer/data/parcellations.py,sha256=9W3cZBS1SS3Rc48-diMYMxuzO3oxQfrsWvnPnONGjDc,51172
43
43
  junifer/data/utils.py,sha256=K9quLIoWRmm2QFM8Rdy_5bYsWb_XhL0l5Uq_1Sie0kA,1274
@@ -62,7 +62,7 @@ junifer/data/VOIs/meta/extDMN_VOIs.txt,sha256=Ogx1QvqZcnXDM3ncF2ha78br8xwQ5wklSj
62
62
  junifer/data/masks/vickery-patil/CAT12_IXI555_MNI152_TMP_GS_GMprob0.2_clean.nii.gz,sha256=j6EY8EtRnUuRxeKgD65Q6B0GPEPIALKDJEIje1TfnAU,88270
63
63
  junifer/data/masks/vickery-patil/CAT12_IXI555_MNI152_TMP_GS_GMprob0.2_clean_3mm.nii.gz,sha256=crb_y7YO1vjjf2PwbRJUm8KamPK6fx1y0B_l-E3g8FY,12862
64
64
  junifer/data/masks/vickery-patil/GMprob0.2_cortex_3mm_NA_rm.nii.gz,sha256=jfMe_4H9XEnArYms5bSQbqS2V1_HbLHTfI5amQa_Pes,8700
65
- junifer/data/tests/test_coordinates.py,sha256=RCYOuaAjs2wqPeFHX-l9Bryt5Zw5mOIV0WpsH891RwA,3240
65
+ junifer/data/tests/test_coordinates.py,sha256=UvB1BexiQUs9e_Lj8VrKGK3XiyukXhA2Tn_kW0wmrUA,4067
66
66
  junifer/data/tests/test_data_utils.py,sha256=Vy7x8zaHws5hmn92PKSv3H38hU2kamOpyaH6nG_NNpw,1086
67
67
  junifer/data/tests/test_masks.py,sha256=uhY3dm0CGbKTMs8hAMJxQx0KMcl9qmfaee3guBrdYas,13269
68
68
  junifer/data/tests/test_parcellations.py,sha256=XHNW_WrYuIfcbSZ04TexY2F2XwY9PqdKztC8HCE-nFU,34791
@@ -107,7 +107,7 @@ junifer/markers/base.py,sha256=Uuaz8MvdHOfAnRGpUf6ISWgbNWzkmHIMo6f30jlW7zY,6109
107
107
  junifer/markers/collection.py,sha256=u5DAWdEPsYK1Jmqob1FZgzOK_cm_8JXJ2CpSVxgamBY,4592
108
108
  junifer/markers/ets_rss.py,sha256=7fr6mmbMM5NKIDV6bUyyu-pwHJH56GwYv6oozK4EX6k,4557
109
109
  junifer/markers/parcel_aggregation.py,sha256=F059dbrow2v8MREm2l29mbPg2_PcSwfNalbUJOwaFsE,8420
110
- junifer/markers/sphere_aggregation.py,sha256=6is1hPIv0PV_iToZ5834RJsxI0HeuNcj4OUNXnbM-0o,7372
110
+ junifer/markers/sphere_aggregation.py,sha256=bnX9aiHf8pon47QVA0BiFOZV1Bgpyy4doPh2K0Nl9OA,8027
111
111
  junifer/markers/utils.py,sha256=kqgnzFqu2BkFW-UcJA2TrtgCctUncIbersWFapxcXBg,3777
112
112
  junifer/markers/falff/__init__.py,sha256=QAUIVtaOFWDL7B8xFrDgsmRum7Q0DCENyDYD1cPMJmM,197
113
113
  junifer/markers/falff/falff_base.py,sha256=W6bwkEOtiBTNMow2OQlPWCtP5GLy75TlEWK-48_xGl8,6001
@@ -198,10 +198,10 @@ junifer/utils/fs.py,sha256=Jd9AoV2fIF7pT7KhXsn8T1O1fJ1_SFZgaFuOBAM7DG8,460
198
198
  junifer/utils/logging.py,sha256=phBwOFaK6ejqbSjkCSAkZhhdo4sr01GdVZmJIL8t-Lw,8994
199
199
  junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
200
200
  junifer/utils/tests/test_logging.py,sha256=l8oo-AiBV7H6_IzlsNcj__cLeZBUvgIGoaMszD9VaJg,7754
201
- junifer-0.0.4.dev119.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
202
- junifer-0.0.4.dev119.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
203
- junifer-0.0.4.dev119.dist-info/METADATA,sha256=H1G7jQ4AnQr8hN8ntw7Cn0Q2ihvpR8367-kITbMXAZE,6825
204
- junifer-0.0.4.dev119.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
205
- junifer-0.0.4.dev119.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
206
- junifer-0.0.4.dev119.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
207
- junifer-0.0.4.dev119.dist-info/RECORD,,
201
+ junifer-0.0.4.dev133.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
202
+ junifer-0.0.4.dev133.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
203
+ junifer-0.0.4.dev133.dist-info/METADATA,sha256=80MHorCb5IZa8m9SBXNaVmzFs5fMG5pPAWYwc_EJ1oI,6825
204
+ junifer-0.0.4.dev133.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
205
+ junifer-0.0.4.dev133.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
206
+ junifer-0.0.4.dev133.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
207
+ junifer-0.0.4.dev133.dist-info/RECORD,,