Skip to content

Commit

Permalink
ENH: Allow returning candidate BIDSPaths (#1083)
Browse files Browse the repository at this point in the history
* ENH: Allow returning candidate BIDSPaths

* FIX: Syntax

* FIX: Update req

* DOC: whats_new.rst
  • Loading branch information
larsoner committed Oct 15, 2022
1 parent bd3c92b commit 9231836
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 12 deletions.
1 change: 1 addition & 0 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Detailed list of changes
^^^^^^^^^^^^^^^

- Speed up :func:`mne_bids.read_raw_bids` when lots of events are present by `Alexandre Gramfort`_ (:gh:`1079`)
- Add the option ``return_candidates`` to :meth:`mne_bids.BIDSPath.find_empty_room` by `Eric Larson`_ (:gh:`1083`)

🧐 API and behavior changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
29 changes: 22 additions & 7 deletions mne_bids/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def _find_matched_empty_room(bids_path):
emptyroom_dir = BIDSPath(root=bids_root, subject='emptyroom').directory

if not emptyroom_dir.exists():
return None
return None, list()

# Find the empty-room recording sessions.
emptyroom_session_dirs = [x for x in emptyroom_dir.iterdir()
Expand Down Expand Up @@ -85,12 +85,14 @@ def _find_matched_empty_room(bids_path):
date_tie = False

failed_to_get_er_date_count = 0
candidates = list()
for er_fname in candidate_er_fnames:
# get entities from filenamme
er_bids_path = get_bids_path_from_fname(er_fname, check=False)
er_bids_path.subject = 'emptyroom' # er subject entity is different
er_bids_path.root = bids_root
er_bids_path.datatype = 'meg'
candidates.append(er_bids_path)
er_meas_date = None

# Try to extract date from filename.
Expand Down Expand Up @@ -137,7 +139,7 @@ def _find_matched_empty_room(bids_path):
'same recording date. Selecting the first match.')
warn(msg)

return best_er_bids_path
return best_er_bids_path, candidates


class BIDSPath(object):
Expand Down Expand Up @@ -893,7 +895,8 @@ def _check(self):
f'{ALLOWED_FILENAME_SUFFIX}.')

@verbose
def find_empty_room(self, use_sidecar_only=False, verbose=None):
def find_empty_room(self, use_sidecar_only=False, *,
return_candidates=False, verbose=None):
"""Find the corresponding empty-room file of an MEG recording.
This will only work if the ``.root`` attribute of the
Expand All @@ -906,13 +909,21 @@ def find_empty_room(self, use_sidecar_only=False, verbose=None):
sidecar JSON file or not. If ``False``, first look for the entry,
and if unsuccessful, try to find the best-matching empty-room
recording in the dataset based on the measurement date.
return_candidates : bool
If True (default False), return candidate filenames checked during
the search for the best-matching empty-room recording.
%(verbose)s
Returns
-------
BIDSPath | None
The path corresponding to the best-matching empty-room measurement.
Returns ``None`` if none was found.
%(verbose)s
list | None
The candidates checked during the search for the best-matching
empty-room recording. Only returned if ``return_candidates`` is
``True``. Will be None if a sidecar is used to find the empty-room
recording.
"""
if self.datatype not in ('meg', None):
raise ValueError('Empty-room data is only supported for MEG '
Expand All @@ -938,28 +949,32 @@ def find_empty_room(self, use_sidecar_only=False, verbose=None):
er_bids_path = get_bids_path_from_fname(emptytoom_path)
er_bids_path.root = self.root
er_bids_path.datatype = 'meg'
candidates = None
elif use_sidecar_only:
logger.info(
'The MEG sidecar file does not contain an '
'"AssociatedEmptyRoom" entry. Aborting search for an '
'empty-room recording, as you passed use_sidecar_only=True'
)
return None
return None if not return_candidates else (None, None)
else:
logger.info(
'The MEG sidecar file does not contain an '
'"AssociatedEmptyRoom" entry. Will try to find a matching '
'empty-room recording based on the measurement date …'
)
er_bids_path = _find_matched_empty_room(self)
er_bids_path, candidates = _find_matched_empty_room(self)

if er_bids_path is not None and not er_bids_path.fpath.exists():
raise FileNotFoundError(
f'Empty-room BIDS path resolved but not found:\n'
f'{er_bids_path}\n'
'Check your BIDS dataset for completeness.')

return er_bids_path
out = er_bids_path
if return_candidates:
out = (out, candidates)
return out

@property
def meg_calibration_fpath(self):
Expand Down
14 changes: 10 additions & 4 deletions mne_bids/tests/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,8 +960,11 @@ def test_find_empty_room(return_bids_test_dir, tmp_path):

# Retrieve empty-room BIDSPath
assert bids_path.find_empty_room() == er_associated_bids_path
assert bids_path.find_empty_room(
use_sidecar_only=True) == er_associated_bids_path
for use_sidecar_only in [True, False]: # same result either way
path, candidates = bids_path.find_empty_room(
use_sidecar_only=use_sidecar_only, return_candidates=True)
assert path == er_associated_bids_path
assert candidates is None

# Should only work for MEG
with pytest.raises(ValueError, match='only supported for MEG'):
Expand All @@ -975,11 +978,14 @@ def test_find_empty_room(return_bids_test_dir, tmp_path):
# Don't create `AssociatedEmptyRoom` entry in sidecar – we should now
# retrieve the empty-room recording closer in time
write_raw_bids(raw, bids_path=bids_path, empty_room=None, overwrite=True)
assert bids_path.find_empty_room() == er_matching_date_bids_path
path, candidates = bids_path.find_empty_room(return_candidates=True)
assert path == er_matching_date_bids_path
assert er_matching_date_bids_path in candidates

# If we enforce searching only via `AssociatedEmptyRoom`, we should get no
# result
assert bids_path.find_empty_room(use_sidecar_only=True) is None
assert bids_path.find_empty_room(
use_sidecar_only=True, return_candidates=True) == (None, None)


@pytest.mark.filterwarnings(warning_str['channel_unit_changed'])
Expand Down
2 changes: 1 addition & 1 deletion test_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ matplotlib>=3.1
pandas>=0.24.0
nibabel>=2.5
pybv>=0.7.3
git+https://github.com/larsoner/openneuro-py@iterate#egg=openneuro-py
openneuro-py>=2022.2
EDFlib-Python>=1.0.6
pymatreader>=0.0.29
pytest
Expand Down

0 comments on commit 9231836

Please sign in to comment.