Skip to content

Commit

Permalink
Simplify raw_to_bids
Browse files Browse the repository at this point in the history
  • Loading branch information
jasmainak committed Oct 4, 2018
1 parent ea3f22e commit 4564c92
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 111 deletions.
13 changes: 11 additions & 2 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ MNE BIDS (:py:mod:`mne_bids.mne_bids`):
.. autosummary::
:toctree: generated/

raw_to_bids
write_raw_bids
make_bids_filename

IO (:py:mod:`mne_bids.io`):

.. current_module:: mne_bids.io

.. autosummary::
:toctree: generated/

read_raw

Utils (:py:mod:`mne_bids.utils`):

Expand All @@ -24,5 +34,4 @@ Utils (:py:mod:`mne_bids.utils`):

print_dir_tree
make_bids_folders
make_bids_filename
make_dataset_description
17 changes: 11 additions & 6 deletions examples/convert_ds000117.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
# Let us import ``mne_bids``

import os.path as op
from mne_bids import raw_to_bids
from mne_bids import raw_to_bids, make_bids_filename
from mne_bids.io import read_raw
from mne_bids.datasets import fetch_faces_data
from mne_bids.utils import print_dir_tree

Expand Down Expand Up @@ -63,13 +64,17 @@
for subject_id in subject_ids:
subject = 'sub%03d' % subject_id
for run in runs:
raw_file = op.join(data_path, repo, subject, 'MEG',
'run_%02d_raw.fif' % run)
fname = op.join(data_path, repo, subject, 'MEG',
'run_%02d_raw.fif' % run)

raw = read_raw(fname)
bids_fname = make_bids_filename(
subject_id='%02d' % subject_id, session='01', run=run,
task='VisualFaces', suffix='meg.fif')

# Make it BIDS compatible
raw_to_bids(subject_id='%02d' % subject_id, session_id='01', run=run,
task='VisualFaces', raw_file=raw_file,
event_id=event_id, output_path=output_path, overwrite=True)
raw_to_bids(raw, output_path, bids_fname, event_id=event_id,
overwrite=True)

###############################################################################
# Now let's see the structure of the BIDS folder we created.
Expand Down
14 changes: 8 additions & 6 deletions examples/convert_mne_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

import os.path as op
from mne.datasets import sample
from mne_bids import raw_to_bids
from mne_bids import write_raw_bids, make_bids_filename
from mne_bids.io import read_raw
from mne_bids.utils import print_dir_tree

###############################################################################
Expand All @@ -29,17 +30,18 @@
event_id = {'Auditory/Left': 1, 'Auditory/Right': 2, 'Visual/Left': 3,
'Visual/Right': 4, 'Smiley': 5, 'Button': 32}

raw_file = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw.fif')
fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw.fif')
events_data = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw-eve.fif')
output_path = op.join(data_path, '..', 'MNE-sample-data-bids')

###############################################################################
# Finally, we specify the raw_file and events_data

raw_to_bids(subject_id='01', run='01', session_id='01', task='audiovisual',
raw_file=raw_file, events_data=events_data,
output_path=output_path, event_id=event_id,
overwrite=True)
raw = read_raw(fname)
bids_fname = make_bids_filename(subject='01', run='01', session='01',
task='audiovisual', suffix='meg.fif')
write_raw_bids(raw, bids_fname, output_path, events_data=events_data,
event_id=event_id, overwrite=True)

###############################################################################
# Now let's see the structure of the BIDS folder we created.
Expand Down
25 changes: 11 additions & 14 deletions examples/make_eeg_bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from mne.datasets import eegbci
from mne.io import read_raw_edf

from mne_bids import raw_to_bids
from mne_bids import write_raw_bids, make_bids_filename
from mne_bids.utils import print_dir_tree

###############################################################################
Expand Down Expand Up @@ -103,7 +103,7 @@
# * output_path
#
# ... as you can see in the docstring:
print(raw_to_bids.__doc__)
print(write_raw_bids.__doc__)

