Skip to content
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
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ stages:
- bash: |
set -e
python -m pip install --progress-bar off --upgrade pip
python -m pip install --progress-bar off "mne-qt-browser[opengl] @ git+https://github.com/mne-tools/mne-qt-browser.git" pyvista scikit-learn python-picard qtpy nibabel sphinx-gallery "PySide6!=6.8.0,!=6.8.0.1,!=6.8.1.1,!=6.9.1" pandas neo pymatreader antio defusedxml
python -m pip install --progress-bar off "mne-qt-browser[opengl] @ git+https://github.com/mne-tools/mne-qt-browser.git" pyvista scikit-learn python-picard qtpy nibabel sphinx-gallery "PySide6!=6.8.0,!=6.8.0.1,!=6.8.1.1,!=6.9.1" pandas neo pymatreader antio defusedxml curryreader
python -m pip uninstall -yq mne
python -m pip install --progress-bar off --upgrade -e . --group=test
displayName: 'Install dependencies with pip'
Expand Down
22 changes: 12 additions & 10 deletions doc/_includes/dig_formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,23 @@ function for more info on reading specific file types.
.. cssclass:: table-bordered
.. rst-class:: midvalign

================= ================ ==============================================
Vendor Extension(s) MNE-Python function
================= ================ ==============================================
Neuromag .fif :func:`mne.channels.read_dig_fif`
===================== ================ ==============================================
Vendor Extension(s) MNE-Python function
===================== ================ ==============================================
Neuromag .fif :func:`mne.channels.read_dig_fif`

Polhemus ISOTRAK .hsp, .elp, .eeg :func:`mne.channels.read_dig_polhemus_isotrak`
Polhemus ISOTRAK .hsp, .elp, .eeg :func:`mne.channels.read_dig_polhemus_isotrak`

EGI .xml :func:`mne.channels.read_dig_egi`
EGI .xml :func:`mne.channels.read_dig_egi`

MNE-C .hpts :func:`mne.channels.read_dig_hpts`
MNE-C .hpts :func:`mne.channels.read_dig_hpts`

Brain Products .bvct :func:`mne.channels.read_dig_captrak`
Brain Products .bvct :func:`mne.channels.read_dig_captrak`

Compumedics .dat :func:`mne.channels.read_dig_dat`
================= ================ ==============================================
Compumedics .dat, .cdt :func:`mne.channels.read_dig_curry`

Compumedics (legacy) .dat :func:`mne.channels.read_dig_dat`
===================== ================ ==============================================

To load Polhemus FastSCAN files you can use
:func:`montage <mne.channels.read_polhemus_fastscan>`.
Expand Down
1 change: 1 addition & 0 deletions doc/api/preprocessing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Projections:
read_dig_polhemus_isotrak
read_dig_captrak
read_dig_dat
read_dig_curry
read_dig_egi
read_dig_fif
read_dig_hpts
Expand Down
1 change: 1 addition & 0 deletions doc/changes/dev/13156.newfeature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added support for file like objects in :func:`read_raw_bdf <mne.io.read_raw_bdf>`, :func:`read_raw_edf <mne.io.read_raw_edf>` and :func:`read_raw_gdf <mne.io.read_raw_gdf>`, by :newcontrib:`Santi Martínez`.
1 change: 1 addition & 0 deletions doc/changes/dev/13176.dependency.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
New reader for Neuroscan Curry files, using the curry-python-reader module, by `Dominik Welke`_.
1 change: 1 addition & 0 deletions doc/changes/dev/13176.newfeature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Read impedances and montage from Neuroscan Curry files, by `Dominik Welke`_.
1 change: 1 addition & 0 deletions doc/changes/names.inc
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@
.. _Samuel Louviot: https://github.com/Sam54000
.. _Samuel Powell: https://github.com/samuelpowell
.. _Santeri Ruuskanen: https://github.com/ruuskas
.. _Santi Martínez: https://github.com/szz-dvl
.. _Sara Sommariva: https://github.com/sarasommariva
.. _Sawradip Saha: https://sawradip.github.io/
.. _Scott Huberty: https://orcid.org/0000-0003-2637-031X
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ channels:
dependencies:
- python >=3.10
- antio >=0.5.0
- curryreader >=0.1.2
- darkdetect
- decorator
- defusedxml
Expand Down
23 changes: 23 additions & 0 deletions mne/_edf/open.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.

# Maybe we can move this one to utils or something like that.
from pathlib import Path

from mne._fiff.open import _NoCloseRead

from ..utils import _file_like, _validate_type, logger


