Skip to content

Commit

Permalink
Merge branch 'release/0.1.0'
Browse files Browse the repository at this point in the history
CHANGES:

- Added: two *new* tools -- metadata generator and BIDS clear
- Fixed: multiple bugfixes
- Added: Aesthetic improvements
  • Loading branch information
TinasheMTapera committed Oct 9, 2019
2 parents a12ae92 + 647b713 commit b339b1a
Show file tree
Hide file tree
Showing 13 changed files with 909 additions and 115 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sandbox
16 changes: 8 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ COPY manifest.json ${FLYWHEEL}/manifest.json
ENTRYPOINT ["/flywheel/v0/fw_heudiconv_run.py"]

# Copy over python scripts that generate the BIDS hierarchy
RUN apt-get -y update
RUN apt-get install -y zip
RUN pip install --no-cache heudiconv flywheel-sdk pandas
RUN apt-get -y update && apt-get install -y curl
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get -y update && apt-get install -y zip nodejs
RUN npm install -g bids-validator
RUN pip install --no-cache heudiconv nipype flywheel-sdk pandas

COPY . /src

RUN cd /src \
&& pip install . \
&& pip install --no-cache --no-deps heudiconv \
&& pip install --no-cache flywheel-sdk \
&& pip install --no-cache nipype \
&& rm -rf /src \
&& apt-get install -y --no-install-recommends zip
&& rm -rf /src

