mne-tools / mne-tools/mne-python
eyetracking feature -- add channel with noisy periods set to nan
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 3.5k
- Forks
- 1.6k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 100
Description
Describe the new feature or enhancement
currently the mne.preprocessing.eyetracking.interpolate_blinks function finds blink periods (with a buffer period around) and interpolates this period of noise.
One aspect of interest is not to interpolate, but to evaluate the amount of missing data, for example:
Rather than just evaluating the amount of missing data across the whole signal (e.g. with something like the suggestion of mne.annotations.quantify_coverage(raw, "BAD_BLINK"), actually adding in a copy of the pupil signal where rather than interpolate you set to nan, you can continue to epoch the data and then use epoch.plot_image to generate something like this.
The specific advantage of this is that your raw data being 'blinky' (lots of coverage in the raw signal) might not matter if those blinks are in e.g. ITI periods where you encourage participants to blink. In these cases, blinks might not contaminate the period you're interested in, thus the coverage of the raw isn't necessarily a problem. Similarly, you might decide to exclude a participant who doesn't have extensive coverage of blink periods, but systematically blinks in your time of interest (which you only find out after epoching).
Describe your proposed implementation
from line 102 in _pupillometry.py
# Linear interpolation
nterpolated_samples = np.interp(
raw.times[blink_indices],
raw.times[non_blink_indices],
raw._data[ci, non_blink_indices],
)
# Replace the samples at the blink_indices with the interpolated values
raw._data[ci, blink_indices] = interpolated_samples
#create nanned array
signal = raw._data[ci].copy()
signal[blink_indices] = np.nan #this now is not interpolated, but the full window of data that would be interpolated is set to nan
#code to add as a channel with name e.g. pupil_channel+'_nan' (not sure how this is easily implemented
Describe possible alternatives
in the custom code i use for work, i do something like this:
if add_nanchannel:
tmp = mne.io.RawArray(signal.reshape(1, -1), info = data.copy().drop_channels(nonpup_chans).info)
tmp.rename_channels({tmp.info.ch_names[0] : 'pupil_nan'}) #rename this channel (with data set to nan) before adding into raw object
data.add_channels([tmp])
where it creates a new temporary RawArray with just one channel (the nanned pupil data) and takes a copy of an info structure from the raw object with just the pupil channel. It then renames this channel, and adds this channel (as the tmp RawArray object into the original data -- this is somewhat hacky because i couldn't find a simpler way of just adding a timeseries to the raw object and giving it a channel name. I'm assuming this is simpler with some base functions i am unaware of!
Additional context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read mne/preprocessing/_pupillometry.py around line 102 and the interpolate_blinks entry point. Review the proposed RawArray approach for representing a NaN pupil channel alongside the interpolated data. Done means blink-window samples are available as NaN in an added, named channel while existing interpolation behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- numpy, python
- Domain
- data
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100