CLI reference¶
scanpath-studio launches the app by default. Its render subcommand writes
one trial without opening the UI.
Launch¶
scanpath-studio
scanpath-studio --server.port 8600
scanpath-studio --no-persist # don't cache the session on this computer
scanpath-studio --download-dir D:\corpora # where ⬇ Download saves public datasets
The app listens on this computer only (127.0.0.1). It has no login, so
serving it to other machines is a deliberate step — pass
--server.address 0.0.0.0 (or set server.address in a Streamlit
config.toml, or STREAMLIT_SERVER_ADDRESS), and only on a network you trust:
Served on a network, the app also turns off everything that reads or writes the
server's own folders — the Data directory box, the folder picker, ⬇ Download
for the public corpora and stimulus-image folders — since any visitor could use
them. On a lab server you trust, turn them back on with SCANPATH_LOCAL_FS=1
(SCANPATH_LOCAL_FS=1 scanpath-studio --server.address 0.0.0.0).
Additional launch flags are forwarded to Streamlit. A word that is not one of
the commands (run, render, corpus, check, cache) is an error that
names the closest one, rather than an argument handed to Streamlit.
Render¶
# Inspect available IDs
scanpath-studio render --sample --list-trials
# Render the bundled demo
scanpath-studio render --sample -o scanpath.html
# Render your data (replace p1 / t3 with ids from --list-trials)
scanpath-studio render \
--words ia.csv --fixations fixations.csv \
--participant p1 --trial t3 --output scanpath.svg
# Render an authoring file saved from the app's Author a scanpath screen
scanpath-studio render --authoring authored-scanpath.json -o authored.html
# Inspect and render an ordered multipart trial
scanpath-studio render --words ia.csv --fixations fix.csv --list-parts
scanpath-studio render --words ia.csv --fixations fix.csv \
-p p1 -t t3 --screen question -o question.svg
scanpath-studio render --words ia.csv --fixations fix.csv \
-p p1 -t t3 --all-screens --animate --screen-transition recorded \
-o replay.html
HTML is interactive and needs no browser. PNG, SVG and PDF need Chrome,
Chromium or Edge installed (or run plotly_get_chrome -y once).
When a column isn't recognized¶
Column names are auto-detected (EyeLink, Tobii, SMI, Pupil Labs, Gazepoint and
snake_case spellings). When one isn't, render stops and prints which field it
could not find, the names it looked for, the columns your table has, and a
mapping to start from. Pass that mapping back as JSON — inline, or as a path to
a .json file — with --word-schema (the --words table) and/or
--fix-schema (the --fixations table). check takes the same two flags.
scanpath-studio render --words ia.csv --fixations fix.csv \
--word-schema '{"trial": "TRIAL_LABEL", "word_id": "IA_ID", "text": "IA_LABEL",
"left": "IA_LEFT", "right": "IA_RIGHT", "top": "IA_TOP", "bottom": "IA_BOTTOM"}' \
--fix-schema fix_schema.json -o scanpath.html
A mapping replaces auto-detection for that table, so it has to name every
required field, not only the one that failed. It is the same dict
load_scanpath_data(word_schema=…, fix_schema=…) takes in Python.
Public corpora¶
A public corpus loads headlessly the same way the app loads it — no export step in between:
# PoTeC, downloaded on first use
scanpath-studio render --potec ./potec --list-trials
# OneStop, choosing the variant, regime and part
scanpath-studio render --onestop ./onestop --onestop-variant public \
--onestop-regime ordinary --onestop-part Paragraph --list-trials
The Python API takes the same corpora through load_potec and
load_onestop.
Compare two scanpaths¶
--compare-with PARTICIPANT:TRIAL draws a second trial beside or over the
first — the headless form of the app's Compare mode.
# Two participants on the same paragraph, overlaid
scanpath-studio render --sample -p l37_1129 -t l37_1129_2_1_1_Ele_r0 \
--compare-with l7_1090:l7_1090_2_1_1_Ele_r0 -o compare.html
# The same overlay, drawing only B's word boxes and text
scanpath-studio render --sample -p l37_1129 -t l37_1129_2_1_1_Ele_r0 \
--compare-with l7_1090:l7_1090_2_1_1_Ele_r0 --compare-stimulus b \
-o compare_b.html
# Side by side — each panel draws its own trial's stimulus
scanpath-studio render --sample -p l37_1129 -t l37_1129_2_1_1_Ele_r0 \
--compare-with l7_1090:l7_1090_2_1_1_Ele_r0 \
--compare-layout side-by-side -o compare.svg
# B from a second dataset
scanpath-studio render --words ia.csv --fixations fix.csv -p p1 -t t1 \
--compare-with p1:t1 \
--compare-words other/ia.csv --compare-fixations other/fix.csv \
--compare-dataset-name "Our lab" \
--canvas 1680x1050 --compare-canvas 1680x1050 \
-o cross.html
| Goal | Option |
|---|---|
| pick B | --compare-with PARTICIPANT:TRIAL |
| pick each screen of a multipart trial | --screen ID (A), --compare-screen ID (B); each defaults to its trial's first screen |
| arrange the panels | --compare-layout {overlay,side-by-side,stacked} (default overlay) |
| whose stimulus an overlay draws | --compare-stimulus {both,a,b} (default both) |
| name the two scanpaths | --label-a TEXT --label-b TEXT (both or neither) |
| style each scanpath | --style-a SPEC, --style-b SPEC (below) |
| the A/B legend (on by default) | --no-compare-legend to leave it off |
| B's own stimulus page (split layouts) | --stimulus-image-b PATH, with --stimulus-image-size-b WxH / --stimulus-image-origin-b X,Y |
| B from another dataset | --compare-words PATH… --compare-fixations PATH… |
| that dataset's raw gaze | --compare-raw-gaze PATH… |
| name that dataset | --compare-dataset-name NAME |
| declare the screens | --canvas WxH, --compare-canvas WxH |
| co-animate both scanpaths | add --animate (HTML output) |
--label-a / --label-b also label the --animate co-animation, and
--style-a / --style-b (below) style it as they style the comparison.
--style-a / --style-b are the app's per-scanpath styling (the Compare rows
under Fixations, Saccades, the
word boxes, heatmap and raw gaze — their Scanpath A / Scanpath B groups), compare_scanpaths's style_a / style_b:
a comma-separated KEY=VALUE list, repeatable, with fix_color,
saccade_color, box_color, box_fill_color and raw_gaze_color (#RRGGBB;
box_color outlines that scanpath's word boxes, its fix_color when left out,
box_fill_color fills them, --word-box-fill-color when left out, and
raw_gaze_color colors its raw-gaze samples, its fix_color when left out —
all three static comparison only, the --animate co-animation draws one set of
boxes and no raw gaze), heatmap_colorscale (a Plotly color scale for that
scanpath's heatmap, --heatmap-colorscale when left out; the range stays shared,
and two different scales get a color bar each), saccade_style (solid, dash,
dot, dashdot), saccade_width (px), marker_size_range (MIN:MAX),
opacity (0.1–1) and hollow (true / false). A key left out keeps that
scanpath's default.
scanpath-studio render --sample -p l37_1129 -t l37_1129_2_1_1_Ele_r0 \
--compare-with l7_1090:l7_1090_2_1_1_Ele_r0 \
--style-a fix_color=#D55E00,opacity=0.5 --style-b saccade_style=dash \
-o compare_styled.html
--animate --compare-with replays both scanpaths on one clock, the same dual
co-animation the app renders with Animate and Compare both on.
--compare-with cannot be combined with --all-screens or --screens: a comparison
is a single figure of two trials, each drawn from one screen. Pick A's with
--screen and B's with --compare-screen; B's is looked up in B's own trial,
so it can be a later page, or a page of the second dataset.
Overlay across two datasets requires matching canvases. On two different
canvases --compare-layout overlay fails rather than falling back, and so does
--animate, which replays both scanpaths in one coordinate space; pass
--compare-layout side-by-side or stacked, without --animate. Without
--compare-canvas the second dataset's screen is read off its data, as A's is
when neither --canvas nor a built-in source gives one. That extent rarely
spans the whole screen, so state both screens when you know them. Within one
dataset, two screens whose own canvases differ are refused the same way.
Nothing is rescaled.
A second dataset is loaded from files only. Any corpus reachable from Python
can still be scanpath B via
compare_scanpaths, which takes
B's frames directly.
Common options¶
| Goal | Option |
|---|---|
| add a layer | --word-boxes, --fixation-index, --heatmap (the default is the app's Scanpath design) |
| hide a layer | --no-text, --no-fixations, --no-saccades |
| animate | --animate and optionally --playback-speed X; every styling flag the replay can draw (api.figure_options("animation")) is honored, and the rest are named in a warning |
| set display geometry | --canvas WIDTHxHEIGHT |
| color fixations | --color-by FIELD — a column of your own too, once --keep-columns COLUMN… carries it through loading |
| size fixations by duration | --marker-size-scale sqrt\|linear\|log\|relative (default sqrt), --marker-duration-range LO HI (ms, default 50 600), --marker-size-range MIN MAX (px), --no-duration-size-legend |
| draw only part of a trial | --fix-index-range START:END (1-based, both inclusive; honored by --animate and --compare-with too) |
| add the stimulus image | --stimulus-image PATH |
| resolve per-trial images | --image-root DIR --image-pattern '{text_id}.png' |
| use a smoothed (Gaussian) heatmap | --heatmap-style interpolated --heatmap-sigma 20 (σ in px; omit it for the automatic σ) |
| map arbitrary source rows to screens | --trial-parts-manifest manifest.json |
| export editable layers | --separable-layers |
| style the word boxes | --word-box-color, --word-box-line-opacity, --word-box-fill-color, --word-box-fill-opacity (0 draws outlines only / fill only) |
| draw the raw gaze | --raw-gaze PATH… (or --sample-raw-gaze with --sample), --raw-gaze-schema JSON, --raw-gaze-color, --raw-gaze-marker-size, --raw-gaze-opacity; --no-raw-gaze loads the table but hides the layer |
| size the figure | --width, --height, --scale |
| size a PNG for print | --width-mm MM or --width-in IN, with --dpi N (default 300) |
| title and caption it | --title, --caption |
| print the equivalent Python | --print-code python (or cli / both, plus --print-code-explicit) |
The figure options table gives every figure option's flag.
Raw gaze is a third table rather than an option: --raw-gaze reads it (columns
auto-detected like --fixations) and draws the plotted trial's samples under the
fixations. With --compare-with it covers both scanpaths, each drawn in its
own color, and --compare-raw-gaze PATH… is B's when B comes from
another dataset. --animate ignores it with a warning.
scanpath-studio render --sample -p l37_1129 -t l37_1129_2_2_2_Adv_r0 \
--sample-raw-gaze --raw-gaze-opacity 0.4 -o raw_gaze.html
On its own, with no other input, --raw-gaze is the dataset: --list-trials
lists its trials and render draws the chosen trial's samples as recorded.
No fixations are detected from them, so --animate and --compare-with exit
with that reason instead.
scanpath-studio render --raw-gaze gaze_samples.csv --list-trials
scanpath-studio render --raw-gaze gaze_samples.csv -t t3 -o samples.png
Corpus figures¶
scanpath-studio corpus goes the other way: it reads a tidy CSV you already
have (for --kind profile, columns word_id and value) and renders a styled
corpus figure
(api.plot_corpus_figure):
Options
| Option | Value | Default | Description |
|---|---|---|---|
--input |
PATH |
required | The CSV. profile reads word_id plus the value column (and optional lo / hi), distribution the value column, difference word_id and diff. |
--kind |
{profile,distribution,difference} |
required | A per-word profile, a distribution, or a difference profile. |
-o, --output |
PATH |
required | Output file; any extension save_figure writes (.html, .png, .svg, .pdf). |
--measure-label |
MEASURE_LABEL |
Value |
Axis / legend label for the value (default: Value). |
--series-col |
SERIES_COL |
series |
Column naming the overlaid series, when present (default: series). |
--value-col |
VALUE_COL |
value |
The value column (default: value). |
--primary-color |
PRIMARY_COLOR |
#1f77b4 |
First series color (default: #1f77b4). |
--secondary-color |
SECONDARY_COLOR |
#e45756 |
Second series color (default: #e45756). |
Data checks¶
check runs the Data Management page's Data checks on your
tables without opening the app: fixations lasting 0 ms or less or with an
infinite duration or onset, fixations and raw-gaze samples with no finite
position, word boxes with no area or no finite position, and per-screen screen
sizes that are not finite and positive. Each
finding gives the rows and trials affected, a few example rows, and what the
app does with them. It changes nothing, and it exits 0 whatever it finds;
--json prints the table
api.check_data_health returns.
scanpath-studio check --words ia.csv --fixations fixations.csv
scanpath-studio check --raw-gaze gaze_samples.csv --json
Options
| Option | Value | Default | Description |
|---|---|---|---|
--sample |
switch | — | Check the bundled OneStop demo instead of your own tables. |
--words |
PATH [PATH ...] |
— | Words table(s), as for render. |
--fixations |
PATH [PATH ...] |
— | Fixations table(s), as for render. |
--raw-gaze |
PATH [PATH ...] |
— | Raw (sample-level) gaze table(s), as for render. |
--raw-gaze-schema |
JSON |
— | Column mapping for the --raw-gaze table, replacing auto-detection (same shape as --fix-schema). |
--trial-parts-manifest |
PATH |
— | JSON manifest assigning source rows to ordered screens. |
--json |
switch | — | Print the findings as JSON (the rows api.check_data_health returns). |
--word-schema |
JSON |
— | Column mapping for the --words table, replacing auto-detection: a JSON object (or a path to a .json file holding one) from each field to a column name, e.g. '{"trial": "TRIAL_INDEX", "word_id": "IA_ID", ...}' — the same dict api.load_scanpath_data takes. Needed only when a column isn't recognized; the error then prints a mapping to start from. |
--fix-schema |
JSON |
— | Column mapping for the --fixations table, replacing auto-detection: a JSON object (or a path to a .json file holding one) from each field to a column name, e.g. '{"trial": "TRIAL_INDEX", "word_id": "IA_ID", ...}' — the same dict api.load_scanpath_data takes. Needed only when a column isn't recognized; the error then prints a mapping to start from. |
--keep-columns |
COLUMN [COLUMN ...] |
— | Further columns of your own to carry through loading under their own names (e.g. a pupil size), from whichever table has them — otherwise loading keeps only the mapped and recognized fields. A kept fixation column can then be --color-by, an axis or a hover field. The keep_columns= of api.load_scanpath_data. |
Many trials¶
The render command renders one trial per invocation; use the Python batch pattern
or Export → Export bundle for many figures.
--all-screens is the multipart exception: it writes one deterministic
__screen-001-<id> file per screen of the selected parent trial.
--screens Title,Paragraph writes only the screens named, each still numbered
by its place in the trial.
Recovery cache¶
A local or desktop run caches your session on your own machine — uploaded
datasets, column mappings, view settings, saved designs, metadata tables and
annotations — so a refresh or a
restart resumes where you left off. cache shows what is stored and removes it:
scanpath-studio cache # datasets, rows, size, folder, last written
scanpath-studio cache --path # just the folder
scanpath-studio cache --json # the same status as JSON
scanpath-studio cache --clear # delete the recovery cache
The same information is at the foot of the Data Management page, under Saved on
this computer. A running app writes a new copy at its next change, so clear
with the app closed. SCANPATH_STUDIO_PERSIST=0 turns caching
off wherever it is set, --no-persist for one launch, and SCANPATH_STUDIO_STATE_DIR
moves the folder. Hosted deployments never cache. See
Privacy.
Version and updates¶
scanpath-studio --version prints the version. version says which build it
is and how it was installed; --check also asks GitHub whether a newer release
is out and prints the command that updates your install — the only time the
command uses the network:
scanpath-studio version # the build, and how it was installed
scanpath-studio version --check # …and whether a newer release is out
Between releases the version names the build: 0.35.0.post3+g8f18219 is three
commits after 0.35.0, at commit 8f18219. The same check is
Help → About → Check for updates
in the app, and check_for_updates() in the API.
Options
| Option | Value | Default | Description |
|---|---|---|---|
--check |
switch | — | Ask GitHub for the latest release and say how to update this install. |
--timeout |
SECONDS |
5.0 |
How long to wait for GitHub (default 5). |
Full reference¶
Generated from the parsers the commands themselves use, so every flag is here
with the default and help --help prints.
scanpath-studio 0.37.1 — visualize eye-tracking-while-reading scanpaths
usage:
scanpath-studio launch the interactive app (Streamlit)
scanpath-studio run [args…] same, forwarding args to `streamlit run`
(its --help lists Streamlit's options only)
scanpath-studio [run] --no-persist
launch without the on-device recovery cache
(this run only; see `cache` below)
scanpath-studio [run] --download-dir DIR
where Download saves public datasets when
the Data Management page's Download folder is blank
scanpath-studio render … render one trial to .html/.png/.svg/.pdf
(see `scanpath-studio render --help`)
scanpath-studio corpus … render a styled corpus-analysis figure
scanpath-studio check … run the Data checks on your tables
scanpath-studio cache … show / clear the on-device recovery cache
scanpath-studio version [--check]
show this build and how it was installed;
--check asks GitHub whether a newer
release is out
scanpath-studio --version print the version
Unrecognized flags are forwarded to `streamlit run` (e.g.
`scanpath-studio --server.port 8502`); an unknown command word is an error.
The app listens on this computer only; `--server.address 0.0.0.0` serves it
on your network (it has no login) with local folder access off, unless
SCANPATH_LOCAL_FS=1.
render — every flag
Options
| Option | Value | Default | Description |
|---|---|---|---|
-p, --participant |
PARTICIPANT |
— | Participant id (default: first available). |
-t, --trial |
TRIAL |
— | Trial id (default: first for the participant). |
--screen |
SCREEN |
— | Screen/part id inside a multipart trial (default: first screen). |
--list-trials |
switch | — | Print every trial (participant, trial and text id) and exit; pass the trial id to -t. |
--list-parts |
switch | — | Print ordered multipart screens, optionally narrowed by -p/-t, and exit. |
--all-screens |
switch | — | Render every screen of the selected parent trial. Screen ids are inserted before the output extension. |
--screens |
ID[,ID...] |
— | Like --all-screens, but only these screens of the parent trial (comma-separated screen ids, e.g. Title,Paragraph); see --list-parts. |
--screen-transition |
{instant,recorded} |
instant |
For --all-screens --animate, record zero or observed inter-screen delay in each output's metadata (default: instant). |
-o, --output |
PATH |
— | Output file; format from extension (.html/.png/.svg/.pdf). |
--animate |
switch | — | Render the animated replay instead of the static figure (HTML only). |
Input (bundled demo, or words and/or fixations)
| Option | Value | Default | Description |
|---|---|---|---|
--sample |
switch | — | Use the bundled OneStop demo: 2 participants, 12 trials each (--list-trials shows them). |
--authoring |
PATH |
— | An authoring file from the app's Author a scanpath screen. |
--words |
PATH [PATH ...] |
— | Words table(s) (csv/tsv/txt/tab/parquet/feather/xlsx/xls, or a .zip of them); columns are auto-detected from EyeLink, Gazepoint, Tobii, SMI, Pupil Labs and snake_case names. Multiple paths or a quoted glob pattern concatenate multi-file datasets. |
--fixations |
PATH [PATH ...] |
— | Fixations table(s) (csv/tsv/txt/tab/parquet/feather/xlsx/xls, or a .zip of them), auto-detected like --words. Multiple paths or a quoted glob pattern concatenate multi-file datasets (e.g. one file per participant). |
--image-root |
DIR |
— | Local stimulus-image folder. Files are matched per row using --image-pattern. |
--image-pattern |
PATTERN |
{text_id}.png |
Relative filename pattern with row placeholders, for example '{text_id}.png' or '{participant_id}/{trial_id}.png'. |
--trial-parts-manifest |
PATH |
— | JSON manifest that assigns arbitrary source rows to ordered screens inside each logical trial. Use with --words/--fixations when the source tables have no explicit screen columns. |
--word-schema |
JSON |
— | Column mapping for the --words table, replacing auto-detection: a JSON object (or a path to a .json file holding one) from each field to a column name, e.g. '{"trial": "TRIAL_INDEX", "word_id": "IA_ID", ...}' — the same dict api.load_scanpath_data takes. Needed only when a column isn't recognized; the error then prints a mapping to start from. |
--fix-schema |
JSON |
— | Column mapping for the --fixations table, replacing auto-detection: a JSON object (or a path to a .json file holding one) from each field to a column name, e.g. '{"trial": "TRIAL_INDEX", "word_id": "IA_ID", ...}' — the same dict api.load_scanpath_data takes. Needed only when a column isn't recognized; the error then prints a mapping to start from. |
--keep-columns |
COLUMN [COLUMN ...] |
— | Further columns of your own to carry through loading under their own names (e.g. a pupil size), from whichever table has them — otherwise loading keeps only the mapped and recognized fields. A kept fixation column can then be --color-by, an axis or a hover field. The keep_columns= of api.load_scanpath_data. |
--potec |
DIR |
— | Load the PoTeC corpus (DiLi-Lab/PoTeC) from DIR, downloading the needed files (~45 MB) on first use. Participants are the corpus's 75 ids (sparse within 0–105; --list-trials shows them); a trial is one participant reading one text, <participant>_<text> (0_b0), with texts b0–b5 and p0–p5. |
--onestop |
DIR |
— | Load the OneStop corpus from DIR. For the public variant the chosen regime + parts' reports are downloaded from OSF on first use (tens–hundreds MB each); the lacclab variant reads a local export. Tune with --onestop-regime / --onestop-part / --onestop-variant. |
--onestop-regime |
REGIME |
ordinary |
OneStop reading regime for --onestop (default: ordinary). |
--onestop-part |
PART |
— | OneStop trial part(s) for --onestop; repeatable (default: Paragraph). Loading several makes each part its own trial. |
--onestop-variant |
VARIANT |
public |
OneStop source variant for --onestop: 'public' (OSF download) or 'lacclab' (a local lab-processed export; no download). |
--participant-metadata |
FILE |
— | Participant-level metadata table: one row per participant, an id column plus anything known about them. The join is validated and reported against the loaded participants, and the fields are added to --list-trials output. |
--trial-metadata |
FILE |
— | Trial-level metadata table: one row per trial, a trial-id column plus anything known about it. Validated and reported the same way, and its fields are added to --list-trials output. |
--trial-metadata-participant-column, --trial-metadata-reader-column |
COLUMN |
— | Key the --trial-metadata table by participant AND trial, using this column as the participant id. Without it the table is keyed by trial id alone: a row describes a text, and every trial of it inherits that row. Never inferred: nothing in the file says which of the two a corpus means. |
--text-metadata |
FILE |
— | Text-level metadata table: one row per text, a text-id column plus anything known about it. Validated and reported the same way, and its fields are added to --list-trials output. Never keyed by participant: a text is a stimulus, not something one participant owns. |
Visualization (draws the app's Scanpath design: fixations, saccades and the text; add --word-boxes, --heatmap or --fixation-index, or hide a layer with its --no-* flag)
| Option | Value | Default | Description |
|---|---|---|---|
--word-boxes |
switch | — | Draw the word boxes. |
--no-word-boxes, --no-words |
switch | — | Hide the word boxes (the default). |
--no-text, --no-labels |
switch | — | Hide the reading text. |
--no-fixations |
switch | — | Hide fixation markers. |
--fixation-index |
switch | — | Number the fixations in reading order. |
--no-fixation-index, --no-order |
switch | — | Hide the fixation numbers (the default). |
--word-hover-fields |
FIELDS |
— | Comma-separated word columns shown on hover (e.g. text,word_id,gpt2_surprisal). |
--fixation-hover-fields |
FIELDS |
— | Comma-separated fixation columns shown on hover (e.g. order_in_trial,duration_ms,eye). |
--no-saccades |
switch | — | Hide saccade lines. |
--heatmap |
switch | — | Draw the heatmap. |
--no-heatmap |
switch | — | Hide the heatmap (the default). |
--saccade-arrows |
switch | — | Draw saccade direction arrowheads. |
--saccade-color |
COLOR |
— | Saccade line/arrow color, hex or CSS name (default: #CC79A7). |
--saccade-style |
{solid,dash,dot,dashdot} |
— | Saccade line dash style (default: solid). |
--saccade-width |
PX |
— | Saccade line width in px, 0.5–10 (default: 2). |
--saccade-color-by-type |
switch | — | Color each saccade by its reading type (forward / skip / refixation / return sweep / regression) instead of one uniform color. |
--saccade-color-by-direction |
switch | — | Color saccades forward vs. regression only — the two-way split between one uniform color and the full --saccade-color-by-type breakdown. |
--saccade-type-color |
CLASS=COLOR |
— | Override a reading-type color, e.g. --saccade-type-color regression=#000000 (repeatable; classes: forward, skip, refixation, return_sweep, regression). Implies --saccade-color-by-type, unless --saccade-color-by-direction is given — then it recolors that two-way split (its forward and regression colors). |
--no-saccade-type-legend |
switch | — | With --saccade-color-by-type: hide the saccade-type color key on the figure (the colored lines still draw). Legend shows by default. |
--fix-index-range |
START:END |
— | Draw only fixations START through END of the trial (1-based, both inclusive), e.g. --fix-index-range 1:40. Honored by --animate too, which then replays only that window, and by --compare-with, which windows both scanpaths (unless --compare-fix-index-range gives B its own). |
--highlight-column |
COLUMN |
— | Boolean words column marking the text to highlight — the critical span (default: is_in_aspan, OneStop's answer span). Pass --highlight-column '' to highlight nothing. How it is drawn is --critical-span-style. |
--critical-span-style |
{mark-text,mark-border,none} |
— | How the --highlight-column words are marked: mark-text recolors them, mark-border outlines their boxes, none draws neither (default: mark-text). |
--fixation-flag |
SPEC |
— | The app's Filters & highlights for fixations, repeatable. SPEC is CATEGORY=MODE[,threshold_ms=N][,symbol=S][,color=#RRGGBB] with CATEGORY one of short, long, oob (outside every word box), blink and MODE one of off, highlight, discard — e.g. --fixation-flag short=discard,threshold_ms=80. discard drops those fixations from the drawing only; measures and exports are untouched. threshold_ms applies to short/long only. |
--legend |
SPEC |
— | Place one legend, repeatable. SPEC is KIND=POSITION[,ARRANGEMENT][,SIZE] with KIND one of compare, saccades, colors (the fixation colour categories), size-key; POSITION one of auto, above, below, left, right, top-left, top-right, bottom-left, bottom-right (the last four inside the plot); ARRANGEMENT stacked or side-by-side; SIZE the text size in px — e.g. --legend saccades=right,stacked,14. Whether a legend is drawn at all is still its own switch. |
--saccade-classes |
CLASSES |
— | Draw only these reading classes, comma-separated, e.g. --saccade-classes regression,return_sweep (classes: forward, skip, refixation, return_sweep, regression, other). Hidden classes lose their line and their direction arrow. Default: all. |
--saccade-arcs |
switch | — | Draw saccades as upward arcs (the linear-reading diagram) instead of straight connectors. |
--snap-fixations |
switch | — | Snap each fixation above the word it lands on instead of its raw gaze point. |
--illustration |
switch | — | Apply the clean schematic preset: snapped fixations, arced saccades, uniform colors, and no analytical overlays. |
--illustration-label |
{auto,show,hide} |
auto |
Auto-label transformed/schematic figures, force the label, or explicitly hide it (default: auto). |
--illustration-text |
TEXT |
— | The Illustration label's text (default: "Illustration · <reasons>"). |
--palette |
{default,print,high-contrast} |
— | Color palette for the marks (the app's Palette): default (colorblind-safe, Okabe–Ito), print (grayscale, survives a B&W print) or high-contrast. The app's own names work too. Individual --*-color flags override it. |
--color-by |
FIELD |
— | Fixation column to color by, e.g. duration_ms, or 'line' to color each fixation by its text line (same as --color-by-line). Default: '(uniform)', one flat color, since marker size already shows duration. |
--fixation-color |
COLOR |
— | Flat fixation marker color used when --color-by is (uniform) (default: #0072B2). |
--fixation-symbol |
{circle,square,diamond,triangle-up,cross,x,star,hexagon,heart} |
— | Fixation marker shape. Unlike color, shape survives a grayscale print (default: circle). |
--heatmap-metric |
COLUMN |
— | Heatmap weighting: the fixation duration column — under your file's name or as duration_ms (the default) — or counts. |
--heatmap-style |
{word-boxes,interpolated} |
— | Heatmap geometry (default: word-boxes). |
--heatmap-sigma |
PX |
— | Gaussian σ in px for --heatmap-style interpolated (default: 2% of the data's larger span, at least 8 px). |
--heatmap-colorscale |
NAME |
— | Heatmap color scale, e.g. Greens (default: Blues). |
--heatmap-norm |
{linear,log} |
— | Heatmap color scaling: linear (default) or log — log compresses heavy-tailed dwell times so a few hot words don't wash out the rest. |
--fixation-colorscale |
NAME |
— | Color scale for --color-by, e.g. Viridis (default: Blues). |
--marker-size-range |
MIN MAX |
— | Min/max fixation marker size in px, e.g. 4 12 (default: 8 24). Smaller ranges suit small thumbnails. |
--marker-size-scale |
{sqrt,linear,log,relative} |
— | How duration sets marker size (default: sqrt). sqrt / linear / log map --marker-duration-range onto --marker-size-range the same way for every figure, so one duration is one size across trials, comparisons and replays; sqrt makes marker area grow with duration. relative stretches each figure from its own shortest to longest fixation. |
--marker-duration-range |
LO HI |
— | Durations in ms given the smallest and largest marker on a fixed scale (default: 50 600). Shorter and longer fixations clamp to them. |
--no-duration-size-legend |
switch | — | Hide the duration-size key (reference circles labelled in ms) drawn on a fixed --marker-size-scale. |
--canvas |
WxH |
— | Monitor size in px, e.g. 2560x1440 (default: the source's screen — 2560x1440 for --sample/--onestop, 1680x1050 for --potec — else estimated from the data). |
--coordinate-grid |
switch | — | Overlay a monitor-pixel X/Y grid on the scanpath. |
--coordinate-grid-spacing |
PX |
— | Pin the major coordinate-grid interval in pixels. Implies --coordinate-grid; omit for automatic 1/2/5×10ⁿ spacing. |
--stimulus-image |
PATH |
— | Draw an image (PNG/JPG) as the stimulus background under the scanpath. By default it's stretched to the image's own pixel size (PNG) or the canvas; set --stimulus-image-size / -origin to place a crop precisely in fixation coordinates. |
--stimulus-image-size |
WxH |
— | Stimulus-image size in px, e.g. 1310x991 (default: the PNG's own pixel size, else the canvas). Use with --stimulus-image. |
--stimulus-image-origin |
X,Y |
— | Top-left of the stimulus image in monitor px, e.g. 305,44 (default: 0,0). Use with --stimulus-image to align a centered crop to the fixation coordinates. |
--stimulus-image-opacity |
O |
— | Stimulus-image opacity 0.1–1.0 (default: 1.0 = opaque). Lower it to dim a busy image so the fixations / saccades / word boxes read over it. |
--fixation-opacity |
O |
— | Fixation marker opacity, 0.1–1.0 (default: 0.7, so overlapping fixations show through). |
--hollow-fixations |
switch | — | Draw the fixations as outlines instead of filled markers. |
--color-by-line |
switch | — | Color each fixation by the text line it lands on (lines inferred from the word boxes); overrides --color-by. Same as --color-by line. |
--fixation-color-range |
LO HI |
— | Pin the --color-by color scale to LO..HI instead of the trial's own range, so several figures share one scale. |
--heatmap-range |
LO HI |
— | Pin the heatmap's color scale to LO..HI instead of the trial's own range. |
--order-font-size |
PX |
— | Fixation index label size (default: 10). |
--order-font-color |
COLOR |
— | Fixation index label color (default: #111111). |
--text-color |
COLOR |
— | Reading-text color (default: #000000). |
--highlight-text-color |
COLOR |
— | Color of the --highlight-column words under --critical-span-style mark-text (default: #D55E00). |
--span-border-color |
COLOR |
— | Box color under --critical-span-style mark-border (default: #000000). |
--background-color |
COLOR |
— | Plot background color (default: #ffffff). |
--line-spacing |
N |
— | Line slots each word box stands for, which sizes the reading text (default: 3 — OneStop's one blank line above and below). |
--no-scale-text-to-boxes |
switch | — | Draw the reading text at --font-size instead of sizing it from the word boxes. |
--word-hover-measure |
FIELD |
— | The reading measure a word's hover shows (default: total_fixation_duration_ms; '' for none). |
--word-heatmap-col |
COLUMN |
— | For a words-only dataset (no fixations): tint each word box by this numeric words column — e.g. gpt2_surprisal — instead of its dwell time. |
--word-heatmap-title |
TEXT |
— | Color-bar title for --word-heatmap-col (default: Value). |
--x-field |
FIELD |
— | Fixation column on the x axis (default: x). A non-spatial one draws a chart of the fixations instead of the scanpath. |
--y-field |
FIELD |
— | Fixation column on the y axis (default: y). |
--crop-to-data, --no-full-monitor |
switch | — | Frame the axes on the data instead of the whole --canvas monitor (the app's Crop to data). |
--no-fixation-colorbar |
switch | — | Leave out --color-by's color bar. |
--fixation-colorbar-orientation |
{vertical,horizontal} |
— | Fixation color bar: beside the plot (vertical, default) or below it. |
--fixation-colorbar-tickangle |
DEG |
— | Fixation color bar: tick-label angle, -90–90 (default: 0). |
--fixation-colorbar-tickfont-size |
PX |
— | Fixation color bar: tick-label size (default: 12). |
--no-heatmap-colorbar |
switch | — | Leave out the heatmap's color bar. |
--heatmap-colorbar-orientation |
{vertical,horizontal} |
— | Heatmap color bar: beside the plot (vertical, default) or below it. |
--heatmap-colorbar-tickangle |
DEG |
— | Heatmap color bar: tick-label angle, -90–90 (default: 0). |
--heatmap-colorbar-tickfont-size |
PX |
— | Heatmap color bar: tick-label size (default: 12). |
--raw-gaze |
PATH [PATH ...] |
— | Raw (sample-level) gaze table(s) to draw under the fixations, columns auto-detected like --fixations (same formats; several paths or a quoted glob concatenate). Static figures and --compare-with comparisons, where each scanpath's samples take its color (not --animate). On its own (no other input) it is the dataset: its trials are listed and drawn as recorded — no fixations are detected from the samples. |
--no-raw-gaze |
switch | — | Load the --raw-gaze table but hide its layer — the app's 🔵 Raw gaze switch turned off. With raw gaze as the only input the figure then draws no gaze. |
--sample-raw-gaze |
switch | — | With --sample: draw the bundled demo's raw gaze (synthesized, for one trial — the one the app overlays it on). |
--raw-gaze-schema |
JSON |
— | Column mapping for the --raw-gaze table, replacing auto-detection (same shape as --fix-schema); needed only when a column isn't recognized. |
--word-box-color |
COLOR |
— | Word-box outline color (default: #6c757d). A comparison outlines each scanpath's boxes in its own color instead. |
--word-box-line-opacity |
O |
— | Word-box outline opacity, 0–1; 0 draws the fill only (default: 1). Below 1 the outline color must be #rrggbb, #rgb or rgb(r, g, b). |
--word-box-fill-color |
COLOR |
— | Word-box fill color, drawn at --word-box-fill-opacity: #rrggbb, #rgb or rgb(r, g, b) (default: #646464). |
--word-box-fill-opacity |
O |
— | Word-box fill opacity, 0–1; 0 draws outlines only (default: 0.05). |
--raw-gaze-color |
COLOR |
— | Raw-gaze sample color (default: #888888). A comparison draws each scanpath's samples in its own color instead. |
--raw-gaze-marker-size |
PX |
— | Raw-gaze sample size, 1–12 (default: 4). |
--raw-gaze-opacity |
O |
— | Raw-gaze sample opacity, 0.1–1.0 (default: 0.6). |
--width |
PX |
— | Image width in px for PNG/SVG/PDF (default: the figure's own size). Use with --height for fixed-size thumbnails. |
--height |
PX |
— | Image height in px for PNG/SVG/PDF (default: the figure's own size). |
--scale |
X |
2.0 |
Raster pixel-density multiplier (PNG/SVG/PDF; default: 2.0). |
--width-mm |
MM |
— | Print width of a PNG in mm, drawn at --dpi (replaces --scale). |
--width-in |
IN |
— | Print width of a PNG in inches, drawn at --dpi. |
--dpi |
N |
— | Resolution of --width-mm / --width-in (default: 300). |
--font-size |
PX |
16 |
Base figure font size (default: 16). |
--font-family |
NAME |
— | Font for all figure text (default: monospace). |
--title |
TEXT |
— | Title band stamped on the figure; off by default. The figure grows to make room rather than shrinking the plot. |
--caption |
TEXT |
— | Caption band stamped on the figure; off by default. |
--separable-layers |
switch | — | Also write the figure split into one file per layer (word boxes / fixations / saccades / heatmap / labels / stimulus image) in a <output>_layers/ folder, so each can be restyled in Illustrator / Inkscape. Static image output only (.svg/.pdf/.png); the layers register when stacked. |
--playback-speed |
X |
1.0 |
Animation speed multiplier for --animate (default: 1.0 = real time). |
--no-autoplay |
switch | — | With --animate: start the replay paused (press ▶ Play to run it). By default the saved HTML autoplays on load at the playback speed. |
--anim-grid-step-ms |
MS |
— | With --animate: emit a frame every MS of reading time (default: 100). Smaller is smoother and larger to export. |
--anim-max-frames |
N |
— | With --animate: cap the frame count at N (default: 360). A long trial coarsens the grid to stay under it. |
--print-code |
FLAVOR |
— | Print the API / CLI code that reproduces this figure to stdout (python | cli | both), then render as usual. Only the options that differ from the defaults are written. |
--print-code-explicit |
switch | — | With --print-code: write every figure option at its current value instead of only the non-defaults. |
Comparison: draw a second scanpath beside or over the first
| Option | Value | Default | Description |
|---|---|---|---|
--compare-with |
PARTICIPANT:TRIAL |
— | Compare against a second scanpath, named as participant:trial. Taken from the loaded dataset unless --compare-words/--compare-fixations name a second one. |
--compare-screen |
SCREEN_ID |
— | Screen of the second scanpath's multipart trial (default: its first screen), looked up in its own trial. --screen picks the first scanpath's. Each scanpath is drawn from one screen. |
--compare-layout |
{overlay,side-by-side,stacked} |
overlay |
How the two scanpaths are arranged (default: overlay). Across two datasets, overlay needs both canvases to be the same size — two different canvases are refused rather than silently split, so pass side-by-side or stacked for them. Matching canvases that a dataset never recorded still overlay, with a warning. |
--compare-stimulus |
{both,a,b} |
both |
On an overlay, whose word boxes and text to draw (default: both). Two datasets' word boxes coincide only when the text is identical. |
--label-a |
TEXT |
— | Name for the FIRST scanpath in the legend and hover, instead of the default. Applies to the comparison figure and the --animate co-animation. Requires --label-b. |
--label-b |
TEXT |
— | Name for the SECOND scanpath in the legend and hover, instead of the default. Requires --label-a. |
--compare-legend, --no-compare-legend |
switch | — | Draw the legend naming the two scanpaths (the app's A/B legend; on by default, as in the app). Applies to the --animate co-animation too. |
--style-a |
SPEC |
— | Styling for the FIRST scanpath, repeatable: KEY=VALUE[,...]. Colors (#RRGGBB): fix_color, saccade_color, box_color (word-box outline; default fix_color), box_fill_color (default --word-box-fill-color), raw_gaze_color (default fix_color). Also heatmap_colorscale (default --heatmap-colorscale, on the shared range), saccade_style (solid|dash|dot|dashdot), saccade_width (px), marker_size_range (MIN:MAX), opacity (0.1–1), hollow (true|false). E.g. --style-a fix_color=#D55E00,opacity=0.5. --animate uses them too, except box_color, box_fill_color and raw_gaze_color. |
--style-b |
SPEC |
— | Styling for the SECOND scanpath, repeatable: KEY=VALUE[,...]. Colors (#RRGGBB): fix_color, saccade_color, box_color (word-box outline; default fix_color), box_fill_color (default --word-box-fill-color), raw_gaze_color (default fix_color). Also heatmap_colorscale (default --heatmap-colorscale, on the shared range), saccade_style (solid|dash|dot|dashdot), saccade_width (px), marker_size_range (MIN:MAX), opacity (0.1–1), hollow (true|false). E.g. --style-b fix_color=#D55E00,opacity=0.5. --animate uses them too, except box_color, box_fill_color and raw_gaze_color. |
--compare-fixation-flag |
SPEC |
— | Filters & highlights for the SECOND scanpath only, repeatable; same SPEC as --fixation-flag, e.g. --compare-fixation-flag short=discard,threshold_ms=80. Replaces --fixation-flag for B. |
--compare-saccade-classes |
CLASSES |
— | The reading classes the SECOND scanpath draws, comma-separated (same names as --saccade-classes). Replaces --saccade-classes for B. Not with --animate, which draws every class. |
--compare-fix-index-range |
START:END |
— | Draw only fixations START through END of the SECOND scanpath (1-based, inclusive). Replaces --fix-index-range for B. |
--stimulus-image-b |
PATH |
— | The SECOND scanpath's stimulus image, for a side-by-side or stacked comparison across two datasets (each panel draws its own page). Sized and placed like --stimulus-image. |
--stimulus-image-size-b |
WxH |
— | Size of --stimulus-image-b in px (default: the PNG's own size, else --compare-canvas, else --canvas). |
--stimulus-image-origin-b |
X,Y |
— | Top-left of --stimulus-image-b in the second screen's px (default: 0,0). |
--compare-words |
PATH [PATH ...] |
— | Words table(s) for the SECOND dataset. Same formats and globbing as --words. |
--compare-fixations |
PATH [PATH ...] |
— | Fixations table(s) for the SECOND dataset. Same formats and globbing as --fixations. |
--compare-raw-gaze |
PATH [PATH ...] |
— | Raw gaze table(s) for the SECOND dataset, drawn under B's scanpath. Same formats as --raw-gaze; with no second dataset, --raw-gaze already covers both scanpaths. |
--compare-dataset-name |
NAME |
Dataset B |
Label for the second dataset, used in the trace names (default: 'Dataset B'). |
--compare-canvas |
WxH |
— | Second dataset's monitor size in px, e.g. 1680x1050. Read off its data when omitted. An overlay, or an --animate co-animation, compares this against --canvas. |
cache — every flag
Options
| Option | Value | Default | Description |
|---|---|---|---|
--path |
switch | — | Print the cache folder and exit. |
--json |
switch | — | Print the status as JSON. |
--clear |
switch | — | Delete the recovery cache. |
corpus, check and version are listed in full in their own sections above.