eyekit.fixation API documentation
Description: Defines the `Fixation` and `FixationSequence` objects, which are used to represent fixation data.

# Module `eyekit.fixation`

Defines the `Fixation` and `FixationSequence` objects, which are used to represent fixation data.

View code on GitHub

## Classes

`class Fixation (index: int, x: int, y: int, start: int, end: int, pupil_size: int = None, *, discarded: bool = False, tags: dict = None)`

  Representation of a single fixation event. It is not usually necessary to create `Fixation` objects manually; they are created automatically during the instantiation of a `FixationSequence`.

  View code on GitHub

  ### Instance variables

  `var index : int`

    Index of the fixation in its parent `FixationSequence`

    View code on GitHub
  `var x : int`

    X-coordinate of the fixation.

    View code on GitHub
  `var y : int`

    Y-coordinate of the fixation.

    View code on GitHub
  `var xy : tuple`

    XY-coordinates of the fixation.

    View code on GitHub
  `var start : int`

    Start time of the fixation in milliseconds.

    View code on GitHub
  `var end : int`

    End time of the fixation in milliseconds.

    View code on GitHub
  `var duration : int`

    Duration of the fixation in milliseconds.

    View code on GitHub
  `var pupil_size : int`

    Size of the pupil. `None` if no pupil size is recorded.

    View code on GitHub
  `var discarded : bool`

    `True` if the fixation has been discarded, `False` otherwise.

    View code on GitHub
  `var tags : dict`

    Tags applied to this fixation.

    View code on GitHub

  ### Methods

  `def discard(self)`

    Mark this fixation as discarded. To completely remove the fixation, you should also call `FixationSequence.purge()`.

    View code on GitHub
  `def add_tag(self, tag: str, value=True)`

    Tag this fixation with some arbitrary tag and (optionally) a value.

    View code on GitHub
  `def has_tag(self, tag: str) ‑> bool`

    Returns `True` if the fixation has a given tag.

    View code on GitHub
  `def shift_x(self, amount: int)`

    Shift the fixation's x-coordinate to the right (+) or left (-) by some amount (in pixels).

    View code on GitHub
  `def shift_y(self, amount: int)`

    Shift the fixation's y-coordinate down (+) or up (-) by some amount (in pixels).

    View code on GitHub
  `def shift_time(self, amount: int)`

    Shift this fixation forwards (+) or backwards (-) in time by some amount (in milliseconds).

    View code on GitHub
  `def serialize(self) ‑> dict`

    Returns representation of the fixation as a dictionary for serialization.

    View code on GitHub
