Skip to content

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:

scanpath-studio --server.address 0.0.0.0

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):

scanpath-studio corpus --input profile.csv --kind profile --output profile.svg

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 &lt;output&gt;_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.