1313 visualqc T1 MRI utility : https://raamana.github.io/visualqc/cli_t1_mri.html
1414"""
1515
16- import argparse
1716import json
1817import random
1918import subprocess
2019from collections import defaultdict
2120from pathlib import Path
2221
2322
24- def get_args ():
25- parser = argparse .ArgumentParser (formatter_class = argparse .RawTextHelpFormatter , description = __doc__ )
26-
27- parser .add_argument ('-i' , '--input' , type = Path , action = 'store' , dest = 'inputdir' , metavar = 'INPUT_DIR' ,
28- help = 'Path to input BIDS directory.' )
29- parser .add_argument ('-o' , '--output' , type = Path , action = 'store' , dest = 'outdir' , metavar = 'SCRIPT_OUTPUT_DIR' ,
30- default = Path ('.' ), help = "Path to directory that'll contain this script's outputs." )
31- args = parser .parse_args ()
32-
33- return args .inputdir .resolve (), args .outdir .resolve ()
34-
35-
3623def run_command (cmdstr , logfile ):
3724 """Runs the given command str as shell subprocess. If logfile object is provided, then the stdout and stderr of the
3825 subprocess is written to the log file.
@@ -88,9 +75,9 @@ def primary_scans_qc_prep(mapping_dict, visualqc_prep):
8875 dest .mkdir (parents = True , exist_ok = True )
8976
9077 id_list .append (dest )
91- Path ( dest / 'primary.nii.gz' ). symlink_to ( primary )
92- # ln_cmd = f"ln -s {primary} {}"
93- # run_command(ln_cmd, "" )
78+ primary_link = dest / 'primary.nii.gz'
79+ if not primary_link . exists ():
80+ primary_link . symlink_to ( primary )
9481
9582 with open (visualqc_prep / 'id_list_t1.txt' , 'w' ) as f :
9683 f .write ('\n ' .join ([str (i ) for i in id_list ]))
@@ -135,26 +122,23 @@ def get_anat_dir_paths(subj_dir_path):
135122 :param Path subj_dir_path : Absolute path to subject directory.
136123 :return: A list of absolute paths to anat directory(s) within subject tree.
137124 """
138- anat_dirs = []
139- no_anat_dirs = []
140125
141126 # check if there are session directories
142- # sess_exist, sessions = is_sessions(subj_dir_path)
143127 sessions = list (subj_dir_path .glob ('ses-*' ))
144128 sess_exist = True if sessions else False
145129
130+ no_anat_dirs = []
131+ anat_dirs = []
146132 if not sess_exist :
147- anat_dir = subj_dir_path . joinpath ( 'anat' )
133+ anat_dir = subj_dir_path / 'anat'
148134 if not anat_dir .exists ():
149- # print(f'No anat directories found for {subj_dir_path.name}.\n')
150135 no_anat_dirs .append (subj_dir_path )
151136 else :
152137 anat_dirs .append (anat_dir )
153138 else :
154139 for sess in sessions :
155- anat_dir = sess . joinpath ( 'anat' )
140+ anat_dir = sess / 'anat'
156141 if not anat_dir .exists ():
157- # print(f'No anat directories found for {subj_dir_path.name} and {sess.name}.\n')
158142 no_anat_dirs .append (sess )
159143 else :
160144 anat_dirs .append (anat_dir )
@@ -183,7 +167,7 @@ def update_mapping_dict(mapping_dict, anat_dir, is_sessions, sidecars, t1_unavai
183167 # latest T1w scan in the session based on acquisition time
184168 nifti_fname = t1_acq_time_list [0 ][0 ].name .split ('.' )[0 ] + '.nii.gz'
185169
186- primary_t1 = t1_acq_time_list [0 ][0 ].parent . joinpath ( nifti_fname )
170+ primary_t1 = t1_acq_time_list [0 ][0 ].parent / nifti_fname
187171 others = [str (s ) for s in list (anat_dir .glob ('*.nii*' )) if s != primary_t1 ]
188172 t1_available .append (anat_dir .parent )
189173 else :
@@ -214,26 +198,23 @@ def summary_to_stdout(vqc_t1_cmd, sess_ct, t1s_found, t1s_not_found, no_anat_dir
214198 print (f"Sessions without a T1w scan: { len (t1s_not_found )} " )
215199 print (f"List of sessions without a T1w scan:\n { readable_path_list } " )
216200 print (
217- f"\n Please find the mapping file in JSON format at { str (output .joinpath ('primary_to_others_mapping.json' ))} \n and other helpful logs at { str (output .joinpath ('logs' ))} \n " )
218-
201+ f"\n Please find the mapping file in JSON format at { str (output / 'primary_to_others_mapping.json' )} \n and other helpful logs at { str (output / 'logs' )} \n " )
219202
220- def main ():
221- input , output = get_args ()
222203
223- # make a logs dir
224- output .joinpath ('logs' ).mkdir (parents = True , exist_ok = True )
204+ def crawl (input_dir , output ):
205+ # make dir for log files and visualqc prep
206+ dir_names = ['logs' , 'visualqc_prep' ]
207+ for dir_name in dir_names :
208+ output .joinpath (dir_name ).mkdir (parents = True , exist_ok = True )
225209
226- # make qc_prep dir
227- output .joinpath ('visualqc_prep' ).mkdir (parents = True , exist_ok = True )
228-
229- # input_layout = bids.BIDSLayout(input) # taking insane amounts of time so not using pybids
230210 t1s_not_found = []
231211 t1s_found = []
232212 total_sessions = 0
233213
234214 mapping_dict = defaultdict (lambda : defaultdict (lambda : defaultdict (list )))
235215
236- for subj_dir in list (input .glob ('sub-*' )):
216+ for subj_dir in list (input_dir .glob ('sub-*' )):
217+ # subj_id = subj_dir.name
237218 anat_dirs , no_anat_dirs , sess_exist = get_anat_dir_paths (subj_dir )
238219 for anat_dir in anat_dirs :
239220 total_sessions += 1
@@ -242,25 +223,20 @@ def main():
242223 t1_sidecars , t1s_not_found , t1s_found )
243224
244225 # write mapping dict to file
245- with open (output . joinpath ( 'primary_to_others_mapping.json' ) , 'w' ) as f1 :
226+ with open (output / 'primary_to_others_mapping.json' , 'w' ) as f1 :
246227 json .dump (mapping_dict , f1 , indent = 4 )
247228
248229 # write session paths without T1w scan to file
249- with open (output .joinpath ('logs' , 't1_unavailable.txt' ), 'w' ) as f2 :
250- for sess_path in t1s_not_found :
251- f2 .write (str (sess_path ) + '\n ' )
230+ with open (output / 'logs' / 't1_unavailable.txt' , 'w' ) as f2 :
231+ f2 .write ('\n ' .join ([str (sess_path ) for sess_path in t1s_not_found ]))
232+
233+ with open (output / 'logs' / 'anat_unavailable.txt' , 'w' ) as f3 :
234+ f3 .write ('\n ' .join ([str (p ) for p in no_anat_dirs ]))
252235
253236 # write vqc command to file
254237 vqc_t1_mri_cmd = primary_scans_qc_prep (mapping_dict , output / 'visualqc_prep' )
255- with open (output / 'visualqc_prep' / 't1_mri_qc_cmd' , 'w' ) as f3 :
256- f3 .write (f"{ vqc_t1_mri_cmd } \n " )
257-
258- with open (output .joinpath ('logs' , 'anat_unavailable.txt' ), 'w' ) as f4 :
259- for p in no_anat_dirs :
260- f4 .write (str (p ) + '\n ' )
238+ with open (output / 'visualqc_prep' / 't1_mri_qc_cmd' , 'w' ) as f4 :
239+ f4 .write (f"{ vqc_t1_mri_cmd } \n " )
261240
262241 summary_to_stdout (vqc_t1_mri_cmd , total_sessions , t1s_found , t1s_not_found , no_anat_dirs , output )
263-
264-
265- if __name__ == "__main__" :
266- main ()
242+ return mapping_dict
0 commit comments