Skip to content

Commit 7fcddd0

Browse files
committed
FIX: Add tests
1 parent 746193d commit 7fcddd0

File tree

9 files changed

+102
-32
lines changed

9 files changed

+102
-32
lines changed

mne/datasets/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def _data_path(path=None, force_update=False, update_path=True, download=True,
239239
path = _get_path(path, key, name)
240240
# To update the testing or misc dataset, push commits, then make a new
241241
# release on GitHub. Then update the "releases" variable:
242-
releases = dict(testing='0.97', misc='0.6')
242+
releases = dict(testing='0.98', misc='0.6')
243243
# And also update the "md5_hashes['testing']" variable below.
244244

245245
# To update any other dataset, update the data archive itself (upload
@@ -326,7 +326,7 @@ def _data_path(path=None, force_update=False, update_path=True, download=True,
326326
sample='12b75d1cb7df9dfb4ad73ed82f61094f',
327327
somato='ea825966c0a1e9b2f84e3826c5500161',
328328
spm='9f43f67150e3b694b523a21eb929ea75',
329-
testing='603c3f087c4dbf151c729341342095c7',
329+
testing='7c1dcfacaac7759aa40bfb800c791d85',
330330
multimodal='26ec847ae9ab80f58f204d09e2c08367',
331331
fnirs_motor='c4935d19ddab35422a69f3326a01fef8',
332332
opm='370ad1dcfd5c47e029e692c85358a374',

mne/surface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ def _read_patch(fname):
796796

797797
# read surrogate surface
798798
rrs, tris = read_surface(
799-
op.join(op.dirname(fname), op.basename(fname)[:3] + 'pial'))
799+
op.join(op.dirname(fname), op.basename(fname)[:3] + 'sphere'))
800800
orig_tris = tris
801801
is_vert = patch['vertno'] > 0 # negative are edges, ignored for now
802802
verts = patch['vertno'][is_vert]

mne/tests/test_surface.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
dig_mri_distances)
1414
from mne.surface import (read_morph_map, _compute_nearest, _tessellate_sphere,
1515
fast_cross_3d, get_head_surf, read_curvature,
16-
get_meg_helmet_surf, _normal_orth)
16+
get_meg_helmet_surf, _normal_orth, _read_patch)
1717
from mne.utils import (_TempDir, requires_vtk, catch_logging,
1818
run_tests_if_main, object_diff, requires_freesurfer)
1919
from mne.io import read_info
@@ -183,6 +183,12 @@ def test_io_surface():
183183
assert_array_equal(pts, c_pts)
184184
assert_array_equal(tri, c_tri)
185185

186+
# reading patches (just a smoke test, let the flatmap viz tests be more
187+
# complete)
188+
fname_patch = op.join(
189+
data_path, 'subjects', 'fsaverage', 'surf', 'rh.cortex.patch.flat')
190+
_read_patch(fname_patch)
191+
186192

187193
@testing.requires_testing_data
188194
def test_read_curv():

mne/utils/docs.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,16 @@
10581058
Can be "vertical" (default) or "horizontal". When using "horizontal" mode,
10591059
the PyVista backend must be used and hemi cannot be "split".
10601060
"""
1061+
docdict['views'] = """
1062+
views : str | list
1063+
View to use. Can be any of::
1064+
1065+
['lateral', 'medial', 'rostral', 'caudal', 'dorsal', 'ventral',
1066+
'frontal', 'parietal', 'axial', 'sagittal', 'coronal']
1067+
1068+
Three letter abbreviations (e.g., ``'lat'``) are also supported.
1069+
Using multiple views (list) is not supported for mpl backend.
1070+
"""
10611071

10621072
# STC label time course
10631073
docdict['eltc_labels'] = """

