Skip to content

read_raw_eyelink() cannot handle empty first trial #13550

@Cathaway

Description

@Cathaway

Description of the problem

In some experiments we start with a few practice trials that will be excluded from analysis, in some cases we put them outside the usual trial loop and has no calibration stage for them

read_raw_eyelink cannot handle these empty trials and will throw a ValueError because it cannot find eyetracking channels to parse annotations with

I know this looks pretty stupid and doesn't really look like a bug - but unexpected data format - though it'd be nice if read_raw_eyelink() can handle cases like these

Steps to reproduce

the problematic Eyelink files start with trials like these

START	1211913 	RIGHT	SAMPLES	EVENTS
PRESCALER	1
VPRESCALER	1
PUPIL	DIAMETER
EVENTS	GAZE	RIGHT	RATE	1000.00	TRACKING	CR	FILTER	1
SAMPLES	GAZE	RIGHT	RATE	1000.00	TRACKING	CR	FILTER	1	INPUT
INPUT	1211913	127
1211913	   .	   .	    0.0	  127.0	...
SSACC R  1211914
SBLINK R 1211914
1211914	   .	   .	    0.0	  127.0	...
1211915	   .	   .	    0.0	  127.0	...
1211916	   .	   .	    0.0	  127.0	...
MSG	1211917 TRIAL 1 STARTS
MSG	1211917 FIXATION START
MSG	1211917 pre 100 pause
1211917	   .	   .	    0.0	  127.0	...
1211918	   .	   .	    0.0	  127.0	...
1211919	   .	   .	    0.0	  127.0	...
1211920	   .	   .	    0.0	  127.0	...
1211921	   .	   .	    0.0	  127.0	...
1211922	   .	   .	    0.0	  127.0	...
1211923	   .	   .	    0.0	  127.0	...
1211924	   .	   .	    0.0	  127.0	...
1211925	   .	   .	    0.0	  127.0	...

calling read_raw_eyelink() will throw an error

Link to data

No response

Expected results

RawEyelink object with these trials converted to NaN values - or whatever value

Actual results


ValueError Traceback (most recent call last)
Cell In[15], line 10
8 pass
9 else:
---> 10 el_raw = read_eyelink_file(file=f)
11 s01e02_el_rawdict[el_parID] = (el_raw)

Cell In[13], line 24, in read_eyelink_file(file, raw, calib, screen_kwarg, event_id, interpolation_buffer, downsample)
22 file = Path(file) if isinstance(file, str) else file
23 assert isinstance(file, pathlib.Path), r'File needs to be string or pathlib.Path'
---> 24 raw = mne.io.read_raw_eyelink(file)
25 calib = mne.preprocessing.eyetracking.read_eyelink_calibration(file, **screen_kwarg)
26 elif (raw and calib) and not file:

File [~/AppData/Local/anaconda3/envs/mne/Lib/site-packages/mne/io/eyelink/eyelink.py#line=58), in read_raw_eyelink(fname, create_annotations, apply_offsets, find_overlaps, overlap_threshold, verbose)
29 """Reader for an Eyelink .asc file.
30
31 Parameters
(...) 55 'BAD_ACQ_SKIP'.
56 """
57 fname = _check_fname(fname, overwrite="read", must_exist=True, name="fname")
---> 59 raw_eyelink = RawEyelink(
60 fname,
61 create_annotations=create_annotations,
62 apply_offsets=apply_offsets,
63 find_overlaps=find_overlaps,
64 overlap_threshold=overlap_threshold,
65 verbose=verbose,
66 )
67 return raw_eyelink

File :12, in init(self, fname, create_annotations, apply_offsets, find_overlaps, overlap_threshold, verbose)

File [~/AppData/Local/anaconda3/envs/mne/Lib/site-packages/mne/io/eyelink/eyelink.py#line=126), in RawEyelink.init(self, fname, create_annotations, apply_offsets, find_overlaps, overlap_threshold, verbose)
123 eye_annots = _make_eyelink_annots(
124 self._raw_extras[0]["dfs"], create_annotations, apply_offsets
125 )
126 if gap_annots and eye_annots: # set both
--> 127 self.set_annotations(gap_annots + eye_annots)
128 elif gap_annots:
129 self.set_annotations(gap_annots)

File :12, in set_annotations(self, annotations, emit_warning, on_missing, verbose)

File [~/AppData/Local/anaconda3/envs/mne/Lib/site-packages/mne/io/base.py#line=746), in BaseRaw.set_annotations(self, annotations, emit_warning, on_missing, verbose)
745 delta = 1.0 / self.info["sfreq"]
746 new_annotations = annotations.copy()
--> 747 new_annotations._prune_ch_names(self.info, on_missing)
748 if annotations.orig_time is None:
749 new_annotations.crop(
750 0, self.times[-1] + delta, emit_warning=emit_warning
751 )

File [~/AppData/Local/anaconda3/envs/mne/Lib/site-packages/mne/annotations.py#line=653), in Annotations._prune_ch_names(self, info, on_missing)
652 if name not in keep:
653 if not warned:
--> 654 _on_missing(
655 on_missing,
656 "At least one channel name in "
657 f"annotations missing from info: {name}",
658 )
659 warned = True
660 else:

File [~/AppData/Local/anaconda3/envs/mne/Lib/site-packages/mne/utils/check.py#line=1220), in _on_missing(on_missing, msg, name, error_klass)
1219 on_missing = "warn" if on_missing == "warning" else on_missing
1220 if on_missing == "raise":
-> 1221 raise error_klass(msg)
1222 elif on_missing == "warn":
1223 warn(msg)

ValueError: At least one channel name in annotations missing from info: xpos_right

Additional information

Platform Windows-11-10.0.26100-SP0
Python 3.13.5 | packaged by conda-forge | (main, Jun 16 2025, 08:20:19) [MSC v.1943 64 bit (AMD64)]
Executable C:\Users...\AppData\Local\anaconda3\envs\mne\python.exe
CPU Intel(R) Core(TM) Ultra 5 135U (14 cores)
Memory 15.5 GiB

Core
X mne 1.10.1 (outdated, release 1.11.0 is available!) (sorry)

  • numpy 2.3.1 (MKL 2023.1-Product with 12 threads)
  • scipy 1.16.0
  • matplotlib 3.10.5 (backend=module://matplotlib_inline.backend_inline)

Numerical (optional)

  • sklearn 1.7.1
  • pandas 2.3.1
  • h5io 0.2.5
  • h5py 3.14.0
  • unavailable numba, nibabel, nilearn, dipy, openmeeg, cupy

Visualization (optional)

  • qtpy 2.4.1 (PyQt5=5.15.2)
  • pyqtgraph 0.13.7
  • mne-qt-browser 0.7.2
  • ipywidgets 8.1.8
  • unavailable pyvista, pyvistaqt, vtk, ipympl, trame_client, trame_server, trame_vtk, trame_vuetify

Ecosystem (optional)

  • mne-icalabel 0.7.0
  • unavailable mne-bids, mne-nirs, mne-features, mne-connectivity, mne-bids-pipeline, neo, eeglabio, edfio, mffpy, pybv

To update to the latest supported release version to get bugfixes and improvements, visit https://mne.tools/stable/install/updating.html

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions