blink#
- pymovements.events.detection.blink(pupil: list[float] | ndarray, *, timesteps: list[int] | ndarray | None = None, delta: float | None = None, minimum_duration: int = 50, maximum_duration: int | None = 500, minimum_gap: int = 5, minimum_candidates_around_gap: tuple[int, int] | int = 2, name: str = 'blink') Events[source]#
Detect blinks from the pupil signal.
The blink detection algorithm consists of three main stages. The implementation is inspired by [Kyröläinen and Porretta, 2025], which adapts the velocity-based method described in [Hershman et al., 2018].
Stage 1 — Flag pupil loss: All samples where the pupil value is NaN or zero (common blink indicators in eye-tracking data) are candidate_mask as blink candidates.
Stage 2 — Flag abrupt pupil changes:: Each sample i+1 is masked as blink candidate if the absolute difference between consecutive pupil samples i, i+1 exceeds a
deltathreshold. IfdeltaisNone, it is automatically estimated as 5 times the 95th percentile of valid absolute differences (non-zero, not NaN) .Stage 3 — Combine blink candidates: Combine consecutive blinks with a time gap lower than the specified
minimum_gap. Blinks are only combined if the candidates before and after the short gap have aminimum_candidate_duration_to_absorb_gap.Blink events shorter than
minimum_durationand longer thanmaximum_durationare discarded. Following [Nyström et al., 2024] typical blinks last 50–500 ms.- Parameters:
pupil (list[float] | np.ndarray) – shape (N,) Continuous 1D pupil size time series (e.g., diameter or area).
timesteps (list[int] | np.ndarray | None) – shape (N,) Corresponding continuous 1D timestep time series. If None, sample-based timesteps are assumed. (default: None)
delta (float | None) – Threshold on absolute pupil difference for flagging rapid changes. If None, it is auto-estimated as
5 * np.nanpercentile(abs_diff, 95)from valid absolute differences. (default: None)minimum_duration (int) – Minimum blink duration. The duration is specified in the units used in
timesteps. Iftimestepsis None, thenminimum_durationis specified in numbers of samples. (default: 50)maximum_duration (int | None) – Maximum blink duration. The duration is specified in the units used in
timesteps. Iftimestepsis None, thenmaximum_durationis specified in numbers of samples. Set to None to disable the upper bound. (default: 500)minimum_gap (int) – Minimum time gap in-between two blinks. Blinks that have a smaller time gap are combined into a single event. The duration is specified in the units used in
timesteps. Iftimestepsis None, thenminimum_durationis specified in numbers of samples. (default: 100)minimum_candidates_around_gap (tuple[int, int] | int) – Minimum number of candidate samples required on each side of a gap for it to be absorbed. If a tuple is provided the values are used for the number of left and right candidates respectively. If an integer is provided the number of candidate samples required is symmetric. (default: (2, 2))
name (str) – Name for detected events in Events. (default: ‘blink’)
- Returns:
A dataframe with detected blink events as rows.
- Return type:
- Raises:
TypeError – If minimum_candidate_duration_to_absorb_gap neither int nor tuple[int].
ValueError – If pupil is not 1D. If pupil and timesteps have different lengths. If delta is not positive. If minimum_duration is not positive. If maximum_duration is not positive or less than minimum_duration.