针对pulse-transit的工具
This commit is contained in:
821
dist/client/mne/datasets/utils.py
vendored
Normal file
821
dist/client/mne/datasets/utils.py
vendored
Normal file
@@ -0,0 +1,821 @@
|
||||
# Authors: The MNE-Python contributors.
|
||||
# License: BSD-3-Clause
|
||||
# Copyright the MNE-Python contributors.
|
||||
|
||||
import importlib
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
import os.path as op
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import zipfile
|
||||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
from typing import cast
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..label import Label, read_labels_from_annot, write_labels_to_annot
|
||||
from ..utils import (
|
||||
_pl,
|
||||
_safe_input,
|
||||
_validate_type,
|
||||
get_config,
|
||||
get_subjects_dir,
|
||||
logger,
|
||||
set_config,
|
||||
verbose,
|
||||
)
|
||||
from ..utils.docs import _docformat, docdict
|
||||
from .config import MNE_DATASETS, _hcp_mmp_license_text
|
||||
|
||||
_data_path_doc = """Get path to local copy of {name} dataset.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : None | str
|
||||
Location of where to look for the {name} dataset.
|
||||
If None, the environment variable or config parameter
|
||||
``{conf}`` is used. If it doesn't exist, the
|
||||
"~/mne_data" directory is used. If the {name} 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 {name} dataset even if a local copy exists.
|
||||
Default is False.
|
||||
update_path : bool | None
|
||||
If True (default), set the ``{conf}`` in mne-python
|
||||
config to the given path. If None, the user is prompted.
|
||||
download : bool
|
||||
If False and the {name} dataset has not been downloaded yet,
|
||||
it will not be downloaded and the path will be returned as
|
||||
'' (empty string). This is mostly used for debugging purposes
|
||||
and can be safely ignored by most users.
|
||||
%(verbose)s
|
||||
|
||||
Returns
|
||||
-------
|
||||
path : instance of Path
|
||||
Path to {name} dataset directory.
|
||||
"""
|
||||
_data_path_doc_accept = _data_path_doc.split("%(verbose)s")
|
||||
_data_path_doc_accept[-1] = "%(verbose)s" + _data_path_doc_accept[-1]
|
||||
_data_path_doc_accept.insert(1, " %(accept)s")
|
||||
_data_path_doc_accept = "".join(_data_path_doc_accept)
|
||||
_data_path_doc = _docformat(_data_path_doc, docdict)
|
||||
_data_path_doc_accept = _docformat(_data_path_doc_accept, docdict)
|
||||
|
||||
_version_doc = """Get version of the local {name} dataset.
|
||||
|
||||
Returns
|
||||
-------
|
||||
version : str | None
|
||||
Version of the {name} local dataset, or None if the dataset
|
||||
does not exist locally.
|
||||
"""
|
||||
|
||||
|
||||
def _dataset_version(path, name):
|
||||
"""Get the version of the dataset."""
|
||||
ver_fname = op.join(path, "version.txt")
|
||||
if op.exists(ver_fname):
|
||||
with open(ver_fname) as fid:
|
||||
version = fid.readline().strip() # version is on first line
|
||||
else:
|
||||
logger.debug(f"Version file missing: {ver_fname}")
|
||||
# Sample dataset versioning was introduced after 0.3
|
||||
# SPM dataset was introduced with 0.7
|
||||
versions = dict(sample="0.7", spm="0.3")
|
||||
version = versions.get(name, "0.0")
|
||||
return version
|
||||
|
||||
|
||||
def _get_path(path, key, name):
|
||||
"""Get a dataset path."""
|
||||
# 1. Input
|
||||
_validate_type(path, ("path-like", None), path)
|
||||
if path is not None:
|
||||
return Path(path).expanduser()
|
||||
# 2. get_config(key) — unless key is None or "" (special get_config values)
|
||||
# 3. get_config('MNE_DATA')
|
||||
path = get_config(key or "MNE_DATA", get_config("MNE_DATA"))
|
||||
if path is not None:
|
||||
path = Path(path).expanduser()
|
||||
if not path.exists():
|
||||
msg = (
|
||||
f"Download location {path} as specified by MNE_DATA does "
|
||||
f"not exist. Either create this directory manually and try "
|
||||
f"again, or set MNE_DATA to an existing directory."
|
||||
)
|
||||
raise FileNotFoundError(msg)
|
||||
return path
|
||||
# 4. ~/mne_data (but use a fake home during testing so we don't
|
||||
# unnecessarily create ~/mne_data)
|
||||
logger.info(f"Using default location ~/mne_data for {name}...")
|
||||
path = Path(os.getenv("_MNE_FAKE_HOME_DIR", "~")).expanduser() / "mne_data"
|
||||
if not path.is_dir():
|
||||
logger.info(f"Creating {path}")
|
||||
try:
|
||||
path.mkdir()
|
||||
except OSError:
|
||||
raise OSError(
|
||||
"User does not have write permissions "
|
||||
f"at '{path}', try giving the path as an "
|
||||
"argument to data_path() where user has "
|
||||
"write permissions, for ex:data_path"
|
||||
"('/home/xyz/me2/')"
|
||||
)
|
||||
return path
|
||||
|
||||
|
||||
def _do_path_update(path, update_path, key, name):
|
||||
"""Update path."""
|
||||
path = op.abspath(path)
|
||||
identical = get_config(key, "", use_env=False) == path
|
||||
if not identical:
|
||||
if update_path is None:
|
||||
update_path = True
|
||||
if "--update-dataset-path" in sys.argv:
|
||||
answer = "y"
|
||||
else:
|
||||
msg = (
|
||||
f"Do you want to set the path:\n {path}\nas the default {name} "
|
||||
"dataset path in the mne-python config [y]/n? "
|
||||
)
|
||||
answer = _safe_input(msg, alt="pass update_path=True")
|
||||
if answer.lower() == "n":
|
||||
update_path = False
|
||||
|
||||
if update_path:
|
||||
set_config(key, str(path), set_env=False)
|
||||
return path
|
||||
|
||||
|
||||
# This is meant to be semi-public: let packages like mne-bids use it to make
|
||||
# sure they don't accidentally set download=True in their tests, too
|
||||
_MODULES_TO_ENSURE_DOWNLOAD_IS_FALSE_IN_TESTS = ("mne",)
|
||||
|
||||
|
||||
def _check_in_testing_and_raise(name, download):
|
||||
"""Check if we're in an MNE test and raise an error if download!=False."""
|
||||
root_dirs = [
|
||||
importlib.import_module(ns)
|
||||
for ns in _MODULES_TO_ENSURE_DOWNLOAD_IS_FALSE_IN_TESTS
|
||||
]
|
||||
root_dirs = [str(Path(ns.__file__).parent) for ns in root_dirs]
|
||||
check = False
|
||||
func = None
|
||||
frame = inspect.currentframe()
|
||||
try:
|
||||
# First, traverse out of the data_path() call
|
||||
while frame:
|
||||
if frame.f_code.co_name in ("data_path", "load_data"):
|
||||
func = frame.f_code.co_name
|
||||
frame = frame.f_back.f_back # out of verbose decorator
|
||||
break
|
||||
frame = frame.f_back
|
||||
# Next, see what the caller was
|
||||
while frame:
|
||||
fname = frame.f_code.co_filename
|
||||
if fname is not None:
|
||||
fname = Path(fname)
|
||||
# in mne namespace, and
|
||||
# (can't use is_relative_to here until 3.9)
|
||||
if any(str(fname).startswith(rd) for rd in root_dirs) and (
|
||||
# in tests/*.py
|
||||
fname.parent.stem == "tests"
|
||||
or
|
||||
# or in a conftest.py
|
||||
fname.stem == "conftest.py"
|
||||
):
|
||||
check = True
|
||||
break
|
||||
frame = frame.f_back
|
||||
finally:
|
||||
del frame
|
||||
if check and download is not False:
|
||||
raise RuntimeError(
|
||||
f"Do not download dataset {repr(name)} in tests, pass "
|
||||
f"{func}(download=False) to prevent accidental downloads"
|
||||
)
|
||||
|
||||
|
||||
def _download_mne_dataset(
|
||||
name, processor, path, force_update, update_path, download, accept=False
|
||||
) -> Path:
|
||||
"""Aux function for downloading internal MNE datasets."""
|
||||
import pooch
|
||||
|
||||
from mne.datasets._fetch import fetch_dataset
|
||||
|
||||
_check_in_testing_and_raise(name, download)
|
||||
|
||||
# import pooch library for handling the dataset downloading
|
||||
dataset_params = MNE_DATASETS[name]
|
||||
dataset_params["dataset_name"] = name
|
||||
config_key = MNE_DATASETS[name]["config_key"]
|
||||
folder_name = MNE_DATASETS[name]["folder_name"]
|
||||
|
||||
# get download path for specific dataset
|
||||
path = _get_path(path=path, key=config_key, name=name)
|
||||
|
||||
# instantiate processor that unzips file
|
||||
if processor == "nested_untar":
|
||||
processor_ = pooch.Untar(extract_dir=op.join(path, folder_name))
|
||||
elif processor == "nested_unzip":
|
||||
processor_ = pooch.Unzip(extract_dir=op.join(path, folder_name))
|
||||
else:
|
||||
processor_ = processor
|
||||
|
||||
# handle case of multiple sub-datasets with different urls
|
||||
if name == "visual_92_categories":
|
||||
dataset_params = []
|
||||
for name in ["visual_92_categories_1", "visual_92_categories_2"]:
|
||||
this_dataset = MNE_DATASETS[name]
|
||||
this_dataset["dataset_name"] = name
|
||||
dataset_params.append(this_dataset)
|
||||
|
||||
return cast(
|
||||
Path,
|
||||
fetch_dataset(
|
||||
dataset_params=dataset_params,
|
||||
processor=processor_,
|
||||
path=path,
|
||||
force_update=force_update,
|
||||
update_path=update_path,
|
||||
download=download,
|
||||
accept=accept,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _get_version(name):
|
||||
"""Get a dataset version."""
|
||||
from mne.datasets._fetch import fetch_dataset
|
||||
|
||||
if not has_dataset(name):
|
||||
return None
|
||||
dataset_params = MNE_DATASETS[name]
|
||||
dataset_params["dataset_name"] = name
|
||||
config_key = MNE_DATASETS[name]["config_key"]
|
||||
|
||||
# get download path for specific dataset
|
||||
path = _get_path(path=None, key=config_key, name=name)
|
||||
|
||||
return fetch_dataset(dataset_params, path=path, return_version=True)[1]
|
||||
|
||||
|
||||
def has_dataset(name):
|
||||
"""Check for presence of a dataset.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str | dict
|
||||
The dataset to check. Strings refer to one of the supported datasets
|
||||
listed :ref:`here <datasets>`. A :class:`dict` can be used to check for
|
||||
user-defined datasets (see the Notes section of :func:`fetch_dataset`),
|
||||
and must contain keys ``dataset_name``, ``archive_name``, ``url``,
|
||||
``folder_name``, ``hash``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
has : bool
|
||||
True if the dataset is present.
|
||||
"""
|
||||
from mne.datasets._fetch import fetch_dataset
|
||||
|
||||
if isinstance(name, dict):
|
||||
dataset_name = name["dataset_name"]
|
||||
dataset_params = name
|
||||
else:
|
||||
dataset_name = "spm" if name == "spm_face" else name
|
||||
dataset_params = MNE_DATASETS[dataset_name]
|
||||
dataset_params["dataset_name"] = dataset_name
|
||||
|
||||
config_key = dataset_params["config_key"]
|
||||
|
||||
# get download path for specific dataset
|
||||
path = _get_path(path=None, key=config_key, name=dataset_name)
|
||||
|
||||
dp = fetch_dataset(dataset_params, path=path, download=False, check_version=False)
|
||||
if dataset_name.startswith("bst_"):
|
||||
check = dataset_name
|
||||
else:
|
||||
check = MNE_DATASETS[dataset_name]["folder_name"]
|
||||
return str(dp).endswith(check)
|
||||
|
||||
|
||||
@verbose
|
||||
def _download_all_example_data(verbose=True):
|
||||
"""Download all datasets used in examples and tutorials."""
|
||||
# This function is designed primarily to be used by CircleCI, to:
|
||||
#
|
||||
# 1. Streamline data downloading
|
||||
# 2. Make CircleCI fail early (rather than later) if some necessary data
|
||||
# cannot be retrieved.
|
||||
# 3. Avoid download statuses and timing biases in rendered examples.
|
||||
#
|
||||
# verbose=True by default so we get nice status messages.
|
||||
# Consider adding datasets from here to CircleCI for PR-auto-build
|
||||
paths = dict()
|
||||
for kind in (
|
||||
"sample testing misc spm_face somato hf_sef multimodal "
|
||||
"fnirs_motor opm mtrf fieldtrip_cmc kiloword phantom_kit phantom_4dbti "
|
||||
"refmeg_noise ssvep epilepsy_ecog ucl_opm_auditory eyelink "
|
||||
"erp_core brainstorm.bst_raw brainstorm.bst_auditory "
|
||||
"brainstorm.bst_resting brainstorm.bst_phantom_ctf "
|
||||
"brainstorm.bst_phantom_elekta phantom_kernel"
|
||||
).split():
|
||||
mod = importlib.import_module(f"mne.datasets.{kind}")
|
||||
data_path_func = getattr(mod, "data_path")
|
||||
kwargs = dict()
|
||||
if "accept" in inspect.getfullargspec(data_path_func).args:
|
||||
kwargs["accept"] = True
|
||||
paths[kind] = data_path_func(**kwargs)
|
||||
logger.info(f"[done {kind}]")
|
||||
|
||||
# Now for the exceptions:
|
||||
from . import (
|
||||
eegbci,
|
||||
fetch_fsaverage,
|
||||
fetch_hcp_mmp_parcellation,
|
||||
fetch_infant_template,
|
||||
fetch_phantom,
|
||||
limo,
|
||||
sleep_physionet,
|
||||
)
|
||||
|
||||
eegbci.load_data(1, [6, 10, 14], update_path=True)
|
||||
for subj in range(4):
|
||||
eegbci.load_data(subj + 1, runs=[3], update_path=True)
|
||||
logger.info("[done eegbci]")
|
||||
|
||||
sleep_physionet.age.fetch_data(subjects=[0, 1], recording=[1])
|
||||
logger.info("[done sleep_physionet]")
|
||||
|
||||
# If the user has SUBJECTS_DIR, respect it, if not, set it to the EEG one
|
||||
# (probably on CircleCI, or otherwise advanced user)
|
||||
fetch_fsaverage(None)
|
||||
logger.info("[done fsaverage]")
|
||||
|
||||
fetch_infant_template("6mo")
|
||||
logger.info("[done infant_template]")
|
||||
|
||||
fetch_hcp_mmp_parcellation(subjects_dir=paths["sample"] / "subjects", accept=True)
|
||||
logger.info("[done hcp_mmp_parcellation]")
|
||||
|
||||
fetch_phantom("otaniemi", subjects_dir=paths["brainstorm.bst_phantom_elekta"])
|
||||
logger.info("[done phantom]")
|
||||
|
||||
limo.load_data(subject=1, update_path=True)
|
||||
logger.info("[done limo]")
|
||||
|
||||
|
||||
@verbose
|
||||
def fetch_aparc_sub_parcellation(subjects_dir=None, verbose=None):
|
||||
"""Fetch the modified subdivided aparc parcellation.
|
||||
|
||||
This will download and install the subdivided aparc parcellation
|
||||
:footcite:'KhanEtAl2018' files for
|
||||
FreeSurfer's fsaverage to the specified directory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
subjects_dir : path-like | None
|
||||
The subjects directory to use. The file will be placed in
|
||||
``subjects_dir + '/fsaverage/label'``.
|
||||
%(verbose)s
|
||||
|
||||
References
|
||||
----------
|
||||
.. footbibliography::
|
||||
"""
|
||||
import pooch
|
||||
|
||||
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
|
||||
destination = subjects_dir / "fsaverage" / "label"
|
||||
urls = dict(lh="https://osf.io/p92yb/download", rh="https://osf.io/4kxny/download")
|
||||
hashes = dict(
|
||||
lh="9e4d8d6b90242b7e4b0145353436ef77", rh="dd6464db8e7762d969fc1d8087cd211b"
|
||||
)
|
||||
downloader = pooch.HTTPDownloader(**_downloader_params())
|
||||
for hemi in ("lh", "rh"):
|
||||
fname = f"{hemi}.aparc_sub.annot"
|
||||
fpath = destination / fname
|
||||
if not fpath.is_file():
|
||||
pooch.retrieve(
|
||||
url=urls[hemi],
|
||||
known_hash=f"md5:{hashes[hemi]}",
|
||||
path=destination,
|
||||
downloader=downloader,
|
||||
fname=fname,
|
||||
)
|
||||
|
||||
|
||||
@verbose
|
||||
def fetch_hcp_mmp_parcellation(
|
||||
subjects_dir=None, combine=True, *, accept=False, verbose=None
|
||||
):
|
||||
"""Fetch the HCP-MMP parcellation.
|
||||
|
||||
This will download and install the HCP-MMP parcellation
|
||||
:footcite:`GlasserEtAl2016` files for FreeSurfer's fsaverage
|
||||
:footcite:`Mills2016` to the specified directory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
subjects_dir : path-like | None
|
||||
The subjects directory to use. The file will be placed in
|
||||
``subjects_dir + '/fsaverage/label'``.
|
||||
combine : bool
|
||||
If True, also produce the combined/reduced set of 23 labels per
|
||||
hemisphere as ``HCPMMP1_combined.annot``
|
||||
:footcite:`GlasserEtAl2016supp`.
|
||||
%(accept)s
|
||||
%(verbose)s
|
||||
|
||||
Notes
|
||||
-----
|
||||
Use of this parcellation is subject to terms of use on the
|
||||
`HCP-MMP webpage <https://balsa.wustl.edu/WN56>`_.
|
||||
|
||||
References
|
||||
----------
|
||||
.. footbibliography::
|
||||
"""
|
||||
import pooch
|
||||
|
||||
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
|
||||
destination = subjects_dir / "fsaverage" / "label"
|
||||
fnames = [destination / f"{hemi}.HCPMMP1.annot" for hemi in ("lh", "rh")]
|
||||
urls = dict(
|
||||
lh="https://ndownloader.figshare.com/files/5528816",
|
||||
rh="https://ndownloader.figshare.com/files/5528819",
|
||||
)
|
||||
hashes = dict(
|
||||
lh="46a102b59b2fb1bb4bd62d51bf02e975", rh="75e96b331940227bbcb07c1c791c2463"
|
||||
)
|
||||
if not all(fname.exists() for fname in fnames):
|
||||
if accept or "--accept-hcpmmp-license" in sys.argv:
|
||||
answer = "y"
|
||||
else:
|
||||
answer = _safe_input(f"{_hcp_mmp_license_text}\nAgree (y/[n])? ")
|
||||
if answer.lower() != "y":
|
||||
raise RuntimeError("You must agree to the license to use this dataset")
|
||||
downloader = pooch.HTTPDownloader(**_downloader_params())
|
||||
for hemi, fpath in zip(("lh", "rh"), fnames):
|
||||
if not op.isfile(fpath):
|
||||
fname = fpath.name
|
||||
pooch.retrieve(
|
||||
url=urls[hemi],
|
||||
known_hash=f"md5:{hashes[hemi]}",
|
||||
path=destination,
|
||||
downloader=downloader,
|
||||
fname=fname,
|
||||
)
|
||||
|
||||
if combine:
|
||||
fnames = [
|
||||
op.join(destination, f"{hemi}.HCPMMP1_combined.annot")
|
||||
for hemi in ("lh", "rh")
|
||||
]
|
||||
if all(op.isfile(fname) for fname in fnames):
|
||||
return
|
||||
# otherwise, let's make them
|
||||
logger.info("Creating combined labels")
|
||||
groups = OrderedDict(
|
||||
[
|
||||
("Primary Visual Cortex (V1)", ("V1",)),
|
||||
("Early Visual Cortex", ("V2", "V3", "V4")),
|
||||
(
|
||||
"Dorsal Stream Visual Cortex",
|
||||
("V3A", "V3B", "V6", "V6A", "V7", "IPS1"),
|
||||
),
|
||||
(
|
||||
"Ventral Stream Visual Cortex",
|
||||
("V8", "VVC", "PIT", "FFC", "VMV1", "VMV2", "VMV3"),
|
||||
),
|
||||
(
|
||||
"MT+ Complex and Neighboring Visual Areas",
|
||||
("V3CD", "LO1", "LO2", "LO3", "V4t", "FST", "MT", "MST", "PH"),
|
||||
),
|
||||
("Somatosensory and Motor Cortex", ("4", "3a", "3b", "1", "2")),
|
||||
(
|
||||
"Paracentral Lobular and Mid Cingulate Cortex",
|
||||
(
|
||||
"24dd",
|
||||
"24dv",
|
||||
"6mp",
|
||||
"6ma",
|
||||
"SCEF",
|
||||
"5m",
|
||||
"5L",
|
||||
"5mv",
|
||||
),
|
||||
),
|
||||
("Premotor Cortex", ("55b", "6d", "6a", "FEF", "6v", "6r", "PEF")),
|
||||
(
|
||||
"Posterior Opercular Cortex",
|
||||
("43", "FOP1", "OP4", "OP1", "OP2-3", "PFcm"),
|
||||
),
|
||||
("Early Auditory Cortex", ("A1", "LBelt", "MBelt", "PBelt", "RI")),
|
||||
(
|
||||
"Auditory Association Cortex",
|
||||
(
|
||||
"A4",
|
||||
"A5",
|
||||
"STSdp",
|
||||
"STSda",
|
||||
"STSvp",
|
||||
"STSva",
|
||||
"STGa",
|
||||
"TA2",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Insular and Frontal Opercular Cortex",
|
||||
(
|
||||
"52",
|
||||
"PI",
|
||||
"Ig",
|
||||
"PoI1",
|
||||
"PoI2",
|
||||
"FOP2",
|
||||
"FOP3",
|
||||
"MI",
|
||||
"AVI",
|
||||
"AAIC",
|
||||
"Pir",
|
||||
"FOP4",
|
||||
"FOP5",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Medial Temporal Cortex",
|
||||
(
|
||||
"H",
|
||||
"PreS",
|
||||
"EC",
|
||||
"PeEc",
|
||||
"PHA1",
|
||||
"PHA2",
|
||||
"PHA3",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Lateral Temporal Cortex",
|
||||
(
|
||||
"PHT",
|
||||
"TE1p",
|
||||
"TE1m",
|
||||
"TE1a",
|
||||
"TE2p",
|
||||
"TE2a",
|
||||
"TGv",
|
||||
"TGd",
|
||||
"TF",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Temporo-Parieto-Occipital Junction",
|
||||
(
|
||||
"TPOJ1",
|
||||
"TPOJ2",
|
||||
"TPOJ3",
|
||||
"STV",
|
||||
"PSL",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Superior Parietal Cortex",
|
||||
(
|
||||
"LIPv",
|
||||
"LIPd",
|
||||
"VIP",
|
||||
"AIP",
|
||||
"MIP",
|
||||
"7PC",
|
||||
"7AL",
|
||||
"7Am",
|
||||
"7PL",
|
||||
"7Pm",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Inferior Parietal Cortex",
|
||||
(
|
||||
"PGp",
|
||||
"PGs",
|
||||
"PGi",
|
||||
"PFm",
|
||||
"PF",
|
||||
"PFt",
|
||||
"PFop",
|
||||
"IP0",
|
||||
"IP1",
|
||||
"IP2",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Posterior Cingulate Cortex",
|
||||
(
|
||||
"DVT",
|
||||
"ProS",
|
||||
"POS1",
|
||||
"POS2",
|
||||
"RSC",
|
||||
"v23ab",
|
||||
"d23ab",
|
||||
"31pv",
|
||||
"31pd",
|
||||
"31a",
|
||||
"23d",
|
||||
"23c",
|
||||
"PCV",
|
||||
"7m",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Anterior Cingulate and Medial Prefrontal Cortex",
|
||||
(
|
||||
"33pr",
|
||||
"p24pr",
|
||||
"a24pr",
|
||||
"p24",
|
||||
"a24",
|
||||
"p32pr",
|
||||
"a32pr",
|
||||
"d32",
|
||||
"p32",
|
||||
"s32",
|
||||
"8BM",
|
||||
"9m",
|
||||
"10v",
|
||||
"10r",
|
||||
"25",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Orbital and Polar Frontal Cortex",
|
||||
(
|
||||
"47s",
|
||||
"47m",
|
||||
"a47r",
|
||||
"11l",
|
||||
"13l",
|
||||
"a10p",
|
||||
"p10p",
|
||||
"10pp",
|
||||
"10d",
|
||||
"OFC",
|
||||
"pOFC",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Inferior Frontal Cortex",
|
||||
(
|
||||
"44",
|
||||
"45",
|
||||
"IFJp",
|
||||
"IFJa",
|
||||
"IFSp",
|
||||
"IFSa",
|
||||
"47l",
|
||||
"p47r",
|
||||
),
|
||||
),
|
||||
(
|
||||
"DorsoLateral Prefrontal Cortex",
|
||||
(
|
||||
"8C",
|
||||
"8Av",
|
||||
"i6-8",
|
||||
"s6-8",
|
||||
"SFL",
|
||||
"8BL",
|
||||
"9p",
|
||||
"9a",
|
||||
"8Ad",
|
||||
"p9-46v",
|
||||
"a9-46v",
|
||||
"46",
|
||||
"9-46d",
|
||||
),
|
||||
),
|
||||
("???", ("???",)),
|
||||
]
|
||||
)
|
||||
assert len(groups) == 23
|
||||
labels_out = list()
|
||||
|
||||
for hemi in ("lh", "rh"):
|
||||
labels = read_labels_from_annot(
|
||||
"fsaverage", "HCPMMP1", hemi=hemi, subjects_dir=subjects_dir, sort=False
|
||||
)
|
||||
label_names = [
|
||||
"???" if label.name.startswith("???") else label.name.split("_")[1]
|
||||
for label in labels
|
||||
]
|
||||
used = np.zeros(len(labels), bool)
|
||||
for key, want in groups.items():
|
||||
assert "\t" not in key
|
||||
these_labels = [
|
||||
li
|
||||
for li, label_name in enumerate(label_names)
|
||||
if label_name in want
|
||||
]
|
||||
assert not used[these_labels].any()
|
||||
assert len(these_labels) == len(want)
|
||||
used[these_labels] = True
|
||||
these_labels = [labels[li] for li in these_labels]
|
||||
# take a weighted average to get the color
|
||||
# (here color == task activation)
|
||||
w = np.array([len(label.vertices) for label in these_labels])
|
||||
w = w / float(w.sum())
|
||||
color = np.dot(w, [label.color for label in these_labels])
|
||||
these_labels = sum(
|
||||
these_labels, Label([], subject="fsaverage", hemi=hemi)
|
||||
)
|
||||
these_labels.name = key
|
||||
these_labels.color = color
|
||||
labels_out.append(these_labels)
|
||||
assert used.all()
|
||||
assert len(labels_out) == 46
|
||||
for hemi, side in (("lh", "left"), ("rh", "right")):
|
||||
table_name = f"./{side}.fsaverage164.label.gii"
|
||||
write_labels_to_annot(
|
||||
labels_out,
|
||||
"fsaverage",
|
||||
"HCPMMP1_combined",
|
||||
hemi=hemi,
|
||||
subjects_dir=subjects_dir,
|
||||
sort=False,
|
||||
table_name=table_name,
|
||||
)
|
||||
|
||||
|
||||
def _manifest_check_download(manifest_path, destination, url, hash_):
|
||||
import pooch
|
||||
|
||||
with open(manifest_path) as fid:
|
||||
names = [name.strip() for name in fid.readlines()]
|
||||
need = list()
|
||||
for name in names:
|
||||
if not (destination / name).is_file():
|
||||
need.append(name)
|
||||
logger.info(
|
||||
"%d file%s missing from %s in %s"
|
||||
% (len(need), _pl(need), manifest_path.name, destination)
|
||||
)
|
||||
if len(need) > 0:
|
||||
downloader = pooch.HTTPDownloader(**_downloader_params())
|
||||
with tempfile.TemporaryDirectory() as path:
|
||||
logger.info("Downloading missing files remotely")
|
||||
|
||||
path = Path(path)
|
||||
fname_path = path / "temp.zip"
|
||||
pooch.retrieve(
|
||||
url=url,
|
||||
known_hash=f"md5:{hash_}",
|
||||
path=path,
|
||||
downloader=downloader,
|
||||
fname=fname_path.name,
|
||||
)
|
||||
|
||||
logger.info(f"Extracting missing file{_pl(need)}")
|
||||
with zipfile.ZipFile(fname_path, "r") as ff:
|
||||
members = set(f for f in ff.namelist() if not f.endswith("/"))
|
||||
missing = sorted(members.symmetric_difference(set(names)))
|
||||
if len(missing):
|
||||
raise RuntimeError(
|
||||
"Zip file did not have correct names:\n{'\n'.join(missing)}"
|
||||
)
|
||||
for name in need:
|
||||
ff.extract(name, path=destination)
|
||||
logger.info(f"Successfully extracted {len(need)} file{_pl(need)}")
|
||||
|
||||
|
||||
def _log_time_size(t0, sz):
|
||||
t = time.time() - t0
|
||||
fmt = "%Ss"
|
||||
if t > 60:
|
||||
fmt = f"%Mm{fmt}"
|
||||
if t > 3600:
|
||||
fmt = f"%Hh{fmt}"
|
||||
sz = sz / 1048576 # 1024 ** 2
|
||||
t = time.strftime(fmt, time.gmtime(t))
|
||||
logger.info(f"Download complete in {t} ({sz:.1f} MB)")
|
||||
|
||||
|
||||
def _downloader_params(*, auth=None, token=None):
|
||||
params = dict(timeout=15)
|
||||
params["progressbar"] = (
|
||||
logger.level <= logging.INFO and get_config("MNE_TQDM", "tqdm.auto") != "off"
|
||||
)
|
||||
if auth is not None:
|
||||
params["auth"] = auth
|
||||
if token is not None:
|
||||
params["headers"] = {"Authorization": f"token {token}"}
|
||||
return params
|
||||
Reference in New Issue
Block a user