11
11
import warnings
12
12
from pathlib import Path
13
13
14
+ SUPPORTED_AGE_UNITS = ('weeks' , 'months' , 'years' )
15
+
14
16
15
17
def write_bidsignore (deriv_dir ):
16
18
# TODO: Port to niworkflows
@@ -237,26 +239,22 @@ def parse_bids_for_age_months(
237
239
238
240
239
241
def _get_age_from_tsv (
240
- bids_tsv : Path , level : ty .Literal ['session' , 'participant' ], key : str
242
+ bids_tsv : Path ,
243
+ level : ty .Literal ['session' , 'participant' ],
244
+ key : str ,
241
245
) -> int | None :
242
246
import pandas as pd
243
247
244
248
df = pd .read_csv (str (bids_tsv ), sep = '\t ' )
245
249
age_col = None
246
- # prefer explicit "age_months" over "age"
247
- for c in ('age_months' , 'age' ):
248
- if c in df .columns :
249
- age_col = c
250
+
251
+ for column in ('age_weeks' , ' age_months' , 'age_years ' , 'age' ):
252
+ if column in df .columns :
253
+ age_col = column
250
254
break
251
255
252
- if age_col == 'age' :
253
- # verify age is in months
254
- bids_json = bids_tsv .with_suffix ('.json' )
255
- if not _verify_age_json (bids_json ):
256
- warnings .warn (
257
- f'Could not verify age column is in months for file: { bids_tsv } ' ,
258
- stacklevel = 1 ,
259
- )
256
+ if age_col is None :
257
+ return
260
258
261
259
# find the relevant row
262
260
if level == 'session' :
@@ -268,13 +266,57 @@ def _get_age_from_tsv(
268
266
# extract age value from row
269
267
age = int (df .loc [mask , age_col ].values [0 ])
270
268
except Exception : # noqa: BLE001
271
- age = None
272
- return age
269
+ return
273
270
271
+ if age_col == 'age' :
272
+ # verify age is in months
273
+ bids_json = bids_tsv .with_suffix ('.json' )
274
+ age_units = _get_age_units (bids_json )
275
+ if age_units is False :
276
+ warnings .warn (
277
+ f'Could not verify age units for file: { bids_tsv } ' ,
278
+ stacklevel = 1 ,
279
+ )
280
+ age_units = 'months'
281
+ else :
282
+ age_units = age_col .split ('_' )[- 1 ]
283
+
284
+ age_months = age_to_months (age , units = age_units )
285
+ return age_months
274
286
275
- def _verify_age_json (bids_json : Path ) -> bool :
287
+
288
+ def _get_age_units (bids_json : Path ) -> ty .Literal ['weeks' , 'months' , 'years' , False ]:
276
289
try :
277
290
data = json .loads (bids_json .read_text ())
278
- return data ['age' ]['Units' ].lower () == 'months'
279
- except Exception : # noqa: BLE001
291
+ except json .JSONDecodeError :
280
292
return False
293
+
294
+ # See if the unit is listed
295
+ units = data .get ('age' , {}).get ('Units' )
296
+ for unit in units :
297
+ if unit .lower () in SUPPORTED_AGE_UNITS :
298
+ return unit
299
+ return False
300
+
301
+
302
+ def age_to_months (age : int , units : ty .Literal ['weeks' , 'months' , 'years' ]) -> int :
303
+ """
304
+ Convert a given age, in either "weeks", "months", or "years", into months.
305
+
306
+ >>> age_to_months(1, 'years')
307
+ 12
308
+ >>> age_to_months(2, 'weeks')
309
+ 0
310
+ >>> age_to_months(3, 'weeks')
311
+ 1
312
+ >>> age_to_months(8, 'months')
313
+ 8
314
+ """
315
+ WEEKS_TO_MONTH = 0.230137
316
+ YEARS_TO_MONTH = 12
317
+
318
+ if units == 'weeks' :
319
+ age = round (age * WEEKS_TO_MONTH )
320
+ elif units == 'years' :
321
+ age *= YEARS_TO_MONTH
322
+ return age
0 commit comments