gazel provides fixation algorithms for aggregating gazes, as well as tools to help you deal with edits that occur during eyetracking sessions.
gazel requires python 3.8.5
You can install gazel using
pip install gazel
gazel comes with a command line interface as well as a python library.
To use either version, you need 3 things:
- itrace core file output
- gaze file output
- changelog
- original source file(s)
To get started:
# import gazel
from gazel import fixation_filter, Tracker
# run fixation filter to get fixations
fixations = fixation_filter(gazes, changelog, sources, **opts)
# Now track edits using Tracker
tracker = Tracker(fixations, changelog, sources, language)
# Note that you need to pass in the source code language,
# to help `gazel` determine which parser to use.
The main goal of Tracker
is to track fixations and source code tokens across edits. Once you create a Tracker
you can query it to get snapshots etc.
Tracker
maintains a list of snapshots corresponding to the original file and subsequent edits. The original version is stored at index 0
and the first edit is stored at index 1
.
# get original
tracker.get_snapshot(0)
# get first edit
tracker.get_snapshot(1)
Each snapshot is represented by a Snapshot
. A Snapshot
is defined as:
class Snapshot:
id: int
source: Source
tokens: Tuple[Token, ...]
changes: Tuple[TokenChange, ...] = ()
time: float = 0.0
Snapshot.time
represents the time at which a snapshot was created. It corresponds to the timestamp in the changelog that was used to create this Snapshot
.
Snapshot.tokens
represents the parsed source code tokens.
Snapshot.changes
represents all the token changes that happened to this Snapshot
since the last version. For the Snapshot
representing the original source, Snapshot.changes
is empty.
Snapshots.source
is a Source
object, containing the raw text of the source code, as well as mappings from text indices to line/column numbers and vice-versa. It is defined as follows:
@dataclass(frozen=True)
class Source:
text: str
mapping: PositionMapping
language: str
You can retreive gazes for a given time window as follows:
tracker.get_gazes()
# all gazes
tracker.get_gazes(start, end)
# returns a dataframe that is filtered
The gaze dataframe is simply a pandas.DataFrame
containing the original gazes, with some additional columns:
syntax_node
- The syntax node associated with the gaze.None
if the gaze doesn't fall on a token.syntax_node_id
- A stable id for the token associated with this gaze.None
if the gaze doesn't fall on a token.
syntax_node_id
is a unique id that is assigned to each token in the source code across different snapshots. For a given token, this id is unique across time and space. Thus, you can use this id to determine how
tracker.diff(0, 2) # gives you the diff between version 0 & version 1
tracker.diff_time(2300, 2400)
# gives you the diff between time unit 2300 & time unit 2400
A SnapshotDiff
is defined as follows:
class SnapshotDiff(NamedTuple):
old: Snapshot
new: Snapshot
token_changes: List[TokenChange]
gaze_changes: List[GazeChange]
gazes: pd.DataFrame
It gives you a list of all token changes and gaze changes.
Token changes can be of 3 types: inserted
, moved
or deleted
.
Gaze changes can be of 2 types: deleted
or moved
. (deleted
means that the token to which the gaze was mapped to has been removed from the source.)
By default, tracker.diff(start, end)
will include all the gazes from the start of the experiment (the time at which the first gaze is recorded), up until the end
snapshot time. If you want to only include gazes within the timespan of the start
and end
snapshots, you can pass an optional parameter:
diff = tracker.diff(0, 3, window_only=True)
gazel
also provides a pretty-printer to help you print diffs for inspecting the data. It supports print gaze changes, token changes and SnapshotDiffs
.
from gazel import pprint
diff = tracker.diff(2, 3)
pprint(diff)
pprint(diff.token_changes)
pprint(diff.gaze_changes)
gazel
provides a module transforms
to help you manipulate gazel
structures including Snapshots
and SnapshotDiff
.
from gazel import transforms as T
diff = tracker.diff(2, 5)
# TODO