###############################################################################
# We loaded 'S001R02.edf', which corresponds to subject 1 in the second task.
Expand All @@ -129,8 +129,10 @@
trial_type = {'rest': 0, 'imagine left fist': 1, 'imagine right fist': 2}

# Now convert our data to be in a new BIDS dataset.
raw_to_bids(subject_id=subject_id, task=task, raw_file=raw_file,
output_path=output_path, kind=kind, event_id=trial_type)
bids_fname = make_bids_filename(subject=subject_id, task=task,
suffix='eeg.edf')
write_raw_bids(raw_file, bids_fname, output_path, kind=kind,
event_id=trial_type)

###############################################################################
# What does our fresh BIDS directory look like?
Expand Down Expand Up @@ -162,16 +164,11 @@
'S{:03}R{:02}.edf'.format(subj_idx, task_idx))
raw = read_raw_edf(edf_path, preload=True)

# `kind` and `trial_type` were already defined above
raw_to_bids(subject_id='{:03}'.format(subj_idx),
task=task_names[task_idx],
run=run_mapping[task_idx],
raw_file=raw,
output_path=output_path,
kind=kind,
event_id=trial_type,
overwrite=False
)
bids_fname = make_bids_filename(
subject='{:03}'.format(subj_idx), task=task_names[task_idx],
run=run_mapping[task_idx], suffix='eeg.edf')
write_raw_bids(raw, bids_fname, output_path, kind=kind,
event_id=trial_type, overwrite=False)

###############################################################################
# Step 3: Check and compare with standard
Expand Down
2 changes: 1 addition & 1 deletion mne_bids/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
__version__ = '0.1.dev0'


from .mne_bids import raw_to_bids # noqa
from .mne_bids import write_raw_bids # noqa
from .utils import make_bids_folders, make_bids_filename # noqa
from .config import BIDS_VERSION # noqa
4 changes: 2 additions & 2 deletions mne_bids/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def _parse_ext(raw_fname, verbose=False):
return fname, ext


def _read_raw(raw_fname, electrode=None, hsp=None, hpi=None, config=None,
montage=None, verbose=None):
def read_raw(raw_fname, electrode=None, hsp=None, hpi=None, config=None,
montage=None, verbose=None):
"""Read a raw file into MNE, making inferences based on extension."""
fname, ext = _parse_ext(raw_fname)

Expand Down
116 changes: 36 additions & 80 deletions mne_bids/mne_bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from mne.io.pick import channel_type
from mne.io import BaseRaw
from mne.channels.channels import _unit2human
from mne.externals.six import string_types

from datetime import datetime
from warnings import warn
Expand All @@ -29,8 +28,8 @@
make_dataset_description, _write_json,
_read_events, _mkdir_p, age_on_date,
copyfile_brainvision, copyfile_eeglab,
_infer_eeg_placement_scheme)
from .io import (_parse_ext, _read_raw, ALLOWED_EXTENSIONS)
_infer_eeg_placement_scheme, _parse_bids_filename)
from .io import (_parse_ext, ALLOWED_EXTENSIONS)


