Spaces:
Running
Running
| # Authors: The MNE-Python contributors. | |
| # License: BSD-3-Clause | |
| # Copyright the MNE-Python contributors. | |
| import os | |
| import re | |
| import time | |
| from importlib.resources import files | |
| from os import path as op | |
| from pathlib import Path | |
| from ...utils import _url_to_local_path, logger, verbose | |
| from ..utils import _do_path_update, _downloader_params, _get_path, _log_time_size | |
| EEGMI_URL = "https://physionet.org/files/eegmmidb/1.0.0/" | |
| def data_path(url, path=None, force_update=False, update_path=None, *, verbose=None): | |
| """Get path to local copy of EEGMMI dataset URL. | |
| This is a low-level function useful for getting a local copy of a remote EEGBCI | |
| dataset :footcite:`SchalkEtAl2004`, which is also available at PhysioNet | |
| :footcite:`GoldbergerEtAl2000`. Metadata, such as the meaning of event markers | |
| may be obtained from the | |
| `PhysioNet documentation page <https://physionet.org/content/eegmmidb/1.0.0/>`_. | |
| Parameters | |
| ---------- | |
| url : str | |
| The dataset to use. | |
| path : None | path-like | |
| Location of where to look for the EEGBCI data. If ``None``, the environment | |
| variable or config parameter ``MNE_DATASETS_EEGBCI_PATH`` is used. If neither | |
| exists, the ``~/mne_data`` directory is used. If the EEGBCI dataset is not found | |
| under the given path, the data will be automatically downloaded to the specified | |
| folder. | |
| force_update : bool | |
| Force update of the dataset even if a local copy exists. | |
| update_path : bool | None | |
| If ``True``, set ``MNE_DATASETS_EEGBCI_PATH`` in the configuration to the given | |
| path. If ``None``, the user is prompted. | |
| %(verbose)s | |
| Returns | |
| ------- | |
| path : list of Path | |
| Local path to the given data file. This path is contained inside a list of | |
| length one for compatibility. | |
| Notes | |
| ----- | |
| For example, one could do: | |
| >>> from mne.datasets import eegbci | |
| >>> url = "http://www.physionet.org/physiobank/database/eegmmidb/" | |
| >>> eegbci.data_path(url, "~/datasets") # doctest:+SKIP | |
| This would download the given EEGBCI data file to the ``~/datasets`` folder and | |
| prompt the user to store this path in the config (if it does not already exist). | |
| References | |
| ---------- | |
| .. footbibliography:: | |
| """ | |
| import pooch | |
| key = "MNE_DATASETS_EEGBCI_PATH" | |
| name = "EEGBCI" | |
| path = _get_path(path, key, name) | |
| fname = "MNE-eegbci-data" | |
| destination = _url_to_local_path(url, op.join(path, fname)) | |
| destinations = [destination] | |
| # fetch the file | |
| downloader = pooch.HTTPDownloader(**_downloader_params()) | |
| if not op.isfile(destination) or force_update: | |
| if op.isfile(destination): | |
| os.remove(destination) | |
| if not op.isdir(op.dirname(destination)): | |
| os.makedirs(op.dirname(destination)) | |
| pooch.retrieve( | |
| url=url, | |
| path=destination, | |
| downloader=downloader, | |
| fname=fname, | |
| ) | |
| # offer to update the path | |
| _do_path_update(path, update_path, key, name) | |
| destinations = [Path(dest) for dest in destinations] | |
| return destinations | |
| def load_data( | |
| subjects, | |
| runs, | |
| *, | |
| path=None, | |
| force_update=False, | |
| update_path=None, | |
| base_url=EEGMI_URL, | |
| verbose=None, | |
| ): # noqa: D301 | |
| """Get paths to local copies of EEGBCI dataset files. | |
| This will fetch data for the EEGBCI dataset :footcite:`SchalkEtAl2004`, which is | |
| also available at PhysioNet :footcite:`GoldbergerEtAl2000`. Metadata, such as the | |
| meaning of event markers may be obtained from the | |
| `PhysioNet documentation page <https://physionet.org/content/eegmmidb/1.0.0/>`_. | |
| Parameters | |
| ---------- | |
| subjects : int | list of int | |
| The subjects to use. Can be in the range of 1-109 (inclusive). | |
| runs : int | list of int | |
| The runs to use (see Notes for details). | |
| path : None | path-like | |
| Location of where to look for the EEGBCI data. If ``None``, the environment | |
| variable or config parameter ``MNE_DATASETS_EEGBCI_PATH`` is used. If neither | |
| exists, the ``~/mne_data`` directory is used. If the EEGBCI dataset is not found | |
| under the given path, the data will be automatically downloaded to the specified | |
| folder. | |
| force_update : bool | |
| Force update of the dataset even if a local copy exists. | |
| update_path : bool | None | |
| If ``True``, set ``MNE_DATASETS_EEGBCI_PATH`` in the configuration to the given | |
| path. If ``None``, the user is prompted. | |
| base_url : str | |
| The URL root for the data. | |
| %(verbose)s | |
| Returns | |
| ------- | |
| paths : list | |
| List of local data paths of the given type. | |
| Notes | |
| ----- | |
| The run numbers correspond to: | |
| ========= =================================== | |
| run task | |
| ========= =================================== | |
| 1 Baseline, eyes open | |
| 2 Baseline, eyes closed | |
| 3, 7, 11 Motor execution: left vs right hand | |
| 4, 8, 12 Motor imagery: left vs right hand | |
| 5, 9, 13 Motor execution: hands vs feet | |
| 6, 10, 14 Motor imagery: hands vs feet | |
| ========= =================================== | |
| For example, one could do:: | |
| >>> from mne.datasets import eegbci | |
| >>> eegbci.load_data([1, 2], [6, 10, 14], "~/datasets") # doctest:+SKIP | |
| This would download runs 6, 10, and 14 (hand/foot motor imagery) runs from subjects | |
| 1 and 2 in the EEGBCI dataset to "~/datasets" and prompt the user to store this path | |
| in the config (if it does not already exist). | |
| References | |
| ---------- | |
| .. footbibliography:: | |
| """ | |
| import pooch | |
| t0 = time.time() | |
| if not hasattr(subjects, "__iter__"): | |
| subjects = [subjects] | |
| if not hasattr(runs, "__iter__"): | |
| runs = [runs] | |
| # get local storage path | |
| config_key = "MNE_DATASETS_EEGBCI_PATH" | |
| folder = "MNE-eegbci-data" | |
| name = "EEGBCI" | |
| path = _get_path(path, config_key, name) | |
| # extract path parts | |
| pattern = r"(?:https?://.*)(files)/(eegmmidb)/(\d+\.\d+\.\d+)/?" | |
| match = re.compile(pattern).match(base_url) | |
| if match is None: | |
| raise ValueError( | |
| "base_url does not match the expected EEGMI folder " | |
| "structure. Please notify MNE-Python developers." | |
| ) | |
| base_path = op.join(path, folder, *match.groups()) | |
| # create the download manager | |
| fetcher = pooch.create( | |
| path=base_path, | |
| base_url=base_url, | |
| version=None, # data versioning is decoupled from MNE-Python version | |
| registry=None, # registry is loaded from file (below) | |
| retry_if_failed=2, # 2 retries = 3 total attempts | |
| ) | |
| # load the checksum registry | |
| registry = files("mne").joinpath("data", "eegbci_checksums.txt") | |
| fetcher.load_registry(registry) | |
| # fetch the file(s) | |
| data_paths = [] | |
| sz = 0 | |
| for subject in subjects: | |
| for run in runs: | |
| file_part = f"S{subject:03d}/S{subject:03d}R{run:02d}.edf" | |
| destination = Path(base_path, file_part) | |
| data_paths.append(destination) | |
| if destination.exists(): | |
| if force_update: | |
| destination.unlink() | |
| else: | |
| continue | |
| if sz == 0: # log once | |
| logger.info("Downloading EEGBCI data") | |
| fetcher.fetch(file_part) | |
| # update path in config if desired | |
| sz += destination.stat().st_size | |
| _do_path_update(path, update_path, config_key, name) | |
| if sz > 0: | |
| _log_time_size(t0, sz) | |
| return data_paths | |
| def standardize(raw): | |
| """Standardize channel positions and names. | |
| Parameters | |
| ---------- | |
| raw : instance of Raw | |
| The raw data to standardize. Operates in-place. | |
| """ | |
| rename = dict() | |
| for name in raw.ch_names: | |
| std_name = name.strip(".") | |
| std_name = std_name.upper() | |
| if std_name.endswith("Z"): | |
| std_name = std_name[:-1] + "z" | |
| if std_name.startswith("FP"): | |
| std_name = "Fp" + std_name[2:] | |
| rename[name] = std_name | |
| raw.rename_channels(rename) | |