-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: find_blinks (pupil) #12946
base: main
Are you sure you want to change the base?
ENH: find_blinks (pupil) #12946
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -9,11 +9,68 @@ | |||||||||||||||||||||||
from ...epochs import BaseEpochs | ||||||||||||||||||||||||
from ...evoked import Evoked | ||||||||||||||||||||||||
from ...io import BaseRaw | ||||||||||||||||||||||||
from ...utils import _check_option, _validate_type, logger, warn | ||||||||||||||||||||||||
from ...utils import _check_option, _validate_type, logger, verbose, warn | ||||||||||||||||||||||||
from .calibration import Calibration | ||||||||||||||||||||||||
from .utils import _check_calibration | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
@verbose | ||||||||||||||||||||||||
def find_blinks( | ||||||||||||||||||||||||
inst, | ||||||||||||||||||||||||
*, | ||||||||||||||||||||||||
chs_src=None, | ||||||||||||||||||||||||
method="by_dropout", | ||||||||||||||||||||||||
dropout_value=None, | ||||||||||||||||||||||||
description="BAD_blink", | ||||||||||||||||||||||||
chs_dest=None, | ||||||||||||||||||||||||
verbose=None, | ||||||||||||||||||||||||
): | ||||||||||||||||||||||||
"""Find blinks in eye-tracking data and create corresponding annotations. | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
Parameters | ||||||||||||||||||||||||
---------- | ||||||||||||||||||||||||
inst : instance of Raw | ||||||||||||||||||||||||
The data instance to use for finding blinks. Must contain pupil channels. | ||||||||||||||||||||||||
chs_src : list | None | ||||||||||||||||||||||||
A list of channel names that will be used to find blinks. None (default) will | ||||||||||||||||||||||||
result in selecting all channels of type ``pupil``. See Notes for more | ||||||||||||||||||||||||
information. | ||||||||||||||||||||||||
method : str | ||||||||||||||||||||||||
Which method to use to find blinks in ``inst``. Currently the only supported | ||||||||||||||||||||||||
method is ``'by_dropout'`` (default), which uses the value specified via | ||||||||||||||||||||||||
``dropout_value`` to identify blinks. | ||||||||||||||||||||||||
dropout_value : float | None | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I imagine that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also believe that if we are to add more methods such as Hershman, the parameters may be many and take various names. To me it makes more sense to replace mne-python/mne/preprocessing/ica.py Lines 250 to 260 in 00c0e21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that regardless of method (including Hershman AFAICT), MNE will still need to know what value represents a missing pupil value (e.g. |
||||||||||||||||||||||||
Which value in the data denotes a dropout. In Eyelink data, this is ``0``, | ||||||||||||||||||||||||
whereas for other eye-tracking data this may be ``np.nan``, or something else. | ||||||||||||||||||||||||
Defaults to None, which sets the ``dropout_value`` to ``np.nan``. | ||||||||||||||||||||||||
description : str | ||||||||||||||||||||||||
Which description to use for the blink annotations. Defaults to ``'BAD_blink'``. | ||||||||||||||||||||||||
chs_dest : list | None | ||||||||||||||||||||||||
A list of channel names that will be associated with the blink annotations. | ||||||||||||||||||||||||
None (default) and passing an empty lists will associate each blink annotation | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't love the fact that to get all channels annotated you pass either There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know what you mean, and I agree in principle. We had a similar discussion in mne-bids recently: However, this choice is based on the I am open to alternative suggestions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could consider having the default behavior be that blink annotations are only associated with eyetrack channels, which would be more consistent with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personallly would prefer this flag to control whetherthe annotation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
users may want to associate EEG channels with blinks that are detected from pupil channels, for artifact cleaning. But as long as this is possible, I do not mind about the exact implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Would There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these are details that we can probably decide later on in the process, for now I think that @scott-huberty's proposal has received a lot of 👍, so we should go with this and revisit when it is time to merge. |
||||||||||||||||||||||||
with all channels in ``inst``. | ||||||||||||||||||||||||
%(verbose)s | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
Returns | ||||||||||||||||||||||||
------- | ||||||||||||||||||||||||
annots : mne.Annotations | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we return an Annotations object but don't attach it to the instance? If the instance already has annotations attached, do we update them? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, I had in mind that this should work: (example 1) annots = find_blinks(raw, ...)
annots = raw.annotations.copy() + annots
raw.set_annotations(annots) The choice of not setting them to (example 2) annots_1 = find_blinks(raw, chs_src=[ch1], description="desc A")
annots_2 = find_blinks(raw, chs_src=[ch2], description="desc B")
raw.set_annotations(annots1 + annots2)
The alternative of the above would be to:
I am open to either (or any) way, as long as we allow workflows that:
My present proposal aims at fulfilling these points without going overboard on parameter number and complexity. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally speaking I think the way most of our annotations functions work is that they return an |
||||||||||||||||||||||||
The annotations objects containing blink annotations. | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
Notes | ||||||||||||||||||||||||
----- | ||||||||||||||||||||||||
If multiple channels are used to find blinks in ``inst``, resulting overlapping | ||||||||||||||||||||||||
blink annotations are always merged over all channels. That is, if a left and a | ||||||||||||||||||||||||
right pupil channel would be used for blink detection, and each on their own would | ||||||||||||||||||||||||
produce overlapping blink annotations with onsets ``[1.5, 1.6]`` and durations | ||||||||||||||||||||||||
``[0.2, 0.3]``, respectively, then passing both channels into this function will | ||||||||||||||||||||||||
result in a single blink annotation with onset ``1.5`` and duration ``0.4``. | ||||||||||||||||||||||||
Note that this corresponds to the minimum onset and the maximum offset between | ||||||||||||||||||||||||
the two annotations. | ||||||||||||||||||||||||
""" | ||||||||||||||||||||||||
logger.info("Found blinks") | ||||||||||||||||||||||||
return | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
# specific function to set eyetrack channels | ||||||||||||||||||||||||
def set_channel_types_eyetrack(inst, mapping): | ||||||||||||||||||||||||
"""Define sensor type for eyetrack channels. | ||||||||||||||||||||||||
|
@@ -168,7 +225,8 @@ def _convert_deg_to_rad(array): | |||||||||||||||||||||||
return array * np.pi / 180.0 | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
def convert_units(inst, calibration, to="radians"): | ||||||||||||||||||||||||
@verbose | ||||||||||||||||||||||||
def convert_units(inst, calibration, to="radians", verbose=None): | ||||||||||||||||||||||||
"""Convert Eyegaze data from pixels to radians of visual angle or vice versa. | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
.. warning:: | ||||||||||||||||||||||||
|
@@ -191,6 +249,7 @@ def convert_units(inst, calibration, to="radians"): | |||||||||||||||||||||||
(in pixels). | ||||||||||||||||||||||||
to : str | ||||||||||||||||||||||||
Must be either ``"radians"`` or ``"pixels"``, indicating the desired unit. | ||||||||||||||||||||||||
%(verbose)s | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
Returns | ||||||||||||||||||||||||
------- | ||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is admittedly a nitpick but I think that instead of using a prepositional phrase (
by_
), using a term like'dropout'
or'pupil_dropout'
for the method parameter would be more consistent with the othermethod
parameters of MNE (ref 1,ref 2, ref 3, ref 4, ref 5), and so I would prefer to change this todropout
orpupil_dropout
.