ALLOWED_KINDS = ['meg', 'eeg', 'ieeg']
Expand Down Expand Up @@ -485,30 +484,20 @@ def _sidecar_json(raw, task, manufacturer, fname, kind, eeg_ref=None,
return fname


def raw_to_bids(subject_id, task, raw_file, output_path, session_id=None,
acquisition=None, run=None, kind='meg', events_data=None,
event_id=None, hpi=None, electrode=None, hsp=None,
eeg_ref=None, eeg_gnd=None, config=None, overwrite=True,
verbose=True):
def write_raw_bids(raw, bids_fname, output_path, kind='meg', events_data=None,
event_id=None, eeg_ref=None, eeg_gnd=None, overwrite=True,
verbose=True):
"""Walk over a folder of files and create BIDS compatible folder.
Parameters
----------
subject_id : str
The subject name in BIDS compatible format ('01', '02', etc.)
task : str
Name of the task the data is based on.
raw_file : str | instance of mne.Raw
raw : instance of mne.Raw
The raw data. If a string, it is assumed to be the path to the raw data
file. Otherwise it must be an instance of mne.Raw
output_path : str
The path of the BIDS compatible folder
session_id : str | None
The session name in BIDS compatible format.
acquisition : str | None
Acquisition parameter for the dataset.
run : int | None
The run number for this dataset.
bids_fname : str
The file path of the BIDS compatible raw file. In the case of multifile
systems (e.g., vhdr, .ds etc.), this is the path to a folder containing
all the files.
kind : str, one of ('meg', 'eeg', 'ieeg')
The kind of data being converted. Defaults to "meg".
events_data : str | array | None
Expand All @@ -517,25 +506,11 @@ def raw_to_bids(subject_id, task, raw_file, output_path, session_id=None,
inferred from the stim channel using `mne.find_events`.
event_id : dict | None
The event id dict used to create a 'trial_type' column in events.tsv
hpi : None | str | list of str
Marker points representing the location of the marker coils with
respect to the MEG Sensors, or path to a marker file.
If list, all of the markers will be averaged together.
electrode : None | str
Digitizer points representing the location of the fiducials and the
marker coils with respect to the digitized head shape, or path to a
file containing these points.
hsp : None | str | array, shape = (n_points, 3)
Digitizer head shape points, or path to head shape file. If more than
10`000 points are in the head shape, they are automatically decimated.
eeg_ref : str
Description of the type of reference used and (when applicable) of
location of the reference electrode. Defaults to None.
eeg_gnd : str
Description of the location of the ground electrode. Defaults to None.
config : str | None
A path to the configuration file to use if the data is from a BTi
system.
overwrite : bool
If the file already exists, whether to overwrite it.
verbose : bool
Expand All @@ -549,26 +524,22 @@ def raw_to_bids(subject_id, task, raw_file, output_path, session_id=None,
of the participant correctly.
"""
if isinstance(raw_file, string_types):
# We must read in the raw data
raw = _read_raw(raw_file, electrode=electrode, hsp=hsp, hpi=hpi,
config=config, verbose=verbose)
_, ext = _parse_ext(raw_file, verbose=verbose)
raw_fname = raw_file
elif isinstance(raw_file, BaseRaw):
# We got a raw mne object, get back the filename if possible
# Assume that if no filename attr exists, it's a fif file.
raw = raw_file.copy()
if hasattr(raw, 'filenames'):
_, ext = _parse_ext(raw.filenames[0], verbose=verbose)
raw_fname = raw.filenames[0]
else:
# FIXME: How to get the filename if no filenames attribute?
raw_fname = 'unknown_file_name'
ext = '.fif'
else:
raise ValueError('raw_file must be an instance of str or BaseRaw, '
'got %s' % type(raw_file))
if not isinstance(raw, BaseRaw):
raise ValueError('raw_file must be an instance of BaseRaw, '
'got %s' % type(raw))

# We got a raw mne object, get back the filename if possible
# Assume that if no filename attr exists, it's a fif file.
if not hasattr(raw, 'filenames'):
raise ValueError('raw.filenames is missing.')

_, ext = _parse_ext(raw.filenames[0], verbose=verbose)
raw_fname = raw.filenames[0]

params = _parse_bids_filename(bids_fname)
subject_id, session_id = params['sub'], params['ses']
acquisition, task, run = params['acq'], params['task'], params['run']
fname = os.path.join(output_path, bids_fname)

data_path = make_bids_folders(subject=subject_id, session=session_id,
kind=kind, root=output_path,
Expand All @@ -594,18 +565,6 @@ def raw_to_bids(subject_id, task, raw_file, output_path, session_id=None,
data_meta_fname = make_bids_filename(
subject=subject_id, session=session_id, task=task, run=run,
acquisition=acquisition, suffix='%s.json' % kind, prefix=data_path)
if ext in ['.fif', '.ds', '.vhdr', '.edf', '.bdf', '.set', '.cnt']:
raw_file_bids = make_bids_filename(
subject=subject_id, session=session_id, task=task, run=run,
acquisition=acquisition, suffix='%s%s' % (kind, ext))
else:
raw_folder = make_bids_filename(
subject=subject_id, session=session_id, task=task, run=run,
acquisition=acquisition, suffix='%s' % kind)
raw_file_bids = make_bids_filename(
subject=subject_id, session=session_id, task=task, run=run,
acquisition=acquisition, suffix='%s%s' % (kind, ext),
prefix=raw_folder)
events_tsv_fname = make_bids_filename(
subject=subject_id, session=session_id, task=task,
acquisition=acquisition, run=run, suffix='events.tsv',
Expand Down Expand Up @@ -636,18 +595,15 @@ def raw_to_bids(subject_id, task, raw_file, output_path, session_id=None,
eeg_gnd, verbose)
_participants_tsv(raw, subject_id, "n/a", participants_fname, verbose)
_channels_tsv(raw, channels_fname, verbose)
_scans_tsv(raw, os.path.join(kind, raw_file_bids), scans_fname, verbose)
_scans_tsv(raw, os.path.join(kind, bids_fname), scans_fname, verbose)

# set the raw file name to now be the absolute path to ensure the files
# are placed in the right location
raw_file_bids = os.path.join(data_path, raw_file_bids)
if os.path.exists(raw_file_bids) and not overwrite:
if os.path.exists(fname) and not overwrite:
raise ValueError('"%s" already exists. Please set'
' overwrite to True.' % raw_file_bids)
_mkdir_p(os.path.dirname(raw_file_bids))
' overwrite to True.' % fname)
_mkdir_p(os.path.dirname(fname))

if verbose:
print('Writing data files to %s' % raw_file_bids)
print('Writing data files to %s' % fname)

if ext not in ALLOWED_EXTENSIONS:
raise ValueError('ext must be in %s, got %s'
Expand All @@ -657,17 +613,17 @@ def raw_to_bids(subject_id, task, raw_file, output_path, session_id=None,
# Re-save FIF files to fix the file pointer for files with multiple parts
# This is WIP, see: https://github.com/mne-tools/mne-python/pull/5470
if ext in ['.fif']:
raw.save(raw_file_bids, overwrite=overwrite)
raw.save(fname, overwrite=overwrite)
# CTF data is saved in a directory
elif ext == '.ds':
sh.copytree(raw_fname, raw_file_bids)
sh.copytree(raw_fname, fname)
# BrainVision is multifile, copy over all of them and fix pointers
elif ext == '.vhdr':
copyfile_brainvision(raw_fname, raw_file_bids)
copyfile_brainvision(raw_fname, fname)
# EEGLAB .set might be accompanied by a .fdt - find out and copy it too
elif ext == '.set':
copyfile_eeglab(raw_fname, raw_file_bids)
copyfile_eeglab(raw_fname, fname)
else:
sh.copyfile(raw_fname, raw_file_bids)
sh.copyfile(raw_fname, fname)

return output_path
14 changes: 14 additions & 0 deletions mne_bids/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ def _mkdir_p(path, overwrite=False, verbose=False):
raise


def _parse_bids_filename(fname):
"""Get dict from BIDS fname."""
params = dict(sub=None, ses=None, task=None, acq=None,
run=None, proc=None, recording=None, space=None)
entities = fname.split('_')
for entity in entities[:-1]:
key, value = entity.split('-')
if key not in params:
raise KeyError('Unexpected entity found in filename %s' % entity)
params[key] = value
params['suffix'] = entities[-1]
return params


def make_bids_filename(subject=None, session=None, task=None,
acquisition=None, run=None, processing=None,
recording=None, space=None, suffix=None, prefix=None):
Expand Down

0 comments on commit 4564c92

Please sign in to comment.