mne/viz/_3d.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,10 +1630,14 @@ def plot_source_estimates(stc, subject=None, surface='inflated', hemi='lh',
16301630
length. If int is provided it will be used to identify the Mayavi
16311631
figure by it's id or create a new figure with the given id. If an
16321632
instance of matplotlib figure, mpl backend is used for plotting.
1633-
views : str | list
1634-
View to use. See `surfer.Brain`. Supported views: ['lat', 'med', 'ros',
1635-
'cau', 'dor' 'ven', 'fro', 'par']. Using multiple views is not
1636-
supported for mpl backend.
1633+
%(views)s
1634+
1635+
When plotting a standard SourceEstimate (not volume, mixed, or vector)
1636+
and using the PyVista backend, ``views='flat'`` is also supported to
1637+
plot cortex as a flatmap.
1638+
1639+
.. versionchanged:: 0.21.0
1640+
Support for flatmaps.
16371641
colorbar : bool
16381642
If True, display colorbar on scene.
16391643
%(clim)s
@@ -1684,6 +1688,17 @@ def plot_source_estimates(stc, subject=None, surface='inflated', hemi='lh',
16841688
figure : instance of surfer.Brain | matplotlib.figure.Figure
16851689
An instance of :class:`surfer.Brain` from PySurfer or
16861690
matplotlib figure.
1691+
1692+
Notes
1693+
-----
1694+
Flatmaps are available by default for ``fsaverage`` but not for other
1695+
subjects reconstructed by FreeSurfer. We recommend using
1696+
:func:`mne.compute_source_morph` to morph source estimates to ``fsaverage``
1697+
for flatmap plotting. If you want to construct your own flatmap for a given
1698+
subject, these links might help:
1699+
1700+
- https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferOccipitalFlattenedPatch
1701+
- https://openwetware.org/wiki/Beauchamp:FreeSurfer
16871702
""" # noqa: E501
16881703
from .backends.renderer import _get_3d_backend, set_3d_backend
16891704
from ..source_estimate import _BaseSourceEstimate
@@ -1740,7 +1755,7 @@ def _plot_stc(stc, subject, surface, hemi, colormap, time_label,
17401755
_require_version('surfer', 'stc.plot', '0.9')
17411756
else: # PyVista
17421757
from ._brain import _Brain as Brain
1743-
1758+
views = _check_views(surface, views, hemi, stc, backend)
17441759
_check_option('hemi', hemi, ['lh', 'rh', 'split', 'both'])
17451760
_check_option('view_layout', view_layout, ('vertical', 'horizontal'))
17461761
time_label, times = _handle_time(time_label, time_unit, stc.times)
@@ -2347,6 +2362,29 @@ def _check_pysurfer_antialias(Brain):
23472362
return kwargs
23482363

23492364

2365+
def _check_views(surf, views, hemi, stc=None, backend=None):
2366+
from ..source_estimate import SourceEstimate
2367+
_validate_type(views, (list, tuple, str), 'views')
2368+
views = [views] if isinstance(views, str) else list(views)
2369+
if surf == 'flat':
2370+
_check_option('views', views, (['auto'], ['flat']))
2371+
views = ['flat']
2372+
elif len(views) == 1 and views[0] == 'auto':
2373+
views = ['lat']
2374+
if views == ['flat']:
2375+
if stc is not None:
2376+
_validate_type(stc, SourceEstimate, 'stc',
2377+
'SourceEstimate when a flatmap is used')
2378+
if backend is not None:
2379+
if backend != 'pyvista':
2380+
raise RuntimeError('The PyVista 3D backend must be used to '
2381+
'plot a flatmap')
2382+
if (views == ['flat']) ^ (surf == 'flat'): # exactly only one of the two
2383+
raise ValueError('surface="flat" must be used with views="flat", got '
2384+
f'surface={repr(surf)} and views={repr(views)}')
2385+
return views
2386+
2387+
23502388
@verbose
23512389
def plot_vector_source_estimates(stc, subject=None, hemi='lh', colormap='hot',
23522390
time_label='auto', smoothing_steps=10,
@@ -2407,8 +2445,7 @@ def plot_vector_source_estimates(stc, subject=None, hemi='lh', colormap='hot',
24072445
split view is requested, this must be a list of the appropriate
24082446
length. If int is provided it will be used to identify the Mayavi
24092447
figure by it's id or create a new figure with the given id.
2410-
views : str | list
2411-
View to use. See `surfer.Brain`.
2448+
%(views)s
24122449
colorbar : bool
24132450
If True, display colorbar on scene.
24142451
%(clim_onesided)s

mne/viz/_brain/_brain.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from .surface import Surface
1818
from .view import views_dicts
1919

20-
from .._3d import _process_clim, _handle_time
20+
from .._3d import _process_clim, _handle_time, _check_views
2121

2222
from ...defaults import _handle_default
2323
from ...surface import mesh_edges
@@ -198,7 +198,7 @@ def __init__(self, subject_id, hemi, surf, title=None,
198198

199199
if isinstance(views, str):
200200
views = [views]
201-
views = _check_views_hemi_flat(surf, views, hemi)
201+
views = _check_views(surf, views, hemi)
202202
col_dict = dict(lh=1, rh=1, both=1, split=2)
203203
shape = (len(views), col_dict[hemi])
204204
if self._view_layout == 'horizontal':
@@ -1737,14 +1737,3 @@ def _update_limits(fmin, fmid, fmax, center, array):
17371737
% (fmid, fmax))
17381738

17391739
return fmin, fmid, fmax
1740-
1741-
1742-
def _check_views_hemi_flat(surf, views, hemi):
1743-
if surf == 'flat':
1744-
if len(views) != 1 or views[0] != 'auto':
1745-
raise ValueError(
1746-
f'views must be "auto" for flat maps, got {views}')
1747-
views = ['flat']
1748-
elif len(views) == 1 and views[0] == 'auto':
1749-
views = ['lat']
1750-
return views

mne/viz/_brain/surface.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from os import path as path
1010

1111
import numpy as np
12-
from ...utils import _check_option, get_subjects_dir
12+
from ...utils import _check_option, get_subjects_dir, _check_fname
1313
from ...surface import (complete_surface_info, read_surface, read_curvature,
1414
_read_patch)
1515

@@ -110,9 +110,11 @@ def load_geometry(self):
110110
None
111111
"""
112112
if self.surf == 'flat': # special case
113-
coords, faces, orig_faces = _read_patch(
114-
path.join(self.data_path, 'surf',
115-
'%s.%s' % (self.hemi, 'cortex.patch.flat')))
113+
fname = path.join(self.data_path, 'surf',
114+
'%s.%s' % (self.hemi, 'cortex.patch.flat'))
115+
_check_fname(fname, overwrite='read', must_exist=True,
116+
name='flatmap surface file')
117+
coords, faces, orig_faces = _read_patch(fname)
116118
else:
117119
coords, faces = read_surface(
118120
path.join(self.data_path, 'surf',

mne/viz/tests/test_3d.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -705,9 +705,10 @@ def test_plot_source_estimates(renderer_interactive, all_src_types_inv_evoked,
705705
with pytest.warns(None): # PCA mag
706706
stc = apply_inverse(evoked, inv, pick_ori=pick_ori)
707707
stc.data[1] *= -1 # make it signed
708-
meth = 'plot_3d' if isinstance(stc, _BaseVolSourceEstimate) else 'plot'
709-
meth = getattr(stc, meth)
710-
kwargs = dict(subject='sample', subjects_dir=subjects_dir,
708+
meth_key = 'plot_3d' if isinstance(stc, _BaseVolSourceEstimate) else 'plot'
709+
stc.subject = 'sample'
710+
meth = getattr(stc, meth_key)
711+
kwargs = dict(subjects_dir=subjects_dir,
711712
time_viewer=False, show_traces=False, # for speed
712713
smoothing_steps=1, verbose='error', src=inv['src'],
713714
volume_options=dict(resolution=None), # for speed
@@ -740,6 +741,31 @@ def test_plot_source_estimates(renderer_interactive, all_src_types_inv_evoked,
740741
with pytest.raises(ValueError, match='view_layout must be'):
741742
meth(view_layout='horizontal', **kwargs)
742743

744+
# flatmaps (mostly a lot of error checking)
745+
these_kwargs = kwargs.copy()
746+
these_kwargs.update(surface='flat', views='auto')
747+
if kind == 'surface' and pick_ori != 'vector' and is_pyvista:
748+
with pytest.raises(FileNotFoundError, match='flatmap'):
749+
meth(**these_kwargs) # sample does not have them
750+
fs_stc = stc.copy()
751+
fs_stc.subject = 'fsaverage' # this is wrong, but don't have to care
752+
flat_meth = getattr(fs_stc, meth_key)
753+
these_kwargs.pop('src')
754+
if pick_ori == 'vector':
755+
pass # can't even pass "surface" variable
756+
elif kind != 'surface':
757+
with pytest.raises(TypeError, match='SourceEstimate when a flatmap'):
758+
flat_meth(**these_kwargs)
759+
elif not is_pyvista:
760+
with pytest.raises(RuntimeError, match='PyVista 3D backend.*flatmap'):
761+
flat_meth(**these_kwargs)
762+
else:
763+
brain = flat_meth(**these_kwargs)
764+
brain.close()
765+
these_kwargs.update(surface='inflated', views='flat')
766+
with pytest.raises(ValueError, match='surface="flat".*views="flat"'):
767+
flat_meth(**these_kwargs)
768+
743769
# just test one for speed
744770
if kind != 'mixed':
745771
return

tutorials/source-modeling/plot_visualize_stc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
clim=dict(kind='value', lims=[3, 6, 9]))
5454

5555
###############################################################################
56-
# You can also morph it to fsaverage and visualize it using a flat map:
56+
# You can also morph it to fsaverage and visualize it using a flatmap:
5757

5858
# sphinx_gallery_thumbnail_number = 2
5959

0 commit comments

Comments
 (0)