Skip to content

Commit

Permalink
ENH: Allow SourceSpaces as restrict_vertices
Browse files Browse the repository at this point in the history
  • Loading branch information
larsoner committed Jun 20, 2016
1 parent 3f3fa49 commit 2f74ba6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 22 deletions.
15 changes: 10 additions & 5 deletions mne/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,11 +709,12 @@ def center_of_mass(self, subject=None, restrict_vertices=False,
----------
subject : string | None
The subject the stc is defined for.
restrict_vertices : bool, or array of int
If True, returned vertex will be one from the label. Otherwise,
it could be any vertex from surf. If an array of int, the
returned vertex will come from that array. For most accuruate
estimates, do not restrict vertices.
restrict_vertices : bool | array of int | instance of SourceSpaces
If True, returned vertex will be one from stc. Otherwise, it could
be any vertex from surf. If an array of int, the returned vertex
will come from that array. If instance of SourceSpaces (as of
0.13), the returned vertex will be from the given source space.
For most accuruate estimates, do not restrict vertices.
subjects_dir : str, or None
Path to the SUBJECTS_DIR. If None, the path is obtained by using
the environment variable SUBJECTS_DIR.
Expand All @@ -734,6 +735,10 @@ def center_of_mass(self, subject=None, restrict_vertices=False,
SourceEstimate.center_of_mass
vertex_to_mni
Notes
-----
.. versionadded: 0.13
References
----------
.. [1] Larson and Lee, "The cortical dynamics underlying effective
Expand Down
12 changes: 8 additions & 4 deletions mne/source_estimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from .surface import (read_surface, _get_ico_surface, read_morph_map,
_compute_nearest, mesh_edges)
from .source_space import (_ensure_src, _get_morph_src_reordering,
_ensure_src_subject)
_ensure_src_subject, SourceSpaces)
from .utils import (get_subjects_dir, _check_subject, logger, verbose,
_time_mask, warn as warn_)
from .viz import plot_source_estimates
Expand Down Expand Up @@ -921,6 +921,9 @@ def _center_of_mass(vertices, values, hemi, surf, subject, subjects_dir,
restrict_vertices = vertices
elif restrict_vertices is False:
restrict_vertices = np.arange(surf[0].shape[0])
elif isinstance(restrict_vertices, SourceSpaces):
idx = 1 if restrict_vertices.kind == 'surface' and hemi == 'rh' else 0
restrict_vertices = restrict_vertices[idx]['vertno']
else:
restrict_vertices = np.array(restrict_vertices, int)
pos = surf[0][vertices, :].T
Expand Down Expand Up @@ -1238,11 +1241,12 @@ def center_of_mass(self, subject=None, hemi=None, restrict_vertices=False,
hemisphere. If None, one of the hemispheres must be all zeroes,
and the center of mass will be calculated for the other
hemisphere (useful for getting COM for clusters).
restrict_vertices : bool, or array of int
restrict_vertices : bool | array of int | instance of SourceSpaces
If True, returned vertex will be one from stc. Otherwise, it could
be any vertex from surf. If an array of int, the returned vertex
will come from that array. For most accuruate estimates, do not
restrict vertices.
will come from that array. If instance of SourceSpaces (as of
0.13), the returned vertex will be from the given source space.
For most accuruate estimates, do not restrict vertices.
subjects_dir : str, or None
Path to the SUBJECTS_DIR. If None, the path is obtained by using
the environment variable SUBJECTS_DIR.
Expand Down
31 changes: 18 additions & 13 deletions mne/source_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,24 +84,29 @@ def __repr__(self):
ss_repr = []
for ss in self:
ss_type = ss['type']
r = "'%r'" % ss_type
if ss_type == 'vol':
if 'seg_name' in ss:
r = ("'vol' (%s), n_used=%i"
% (ss['seg_name'], ss['nuse']))
r += " (%s)" % (ss['seg_name'],)
else:
r = ("'vol', shape=%s, n_used=%i"
% (repr(ss['shape']), ss['nuse']))
r += ", shape=%s" % (ss['shape'],)
elif ss_type == 'surf':
r = "'surf', n_vertices=%i, n_used=%i" % (ss['np'], ss['nuse'])
else:
r = "%r" % ss_type
coord_frame = ss['coord_frame']
if isinstance(coord_frame, np.ndarray):
coord_frame = coord_frame[0]
r += ', coordinate_frame=%s' % _coord_frame_name(coord_frame)
r += (" (%s), n_vertices=%i" % (ss['hemi'], ss['np']))
r += (', n_used=%i, coordinate_frame=%s'
% (ss['nuse'], _coord_frame_name(int(ss['coord_frame']))))
ss_repr.append('<%s>' % r)
ss_repr = ', '.join(ss_repr)
return "<SourceSpaces: [{ss}]>".format(ss=ss_repr)
return "<SourceSpaces: [%s]>" % ', '.join(ss_repr)

@property
def kind(self):
"""The kind of source space (surface, volume, discrete)"""
ss_types = [ss['type'] for ss in self]
if len(ss_types) == 2 and list(set(ss_types)) == ['surf']:
return 'surface'
ss_types = list(set(ss_types))
if len(ss_types) != 1:
return 'unknown'
return ss_types[0]

def __add__(self, other):
return SourceSpaces(list.__add__(self, other))
Expand Down
17 changes: 17 additions & 0 deletions mne/tests/test_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ def test_label_center_of_mass():

labels = read_labels_from_annot('sample', parc='aparc.a2009s',
subjects_dir=subjects_dir)
src = read_source_spaces(src_fname)
# Try a couple of random ones, one from left and one from right
# Visually verified in about the right place using mne_analyze
for label, expected in zip([labels[2], labels[3], labels[-5]],
Expand All @@ -818,6 +819,22 @@ def test_label_center_of_mass():
assert_equal(label.center_of_mass(subjects_dir=subjects_dir,
restrict_vertices=label.vertices),
expected)
# restrict to source space
idx = 0 if label.hemi == 'lh' else 1
# this simple nearest version is not equivalent, but is probably
# close enough for many labels (including the test ones):
pos = label.pos[np.where(label.vertices == expected)[0][0]]
pos = (src[idx]['rr'][src[idx]['vertno']] - pos)
pos = np.argmin(np.sum(pos * pos, axis=1))
src_expected = src[idx]['vertno'][pos]
# see if we actually get the same one
src_restrict = np.intersect1d(label.vertices, src[idx]['vertno'])
assert_equal(label.center_of_mass(subjects_dir=subjects_dir,
restrict_vertices=src_restrict),
src_expected)
assert_equal(label.center_of_mass(subjects_dir=subjects_dir,
restrict_vertices=src),
src_expected)
# degenerate cases
assert_raises(ValueError, label.center_of_mass, subjects_dir=subjects_dir,
restrict_vertices='foo')
Expand Down

0 comments on commit 2f74ba6

Please sign in to comment.