COPY fw_heudiconv_run.py /flywheel/v0/fw_heudiconv_run.py
RUN chmod +x ${FLYWHEEL}/*
Expand Down
170 changes: 170 additions & 0 deletions fw_heudiconv/cli/clear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import argparse
import flywheel
import logging
import warnings
import sys

with warnings.catch_warnings():
warnings.simplefilter('ignore')
from fw_heudiconv.cli.export import get_nested


logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('fw-heudiconv-clearer')


def clear_bids(client, project_label, session_labels=None, subject_labels=None, dry_run=False, file_types = ['.nii', '.bval', '.bvec']):

logger.info("Querying Flywheel server...")

with warnings.catch_warnings():
warnings.simplefilter("ignore")
project_obj = client.projects.find_first('label="{}"'.format(project_label))

if project_obj is None:
logger.error("Project not found! Maybe check spelling...?")
return 1

logger.debug('\tFound project: \n\t\t%s (%s)', project_obj['label'], project_obj.id)
sessions = client.get_project_sessions(project_obj.id)

# filters
if subject_labels:
sessions = [s for s in sessions if s.subject['label'] in subject_labels]
if session_labels:
sessions = [s for s in sessions if s.label in session_labels]

if not sessions:
logger.error("No sessions found!")
return 1

logger.info('\tFound subjects:\n\t\t%s',
"\n\t\t".join(set(['%s (%s)' % (ses.subject.label, ses.subject.id) for ses in sessions])))

logger.info('\tFound sessions:\n\t\t%s',
"\n\t\t".join(['%s (%s)' % (ses['label'], ses.id) for ses in sessions]))

file_list = []
for ses in sessions:

acquisitions = ses.acquisitions()

for acq in acquisitions:

files = [f.to_dict() for f in acq.files if any([x in f.name for x in file_types])]

files = [f for f in files if get_nested(f, 'info', 'BIDS') != 'NA' and get_nested(f, 'info', 'BIDS') is not None and get_nested(f, 'info', 'BIDS', 'Filename') != '']

if files:
file_list.append({acq.id: files})

fnames = []
for x in file_list:
for k, v in x.items():
for u in v:
name = get_nested(u, 'info', 'BIDS', 'Filename')
if name is not None:
fnames.append(name)

if file_list:
logger.debug("This will remove BIDS data from %d files:\n\t%s" % (len(file_list), "\n\t".join([x for x in fnames])))


if not dry_run:
logger.info('\t\t=======: Removing BIDS data :=======\n')

for acq_files in file_list:

for k, v in acq_files.items():
acq = client.get(k)

for fi in v:

BIDS = get_nested(fi, 'info', 'BIDS')
new_bids = {k:'' for k,v in BIDS.items()}
acq.update_file_info(fi['name'], {'BIDS': new_bids})

else:
logger.info("Disable `dry_run` mode to apply these changes and remove the BIDS information.")

else:
logger.info("No BIDS data to remove! (That was easy...)")

return 0


def get_parser():

parser = argparse.ArgumentParser(
description="Go nuclear: clear BIDS data from Flywheel")
parser.add_argument(
"--project",
help="The project in flywheel",
nargs="+",
required=True
)
parser.add_argument(
"--subject",
help="The subject label(s)",
nargs="+",
default=None
)
parser.add_argument(
"--session",
help="The session label(s)",
nargs="+",
default=None
)
parser.add_argument(
"--verbose",
help="Print ongoing messages of progress",
action='store_true',
default=False
)
parser.add_argument(
"--dry-run",
help="Don't apply changes",
action='store_true',
default=False
)
parser.add_argument(
"--api-key",
help="API Key",
action='store',
default=None
)

return parser


def main():

logger.info("{:=^70}\n".format(": fw-heudiconv clearer starting up :"))
parser = get_parser()
args = parser.parse_args()

with warnings.catch_warnings():
warnings.simplefilter("ignore")
if args.api_key:
fw = flywheel.Client(args.api_key)
else:
fw = flywheel.Client()
assert fw, "Your Flywheel CLI credentials aren't set!"

# Print a lot if requested
if args.verbose:
logger.setLevel(logging.DEBUG)

project_label = ' '.join(args.project)
status = clear_bids(client=fw,
project_label=project_label,
session_labels=args.session,
subject_labels=args.subject,
dry_run=args.dry_run)

logger.info("Done!")
logger.info("{:=^70}".format(": Exiting fw-heudiconv clearer :"))
sys.exit(status)

if __name__ == '__main__':
main()
45 changes: 31 additions & 14 deletions fw_heudiconv/cli/curate.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
import argparse
import warnings
import flywheel
import pprint
from collections import defaultdict
from ..convert import apply_heuristic, confirm_intentions, confirm_bids_namespace
from ..query import get_seq_info
from heudiconv import utils
from heudiconv import heuristics
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('fwHeuDiConv-curator')
logger = logging.getLogger('fw-heudiconv-curator')


def pretty_string_seqinfo(seqinfo):
tr = seqinfo.TR if seqinfo.TR is not None else -1.0
Expand Down Expand Up @@ -86,6 +87,7 @@ def convert_to_bids(client, project_label, heuristic_path, subject_labels=None,
logger.info("Applying heuristic to query results...")
to_rename = heuristic.infotodict(seq_infos)

print(to_rename)
if not to_rename:
logger.debug("No changes to apply!")
sys.exit(1)
Expand All @@ -94,7 +96,7 @@ def convert_to_bids(client, project_label, heuristic_path, subject_labels=None,
if hasattr(heuristic, "IntendedFor"):
logger.info("Processing IntendedFor fields based on heuristic file")
intention_map.update(heuristic.IntendedFor)
logger.debug("Intention map: %s", intention_map)
logger.debug("Intention map: %s", pprint.pformat([(k[0], v) for k, v in dict(intention_map).items()]))

metadata_extras = defaultdict(list)
if hasattr(heuristic, "MetadataExtras"):
Expand Down Expand Up @@ -123,18 +125,17 @@ def convert_to_bids(client, project_label, heuristic_path, subject_labels=None,
apply_heuristic(client, key, value, dry_run, intention_map[key],
metadata_extras[key], subject_rename, session_rename, seqitem+1)

if not dry_run:
for ses in sessions:
confirm_intentions(client, ses)
for ses in sessions:
confirm_intentions(client, ses, dry_run)


def get_parser():

parser = argparse.ArgumentParser(
description="Use a heudiconv heuristic to curate bids on flywheel")
description="Use a heudiconv heuristic to curate data into BIDS on flywheel")
parser.add_argument(
"--project",
help="The project in flywheel",
nargs="+",
required=True
)
parser.add_argument(
Expand All @@ -161,35 +162,51 @@ def get_parser():
default=False
)
parser.add_argument(
"--dry_run",
"--dry-run",
help="Don't apply changes",
action='store_true',
default=False
)
parser.add_argument(
"--api-key",
help="API Key",
action='store',
default=None
)

return parser


def main():

logger.info("{:=^70}\n".format(": fw-heudiconv curator starting up :"))

parser = get_parser()
args = parser.parse_args()

with warnings.catch_warnings():
warnings.simplefilter("ignore")
fw = flywheel.Client()
if args.api_key:
fw = flywheel.Flywheel(args.api_key)
else:
fw = flywheel.Client()
assert fw, "Your Flywheel CLI credentials aren't set!"
parser = get_parser()
args = parser.parse_args()

# Print a lot if requested
if args.verbose:
logger.setLevel(logging.DEBUG)

project_label = ' '.join(args.project)
convert_to_bids(client=fw,
project_label=project_label,
project_label=args.project,
heuristic_path=args.heuristic,
session_labels=args.session,
subject_labels=args.subject,
dry_run=args.dry_run)

logger.info("Done!")
logger.info("{:=^70}".format(": Exiting fw-heudiconv curator :"))
sys.exit()


if __name__ == '__main__':
main()
Loading

0 comments on commit b339b1a

Please sign in to comment.