Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MRG] construct mgh image only when vox2ras_tkr is needed #241

Merged
merged 4 commits into from
Jul 23, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/convert_mri_and_trans.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@

import numpy as np
import matplotlib.pyplot as plt

from nilearn.plotting import plot_anat

import mne
from mne.datasets import sample
from mne.source_space import head_to_mri
Expand Down Expand Up @@ -148,6 +150,7 @@
plot_anat(t1_mgh_fname, axes=axs[point_idx],
cut_coords=mri_pos[point_idx, :],
title=label)
plt.show()


###############################################################################
Expand Down
101 changes: 45 additions & 56 deletions mne_bids/tests/test_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
task=task)
bids_basename_minimal = make_bids_basename(subject=subject_id, task=task)


# WINDOWS issues:
# the bids-validator development version does not work properly on Windows as
# of 2019-06-25 --> https://github.com/bids-standard/bids-validator/issues/790
Expand All @@ -56,16 +57,26 @@
# using the stable bids-validator and make a direct call of bids-validator
# also: for windows, shell = True is needed to call npm, bids-validator etc.
# see: https://stackoverflow.com/q/28891053/5201771
shell = False
bids_validator_exe = ['bids-validator']
if platform.system() == 'Windows':
shell = True
exe = os.getenv('VALIDATOR_EXECUTABLE', 'n/a')
if 'VALIDATOR_EXECUTABLE' != 'n/a':
bids_validator_exe = ['node', exe]


def test_fif():
@pytest.fixture(scope="session")
sappelhoff marked this conversation as resolved.
Show resolved Hide resolved
def _bids_validate():
jasmainak marked this conversation as resolved.
Show resolved Hide resolved
"""Fixture to run BIDS validator."""
shell = False
bids_validator_exe = ['bids-validator', '--config.error=41',
'--config.error=41']
if platform.system() == 'Windows':
shell = True
exe = os.getenv('VALIDATOR_EXECUTABLE', 'n/a')
if 'VALIDATOR_EXECUTABLE' != 'n/a':
bids_validator_exe = ['node', exe]

def _validate(output_path):
cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)

return _validate


def test_fif(_bids_validate):
"""Test functionality of the write_raw_bids conversion for fif."""
output_path = _TempDir()
data_path = testing.data_path()
Expand Down Expand Up @@ -98,8 +109,7 @@ def test_fif():
with pytest.warns(UserWarning, match='No events found or provided.'):
write_raw_bids(raw, bids_basename, output_path, overwrite=False)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

# write the same data but pretend it is empty room data:
raw = mne.io.read_raw_fif(raw_fname)
Expand Down Expand Up @@ -174,8 +184,7 @@ def test_fif():
with pytest.raises(ValueError, match='raw.filenames is missing'):
write_raw_bids(raw, bids_basename2, output_path)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

assert op.exists(op.join(output_path, 'participants.tsv'))

Expand Down Expand Up @@ -203,7 +212,7 @@ def test_fif():
assert 'part' in FILE


def test_kit():
def test_kit(_bids_validate):
"""Test functionality of the write_raw_bids conversion for KIT data."""
output_path = _TempDir()
data_path = op.join(base_path, 'kit', 'tests', 'data')
Expand All @@ -224,8 +233,8 @@ def test_kit():
write_raw_bids(raw, kit_bids_basename, output_path,
events_data=events_fname,
event_id=event_id, overwrite=False)
cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)

_bids_validate(output_path)
assert op.exists(op.join(output_path, 'participants.tsv'))

read_raw_bids(kit_bids_basename + '_meg.sqd', output_path)
Expand Down Expand Up @@ -268,8 +277,8 @@ def test_kit():
kit_bids_basename.replace('sub-01', 'sub-%s' % subject_id2),
output_path, events_data=events_fname, event_id=event_id,
overwrite=False)
cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)

_bids_validate(output_path)
# ensure the marker files are renamed correctly
marker_fname = make_bids_basename(
subject=subject_id2, session=session_id, task=task, run=run,
Expand All @@ -295,7 +304,7 @@ def test_kit():
overwrite=True)


def test_ctf():
def test_ctf(_bids_validate):
"""Test functionality of the write_raw_bids conversion for CTF data."""
output_path = _TempDir()
data_path = op.join(testing.data_path(download=False), 'CTF')
Expand All @@ -305,8 +314,7 @@ def test_ctf():
with pytest.warns(UserWarning, match='No line frequency'):
write_raw_bids(raw, bids_basename, output_path=output_path)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)
with pytest.warns(UserWarning, match='Did not find any events'):
raw = read_raw_bids(bids_basename + '_meg.ds', output_path)

Expand All @@ -317,7 +325,7 @@ def test_ctf():
assert op.exists(op.join(output_path, 'participants.tsv'))


def test_bti():
def test_bti(_bids_validate):
"""Test functionality of the write_raw_bids conversion for BTi data."""
output_path = _TempDir()
data_path = op.join(base_path, 'bti', 'tests', 'data')
Expand All @@ -331,9 +339,7 @@ def test_bti():
write_raw_bids(raw, bids_basename, output_path, verbose=True)

assert op.exists(op.join(output_path, 'participants.tsv'))

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

raw = read_raw_bids(bids_basename + '_meg', output_path)

