/ 4dConcatDataTable
4dConcatDataTable
 1  #!/usr/bin/env bash
 2  set -euo pipefail
 3  trap 'e=$?; [ $e -ne 0 ] && echo "$0 exited in error"' EXIT
 4  
 5  # wrap around 3dbucket and 3drefit
 6  # extract a subbrick from a list of nifti 
 7  # label with luna ids
 8  # 20200430 - like 4dConcatSubBriks but for a datatable file
 9  # 20231016 - add stdin option
10  #
11  usage(){
12     cat <<HEREDOC
13  use 3dMVM/3dLME datatable to create 4d concat image
14  Useful for quality checking many structurals, subject masks, or individual contrasts.
15  Wraps (1) 3dbucket InputFile column (2) 3drefit w/ Subj column
16  
17   USAGE:
18    $(basename "$0") output.nii.gz datatable.tsv [extraidcol]
19  
20   OPTIONS:
21    output.nii.gz   the file to create
22                    will not overwrite (must rm to rerun)
23  
24    datatable.tsv   input file as used by AFNI's 3dMVM or 3dLME
25                    tab separated.
26                    must have header w/ 'Subj' and 'InputFile' columns
27                    can be '-' to read from stdin
28  
29    extraidcol      optional extra column(s) to add to 3drefit ids (regexp)
30                    '|' to seprate multiples: 'Sess|Sex' (id is combined Subj,Sess,Sex)
31  
32   EXAMPLES:
33    4dConcatDataTable /tmp/all.nii.gz r2p.tsv
34  
35    4dConcatDataTable /tmp/all.nii.gz r2p.tsv 'session|shapes'
36  
37    mlr --tsv filter '\$InputFile =~ "ses-01"' r2p.tsv| 4dConcatDataTable /tmp/ses1.nii.gz -
38  
39  HEREDOC
40  }
41  
42  [ $# -lt 2 -o $# -gt 3 ] && usage >&2 && exit 1
43  
44  prefix="$1"; shift
45  datatable="$1"; shift
46  
47  ! [[ $prefix =~ .nii$|.nii.gz$|.HEAD$ ]] &&
48     echo "prefix '$prefix' must end in .nii, .nii.gz, or .HEAD" && exit 1
49  
50  [ -r "$prefix" ] &&
51     echo "rm $prefix # to regenerate; skipping 3dbucket and 3drefit" &&
52     exit 0
53  
54  if [ "$datatable" = "-" ]; then
55     tty >/dev/null  &&
56        echo -e "ERROR: using '$datatable' as datatable requires pipe;\n\t grep thing | $(basename "$0") $prefix $datatable $*" &&
57        exit 1
58     datatable=$(mktemp "${TMPDIR:-/tmp}/4dConcatTable_XXXX.tsv")
59     cat > "$datatable"
60     # TODO: this disables original exit in error trap
61     trap 'echo "# removing $datatable" && rm "$datatable"; exit' EXIT
62  fi
63  
64  [ ! -r "$datatable" ] &&
65     echo "$datatable file doesn't exist!" && exit 1
66  #read ididx fileidx <<< $(sed 1q $datatable | sed 's/[ \t]\+/\n/g' | perl -lne 'print $. if m/(Subj|InputFile)/i')
67  
68  # if we want to use an extra id
69  extraid=""; extraidpatt=""; awkextra="" 
70  [ $# -eq 1 ] && extraid="$1" && extraidpatt="|$extraid" 
71  
72  mapfile -t idxs < <(sed 1q "$datatable" | sed 's/[ \t]\+/\n/g' | perl -lne "print $. if m/(Subj$extraidpatt|InputFile)/i")
73  # index of the file index is last item
74  # but 0-based. so minus 1
75  fii=${#idxs[@]}
76  ! let fii-- && echo "ERROR: no files in $datatable!? Does input have a header?"  && exit 1
77  
78  # TODO: test only 2 if not $3, 3 otherwise?
79  
80  ididx=${idxs[0]}
81  fileidx=${idxs[$fii]}
82  [ ${#idxs[@]} -eq 3 ] && awkextra=' "_"'"\$${idxs[1]}"
83  
84  [ -z "$fileidx" ] && echo "no InputFile in '$datatable' header?! (idxs '$ididx' '$fileidx')" && exit 1
85  mapfile -t ids < <(awk "(NR>1) { print \$$ididx$awkextra}" "$datatable")
86  mapfile -t files < <(awk "(NR>1){ print \$$fileidx}" "$datatable")
87  [ ${#ids[@]} -ne "${#files[@]}" ] &&
88     echo "error parsing '$datatable'. have different number of ids and files!" &&
89     exit 1
90  
91  
92  echo "3dbucket: combine"
93  dryrun 3dbucket -prefix "$prefix" "${files[@]}"
94  echo "3drefit: relabel"
95  dryrun 3drefit -relabel_all_str "${ids[*]}" "$prefix"