Skip to content

Commit d4c24cb

Browse files
larsoneragramfort
authored andcommitted
MRG: Add helper functions for label data (#5805)
* ENH: Add helper functions for label data * FIX: Reqs * FIX: Coverage * FIX: Backport * STY: Comment [ci skip] * FIX: Fix fixes more * FIX: More doc cleanups * DOC: See also * FIX: Dont need * FIX: Flake * FIX: Axis
1 parent d786651 commit d4c24cb

File tree

9 files changed

+356
-69
lines changed

9 files changed

+356
-69
lines changed

doc/python_reference.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,8 @@ Source Space Data
689689
grade_to_vertices
690690
grow_labels
691691
label_sign_flip
692+
labels_to_stc
693+
morph_labels
692694
random_parcellation
693695
read_labels_from_annot
694696
read_dipole

doc/whats_new.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ Changelog
3131

3232
- Add use of :func:`scipy.signal.windows.dpss` for faster multitaper window computations in PSD functions by `Eric Larson`_
3333

34+
- Add :func:`mne.morph_labels` to facilitate morphing label sets obtained from parcellations, by `Eric Larson`_
35+
36+
- Add :func:`mne.labels_to_stc` to facilitate working with label data, by `Eric Larson`_
37+
38+
- Add ``overlap`` argument to :func:`mne.make_fixed_length_events` by `Eric Larson`_
3439
- Add 448-labels subdivided aparc cortical parcellation by `Denis Engemann`_ and `Sheraz Khan`_
3540

3641
- Add keyboard shortcuts to nativate volume source estimates in time using (shift+)left/right arrow keys by `Mainak Jas`_
@@ -3127,4 +3132,4 @@ of commits):
31273132

31283133
.. _David Haslacher: https://github.com/davidhaslacher
31293134

3130-
.. _lneisenman: https://github.com/lneisenman
3135+
.. _lneisenman: https://github.com/lneisenman

mne/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@
7575
from .evoked import Evoked, EvokedArray, read_evokeds, write_evokeds, combine_evoked
7676
from .label import (read_label, label_sign_flip,
7777
write_label, stc_to_label, grow_labels, Label, split_label,
78-
BiHemiLabel, read_labels_from_annot, write_labels_to_annot, random_parcellation)
78+
BiHemiLabel, read_labels_from_annot, write_labels_to_annot,
79+
random_parcellation, morph_labels, labels_to_stc)
7980
from .misc import parse_config, read_reject_parameters
8081
from .coreg import (create_default_subject, scale_bem, scale_mri, scale_labels,
8182
scale_source_space)

mne/event.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ def shift_time_events(events, ids, tshift, sfreq):
824824

825825

826826
def make_fixed_length_events(raw, id=1, start=0, stop=None, duration=1.,
827-
first_samp=True):
827+
first_samp=True, overlap=0.):
828828
"""Make a set of events separated by a fixed duration.
829829
830830
Parameters
@@ -846,6 +846,10 @@ def make_fixed_length_events(raw, id=1, start=0, stop=None, duration=1.,
846846
returned events will be combined with event times that already
847847
have ``raw.first_samp`` added to them, e.g. event times that come
848848
from :func:`mne.find_events`.
849+
overlap : float
850+
The overlap between events. Must be ``0 <= overlap < duration``.
851+
852+
.. versionadded:: 0.18
849853
850854
Returns
851855
-------
@@ -856,6 +860,11 @@ def make_fixed_length_events(raw, id=1, start=0, stop=None, duration=1.,
856860
_validate_type(raw, BaseRaw, "raw")
857861
_validate_type(id, int, "id")
858862
_validate_type(duration, "numeric", "duration")
863+
_validate_type(overlap, "numeric", "overlap")
864+
duration, overlap = float(duration), float(overlap)
865+
if not 0 <= overlap < duration:
866+
raise ValueError('overlap must be >=0 but < duration (%s), got %s'
867+
% (duration, overlap))
859868

860869
start = raw.time_as_index(start, use_rounding=True)[0]
861870
if stop is not None:
@@ -870,7 +879,8 @@ def make_fixed_length_events(raw, id=1, start=0, stop=None, duration=1.,
870879
# Make sure we don't go out the end of the file:
871880
stop -= int(np.round(raw.info['sfreq'] * duration))
872881
# This should be inclusive due to how we generally use start and stop...
873-
ts = np.arange(start, stop + 1, raw.info['sfreq'] * duration).astype(int)
882+
ts = np.arange(start, stop + 1,
883+
raw.info['sfreq'] * (duration - overlap)).astype(int)
874884
n_events = len(ts)
875885
if n_events == 0:
876886
raise ValueError('No events produced, check the values of start, '

mne/fixes.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,66 @@ def _remove_duplicate_rows(arr):
10651065
return arr[~remove, :]
10661066

10671067

1068+
###############################################################################
1069+
# csr_matrix.argmax from SciPy 0.19+
1070+
1071+
def _find_missing_index(ind, n):
1072+
for k, a in enumerate(ind):
1073+
if k != a:
1074+
return k
1075+
1076+
k += 1
1077+
if k < n:
1078+
return k
1079+
else:
1080+
return -1
1081+
1082+
1083+
def _sparse_argmax(mat, axis):
1084+
import scipy
1085+
if LooseVersion(scipy.__version__) >= '0.19':
1086+
return mat.argmax(axis)
1087+
else:
1088+
op = np.argmax
1089+
compare = np.greater
1090+
self = mat
1091+
if self.shape[axis] == 0:
1092+
raise ValueError("Can't apply the operation along a zero-sized "
1093+
"dimension.")
1094+
1095+
if axis < 0:
1096+
axis += 2
1097+
1098+
zero = self.dtype.type(0)
1099+
1100+
mat = self.tocsc() if axis == 0 else self.tocsr()
1101+
mat.sum_duplicates()
1102+
1103+
ret_size, line_size = mat._swap(mat.shape)
1104+
ret = np.zeros(ret_size, dtype=int)
1105+
1106+
nz_lines, = np.nonzero(np.diff(mat.indptr))
1107+
for i in nz_lines:
1108+
p, q = mat.indptr[i:i + 2]
1109+
data = mat.data[p:q]
1110+
indices = mat.indices[p:q]
1111+
am = op(data)
1112+
m = data[am]
1113+
if compare(m, zero) or q - p == line_size:
1114+
ret[i] = indices[am]
1115+
else:
1116+
zero_ind = _find_missing_index(indices, line_size)
1117+
if m == zero:
1118+
ret[i] = min(am, zero_ind)
1119+
else:
1120+
ret[i] = zero_ind
1121+
1122+
if axis == 1:
1123+
ret = ret.reshape(-1, 1)
1124+
1125+
return np.asmatrix(ret)
1126+
1127+
10681128
###############################################################################
10691129
# From nilearn
10701130

0 commit comments

Comments
 (0)