Get a list of annotations that occur during each epoch. Parameters ---------- with_extras : bool Whether to include the annotations extra fields in the output, as an additional last element of the tuple. Default is False. .. versionadded:
(self, *, with_extras=False)
| 1427 | return self |
| 1428 | |
| 1429 | def get_annotations_per_epoch(self, *, with_extras=False): |
| 1430 | """Get a list of annotations that occur during each epoch. |
| 1431 | |
| 1432 | Parameters |
| 1433 | ---------- |
| 1434 | with_extras : bool |
| 1435 | Whether to include the annotations extra fields in the output, |
| 1436 | as an additional last element of the tuple. Default is False. |
| 1437 | |
| 1438 | .. versionadded:: 1.10 |
| 1439 | |
| 1440 | Returns |
| 1441 | ------- |
| 1442 | epoch_annots : list |
| 1443 | A list of lists (with length equal to number of epochs) where each |
| 1444 | inner list contains any annotations that overlap the corresponding |
| 1445 | epoch. Annotations are stored as a :class:`tuple` of onset, |
| 1446 | duration, description (not as a :class:`~mne.Annotations` object), |
| 1447 | where the onset is now relative to time=0 of the epoch, rather than |
| 1448 | time=0 of the original continuous (raw) data. |
| 1449 | """ |
| 1450 | # create a list of annotations for each epoch |
| 1451 | epoch_annot_list = [[] for _ in range(len(self.events))] |
| 1452 | |
| 1453 | # check if annotations exist |
| 1454 | if self.annotations is None: |
| 1455 | return epoch_annot_list |
| 1456 | |
| 1457 | # when each epoch and annotation starts/stops |
| 1458 | # no need to account for first_samp here... |
| 1459 | epoch_tzeros = self.events[:, 0] / self._raw_sfreq |
| 1460 | epoch_starts, epoch_stops = ( |
| 1461 | np.atleast_2d(epoch_tzeros) + np.atleast_2d(self.times[[0, -1]]).T |
| 1462 | ) |
| 1463 | # ... because first_samp isn't accounted for here either |
| 1464 | annot_starts = self._annotations.onset |
| 1465 | annot_stops = annot_starts + self._annotations.duration |
| 1466 | |
| 1467 | # the first two cases (annot_straddles_epoch_{start|end}) will both |
| 1468 | # (redundantly) capture cases where an annotation fully encompasses |
| 1469 | # an epoch (e.g., annot from 1-4s, epoch from 2-3s). The redundancy |
| 1470 | # doesn't matter because results are summed and then cast to bool (all |
| 1471 | # we care about is presence/absence of overlap). |
| 1472 | annot_straddles_epoch_start = np.logical_and( |
| 1473 | np.atleast_2d(epoch_starts) >= np.atleast_2d(annot_starts).T, |
| 1474 | np.atleast_2d(epoch_starts) < np.atleast_2d(annot_stops).T, |
| 1475 | ) |
| 1476 | |
| 1477 | annot_straddles_epoch_end = np.logical_and( |
| 1478 | np.atleast_2d(epoch_stops) > np.atleast_2d(annot_starts).T, |
| 1479 | np.atleast_2d(epoch_stops) <= np.atleast_2d(annot_stops).T, |
| 1480 | ) |
| 1481 | |
| 1482 | # this captures the only remaining case we care about: annotations |
| 1483 | # fully contained within an epoch (or exactly coextensive with it). |
| 1484 | annot_fully_within_epoch = np.logical_and( |
| 1485 | np.atleast_2d(epoch_starts) <= np.atleast_2d(annot_starts).T, |
| 1486 | np.atleast_2d(epoch_stops) >= np.atleast_2d(annot_stops).T, |