@@ -215,33 +215,51 @@ def parse_bids_for_age_months(
215
215
session_id : str | None = None ,
216
216
) -> int | None :
217
217
"""
218
- Given a BIDS root, query the BIDS metadata files for participant age, in months.
218
+ Given a BIDS root, query the BIDS metadata files for participant age, and return in
219
+ chronological months.
219
220
220
221
The heuristic followed is:
221
- 1) Check `sub-<subject_id>/sub-<subject_id>_sessions.tsv`
222
- 2) Check `<root>/participants.tsv`
222
+ 1) Check `sub-<subject_id>[/ses-<session_id>]/<sub-<subject_id>[_ses-<session-id>]_scans.tsv
223
+ 2) Check `sub-<subject_id>/sub-<subject_id>_sessions.tsv`
224
+ 3) Check `<root>/participants.tsv`
223
225
"""
224
- age = None
225
226
if subject_id .startswith ('sub-' ):
226
227
subject_id = subject_id [4 :]
227
228
if session_id and session_id .startswith ('ses-' ):
228
229
session_id = session_id [4 :]
229
230
230
- sessions_tsv = Path (bids_root ) / f'sub-{ subject_id } ' / f'sub-{ subject_id } _sessions.tsv'
231
+ # Play nice with sessions
232
+ subject = f'sub-{ subject_id } '
233
+ session = f'ses-{ session_id } ' or ''
234
+ prefix = f'{ subject } ' + f'_{ session } ' if session else ''
235
+
236
+ subject_level = session_level = Path (bids_root ) / subject
237
+ if session_id :
238
+ session_level = subject_level / session
239
+
240
+ scans_tsv = session_level / f'{ prefix } _scans.tsv'
241
+ if scans_tsv .exists ():
242
+ age = _get_age_from_tsv (scans_tsv )
243
+
244
+ if age is not None :
245
+ return age
246
+
247
+ sessions_tsv = subject_level / f'{ subject } _sessions.tsv'
231
248
if sessions_tsv .exists () and session_id is not None :
232
- age = _get_age_from_tsv (sessions_tsv , level = 'session' , key = f'ses-{ session_id } ' )
249
+ age = _get_age_from_tsv (sessions_tsv , index_column = 'session_id' , index_val = session )
250
+
251
+ if age is not None :
252
+ return age
233
253
234
254
participants_tsv = Path (bids_root ) / 'participants.tsv'
235
255
if participants_tsv .exists () and age is None :
236
- age = _get_age_from_tsv (participants_tsv , level = 'participant ' , key = f'sub- { subject_id } ' )
256
+ age = _get_age_from_tsv (participants_tsv , index_column = 'participant_id ' , index_val = subject )
237
257
238
258
return age
239
259
240
260
241
261
def _get_age_from_tsv (
242
- bids_tsv : Path ,
243
- level : ty .Literal ['session' , 'participant' ],
244
- key : str ,
262
+ bids_tsv : Path , index_column : str | None = None , index_val : str | None = None
245
263
) -> int | None :
246
264
import pandas as pd
247
265
@@ -252,19 +270,17 @@ def _get_age_from_tsv(
252
270
if column in df .columns :
253
271
age_col = column
254
272
break
255
-
256
273
if age_col is None :
257
274
return
258
275
259
- # find the relevant row
260
- if level == 'session' :
261
- mask = df .session_id == key
262
- elif level == 'participant' :
263
- mask = df .participant_id == key
276
+ if not index_column or not index_val : # Just grab first value
277
+ idx = df .index [0 ]
278
+ else :
279
+ idx = df .index [df [index_column ] == index_val ].item ()
264
280
265
281
try :
266
282
# extract age value from row
267
- age = int (df .loc [mask , age_col ].values [ 0 ] )
283
+ age = int (df .loc [idx , age_col ].item () )
268
284
except Exception : # noqa: BLE001
269
285
return
270
286
@@ -288,7 +304,7 @@ def _get_age_from_tsv(
288
304
def _get_age_units (bids_json : Path ) -> ty .Literal ['weeks' , 'months' , 'years' , False ]:
289
305
try :
290
306
data = json .loads (bids_json .read_text ())
291
- except json .JSONDecodeError :
307
+ except ( json .JSONDecodeError , OSError ) :
292
308
return False
293
309
294
310
# See if the unit is listed
0 commit comments