def _gdf_edf_get_fid(fname, **kwargs):
"""Open a EDF/BDF/GDF file with no additional parsing."""
if _file_like(fname):
logger.debug("Using file-like I/O")
fid = _NoCloseRead(fname)
fid.seek(0)
else:
_validate_type(fname, [Path, str], "fname", extra="or file-like")
logger.debug("Using normal I/O")
fid = open(fname, "rb", **kwargs) # Open in binary mode
return fid
4 changes: 4 additions & 0 deletions mne/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1415,6 +1415,8 @@ def read_annotations(
".csv": _read_annotations_csv,
".cnt": _read_annotations_cnt,
".ds": _read_annotations_ctf,
".dat": _read_annotations_curry,
".cdt": _read_annotations_curry,
".cef": _read_annotations_curry,
".set": _read_annotations_eeglab,
".edf": _read_annotations_edf,
Expand All @@ -1427,6 +1429,8 @@ def read_annotations(
kwargs = {
".vmrk": {"sfreq": sfreq, "ignore_marker_types": ignore_marker_types},
".amrk": {"sfreq": sfreq, "ignore_marker_types": ignore_marker_types},
".dat": {"sfreq": sfreq},
".cdt": {"sfreq": sfreq},
".cef": {"sfreq": sfreq},
".set": {"uint16_codec": uint16_codec},
".edf": {"encoding": encoding},
Expand Down
2 changes: 2 additions & 0 deletions mne/channels/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ __all__ = [
"read_ch_adjacency",
"read_custom_montage",
"read_dig_captrak",
"read_dig_curry",
"read_dig_dat",
"read_dig_egi",
"read_dig_fif",
Expand Down Expand Up @@ -67,6 +68,7 @@ from .montage import (
make_standard_montage,
read_custom_montage,
read_dig_captrak,
read_dig_curry,
read_dig_dat,
read_dig_egi,
read_dig_fif,
Expand Down
45 changes: 45 additions & 0 deletions mne/channels/_dig_montage_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.

import re

import numpy as np

from ..utils import Bunch, _check_fname, _soft_import, warn
Expand Down Expand Up @@ -94,3 +96,46 @@ def _parse_brainvision_dig_montage(fname, scale):
ch_pos=dig_ch_pos,
coord_frame="unknown",
)


def _read_dig_montage_curry(ch_names, ch_types, ch_pos, landmarks, landmarkslabels):
# scale ch_pos to m?!
ch_pos /= 1000.0
landmarks /= 1000.0
# channel locations
# what about misc without pos? can they mess things up if unordered?
assert len(ch_pos) >= (ch_types.count("mag") + ch_types.count("eeg"))
assert len(ch_pos) == (ch_types.count("mag") + ch_types.count("eeg"))
ch_pos_eeg = {
ch_names[i]: ch_pos[i, :3] for i, t in enumerate(ch_types) if t == "eeg"
}
# landmarks and headshape
landmark_dict = dict(zip(landmarkslabels, landmarks))
for k in ["Nas", "RPA", "LPA"]:
if k not in landmark_dict.keys():
landmark_dict[k] = None
if len(landmarkslabels) > 0:
hpi_pos = landmarks[
[i for i, n in enumerate(landmarkslabels) if re.match("HPI[1-99]", n)], :
]
else:
hpi_pos = None
if len(landmarkslabels) > 0:
hsp_pos = landmarks[
[i for i, n in enumerate(landmarkslabels) if re.match("H[1-99]", n)], :
]
else:
hsp_pos = None
# compile dig montage positions for eeg
if len(ch_pos_eeg) > 0:
return dict(
ch_pos=ch_pos_eeg,
nasion=landmark_dict["Nas"],
lpa=landmark_dict["LPA"],
rpa=landmark_dict["RPA"],
hsp=hsp_pos,
hpi=hpi_pos,
coord_frame="unknown",
)
else: # not recorded?
raise ValueError("No eeg sensor locations found in header file.")
72 changes: 61 additions & 11 deletions mne/channels/montage.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,17 @@
check_fname,
copy_function_doc_to_method_doc,
fill_doc,
legacy,
verbose,
warn,
)
from ..utils.docs import docdict
from ..viz import plot_montage
from ._dig_montage_utils import _parse_brainvision_dig_montage, _read_dig_montage_egi
from ._dig_montage_utils import (
_parse_brainvision_dig_montage,
_read_dig_montage_curry,
_read_dig_montage_egi,
)


@dataclass
Expand Down Expand Up @@ -322,7 +327,6 @@ class DigMontage:
See Also
--------
read_dig_captrak
read_dig_dat
read_dig_egi
read_dig_fif
read_dig_hpts
Expand Down Expand Up @@ -757,6 +761,7 @@ def transform_to_head(montage):
return montage


@legacy(alt="read_dig_curry()")
def read_dig_dat(fname):
r"""Read electrode positions from a ``*.dat`` file.

Expand All @@ -779,7 +784,7 @@ def read_dig_dat(fname):
See Also
--------
read_dig_captrak
read_dig_dat
read_dig_curry
read_dig_egi
read_dig_fif
read_dig_hpts
Expand Down Expand Up @@ -845,9 +850,9 @@ def read_dig_fif(fname, *, verbose=None):
See Also
--------
DigMontage
read_dig_dat
read_dig_egi
read_dig_captrak
read_dig_curry
read_dig_polhemus_isotrak
read_dig_hpts
read_dig_localite
Expand Down Expand Up @@ -898,7 +903,7 @@ def read_dig_hpts(fname, unit="mm"):
--------
DigMontage
read_dig_captrak
read_dig_dat
read_dig_curry
read_dig_egi
read_dig_fif
read_dig_localite
Expand Down Expand Up @@ -991,7 +996,7 @@ def read_dig_egi(fname):
--------
DigMontage
read_dig_captrak
read_dig_dat
read_dig_curry
read_dig_fif
read_dig_hpts
read_dig_localite
Expand Down Expand Up @@ -1023,7 +1028,7 @@ def read_dig_captrak(fname):
See Also
--------
DigMontage
read_dig_dat
read_dig_curry
read_dig_egi
read_dig_fif
read_dig_hpts
Expand All @@ -1037,6 +1042,51 @@ def read_dig_captrak(fname):
return make_dig_montage(**data)


def read_dig_curry(fname):
"""Read electrode locations from Neuroscan Curry files.

Parameters
----------
fname : path-like
A valid Curry file.

Returns
-------
montage : instance of DigMontage | None
The montage.

See Also
--------
DigMontage
read_dig_captrak
read_dig_egi
read_dig_fif
read_dig_hpts
read_dig_localite
read_dig_polhemus_isotrak
make_dig_montage

Notes
-----
.. versionadded:: 1.11
"""
from ..io.curry.curry import (
_check_curry_filename,
_extract_curry_info,
)

# TODO - REVIEW NEEDED
fname = _check_curry_filename(fname)
(_, _, ch_names, ch_types, ch_pos, landmarks, landmarkslabels, _, _, _, _, _, _) = (
_extract_curry_info(fname)
)
data = _read_dig_montage_curry(
ch_names, ch_types, ch_pos, landmarks, landmarkslabels
)
mont = make_dig_montage(**data) if data else None
return mont


def read_dig_localite(fname, nasion=None, lpa=None, rpa=None):
"""Read Localite .csv file.

Expand All @@ -1060,7 +1110,7 @@ def read_dig_localite(fname, nasion=None, lpa=None, rpa=None):
--------
DigMontage
read_dig_captrak
read_dig_dat
read_dig_curry
read_dig_egi
read_dig_fif
read_dig_hpts
Expand Down Expand Up @@ -1461,7 +1511,7 @@ def read_dig_polhemus_isotrak(fname, ch_names=None, unit="m"):
make_dig_montage
read_polhemus_fastscan
read_dig_captrak
read_dig_dat
read_dig_curry
read_dig_egi
read_dig_fif
read_dig_localite
Expand Down Expand Up @@ -1821,8 +1871,8 @@ def make_standard_montage(kind, head_size="auto"):
Notes
-----
Individualized (digitized) electrode positions should be read in using
:func:`read_dig_captrak`, :func:`read_dig_dat`, :func:`read_dig_egi`,
:func:`read_dig_fif`, :func:`read_dig_polhemus_isotrak`,
:func:`read_dig_captrak`, :func:`read_dig_curry`,
:func:`read_dig_egi`, :func:`read_dig_fif`, :func:`read_dig_polhemus_isotrak`,
:func:`read_dig_hpts`, or manually made with :func:`make_dig_montage`.

.. versionadded:: 0.19.0
Expand Down
4 changes: 2 additions & 2 deletions mne/datasets/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
# update the checksum in the MNE_DATASETS dict below, and change version
# here: ↓↓↓↓↓↓↓↓
RELEASES = dict(
testing="0.167",
testing="0.168",
misc="0.27",
phantom_kit="0.2",
ucl_opm_auditory="0.2",
Expand Down Expand Up @@ -115,7 +115,7 @@
# Testing and misc are at the top as they're updated most often
MNE_DATASETS["testing"] = dict(
archive_name=f"{TESTING_VERSIONED}.tar.gz",
hash="md5:d82318a83b436ca2c7ca8420487c05c2",
hash="md5:7782a64f170b9435b0fd126862b0cf63",
url=(
"https://codeload.github.com/mne-tools/mne-testing-data/"
f"tar.gz/{RELEASES['testing']}"
Expand Down
Loading
Loading