Skip to content

Commit 9cc5d14

Browse files
massichagramfort
authored andcommitted
ENH: Add MNE-fsaverage (#6174)
* Keep eric's fsaverage * make set_montage_coreg_path as private * stip check manifest out from fsaverage * ENH: better parameter name * move the fsaverage info to fsaverage * FIX: docstring * [skip ci] move fsaverage files * rename * update the fsaverage manifests * FIX: use the new zip files * FIX: Fix test * FIX: manifests * FIX: Manifest again * FIX: Doc * FIX: call montage setter * ENH: Simplify * FIX: string * fix * Skip the test for 3.5, since zipfiles cannot be written
1 parent c9fa690 commit 9cc5d14

13 files changed

Lines changed: 468 additions & 21 deletions

File tree

.circleci/config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ jobs:
107107
if [[ $(cat $FNAME | grep -x ".*datasets.*sample.*" | wc -l) -gt 0 ]]; then
108108
python -c "import mne; print(mne.datasets.sample.data_path(update_path=True))";
109109
fi;
110+
if [[ $(cat $FNAME | grep -x ".*datasets.*fetch_fsaverage.*" | wc -l) -gt 0 ]]; then
111+
python -c "import mne; print(mne.datasets.fetch_fsaverage(verbose=True))";
112+
fi;
110113
if [[ $(cat $FNAME | grep -x ".*datasets.*spm_face.*" | wc -l) -gt 0 ]]; then
111114
python -c "import mne; print(mne.datasets.spm_face.data_path(update_path=True))";
112115
fi;

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ recursive-include mne/data *
1414
recursive-include mne/data/helmets *
1515
recursive-include mne/data/image *
1616
recursive-include mne/data/fsaverage *
17+
include mne/datasets/_fsaverage/root.txt
18+
include mne/datasets/_fsaverage/bem.txt
1719

1820
recursive-include mne/channels/data/layouts *
1921
recursive-include mne/channels/data/montages *

doc/manual/datasets_index.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ as soon as possible after the appearance of the face.
2525

2626
Once the ``data_path`` is known, its contents can be examined using :ref:`IO functions <ch_convert>`.
2727

28+
fsaverage
29+
=========
30+
:func:`mne.datasets.fetch_fsaverage`
31+
32+
For convenience, we provide a function to separately download and extract the
33+
(or update an existing) fsaverage subject.
34+
2835
Brainstorm
2936
==========
3037
Dataset fetchers for three Brainstorm tutorials are available. Users must agree to the

doc/python_reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Datasets
183183
brainstorm.bst_raw.data_path
184184
eegbci.load_data
185185
fetch_aparc_sub_parcellation
186+
fetch_fsaverage
186187
fetch_hcp_mmp_parcellation
187188
hf_sef.data_path
188189
kiloword.data_path

doc/whats_new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Current
1919
Changelog
2020
~~~~~~~~~
2121

22+
- Add convenience ``fsaverage`` subject dataset fetcher / updater :func:`mne.datasets.fetch_fsaverage` by `Eric Larson`_
23+
2224
- Add ``fmin`` and ``fmax`` argument to :meth:`mne.time_frequency.AverageTFR.crop` and to :meth:`mne.time_frequency.EpochsTFR.crop` to crop TFR objects along frequency axis by `Dirk Gütlin`_
2325

2426
- Add support to :func:`mne.read_annotations` to read CNT formats by `Joan Massich`_

mne/datasets/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,12 @@
2323
from . import sleep_physionet
2424
from .utils import (_download_all_example_data, fetch_hcp_mmp_parcellation,
2525
fetch_aparc_sub_parcellation)
26+
from ._fsaverage.base import fetch_fsaverage
27+
28+
__all__ = [
29+
'_download_all_example_data', '_fake', 'brainstorm', 'eegbci',
30+
'fetch_aparc_sub_parcellation', 'fetch_fsaverage',
31+
'fetch_hcp_mmp_parcellation', 'fieldtrip_cmc', 'hf_sef', 'kiloword',
32+
'megsim', 'misc', 'mtrf', 'multimodal', 'opm', 'phantom_4dbti', 'sample',
33+
'sleep_physionet', 'somato', 'spm_face', 'testing', 'visual_92_categories',
34+
]

mne/datasets/_fsaverage/__init__.py

Whitespace-only changes.

mne/datasets/_fsaverage/base.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# -*- coding: utf-8 -*-
2+
# Authors: Eric Larson <larson.eric.d@gmail.com>
3+
# License: BSD Style.
4+
5+
import os
6+
import os.path as op
7+
8+
9+
from ...utils import (verbose, get_subjects_dir, set_config)
10+
11+
FSAVERAGE_MANIFEST_PATH = op.dirname(__file__)
12+
13+
14+
@verbose
15+
def fetch_fsaverage(subjects_dir=None, verbose=None):
16+
"""Fetch and update fsaverage.
17+
18+
Parameters
19+
----------
20+
subjects_dir : str | None
21+
The path to use as the subjects directory in the MNE-Python
22+
config file. None will use the existing config variable (i.e.,
23+
will not change anything), and if it does not exist, will use
24+
``~/mne_data/MNE-fsaverage-data``.
25+
%(verbose)s
26+
27+
Returns
28+
-------
29+
fs_dir : str
30+
The fsaverage directory.
31+
(essentially ``subjects_dir + '/fsaverage'``)
32+
33+
Notes
34+
-----
35+
This function is designed to provide
36+
37+
1. All modern (Freesurfer 6) fsaverage subject files
38+
2. All MNE fsaverage parcellations
39+
3. fsaverage head surface, fiducials, head<->MRI trans, 1- and 3-layer
40+
BEMs (and surfaces)
41+
42+
This function will compare the contents of ``subjects_dir/fsaverage``
43+
to the ones provided in the remote zip file. If any are missing,
44+
the zip file is downloaded and files are updated. No files will
45+
be overwritten.
46+
47+
.. versionadded:: 0.18
48+
"""
49+
# Code used to create the BEM (other files taken from MNE-sample-data):
50+
#
51+
# $ mne watershed_bem -s fsaverage -d $PWD --verbose info --copy
52+
# $ python
53+
# >>> bem = mne.make_bem_model('fsaverage', subjects_dir='.', verbose=True)
54+
# >>> mne.write_bem_surfaces(
55+
# ... 'fsaverage/bem/fsaverage-5120-5120-5120-bem.fif', bem)
56+
# >>> sol = mne.make_bem_solution(bem, verbose=True)
57+
# >>> mne.write_bem_solution(
58+
# ... 'fsaverage/bem/fsaverage-5120-5120-5120-bem-sol.fif', sol)
59+
# >>> import os
60+
# >>> import os.path as op
61+
# >>> names = sorted(op.join(r, f)
62+
# ... for r, d, files in os.walk('fsaverage')
63+
# ... for f in files)
64+
# with open('fsaverage.txt', 'w') as fid:
65+
# fid.write('\n'.join(names))
66+
#
67+
from ..utils import _manifest_check_download
68+
subjects_dir = _set_montage_coreg_path(subjects_dir)
69+
subjects_dir = op.abspath(subjects_dir)
70+
fs_dir = op.join(subjects_dir, 'fsaverage')
71+
os.makedirs(fs_dir, exist_ok=True)
72+
73+
fsaverage_data_parts = {
74+
'root.zip': dict(
75+
url='https://osf.io/3bxqt/download?revision=1',
76+
hash_='98fd27539b7a2b02e3d98398179ae378',
77+
manifest=op.join(FSAVERAGE_MANIFEST_PATH, 'root.txt'),
78+
destination=op.join(subjects_dir),
79+
),
80+
'bem.zip': dict(
81+
url='https://osf.io/7ve8g/download?revision=1',
82+
hash_='07c3ccde63121f5e82d1fc20e3194497',
83+
manifest=op.join(FSAVERAGE_MANIFEST_PATH, 'bem.txt'),
84+
destination=op.join(subjects_dir, 'fsaverage'),
85+
),
86+
}
87+
for fname, data in fsaverage_data_parts.items():
88+
_manifest_check_download(
89+
destination=data['destination'],
90+
manifest_path=data['manifest'],
91+
url=data['url'],
92+
hash_=data['hash_'],
93+
)
94+
return fs_dir
95+
96+
97+
def _get_create_subjects_dir(subjects_dir):
98+
from ..utils import _get_path
99+
subjects_dir = get_subjects_dir(subjects_dir, raise_error=False)
100+
if subjects_dir is None:
101+
subjects_dir = _get_path(None, '', 'montage coregistration')
102+
subjects_dir = op.join(subjects_dir, 'MNE-fsaverage-data')
103+
os.makedirs(subjects_dir, exist_ok=True)
104+
return subjects_dir
105+
106+
107+
def _set_montage_coreg_path(subjects_dir=None):
108+
"""Set a subject directory suitable for montage(-only) coregistration.
109+
110+
Parameters
111+
----------
112+
subjects_dir : str | None
113+
The path to use as the subjects directory in the MNE-Python
114+
config file. None will use the existing config variable (i.e.,
115+
will not change anything), and if it does not exist, will use
116+
``~/mne_data/MNE-fsaverage-data``.
117+
118+
Returns
119+
-------
120+
subjects_dir : str
121+
The subjects directory that was used.
122+
123+
See Also
124+
--------
125+
mne.datasets.fetch_fsaverage
126+
mne.get_config
127+
mne.set_config
128+
129+
Notes
130+
-----
131+
If you plan to only do EEG-montage based coregistrations with fsaverage
132+
without any MRI warping, this function can facilitate the process.
133+
Essentially it sets the default value for ``subjects_dir`` in MNE
134+
functions to be ``~/mne_data/MNE-fsaverage-data`` (assuming it has
135+
not already been set to some other value).
136+
137+
.. versionadded:: 0.18
138+
"""
139+
subjects_dir = _get_create_subjects_dir(subjects_dir)
140+
old_subjects_dir = get_subjects_dir(None, raise_error=False)
141+
if old_subjects_dir is not None and old_subjects_dir != subjects_dir:
142+
raise ValueError('The subjects dir is already set to %r, which does '
143+
'not match the provided subjects_dir=%r'
144+
% (old_subjects_dir, subjects_dir))
145+
set_config('SUBJECTS_DIR', subjects_dir)
146+
return subjects_dir

mne/datasets/_fsaverage/bem.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
bem/fsaverage-fiducials.fif
2+
bem/fsaverage-5120-5120-5120-bem.fif
3+
bem/fsaverage-head.fif
4+
bem/outer_skin.surf
5+
bem/brain.surf
6+
bem/fsaverage-trans.fif
7+
bem/fsaverage-ico-5-src.fif
8+
bem/outer_skull.surf
9+
bem/inner_skull.surf
10+
bem/fsaverage-5120-5120-5120-bem-sol.fif
11+
bem/fsaverage-inner_skull-bem.fif

0 commit comments

Comments
 (0)