v0.21.0
Added
- Scanpath Visualization screen redesign (cognitive-load pass). The plot now
sits full-width at the top; a Trial Selection panel below it gathers the
trial picker, the Filter trials controls (moved out of the sidebar), the
Compare with another trial toggle, and Animate in one place. The
per-trial panels became one full-width subtab bar under the plot —
Stimulus & questions · Annotations · Trial Info · Export. - Quick-view presets. One-click buttons in the Visualization panel
(Scanpath · Heatmap · Reading order · Everything) set the layers for a
focused picture instead of toggling each one. - Calmer default. First load now shows just the core scanpath (text +
fixations + saccades); the density Heatmap and the Bounding boxes grid
are off by default and one click (or one Quick view) away. - Layer toggles + inline styling. Each main layer (Fixations, Saccades, Text,
Heatmap, Bounding boxes, Raw gaze) is now anst.togglewith a bold label,
and that layer's styling appears inline only while it's on — no catch-all
"advanced" drawer. - Sidebar navigation. The top tab strip is replaced by a vertical menu at the
top of the sidebar (Scanpath Visualization · Corpus Analysis · Data Inspection),
removing the brittle client-side tab-persistence hack. - Consolidated Export. The standalone Bulk Export tab is folded into an
Export subtab with two sections — This trial (the live figure: static
PNG/SVG/PDF/HTML, or the HTML/GIF/MP4 animation) and Multiple trials (the
bulk export). Bulk export gained an HTML figure format, and its figure /
config / tabular pickers were modernized (pills + a toggle). - About in the sidebar. The About popover (version, authors, citation) moved
to the sidebar Help group; Share stays in the header. - Setup-wizard progress indicator. The upload wizard shows a native progress
bar + step checklist driven by the actual upload/mapping state. - Trial Info table. The trial id / participant / text now lead the metadata
table (renamed Trial Info); the separate header block is gone.
Changed
- Streamlit 1.58 and all dependencies bumped to current latest;
use_container_widthmigrated to thewidth=API. - Cohesive visual polish (gradient title, refined tabs / expanders / buttons,
pill-style id badges) that adapts to both light and dark themes.
Fixed
- Saccade direction arrows no longer draw when the Saccades layer is off.
- Highlight a span is now an on/off
st.togglethat reveals the
Mark-text / Mark-border choice only when on (the "None" option is gone).
Added
- One Data Inspection tab. The former Raw Data and Data Statistics
tabs are merged into a single Data Inspection tab that, top to bottom,
shows the headline dataset counts, every raw table (Stimuli, Word-level,
Fixation-level, Raw gaze), the per-metric summary statistics, and a new
Column mapping table. - Column mapping table. Data Inspection now lists how each source column was
mapped to the app's canonical fields (per table: Words/IA, Fixations, Raw
gaze) — so you can confirm at a glance which of your columns became the
participant, trial id, word box, fixation duration, and so on. - Share button. A Share popover in the header builds a link that reopens
the app on the current trial with your visualization settings (which layers are
on, the colorscales, animation). The link uses the existing deep-link URL schema
and a new?trial_id=param that lands on the exact trial regardless of how it
was picked; copy it from the popover and send it. Works for the bundled demo,
the synthetic trial, and the OneStop server bundle (an uploaded dataset can't be
rebuilt from a URL, so the link then shares the view settings only, with a note). - Stimuli view. A new Stimuli subtab (first under Data Inspection)
reconstructs each passage from the word table — one row per Text ID with the
full text rebuilt by joining its words in reading order, plus a word count.
It honours the column mapping (groups by the mapped Text ID, uses the mapped
word text) and dedupes shared stimulus words across readers. - Guided setup wizard for uploads. Uploading now walks you through an
incremental flow where only the step you still need to fill stays open
(finished and auto-detected steps tuck away). You name the dataset and set the
display up front, upload each table in its own toggle (each showing its row
count — "✓ N fixations detected — make sure this is the number you expect"),
then map the trial id, participants, texts, and required fields in collapsible
parts. After loading it collapses into a compact Data & mapping panel you
can re-open to tweak. - Reusable named datasets. Finishing an upload saves it (under a name you
choose) as a first-class data source. Switching between it, the bundled demo,
and other datasets is instant — no re-uploading or re-mapping. Add another via
the sidebar's ➕ Add data button. - Optional participant & text. Datasets without a participant column (a
single anonymous reader) or without a text/passage column now load and
visualize — the app fills sensible defaults and hides the Participant / Text
selectors when a dimension has only one value. The wizard maps Participants
and Texts in their own steps (mirroring the Trial id: one shared picker, an
opt-in per-table override, and several columns composable into one id). - Choose the text-highlight column. A new Highlight words by picker chooses
which per-word column (the OneStop answer span by default, or any boolean
column in your data) is marked on the reading text. - Pick the saccade colour. A colour picker under Saccades sets the saccade
line and arrow colour (two-trial comparisons keep their per-scanpath colours). - Saved configs record their export date (and the data source + app version),
shown when you restore one — including a confirmation line under the wizard's
Restore a saved setup box naming where the loaded setup came from. - Keep only the fields you need. The wizard auto-detects reading measures,
linguistic features and condition columns and lets you drop the ones you don't
need; everything unmapped is pruned before processing, which is the main
speed-up on wide datasets (hundreds of columns). - Dynamic trial filters. The Filter trials panel now offers a value
picker for whichever condition fields your dataset actually has (and which you
chose to keep), instead of a fixed set of OneStop-specific conditions. - Display calibration in the loading flow. The Experimental Setup
(monitor size, font, line spacing, background) is now part of the wizard, so
the scanpath is true-to-scale from the first render; it stays adjustable from
the sidebar afterwards. - PoTeC loader.
sps.load_potec(root, download=True)/
scanpath-studio render --potecload the Potsdam Textbook Corpus end-to-end
— its filename-encoded ids and separate character-AoI coordinates can't go
through the generic upload flow. An in-app Public datasets source (with
a dataset registry built for more corpora) ships feature-flagged off
(SCANPATH_PUBLIC_DATASETS=1to preview); it will be enabled in a future
release. - Step-by-step setup guide. The upload wizard now has a short guided
walkthrough — a ❓ Show setup guide dialog that explains each step (naming,
experimental setup, uploading, column mapping, and finishing). It opens
automatically the first time you set up a dataset in a session and is
replayable anytime. - Export your column mapping. A ⬇️ Download setup button next to Add
dataset saves the current column mapping to a JSON file you can re-apply to
similar data later via Restore a saved setup.
Changed
- Header buttons grouped together. The Share and About buttons in
the header now sit side by side with a small gap, instead of a wide blank
between them. - Much faster on large datasets. Switching trial, participant, or settings
on a big dataset (hundreds of columns, many trials) is now near-instant
instead of taking minutes — heavy work is cached and thinned, with a visible
loading spinner while the first render builds. - One Visualization controls panel. The former Advanced styling expander
is merged into Visualization controls, grouped by layer (Fixations,
Saccades, Text, Heatmap) with thin separators; per-layer size/colour/colorscale
controls sit under each layer, and the fixation/heatmap colour-range sliders
show whenever they apply (no longer gated behind Show color bars). - Clearer trial-id mapping. One shared Trial ID picker applies to every
table by default (with an opt-in Different trial-id columns per table toggle
that keeps the columns you already picked instead of clearing them), and
defaults to composing the participant and the finest passage id (paragraph,
plus a repeated-reading column when the data has one, so the two readings of a
paragraph stay distinct). If the per-table trial counts disagree the wizard
says so. - Tidier wizard. The mapping steps are grouped under Column mapping with
one collapsible part each (trial id, participants, texts, Column mapping:
Fixations, Column mapping: Text & Interest Areas, More text mappings,
More fixation mappings); a single cross-table Filter trials by picker
and a single Additional fields to keep picker replace the per-table
duplicates; the upload boxes are narrower; and uploaded data defaults to a
2560×1440 monitor. Niche fixation columns (pass index, saccade type/amplitude,
eye) are auto-detected under fields to keep rather than mapped by hand. - Integer colour ranges. The fixation- and heatmap-colour range sliders read
as whole numbers instead of long decimals. - Refreshed the welcome tour to match the current app (the Experimental
Setup / merged Visualization controls panels, the guided upload). - Simpler data-source picker. "Use bundled demo" is now Bundled Demo;
the synthetic trial is no longer offered as a fresh source; a grayed-out
Public Datasets entry previews what's coming. - Clearer Bulk Export controls. The whole-dataset and filtered scopes are
now both All / All filtered trials options inside the Trials to
include picker (no separate checkbox), and the Scope section ends with a live
"N of M trials will be exported" count. Figures are listed one per row
(PDF → SVG → PNG), default to PDF + Config only, the plot-config checkbox
is renamed Config with a short explanation, and the PNG-scale stepper is
compact and only shown when PNG is ticked. - Faster bulk figure export. Rasterizing PNG/SVG/PDF for many trials now
reuses one persistent Kaleido browser for the whole batch instead of
cold-starting Chrome per trial — quicker on large exports and no more
per-trial "Resorting to unclean kill browser." log noise. - Clearer, numbered setup steps. The wizard's sections are now numbered
(1 Dataset name → 5 Filter & keep), the "upload to begin" prompt moved to the
top of the upload step, and a tip points large-dataset users to running the
app locally (pip install scanpath-studio). - See your uploaded tables. Each table's upload box stays open after
uploading and previews its first rows, so you can sanity-check the columns;
the participant and text counts now carry the same "make sure this is the
number you expect to see" reassurance as the trial and row counts.
Fixed
- Animated scanpath replays at its real speed again. The Play button forced a
full figure redraw on every frame, so each frame also paid the ~50 ms cost of
re-rendering the static word boxes + labels; on a long trial that dwarfed the
per-frame budget and the replay crawled — far slower than its quoted time, and
the speed slider stopped helping above ~×4. Every animated trace is now full
length with not-yet-reached fixations masked out, so a frame only changes point
positions and Play can useredraw=False(updating just those traces). The
replay now actually runs atreading time ÷ speed. - Uploading a large EyeLink report no longer crashes the app. Reports with
sentinel values (e.g..in theCURRENT_FIX_PRECISION_MEASURE_*columns)
could read as a column mixing numbers and text, which crashed the cloud worker
when the table was displayed — a full report would die on the cloud while a
small one loaded fine locally. Uploaded CSV/TSV files are now parsed in a
single pass so the column type stays consistent. - Colour bars no longer squash the scanpath. Turning on Show color bars or
colouring fixations by a categorical field used to shrink the plot and throw
off its aspect ratio (the reading text then overflowed its word boxes). The
colour bar / legend now sits in reserved margin, so the plot keeps its true
scale either way. - Dropped the stale Reading regime line from the Text & question panel, and
fixed the per-trial annotations note that pointed at an Annotations sidebar
panel that no longer exists (it lives in 💾 Save & restore). - Word hover shows the real line number. The word tooltip used to always say
Line 1 because it read the sourceline_idxcolumn, which is usually a
constant. It now infers the visual line from the word-box layout (the same
clustering the by-line colouring uses), so each line reads correctly. - Fixation hover no longer shows Pass #NaN. The fixation tooltip dropped the
Pass line, which displayedNaNwhenever the data had no pass/reread column.
Removed
- Noise-flag auto-filtering. A mapped noise/validity column used to silently
drop "noisy" fixations from every view with no way to turn it off. It's gone —
every uploaded fixation is shown. If your data has such a column you can still
keep it (via fields to keep) and filter on it explicitly. - Trimmed the data views. Folding Raw Data and Data Statistics together
dropped the second statistics row (mean fixation duration / saccade amplitude
/ regression rate / reading speed), the fixation-duration distribution plot,
and the per-word measure picker, plus the per-table download buttons,
pagination banner, and descriptive captions — keeping the merged tab focused
on inspecting the tables and their mapping.
Install/upgrade: pip install -U scanpath-studio