Expand All @@ -342,7 +348,7 @@ def test_bti():
# see: https://github.com/mne-tools/mne-python/pull/6558
@pytest.mark.skipif(LooseVersion(mne.__version__) < LooseVersion('0.19'),
reason="requires mne 0.19.dev0 or higher")
def test_vhdr():
def test_vhdr(_bids_validate):
"""Test write_raw_bids conversion for BrainVision data."""
output_path = _TempDir()
data_path = op.join(base_path, 'brainvision', 'tests', 'data')
Expand All @@ -357,9 +363,7 @@ def test_vhdr():

# write with injected bad channels
write_raw_bids(raw, bids_basename_minimal, output_path, overwrite=False)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

# read and also get the bad channels
raw = read_raw_bids(bids_basename_minimal + '_eeg.vhdr', output_path)
Expand Down Expand Up @@ -394,12 +398,10 @@ def test_vhdr():
for i in mne.pick_types(raw.info, eeg=True)})
output_path = _TempDir()
write_raw_bids(raw, bids_basename, output_path, overwrite=False)
_bids_validate(output_path)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)


def test_edf():
def test_edf(_bids_validate):
"""Test write_raw_bids conversion for European Data Format data."""
output_path = _TempDir()
data_path = op.join(testing.data_path(), 'EDF')
Expand All @@ -426,9 +428,7 @@ def test_edf():

bids_fname = bids_basename.replace('run-01', 'run-%s' % run2)
write_raw_bids(raw, bids_fname, output_path, overwrite=True)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

# ensure there is an EMG channel in the channels.tsv:
channels_tsv = make_bids_basename(
Expand All @@ -451,12 +451,10 @@ def test_edf():
for i in mne.pick_types(raw.info, eeg=True)})
output_path = _TempDir()
write_raw_bids(raw, bids_basename, output_path)
_bids_validate(output_path)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)


def test_bdf():
def test_bdf(_bids_validate):
"""Test write_raw_bids conversion for Biosemi data."""
output_path = _TempDir()
data_path = op.join(base_path, 'edf', 'tests', 'data')
Expand All @@ -465,9 +463,7 @@ def test_bdf():
raw = mne.io.read_raw_bdf(raw_fname)
with pytest.warns(UserWarning, match='No line frequency found'):
write_raw_bids(raw, bids_basename, output_path, overwrite=False)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

# Test also the reading of channel types from channels.tsv
# the first channel in the raw data is not MISC right now
Expand Down Expand Up @@ -495,7 +491,7 @@ def test_bdf():
write_raw_bids(raw, bids_basename, output_path)


def test_set():
def test_set(_bids_validate):
"""Test write_raw_bids conversion for EEGLAB data."""
# standalone .set file
output_path = _TempDir()
Expand All @@ -522,9 +518,7 @@ def test_set():
with pytest.raises(FileExistsError, match="already exists"): # noqa: F821
write_raw_bids(raw, bids_basename, output_path=output_path,
overwrite=False)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

# check events.tsv is written
# XXX: only from 0.18 onwards because events_from_annotations
Expand All @@ -541,13 +535,11 @@ def test_set():
for i in mne.pick_types(raw.info, eeg=True)})
output_path = _TempDir()
write_raw_bids(raw, bids_basename, output_path)

cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)


@requires_nibabel()
def test_write_anat():
def test_write_anat(_bids_validate):
"""Test writing anatomical data."""
# Get the MNE testing sample data
output_path = _TempDir()
Expand All @@ -574,10 +566,7 @@ def test_write_anat():

anat_dir = write_anat(output_path, subject_id, t1w_mgh, session_id, acq,
raw=raw, trans=trans, verbose=True)

# Validate BIDS
cmd = bids_validator_exe + [output_path]
run_subprocess(cmd, shell=shell)
_bids_validate(output_path)

# Validate that files are as expected
t1w_json_path = op.join(anat_dir, 'sub-01_ses-01_acq-01_T1w.json')
Expand Down
6 changes: 3 additions & 3 deletions mne_bids/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,17 +1015,16 @@ def write_anat(bids_root, subject, t1w, session=None, acquisition=None,
raise ValueError('`t1w` must be a path to a T1 weighted MRI data file '
', or a nibabel image object, but it is of type '
'"{}"'.format(type(t1w)))
t1_mgh = nib.MGHImage(t1w.dataobj, t1w.affine)

# Now give the NIfTI file a BIDS name and write it to the BIDS location
t1w_basename = make_bids_basename(subject=subject, session=session,
acquisition=acquisition, prefix=anat_dir,
suffix='T1w.nii.gz')
if not op.exists(t1w_basename):
nib.save(t1_mgh, t1w_basename)
nib.save(t1w, t1w_basename)
elif overwrite:
os.remove(t1w_basename)
nib.save(t1_mgh, t1w_basename)
nib.save(t1w, t1w_basename)
else:
raise IOError('Wanted to write a file but it already exists and '
'`overwrite` is set to False. File: "{}"'
Expand All @@ -1051,6 +1050,7 @@ def write_anat(bids_root, subject, t1w, session=None, acquisition=None,
mri_landmarks = apply_trans(trans, meg_landmarks, move=True) * 1e3

# Get landmarks in voxel space, using the mgh version of our T1 data
t1_mgh = nib.MGHImage(t1w.dataobj, t1w.affine)
vox2ras_tkr = t1_mgh.header.get_vox2ras_tkr()
ras2vox_tkr = np.linalg.inv(vox2ras_tkr)
mri_landmarks = apply_trans(ras2vox_tkr, mri_landmarks) # in vox
Expand Down