Skip to content

Commit 37b8c5e

Browse files
committed
ENH: Add support for parsing scans.tsv
1 parent 915269d commit 37b8c5e

File tree

1 file changed

+34
-18
lines changed

1 file changed

+34
-18
lines changed

nibabies/utils/bids.py

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -215,33 +215,51 @@ def parse_bids_for_age_months(
215215
session_id: str | None = None,
216216
) -> int | None:
217217
"""
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.
219220
220221
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`
223225
"""
224-
age = None
225226
if subject_id.startswith('sub-'):
226227
subject_id = subject_id[4:]
227228
if session_id and session_id.startswith('ses-'):
228229
session_id = session_id[4:]
229230

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'
231248
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
233253

234254
participants_tsv = Path(bids_root) / 'participants.tsv'
235255
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)
237257

238258
return age
239259

240260

241261
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
245263
) -> int | None:
246264
import pandas as pd
247265

@@ -252,19 +270,17 @@ def _get_age_from_tsv(
252270
if column in df.columns:
253271
age_col = column
254272
break
255-
256273
if age_col is None:
257274
return
258275

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()
264280

265281
try:
266282
# extract age value from row
267-
age = int(df.loc[mask, age_col].values[0])
283+
age = int(df.loc[idx, age_col].item())
268284
except Exception: # noqa: BLE001
269285
return
270286

@@ -288,7 +304,7 @@ def _get_age_from_tsv(
288304
def _get_age_units(bids_json: Path) -> ty.Literal['weeks', 'months', 'years', False]:
289305
try:
290306
data = json.loads(bids_json.read_text())
291-
except json.JSONDecodeError:
307+
except (json.JSONDecodeError, OSError):
292308
return False
293309

294310
# See if the unit is listed

0 commit comments

Comments
 (0)