`class FixationSequence (sequence: list)`

  Representation of a sequence of consecutive fixations, typically from a single trial.

  Initialized with:

  - `sequence` List of tuples of ints, or something similar, that conforms to the following structure: `[(106, 540, 100, 200), (190, 536, 200, 300), ..., (763, 529, 1000, 1100)]`, where each tuple contains the X-coordinate, Y-coordinate, start time, and end time of a fixation. Alternatively, `sequence` may be a list of dicts, where each dict is something like `{'x': 106, 'y': 540, 'start': 100, 'end': 200}`.
  View code on GitHub

  ### Instance variables

  `var start : int`

    Start time of the fixation sequence (in milliseconds).

    View code on GitHub
  `var end : int`

    End time of the fixation sequence (in milliseconds).

    View code on GitHub
  `var duration : int`

    Duration of the fixation sequence, incuding any gaps between fixations (in milliseconds).

    View code on GitHub

  ### Methods

  `def copy(self, include_discards=True)`

    Returns a copy of the fixation sequence.

    View code on GitHub
  `def purge(self)`

    Permanently removes all discarded fixations from the sequence, and reindexes the fixations.

    View code on GitHub
  `def iter_with_discards(self)`

    Iterates over the fixation sequence including any discarded fixations. This is also the default behavior when iterating over a `FixationSequence` directly.

    View code on GitHub
  `def iter_without_discards(self)`

    Iterates over the fixation sequence without any discarded fixations.

    View code on GitHub
  `def iter_pairs(self, include_discards=True)`

    Iterate over fixations in consecutive pairs. This is useful if you want to compare consecutive fixations in some way. For example, if you wanted to detect when a fixation leaves an interest area, you might do something like this:

        for curr_fxn, next_fxn in seq.iter_pairs():
            if curr_fxn in interest_area and next_fxn not in interest_area:
                print('A fixation has left the interest area')

    View code on GitHub
  `def shift_x(self, amount: int)`

    Shift all fixations' x-coordinates to the right (+) or left (-) by some amount (in pixels).

    View code on GitHub
  `def shift_y(self, amount: int)`

    Shift all fixations' y-coordinates down (+) or up (-) by some amount (in pixels).

    View code on GitHub
  `def shift_time(self, amount: int)`

    Shift all fixations forwards (+) or backwards (-) in time by some amount (in milliseconds).

    View code on GitHub
  `def shift_start_time_to_zero(self) ‑> int`

    Shift all fixations backwards in time, such that the first fixation in the sequence starts at time 0. Returns the amount (in milliseconds) by which the entire sequence was shifted.

    View code on GitHub
  `def segment(self, time_intervals: list) ‑> list`

    Given a list of time intervals, segment the fixation sequence into subsequences. This may be useful if you want to split the sequence based on, for example, page turns or subtitle timings. Returns a list of n `FixationSequence`s, where n = `len(time_intervals)`. The time intervals should be specified as a list of tuples or something similarly interpretable: `[(500, 1000), (1500, 2000), (2500, 5000)]`.

    View code on GitHub
  `def discard_short_fixations(self, threshold: int = 50)`

    Discard all fixations that are shorter than some threshold value (defualt: 50ms). Note that this only flags fixations as discarded and doesn't actually remove them; to remove discarded fixations, call `FixationSequence.purge()` after discarding.

    View code on GitHub
  `def discard_long_fixations(self, threshold: int = 500)`

    Discard all fixations that are longer than some threshold value (defualt: 500ms). Note that this only flags fixations as discarded and doesn't actually remove them; to remove discarded fixations, call `FixationSequence.purge()` after discarding.

    View code on GitHub
  `def discard_out_of_bounds_fixations(self, text_block, threshold: int = 100)`

    Given a `TextBlock`, discard all fixations that do not fall within some threshold distance of any character in the text. Note that this only flags fixations as discarded and doesn't actually remove them; to remove discarded fixations, call `FixationSequence.purge()` after discarding.

    View code on GitHub
  `def snap_to_lines(self, text_block, method='warp', **kwargs)`

    Given a `TextBlock`, snap each fixation to the line that it most likely belongs to, eliminating any y-axis variation. Several methods are available (see below), some of which take optional parameters or require NumPy/SciPy to be installed. See Carr et al. (2021) for a full description and evaluation of these methods. Note that in single-line TextBlocks, the `method` parameter has no effect: all fixations will be snapped to the one line. If a list of methods is passed in, each fixation will be snapped to the line with the most "votes" across the selection of methods (in case of ties, the left-most method takes priority). This "wisdom of the crowd" approach usually results in greater performance than any one algorithm individually; ideally, you should choose a selection of methods that have different general properties: for example, `['slice', 'cluster', 'warp']`. The `snap_to_lines()` method returns two values, delta and kappa, which are indicators of data quality. Delta is the average amount by which a fixation is moved in the correction. If this value is high (e.g. > 30), this may indicate that the quality of the data or the correction is low. Kappa, which is only calculated when multiple methods are applied, is a measure of agreement among the methods. If this value is low (e.g. < 0.7), this may indicate that the correction is unreliable.

    - `chain` : Chain consecutive fixations that are sufficiently close to each other, and then assign chains to their closest text lines. Default params: `x_thresh=192`, `y_thresh=32`. Requires NumPy. Original method implemented in popEye.

    - `cluster` : Classify fixations into m clusters based on their Y-values, and then assign clusters to text lines in positional order. Requires SciPy. Original method implemented in popEye.

    - `merge` : Form a set of progressive sequences and then reduce the set to m by repeatedly merging those that appear to be on the same line. Merged sequences are then assigned to text lines in positional order. Default params: `y_thresh=32`, `gradient_thresh=0.1`, `error_thresh=20`. Requires NumPy. Original method by Špakov et al. (2019).

    - `regress` : Find m regression lines that best fit the fixations and group fixations according to best fit regression lines, and then assign groups to text lines in positional order. Default params: `slope_bounds=(-0.1, 0.1)`, `offset_bounds=(-50, 50)`, `std_bounds=(1, 20)`. Requires SciPy. Original method by Cohen (2013).

    - `segment` : Segment fixation sequence into m subsequences based on m–1 most-likely return sweeps, and then assign subsequences to text lines in chronological order. Requires NumPy. Original method by Abdulin & Komogortsev (2015).

    - `slice` : Form a set of runs and then reduce the set to m by repeatedly merging those that appear to be on the same line. Merged sequences are then assigned to text lines in positional order. Default params: `x_thresh=192`, `y_thresh=32`, `w_thresh=32`, `n_thresh=90`. Requires NumPy. Original method by Glandorf & Schroeder (2021).

    - `split` : Split fixation sequence into subsequences based on best candidate return sweeps, and then assign subsequences to closest text lines. Requires SciPy. Original method by Carr et al. (2022).

    - `stretch` : Find a stretch factor and offset that results in a good alignment between the fixations and lines of text, and then assign the transformed fixations to the closest text lines. Default params: `stretch_bounds=(0.9, 1.1)`, `offset_bounds=(-50, 50)`. Requires SciPy. Original method by Lohmeier (2015).

    - `warp` : Map fixations to word centers using Dynamic Time Warping. This finds a monotonically increasing mapping between fixations and words with the shortest overall distance, effectively resulting in m subsequences. Fixations are then assigned to the lines that their mapped words belong to, effectively assigning subsequences to text lines in chronological order. Requires NumPy. Original method by Carr et al. (2022).

    View code on GitHub
  `def serialize(self) ‑> list`

    Returns representation of the fixation sequence in simple list format for serialization.

    View code on GitHub