Interactive Streamlit workbench for visualizing eye-tracking-while-reading scanpaths, computing reading measures, and exporting figures and tabular data.
Project description
Scanpath Studio
An interactive workbench for visualizing eye-tracking-while-reading data. Drop in a trial and see the scanpath the way the reader saw it — words at their true on-screen positions, with fixations, saccades, a density heatmap, and animated replay layered on top, all exportable as publication-ready figures.
It is dataset-agnostic (auto-detects EyeLink / Gazepoint / snake-case columns) and ships with a small OneStop demo, so you can try it with zero setup.
Authors: Omer Shubi, Keren Gruteke Klein, and others (TBD) — LACC Lab, Technion.
A scanpath replayed fixation by fixation over the text the reader saw.
Try it
Live demo (zero install): https://scanpath-studio.streamlit.app
pip install scanpath-studio
scanpath-studio # launches the app in your browser
What it does
The scanpath plot is built from layers you toggle independently:
- Text drawn at the exact pixel coordinates the participant saw.
- Fixations sized and colored by any column in your data (duration, GPT-2 surprisal, word frequency, …).
- Saccades, with backward jumps (regressions) standing out.
- Areas of interest (word boxes from your data) and a word-level heatmap (total fixation duration, count, …).
On top of that:
- Animated replay — watch the scanpath unfold at real or scaled speed; export as interactive HTML, GIF, or MP4.
- Compare readings — overlay two trials on one canvas or place them side by side (e.g. ordinary vs. information-seeking, first vs. repeated, L1 vs. L2).
- Critical-span, out-of-text & by-line highlights — mark an answer span, flag fixations outside every word box, or color fixations by text line.
- Triage — star, tag, and annotate trials; save and restore everything as a JSON sidecar.
- Bulk export — one zip of per-trial PNG + SVG figures, plot settings, and tabular data across every filtered trial.
Overlay a second reading to compare two readers of the same text on a shared clock.
The app is organized into five tabs:
| Tab | What's there |
|---|---|
| Scanpath Visualization | The layered scanpath with the trial picker, metadata, and two-trial comparison. Tick Animate to replay it frame by frame (export HTML / GIF / MP4). |
| Generations (WIP) | A real scanpath vs. several model-generated ones over the same text, scored by similarity (model outputs are reproducible placeholders for now). |
| Raw Data | Paginated word / fixation / raw-gaze tables, each with CSV + Parquet download. |
| Data Statistics | Summary stats (fixation duration, saccade amplitude, regression rate, …) and per-word / distribution plots. |
| Bulk Export | One zip of per-trial figures, plot settings, and tabular data across the filtered trials — or the whole dataset. |
Your data
Upload CSV, TSV, Parquet, or Feather tables for words/AoIs, fixations, and
(optionally) raw gaze. Columns are auto-detected from common EyeLink, Gazepoint,
and snake-case conventions; a sidebar Column mapping panel overrides any
guess. The loader bends to fit real corpora — many files per table (concatenated
with a source_file tag), a single report (words- or fixations-only),
stimulus-level word boxes broadcast across readers, and AoI-sequence fixations
placed at word/character-box centers.
If your data carries only raw fixations, the app computes the canonical per-word measures itself — FFD, FPRT (gaze duration), RPD (go-past), TFD (dwell), plus skips and regressions, following Rayner (1998) and Inhoff & Radach (1998). Pre-aggregated EyeLink columns, when present, take precedence.
A ready-made PoTeC loader (Potsdam Textbook Corpus) exercises that flexible pipeline end to end:
import scanpath_studio as sps
words, fixations = sps.load_potec("data/PoTeC", download=True) # ~45 MB on first call
fig = sps.plot_scanpath(words, fixations, "0", "b0", canvas_size=(1680, 1050))
Command line & Python API
Everything the app draws is also available headless — same pipeline, same figure.
scanpath-studio render --sample --list-trials # what's available
scanpath-studio render --sample -o scanpath.html # interactive HTML
scanpath-studio render --words ia.csv --fixations fix.csv -p p1 -t t3 -o figure.png
scanpath-studio render --sample --animate -o replay.html # animated replay
import scanpath_studio as sps
words, fixations = sps.load_scanpath_data("ia.csv", "fixations.csv") # paths, globs, or lists; either table optional
sps.list_trials(words, fixations)
fig = sps.plot_scanpath(words, fixations, "p1", "t3") # every layer toggle is a kwarg
sps.save_figure(fig, "scanpath.png") # .html / .png / .svg / .pdf
measures = sps.compute_word_metrics(words, fixations) # FFD / FPRT / RPD / TFD …
HTML export is browser-free; PNG/SVG/PDF/GIF/MP4 go through Kaleido (run
plotly_get_chrome -y once). See scanpath-studio render --help for all flags.
Run from source
git clone https://github.com/lacclab/scanpath-studio.git
cd scanpath-studio
pip install -e ".[test]" # or: uv sync
streamlit run streamlit_app.py
Tested on Python 3.11–3.14. Run the tests with pytest; see
AGENTS.md for an architectural overview.
Citation
A system-demo paper is in preparation — citation TBD. Until then, cite the
software via GitHub's "Cite this repository" button (generated from
CITATION.cff).
If you use the bundled demo data, please cite the OneStop corpus:
@article{berzak2025onestop,
title = {{OneStop}: A 360-Participant {E}nglish Eye Tracking Dataset
with Different Reading Regimes},
author = {Berzak, Yevgeni and Malmaud, Jonathan and Shubi, Omer
and Meiri, Yoav and Lion, Ella and Levy, Roger},
journal = {Scientific Data},
year = {2025},
publisher = {Nature Publishing Group},
doi = {10.1038/s41597-025-06272-2},
url = {https://www.nature.com/articles/s41597-025-06272-2},
}
The bundled demo is a subset of OneStop Eye Movements, used under its original license (docs).
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scanpath_studio-0.20.0.tar.gz.
File metadata
- Download URL: scanpath_studio-0.20.0.tar.gz
- Upload date:
- Size: 808.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0379ba0bdc09183d912140095fcce37d56926338743693ca321faa870fcfd624
|
|
| MD5 |
8ede9c0a7373db5292b68eb9774ea85d
|
|
| BLAKE2b-256 |
fa02f4313f1ad651d993f87a90b5aa59b0d9955973a69d82d3c7a4f2df610a19
|
Provenance
The following attestation bundles were made for scanpath_studio-0.20.0.tar.gz:
Publisher:
publish.yml on lacclab/scanpath-studio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scanpath_studio-0.20.0.tar.gz -
Subject digest:
0379ba0bdc09183d912140095fcce37d56926338743693ca321faa870fcfd624 - Sigstore transparency entry: 1853028135
- Sigstore integration time:
-
Permalink:
lacclab/scanpath-studio@a51488152852d033a47446d6e1895648db130c18 -
Branch / Tag:
refs/tags/v0.20.0 - Owner: https://github.com/lacclab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a51488152852d033a47446d6e1895648db130c18 -
Trigger Event:
push
-
Statement type:
File details
Details for the file scanpath_studio-0.20.0-py3-none-any.whl.
File metadata
- Download URL: scanpath_studio-0.20.0-py3-none-any.whl
- Upload date:
- Size: 761.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
468e354e67582d5552b90519115434377d7315b95eba2f4949c84d2fd55ebe50
|
|
| MD5 |
520ef0875404e8345626d296220069d4
|
|
| BLAKE2b-256 |
cde0e87be03e37aec0a29a1fbc5076250d7cb6368ea2fed341a588640bdd8045
|
Provenance
The following attestation bundles were made for scanpath_studio-0.20.0-py3-none-any.whl:
Publisher:
publish.yml on lacclab/scanpath-studio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scanpath_studio-0.20.0-py3-none-any.whl -
Subject digest:
468e354e67582d5552b90519115434377d7315b95eba2f4949c84d2fd55ebe50 - Sigstore transparency entry: 1853028274
- Sigstore integration time:
-
Permalink:
lacclab/scanpath-studio@a51488152852d033a47446d6e1895648db130c18 -
Branch / Tag:
refs/tags/v0.20.0 - Owner: https://github.com/lacclab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a51488152852d033a47446d6e1895648db130c18 -
Trigger Event:
push
-
Statement type: