Skip to content

Commit 234e4fe

Browse files
Merge branch 'main' into lite-docs-wiring
2 parents 9245fec + 939b4d0 commit 234e4fe

29 files changed

Lines changed: 756 additions & 89 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,5 @@ doc/jupyterlite_contents/*
110110
!doc/jupyterlite_contents/.gitkeep
111111
doc/lite_extra/
112112

113-
/.claude/
113+
/.claude/
114+
uv.lock

doc/api/datasets.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ Datasets
4848
refmeg_noise.data_path
4949
ssvep.data_path
5050
erp_core.data_path
51+
erp_core.fetch_file
5152
epilepsy_ecog.data_path
5253
eyelink.data_path

doc/changes/dev/13795.other.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Made :meth:`evoked.plot() <mne.Evoked.plot>` instantiate ``MNELineFigure`` when it creates its own figure, aligning this path with the ongoing 2D plotting figure-class refactor discussed in :gh:`7751`, by `Pragnya Khandelwal`_.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added :ref:`tut-gal-decoding`, a tutorial on Generalization Across Location
2+
(GAL) and Time-GAL decoding of EEG data, by `Bruno Aristimunha`_ and
3+
:newcontrib:`Alejandro Santos Mayo`.

doc/changes/dev/14213.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Preserve caller-owned memory-mapped preload files after Raw objects are destroyed, by `Bruno Aristimunha`_.

doc/changes/names.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
.. _Akhilesh S. Yadav: https://github.com/YadavAkhileshh
99
.. _Akshay: https://github.com/Akshay0724
1010
.. _Alan Leggitt: https://github.com/leggitta
11+
.. _Alejandro Santos Mayo: https://github.com/ASantosMayo
1112
.. _Alejandro Weinstein: http://ocam.cl
1213
.. _Alessandro Tonin: https://www.linkedin.com/in/alessandro-tonin-7892b046
1314
.. _Alex Ciok: https://github.com/alexCiok

mne/datasets/erp_core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
"""ERP-CORE EEG dataset."""
66

7-
from .erp_core import data_path, get_version
7+
from .erp_core import data_path, fetch_file, get_version

mne/datasets/erp_core/erp_core.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,30 @@
22
# License: BSD-3-Clause
33
# Copyright the MNE-Python contributors.
44

5-
from ...utils import verbose
6-
from ..utils import _data_path_doc, _download_mne_dataset, _get_version, _version_doc
5+
from pathlib import Path
6+
7+
from ...utils import _check_option, logger, verbose
8+
from ..utils import (
9+
_data_path_doc,
10+
_download_mne_dataset,
11+
_downloader_params,
12+
_get_path,
13+
_get_version,
14+
_version_doc,
15+
)
16+
17+
_N170_BASE_URL = "https://data.nemar.org/nm000132/v1.1.1/"
18+
_N170_REGISTRY = {
19+
"sub-001/eeg/sub-001_task-N170_eeg.fdt": (
20+
"sha256:08406f3c6b4a869dc8f67c9acc233a91993bae1b04b7dee5bc0521677ed8949b"
21+
),
22+
"sub-001/eeg/sub-001_task-N170_eeg.set": (
23+
"sha256:9c53dbdc3b469934a5eb6e9f01e59090dd47aeb495b8f21ceca03670991e5b11"
24+
),
25+
"sub-001/eeg/sub-001_task-N170_events.tsv": (
26+
"sha256:07c87e728d097b0deb05b17d77bbdbd22ef58105111b0b56e659a767b9421e34"
27+
),
28+
}
729

830

931
@verbose
@@ -25,6 +47,37 @@ def data_path(
2547
)
2648

2749

50+
def fetch_file(fname, path=None):
51+
"""Fetch a raw ERP CORE file used by MNE-Python examples.
52+
53+
Parameters
54+
----------
55+
fname : str
56+
Relative path of the file within the ERP CORE dataset.
57+
path : path-like | None
58+
Parent directory for the ``ERP-CORE-N170`` folder. If ``None``, the
59+
``MNE_DATASETS_ERP_CORE_PATH`` configuration value is used.
60+
61+
Returns
62+
-------
63+
path : instance of Path
64+
Local path to the requested file.
65+
"""
66+
import pooch
67+
68+
_check_option("fname", fname, _N170_REGISTRY)
69+
path = _get_path(path, "MNE_DATASETS_ERP_CORE_PATH", "ERP CORE")
70+
fetcher = pooch.create(
71+
path=path / "ERP-CORE-N170",
72+
base_url=_N170_BASE_URL,
73+
registry=_N170_REGISTRY,
74+
retry_if_failed=2,
75+
)
76+
pooch.get_logger().setLevel(logger.getEffectiveLevel())
77+
downloader = pooch.HTTPDownloader(**_downloader_params())
78+
return Path(fetcher.fetch(fname, downloader=downloader, progressbar=True))
79+
80+
2881
def get_version(): # noqa: D103
2982
return _get_version("erp_core")
3083

mne/datasets/tests/test_datasets.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,29 @@ def noop(*args, **kwargs):
9090
assert sd / "fsaverage" == sd_2
9191

9292

93+
def test_erp_core_fetch_file(tmp_path, monkeypatch):
94+
"""Test fetching individual ERP CORE files."""
95+
fnames = (
96+
"sub-001/eeg/sub-001_task-N170_eeg.fdt",
97+
"sub-001/eeg/sub-001_task-N170_eeg.set",
98+
"sub-001/eeg/sub-001_task-N170_events.tsv",
99+
)
100+
101+
def fetch(pooch_instance, fname, **kwargs):
102+
assert fname in pooch_instance.registry
103+
destination = pooch_instance.abspath / fname
104+
destination.parent.mkdir(parents=True, exist_ok=True)
105+
destination.touch()
106+
return str(destination)
107+
108+
monkeypatch.setattr(pooch.Pooch, "fetch", fetch)
109+
for fname in fnames:
110+
destination = datasets.erp_core.fetch_file(fname, path=tmp_path)
111+
assert destination == tmp_path / "ERP-CORE-N170" / fname
112+
with pytest.raises(ValueError, match="Invalid value for.*fname"):
113+
datasets.erp_core.fetch_file("unknown", path=tmp_path)
114+
115+
93116
@requires_good_network
94117
def test_downloads(tmp_path, monkeypatch, capsys):
95118
"""Test dataset URL and version handling."""

mne/datasets/utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,17 @@ def _download_all_example_data(verbose=True):
366366
limo,
367367
sleep_physionet,
368368
)
369+
from .erp_core import fetch_file as fetch_erp_core_file
369370

370371
eegbci.load_data(subjects=1, runs=[6, 10, 14], update_path=True)
371372
eegbci.load_data(subjects=range(1, 5), runs=[3], update_path=True)
372373
logger.info("[done eegbci]")
373374

375+
fetch_erp_core_file("sub-001/eeg/sub-001_task-N170_eeg.fdt")
376+
fetch_erp_core_file("sub-001/eeg/sub-001_task-N170_eeg.set")
377+
fetch_erp_core_file("sub-001/eeg/sub-001_task-N170_events.tsv")
378+
logger.info("[done erp_core N170]")
379+
374380
sleep_physionet.age.fetch_data(subjects=[0, 1], recording=[1])
375381
logger.info("[done sleep_physionet]")
376382

0 commit comments

Comments
 (0)