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

MAINT: Updates for latest MNE #1312

Merged
merged 7 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
60 changes: 47 additions & 13 deletions mne_bids/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import os
import os.path as op
import re
from datetime import datetime, timezone
from datetime import datetime, timedelta, timezone
from difflib import get_close_matches
from pathlib import Path

Expand Down Expand Up @@ -260,38 +260,72 @@ def _handle_participants_reading(participants_fname, raw, subject):
raw.info["subject_info"] = dict() # start from scratch

# set data from participants tsv into subject_info
# TODO: Could potentially use "comment" someday to store other options e.g. in JSON
# https://github.com/mne-tools/fiff-constants/blob/e27f68cbf74dbfc5193ad429cc77900a59475181/DictionaryTags.txt#L369
allowed_keys = set(
"""
id his_id last_name first_name middle_name birthday sex hand weight height
""".strip().split()
)
bad_key_vals = list()
for col_name, value in participants_tsv.items():
orig_value = value = value[row_ind]
if col_name in ("sex", "hand"):
value = _map_options(
what=col_name, key=value[row_ind], fro="bids", to="mne"
)
value = _map_options(what=col_name, key=value, fro="bids", to="mne")
# We don't know how to translate to MNE, so skip.
if value is None:
if col_name == "sex":
info_str = "subject sex"
else:
info_str = "subject handedness"
warn(
f'Unable to map "{col_name}" value "{value}" to MNE. '
f"Not setting {info_str}."
)
bad_key_vals.append((col_name, orig_value, info_str))
elif col_name in ("height", "weight"):
try:
value = float(value[row_ind])
value = float(value)
except ValueError:
value = None
elif col_name == "age":
if raw.info["meas_date"] is None:
value = None
elif value is not None:
try:
value = float(value)
except Exception:
value = None
else:
value = (
raw.info["meas_date"]
- timedelta(days=int(np.ceil(365.25 * value)))
).date()
else:
if value[row_ind] == "n/a":
if value == "n/a":
value = None
else:
value = value[row_ind]

# adjust keys to match MNE nomenclature
key = col_name
if col_name == "participant_id":
key = "his_id"
elif col_name == "age":
key = "birthday"

if key not in allowed_keys:
bad_key_vals.append((col_name, orig_value, None))
continue

# add data into raw.Info
key = "his_id" if col_name == "participant_id" else col_name
if value is not None:
assert key not in raw.info["subject_info"]
raw.info["subject_info"][key] = value

if bad_key_vals:
warn_str = "Unable to map the following column(s) to to MNE:"
for col_name, orig_value, info_str in bad_key_vals:
warn_str += f"\n{col_name}"
if info_str is not None:
warn_str += f" ({info_str})"
warn_str += f": {orig_value}"
warn(warn_str)

return raw


Expand Down
2 changes: 1 addition & 1 deletion mne_bids/tests/test_copyfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def test_copyfile_brainvision(tmp_path):

# Try to read with MNE - if this works, the links are correct
raw = mne.io.read_raw_brainvision(new_name)
assert raw.filenames[0] == (op.join(head, "tested_conversion.eeg"))
assert Path(raw.filenames[0]) == Path(head) / "tested_conversion.eeg"

# Test with anonymization
raw = mne.io.read_raw_brainvision(raw_fname)
Expand Down
5 changes: 4 additions & 1 deletion mne_bids/tests/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,10 @@ def test_read_participants_data(tmp_path):
participants_tsv_fpath = tmp_path / "participants.tsv"
participants_tsv = _from_tsv(participants_tsv_fpath)
participants_tsv["hand"][0] = "n/a"
participants_tsv["outcome"] = ["good"] # e.g. clinical tutorial from MNE-Python
_to_tsv(participants_tsv, participants_tsv_fpath)
raw = read_raw_bids(bids_path=bids_path)
with pytest.warns(RuntimeWarning, match="Unable to map"):
raw = read_raw_bids(bids_path=bids_path)
assert raw.info["subject_info"]["hand"] == 0
assert raw.info["subject_info"]["sex"] == 2
assert raw.info["subject_info"]["weight"] == 70.5
Expand All @@ -163,6 +165,7 @@ def test_read_participants_data(tmp_path):
# 'n/a' values should get omitted
participants_tsv["weight"] = ["n/a"]
participants_tsv["height"] = ["tall"]
del participants_tsv["outcome"]

_to_tsv(participants_tsv, participants_tsv_fpath)
with pytest.warns(RuntimeWarning, match="Unable to map"):
Expand Down
16 changes: 8 additions & 8 deletions mne_bids/tests/test_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@
cnt_warning2="ignore:.*Could not define the number of bytes automatically."
" Defaulting to 2.",
cnt_warning3="ignore:.*Coordinate frame could not be inferred.*",
no_hand="ignore:.*Not setting subject handedness.:RuntimeWarning:mne",
no_hand=r"ignore:Unable to map.*\n.*subject handedness.*:RuntimeWarning:mne",
no_montage=r"ignore:Not setting position of.*channel found in "
r"montage.*:RuntimeWarning:mne",
)


def _wrap_read_raw(read_raw):
def fn(fname, *args, **kwargs):
if str(fname).endswith(".mff") and check_version("mne", "1.8"):
if Path(fname).suffix == ".mff" and check_version("mne", "1.8"):
kwargs["events_as_annotations"] = True
raw = read_raw(fname, *args, **kwargs)
raw.info["line_freq"] = 60
Expand Down Expand Up @@ -3414,10 +3414,10 @@ def test_convert_eeg_formats(dir_name, fmt, fname, reader, tmp_path):
assert channels_tsv["units"][0] == "V"

if fmt == "BrainVision":
assert raw2.filenames[0].endswith(".eeg")
assert Path(raw2.filenames[0]).suffix == ".eeg"
assert bids_output_path.extension == ".vhdr"
elif fmt == "EDF":
assert raw2.filenames[0].endswith(".edf")
assert Path(raw2.filenames[0]).suffix == ".edf"
assert bids_output_path.extension == ".edf"

orig_len = len(raw)
Expand Down Expand Up @@ -3513,7 +3513,7 @@ def test_convert_meg_formats(dir_name, fmt, fname, reader, tmp_path):
raw2 = read_raw_bids(bids_output_path)

if fmt == "FIF":
assert raw2.filenames[0].endswith(".fif")
assert Path(raw2.filenames[0]).suffix == ".fif"
assert bids_output_path.extension == ".fif"

orig_len = len(raw)
Expand Down Expand Up @@ -4086,16 +4086,16 @@ def test_unknown_extension(_bids_validate, tmp_path):
raw_fname = data_path / "MEG" / "sample" / "sample_audvis_trunc_raw.fif"

raw = _read_raw_fif(raw_fname)
raw._filenames = (raw.filenames[0].replace(".fif", ".foo"),)
raw._filenames = (Path(raw.filenames[0]).with_suffix(".foo"),)

# When data is not preloaded, we should raise an exception.
with pytest.raises(ValueError, match="file format not supported by BIDS"):
write_raw_bids(raw, bids_path)

# With preloaded data, writing should work.
raw._filenames = (raw.filenames[0].replace(".foo", ".fif"),)
raw._filenames = (Path(raw.filenames[0]).with_suffix(".fif"),)
raw.load_data()
raw._filenames = (raw.filenames[0].replace(".fif", ".foo"),)
raw._filenames = (Path(raw.filenames[0]).with_suffix(".foo"),)

write_raw_bids(raw, bids_path, allow_preload=True, format="FIF")
_bids_validate(bids_root)
Expand Down