Skip to content
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

Feature Request: Interpolate blinks in eyegaze / pupil channels. #11725

Closed
scott-huberty opened this issue Jun 7, 2023 · 4 comments · Fixed by #11740
Closed

Feature Request: Interpolate blinks in eyegaze / pupil channels. #11725

scott-huberty opened this issue Jun 7, 2023 · 4 comments · Fixed by #11740
Labels

Comments

@scott-huberty
Copy link
Contributor

scott-huberty commented Jun 7, 2023

Describe the new feature or enhancement

While I wrap up my open PR soon, I wanted to initiate a discussion on the next task that I'd like to work on for my GSoC project.

CC @larsoner and @britta-wstnr

Proposed function:

mne.preprocessing.interpolate_blinks (or remove_blink_artifact). For pupil channels

Background

it is a common pre-processing step in pupillometry research to interpolate missing values during blinks (see this paper, this paper, this package, and this package).

The basic idea is that blinks are very short in duration, but the pupil response is relatively slow; so it can be reasonably assumed that the pupil size during a blink was close to the pupil size values just before and just after the blink.

Use-case

Currently in mne, if you have a RawEyelink object with pupil channels, and you want to to assess the average pupil size across trials, you have to:

  • epoch the data
  • drop any epochs that have a blink in them (which can result in data loss).
  • average aross the remaining epochs

This is because pupil channels contain 0's during blinks. Including blink periods in epochs.average() would bias the result such that the the pupil size would seem to be unrealistically small!

Having an interpolate_blinks function would help users move beyond a Raw object to epoching the data and being able to use those epochs for analyses.

Describe your proposed implementation

I propose we add a function, called interpolate_blinks or remove_blink_artifact to mne.preprocessing.eyetracking.

How:

The way I am thinking about it now:

  • This function would accept a Raw object, and will rely on Annotations in the Raw object that start with blink to identify periods to be interpolated.

    • For example, mne.io.read_raw_eyelink extracts any blink periods (that EyeLink wrote to the file) and stores them as mne.Annotations. So this function would rely on those Annotations.
  • This function would accept a parameter named something like method, which would accept 'linear' or 'cubic_spline', and would use:

    • numpy.interp for linear interpolation
    • scipy.interpolate.CubicSpline for cubic-spline interpolation (see this eye-tracking paper).

Summary:

So I suggest that:

  • This function will only operate on pupil channels (not eyegaze, EEG, MEG, NIRS etc.).
  • This function can start with interpolating data during blinks. Then maybe we can extend this to interpolating pupil data during saccades (There is precedent for this because pupil-size measurement is thought to be less reliable during saccades).
  • Then, maybe we can extend this function to eyegaze channels (There is one package that does this), but AFAIK it is harder to justify interpolating eyegaze data, because it can change at a much faster rate / is more variable across time. I'll need to do more literature review to see how often this has been done.

Describe possible alternatives

I'm open to any other ideas!

Additional context

To see an example of a file that could benefit from interpolate_blinks see:

from mne.datasets.testing import data_path
from mne.io import read_raw_eyelink
fname = data_path() / "eyetrack" / "test_eyelink.asc"
raw = read_raw_eyelink(fname, find_overlaps=True, create_annotations=['blinks'])
raw.plot(scalings='auto')

test_eyelink_plot

@larsoner
Copy link
Member

larsoner commented Jun 8, 2023

I like the suggestion to start with the basics (just interp during blinks) and expand later as needed/helpful for people. I'd suggest to put in mne.preprocessing.eyetracking.interpolate_blinks to make it clear it's eye-tracking-related interp, not to be confused with interpolating brain data or EOG during blinks or anything like that.

@scott-huberty
Copy link
Contributor Author

yes totally, sorry, I meant to say mne.preprocessing.eyetracking. !

@britta-wstnr
Copy link
Member

I like it!

@schekroud
Copy link
Contributor

schekroud commented Jun 20, 2023

would be nice to add an option to pad data around the blinks - when you inspect blink periods in eyetracking data it's often corrupted just before/after the blink too. it's pretty common to leave some space around the blink that you also interpolate to account for this (which can vary between researchers). an option to allow this would be cool

(i should say this is such a cool addition i've been using my own hacky stuff for years and tried to get it to work within mne but struggled. I just stumbled upon eyelink data now being supported)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants