@@ -914,7 +914,7 @@ def convert(items, symlink=True, converter=None,
914
914
# save acquisition time information if it's BIDS
915
915
# at this point we still have acquisition date
916
916
if is_bids :
917
- save_scans_key (items , outname_bids_files )
917
+ save_scans_key (item , outname_bids_files )
918
918
# Fix up and unify BIDS files
919
919
tuneup_bids_json_files (outname_bids_files )
920
920
# we should provide specific handling for fmap,
@@ -967,13 +967,16 @@ def get_formatted_scans_key_row(item):
967
967
mw = ds .wrapper_from_data (dcm .read_file (dcm_fn , stop_before_pixels = True ))
968
968
# we need to store filenames and acquisition times
969
969
# parse date and time and get it into isoformat
970
- date = mw .dcm_data .AcquisitionDate
971
- time = mw .dcm_data .AcquisitionTime .split ('.' )[0 ]
970
+ date = mw .dcm_data .ContentDate
971
+ time = mw .dcm_data .ContentTime .split ('.' )[0 ]
972
972
td = time + date
973
973
acq_time = datetime .strptime (td , '%H%M%S%Y%m%d' ).isoformat ()
974
974
# add random string
975
975
randstr = '' .join (map (chr , sample (k = 8 , population = range (33 , 127 ))))
976
976
row = [acq_time , mw .dcm_data .PerformingPhysicianName , randstr ]
977
+ # empty entries should be 'n/a'
978
+ # https://github.com/dartmouth-pbs/heudiconv/issues/32
979
+ row = ['n/a' if not str (e ) else e for e in row ]
977
980
return row
978
981
979
982
@@ -1012,35 +1015,59 @@ def add_rows_to_scans_keys_file(fn, newrows):
1012
1015
writer .writerow ([key ] + fnames2info [key ])
1013
1016
1014
1017
1015
- def save_scans_key (items , outname_bids_files ):
1018
+ def _find_subj_ses (f_name ):
1019
+ """Given a path to the bids formatted filename parse out subject/session"""
1020
+ # we will allow the match at either directories or within filename
1021
+ # assuming that bids layout is "correct"
1022
+ regex = re .compile ('sub-(?P<subj>[a-zA-Z0-9]*)([/_]ses-(?P<ses>[a-zA-Z0-9]*))?' )
1023
+ res = regex .search (f_name ).groupdict ()
1024
+ return res .get ('subj' ), res .get ('ses' , None )
1025
+
1026
+
1027
+ def save_scans_key (item , bids_files ):
1016
1028
"""
1017
1029
Parameters
1018
1030
----------
1019
1031
items:
1020
- outname_bids_files:
1032
+ bids_files: str or list
1021
1033
1022
1034
Returns
1023
1035
-------
1024
1036
1025
1037
"""
1026
1038
rows = dict ()
1027
- for item , outname_bids_file in zip (items , outname_bids_files ):
1039
+ assert bids_files , "we do expect some files since it was called"
1040
+ # we will need to deduce subject and session from the bids_filename
1041
+ # and if there is a conflict, we would just blow since this function
1042
+ # should be invoked only on a result of a single item conversion as far
1043
+ # as I see it, so should have the same subject/session
1044
+ subj , ses = None , None
1045
+ for bids_file in bids_files :
1028
1046
# get filenames
1029
- f_name = '/' .join (outname_bids_file .split ('/' )[- 2 :])
1047
+ f_name = '/' .join (bids_file .split ('/' )[- 2 :])
1030
1048
f_name = f_name .replace ('json' , 'nii.gz' )
1031
1049
rows [f_name ] = get_formatted_scans_key_row (item )
1050
+ subj_ , ses_ = _find_subj_ses (f_name )
1051
+ if subj and subj_ != subj :
1052
+ raise ValueError (
1053
+ "We found before subject %s but now deduced %s from %s"
1054
+ % (subj , subj_ , f_name )
1055
+ )
1056
+ subj = subj_
1057
+ if ses and ses_ != ses :
1058
+ raise ValueError (
1059
+ "We found before session %s but now deduced %s from %s"
1060
+ % (ses , ses_ , f_name )
1061
+ )
1062
+ ses = ses_
1032
1063
# where should we store it?
1033
- output_dir = dirname (dirname (outname_bids_file ))
1034
- # get subject info
1035
- subj_pattern = re .compile ('(sub-[a-zA-Z0-9]*)' )
1036
- subj = subj_pattern .findall (f_name )
1037
- assert (len (subj ) >= 1 )
1038
- subj = subj [0 ]
1039
-
1064
+ output_dir = dirname (dirname (bids_file ))
1040
1065
# save
1066
+ ses = '_ses-%s' % ses if ses else ''
1041
1067
add_rows_to_scans_keys_file (
1042
- pjoin (output_dir , '{0}_scans.tsv' .format (subj )),
1043
- rows )
1068
+ pjoin (output_dir , 'sub-{0}{1}_scans.tsv' .format (subj , ses )),
1069
+ rows
1070
+ )
1044
1071
1045
1072
1046
1073
def tuneup_bids_json_files (json_files ):
@@ -1052,8 +1079,9 @@ def tuneup_bids_json_files(json_files):
1052
1079
for jsonfile in json_files :
1053
1080
json_ = json .load (open (jsonfile ))
1054
1081
# sanitize!
1055
- for f in ['AcquisitionDateTime' , 'AcquisitionDate' ]:
1056
- json_ .pop (f , None )
1082
+ for f1 in ['Acquisition' , 'Study' , 'Series' ]:
1083
+ for f2 in ['DateTime' , 'Date' ]:
1084
+ json_ .pop (f1 + f2 , None )
1057
1085
# TODO: should actually be placed into series file which must
1058
1086
# go under annex (not under git) and marked as sensitive
1059
1087
if 'Date' in str (json_ ):
@@ -1725,8 +1753,9 @@ def add_to_datalad(topdir, studydir, msg=None, bids=False):
1725
1753
mark_sensitive (ds , 'sourcedata' )
1726
1754
mark_sensitive (ds , '*_scans.tsv' ) # top level
1727
1755
mark_sensitive (ds , '*/*_scans.tsv' ) # within subj
1756
+ mark_sensitive (ds , '*/*/*_scans.tsv' ) # within sess/subj
1728
1757
mark_sensitive (ds , '*/anat' ) # within subj
1729
- mark_sensitive (ds , '*/*/anat' ) # within subj/ ses
1758
+ mark_sensitive (ds , '*/*/anat' ) # within ses/subj
1730
1759
if dsh :
1731
1760
mark_sensitive (dsh ) # entire .heudiconv!
1732
1761
dsh .save (message = msg )
0 commit comments