Skip to content

Conversation

scott-huberty
Copy link
Contributor

@anomalosepia and I discovered another edge case that breaks our eyelink reader. I've added a test that demonstrates this failure and will add a fix soon.

I know not everyone will follow this, but posting in detail for posterity 🙂 No obligation to read further


As discussed with Sam Hutton from SR Research:

On an EyeLink acquisition computer (referred to as the "Host PC"), the data acquisition GUI exposes a parameter "Eye Event Data", that defaults to "GAZE" but can be manually set to "HREF":

image

When "Eye Event Data" is set to "HREF" (Head-Referenced-Eye-Angle), then extra fields are written to the EDF (EyeLink-Data-Format) file for Saccade and Fixation events. These extra fields also show up in the ASCII file (after EDF -> ASCII file conversion).

For example in a typical file with "GAZE" Eye Event Data, a Saccade event would look like this:

ESACC L  14211302 14211390 90 964.9  590.9 1654.8  665.8  14.33    224

Which translates to...

ESACC <eye> <stime> <etime> <dur> <start-xpos> <start-ypos> <end-xpos> <end-ypos> <ampl> <pupil-size>

But in a file with "HREF" Eye Event Data, a Saccade event has 4 extra columns of info:

ESACC L  14211302 14211390 90   1709   4696   5855   4171  14.51    224  964.9  590.9 1654.8  665.8  14.33    224

Basically, in this case the start x/y, end x/y amplitude, pupil-size columns are reported for both HREF and then GAZE datatypes.

Likewise for Fixation data, the avg-fixation x/y and avg-pupil-size columns are duplicated in the HREF case:

Fixation: GAZE Eye Event Data

EFIX R   14211390 14211488 100 1747.0  677.1    722 

Fixation: HREF Eye Event Data

EFIX R   14211390 14211488 100 6424.0 4091.0    722 1747.0  677.1    722

The fix I'm about to implement will use defensive-programming extract the start/end time from saccade events even if they unexpectedly contain this extra information, which we don't need anyways.

1. If len(df.columns) > expected_col_names, and the df is for Sacccade or Fixation data, then just rename the first 4 columns of the df to the first 4 elements of expected_col_names,  which should always be ('eye', 'start_time', 'end_time', 'duration')
2. Otherwise, if len(df.columns) != expected_col_names, then raise an error  before doing df.rename(...), that is more informative than the error that Pandas would raise. I added this because the majority of bugs users are reporting come back to that column assignment line.
3. Move "messages" cols to the EYELINK_COLS constant, where the rest of the column names are..
@scott-huberty scott-huberty changed the title TST: Add failing test for newly discovered edge case FIX: Handle EyeLink Files with Eye Event Data set to "HREF" Aug 1, 2025
if key in ("samples", "blinks", "fixations", "saccades", "messages"):
cols = col_names[key]
else:
logger.debug(f"Skipping unsupported EyeLink Event type: {key}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to make a list of these and at the end of the loop if the list is non-empty logger.info it? Depends on how many messages we're skipping and how often I guess...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ace2530. The number of event types being skipped depends on the file, but typically it might be for example 'BUTTONS' (at least until #13287 is merged).

I kept the log level at DEBUG for now, I personally don't think the user needs to see this info every time, but if you feel strongly about it I can certainly bump it to INFO.

Copy link
Member

@larsoner larsoner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Committed a tiny tweak, otherwise LGTM marking for merge-when-green

@larsoner larsoner enabled auto-merge (squash) August 1, 2025 16:29
@larsoner larsoner merged commit f04fcaa into mne-tools:main Aug 1, 2025
32 checks passed
@scott-huberty scott-huberty deleted the href_events branch August 1, 2025 18:06
WouterKroot pushed a commit to WouterKroot/mne-python that referenced this pull request Aug 13, 2025
zEdS15B3GCwq pushed a commit to zEdS15B3GCwq/mne-python that referenced this pull request Aug 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants