Skip to content

Commit

Permalink
Merge pull request #244 from eurunuela/enh/dataset_description
Browse files Browse the repository at this point in the history
Generate participants.tsv if it doesn't exist or update it if subject is missing in the file
  • Loading branch information
eurunuela authored Jun 17, 2020
2 parents 1ea3ce2 + f84cbd8 commit 5a9972c
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 4 deletions.
74 changes: 73 additions & 1 deletion phys2bids/bids.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os
import logging

from csv import reader
from pathlib import Path

import yaml

from phys2bids import utils

LGR = logging.getLogger(__name__)
Expand Down Expand Up @@ -170,3 +172,73 @@ def use_heuristic(heur_file, sub, ses, filename, outdir, record_label=''):
heurpath = os.path.join(fldr, f'{name}physio')

return heurpath


def participants_file(outdir, yml, sub):
"""
Create participants.tsv file if it does not exist.
If it exists and the subject is missing, then add it.
Otherwise, do nothing.
Parameters
----------
outdir: path
Full path to the output directory.
yml: path
Full path to the yaml file.
sub: str
Subject ID.
"""
LGR.info('Updating participants.tsv ...')
file_path = os.path.join(outdir, 'participants.tsv')
if not os.path.exists(file_path):
LGR.warning('phys2bids could not find participants.tsv')
# Read yaml info if file exists
if '.yml' in yml and os.path.exists(yml):
LGR.info('Using yaml data to populate participants.tsv')
with open(yml) as f:
yaml_data = yaml.load(f, Loader=yaml.FullLoader)
p_id = f'sub-{sub}'
p_age = yaml_data['participant']['age']
p_sex = yaml_data['participant']['sex']
p_handedness = yaml_data['participant']['handedness']
else:
LGR.info('No yaml file was provided. Using phys2bids data to '
'populate participants.tsv')
# Fill in with data from phys2bids
p_id = f'sub-{sub}'
p_age = 'n/a'
p_sex = 'n/a'
p_handedness = 'n/a'

# Write to participants.tsv file
header = ['participant_id', 'age', 'sex', 'handedness']
utils.append_list_as_row(file_path, header)

participants_data = [p_id, p_age, p_sex, p_handedness]
utils.append_list_as_row(file_path, participants_data)

else: # If participants.tsv exists only update when subject is not there
LGR.info('phys2bids found participants.tsv. Updating if needed...')
# Find participant_id column in header
pf = open(file_path, 'r')
header = pf.readline().split("\t")
header_length = len(header)
pf.close()
p_id_idx = header.index('participant_id')

# Check if subject is already in the file
sub_exists = False
with open(file_path) as pf:
tsvreader = reader(pf, delimiter="\t")
for line in tsvreader:
if sub in line[p_id_idx]:
sub_exists = True
break
# Only append to file if subject is not in the file
if not sub_exists:
LGR.info(f'Appending subjet sub-{sub} to participants.tsv ...')
participants_data = ['n/a'] * header_length
participants_data[p_id_idx] = f'sub-{sub}'
utils.append_list_as_row(file_path, participants_data)
6 changes: 6 additions & 0 deletions phys2bids/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ def _get_parser():
type=str,
help='full path to store channels plot ',
default='')
optional.add_argument('-yml', '--participant-yml',
dest='yml',
type=str,
help='full path to file with info needed to generate '
'participant.tsv file ',
default='')
optional.add_argument('-debug', '--debug',
dest='debug',
action='store_true',
Expand Down
5 changes: 5 additions & 0 deletions phys2bids/heuristics/participant.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
participant:
participant_id: # Required
age: n/a
sex: n/a
handedness: n/a
9 changes: 7 additions & 2 deletions phys2bids/phys2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from numpy import savetxt

from phys2bids import utils, viz, _version
from phys2bids.bids import bidsify_units, use_heuristic
from phys2bids.bids import bidsify_units, use_heuristic, participants_file
from phys2bids.cli.run import _get_parser
from phys2bids.physio_obj import BlueprintOutput

Expand Down Expand Up @@ -112,7 +112,8 @@ def print_json(outfile, samp_freq, time_offset, ch_name):

def phys2bids(filename, info=False, indir='.', outdir='.', heur_file=None,
sub=None, ses=None, chtrig=0, chsel=None, num_timepoints_expected=0,
tr=1, thr=None, ch_name=[], chplot='', debug=False, quiet=False):
tr=1, thr=None, ch_name=[], chplot='', debug=False, quiet=False,
yml=''):
"""
Main workflow of phys2bids.
Expand Down Expand Up @@ -264,6 +265,10 @@ def phys2bids(filename, info=False, indir='.', outdir='.', heur_file=None,

if heur_file and sub:
LGR.info(f'Preparing BIDS output using {heur_file}')
# Generate participants.tsv file if it doesn't exist already.
# Update the file if the subject is not in the file.
# Do not update if the subject is already in the file.
participants_file(outdir, yml, sub)
elif heur_file and not sub:
LGR.warning('While "-heur" was specified, option "-sub" was not.\n'
'Skipping BIDS formatting.')
Expand Down
14 changes: 14 additions & 0 deletions phys2bids/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import re
import subprocess
from csv import reader
from pkg_resources import resource_filename

from phys2bids._version import get_versions
Expand Down Expand Up @@ -336,6 +337,19 @@ def test_integration_heuristic(samefreq_short_txt_file):
assert math.isclose(json_data['StartTime'], -189.6,)
assert json_data['Columns'] == ['time', 'RESP - RSP100C', 'MR TRIGGER - Custom, HLT100C - A 5']

# Check that participant.tsv gets updated
phys2bids(filename=test_full_path, chtrig=test_chtrig, outdir=test_outdir,
num_timepoints_expected=test_ntp, tr=test_tr, thr=test_thr, sub='002',
ses='01', heur_file=test_heur)

counter = 0
subject_list = ['participant_id', '006', '002']
with open(os.path.join(test_path, 'participants.tsv')) as pf:
tsvreader = reader(pf, delimiter="\t")
for line in tsvreader:
assert subject_list[counter] in line[0]
counter += 1

# Remove generated files
for filename in glob.glob(os.path.join(test_path, 'phys2bids*')):
os.remove(filename)
Expand Down
10 changes: 10 additions & 0 deletions phys2bids/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import os
import sys
from csv import writer
from pathlib import Path

LGR = logging.getLogger(__name__)
Expand Down Expand Up @@ -280,3 +281,12 @@ def load_heuristic(heuristic):
except Exception as exc:
raise ImportError(f'Failed to import heuristic {heuristic}: {exc}')
return mod


def append_list_as_row(file_name, list_of_elem):
# Open file in append mode
with open(file_name, 'a+', newline='') as write_obj:
# Create a writer object from csv module
csv_writer = writer(write_obj, delimiter='\t')
# Add contents of list as last row in the csv file
csv_writer.writerow(list_of_elem)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
numpy>=1.9.3
matplotlib>=3.1.1
PyYAML
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ python_requires = >=3.6.1
install_requires =
numpy >=1.9.3
matplotlib >=3.1.1
PyYAML
tests_require =
pytest >=3.6
test_suite = pytest
Expand All @@ -47,8 +48,8 @@ test =
interfaces =
%(acq)s
all =
%(interfaces)s
%(doc)s
%(interfaces)s
%(style)s
%(test)s

Expand Down

0 comments on commit 5a9972c

Please sign in to comment.