Skip to content

Releases: lacclab/scanpath-studio

v0.25.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 05:39

Added

  • Standalone desktop app (ENG-15) — a double-clickable PyInstaller bundle per OS (Windows / macOS-arm64 / Linux; no Python install needed, data stays local): desktop/ launcher + spec + icons + smoke test, built and attached to releases by the new Desktop builds workflow. Design in plans/eng-15-desktop-app.md.

Changed

  • Docs overhaul — branded MkDocs Material theme (app palette + logo, nav tabs, grouped sections), a landing page with feature cards and a fresh app screenshot (README screenshot refreshed too), and a dedicated Desktop app page with per-OS install steps. Stale claims fixed: the two-view layout (was "three tabs"), OneStop part names, PoTeC reader ids (also in the --potec CLI help).

Install/upgrade: pip install -U scanpath-studio

v0.24.0

Choose a tag to compare

@github-actions github-actions released this 03 Jul 14:12

Added

  • Comparisons subtab (ENG-8) — score the selected scanpath against other scanpaths of the same text, grouped by a Comparison column you pick (regime / repeated-reading id / model generation / participant / trial); closest shown, ranked by NLD. Line assignment (drift-correction grid) is now its own top-level subtab.
  • Corpus Analysis (AN) — question-oriented views Per text · Per reader · Groups (profile one cohort or compare two): metric distributions + word profiles, per-text heatmaps pooled over readers, reader summaries, and group differences with effect sizes; shared measure / aggregation / spread pickers with 95% bootstrap CI bands.
  • Image-based stimuli (VIZ-4) — show a stimulus image on any dataset: an upload overrides a dataset's built-in image; image_path / image_x / image_y columns declare native per-trial images; Align to text (X/Y offset + scale) and an opacity slider fit/dim it.
  • Colour saccades by reading type (VIZ-8) — Uniform / By type (forward · skip · refixation · return-sweep · regression), editable class colours, optional legend.
  • "Linear reading" view (VIZ-9) — arched saccades + snap each fixation above its word.
  • Animated replay autoplays on load (VIZ-10) — at the configured speed; an Autoplay on load checkbox turns it off. Slider is now a linear time scrubber with an elapsed/total-seconds readout (VIZ-11).
  • Vertical drift correction (PRE-3) — the ten Carr et al. (2021) line-assignment algorithms, applied in place or compared in the Line assignment subtab.
  • Separable-layer export (VIZ-5) — one file per layer (boxes / fixations / saccades / heatmap / labels / image) that register when stacked.
  • Heatmap colour scaling: Linear or Log (VIZ-3).
  • Public OneStop corpus (DATA-3) — all four regimes, seven parts, two variants; shareable via deep link. The bundled demo now ships per-trial stimulus images.
  • Data sidebar reorganized (DATA-8/9) — one flat source picker tagged by kind, one ordered ⚙️ Configure group, native folder picker; plus stable trial selectors + annotation markers (UX-5/6), a quick-view preset indicator (VIZ-12), a configurable word-hover measure (VIZ-13), and a px-vs-pt font note (VIZ-1).

Every feature reaches all surfaces: UI · deep-link + Share · Save & restore · CLI · headless API.

Changed

  • Save & restore configs are versioned (ENG-11) — a schema version + migration on load; a newer config restores best-effort with a warning.
  • Word labels are left-aligned in their AOI box (was centered) so they coincide with the stimulus image + fixations.
  • Author list (ENG-14) — full co-author set with affiliations in the About panel, CITATION.cff, and README.
  • Slightly larger small text (VIZ-2).

Fixed

  • Branded theme applies from any launch directory (BUG-6) — injected as --theme.* flags, so python -m scanpath_studio from anywhere renders the pinned blue theme instead of Streamlit's default red.
  • Bulk export no longer skips trials whose words don't join (VIZ-5) — a fixations-only / non-joining-words dataset now exports instead of reporting "empty data".
  • Large uploads no longer OOM-crash the hosted demo (BUG-5) — a pre-parse size guard warns and asks to confirm above ~25 MB.
  • MultiplEYE stimulus text alignment (BUG-3), the bundled-demo stimulus-image vertical origin, and "No data found" when run outside the repo root (default data dirs anchored to the project root).

Docs


Install/upgrade: pip install -U scanpath-studio

v0.23.0

Choose a tag to compare

@github-actions github-actions released this 24 Jun 09:01

Added

  • Stimulus-font install hint — when a dataset declares its typeface
    (MultiplEYE), a note under Text font names the font, links a download, and
    gives per-OS install steps. The overlaid labels only match the stimulus image
    pixel-for-pixel when that exact font is installed (the browser otherwise falls
    back per script, so a CJK font's half-width Latin — URLs/digits — drifts); the
    note also points to the stimulus image as the reliable fallback.
  • Corpus Analysis — question-oriented analysis sections (AN-1…28) — the single
    Aggregated Views subtab is replaced by four sections, each answering one
    question, plus the WIP Generations tab:
    • Per text (one text, many readers): stacked per-reader word profiles with an
      optional cohort-mean overlay, a word × reader heatmap, the cohort word profile
      with a spread band, word difficulty tinted on the true-to-scale stimulus, a
      per-word measure-vs-linguistic-feature scatter (surprisal / frequency / length /
      POS) with a trend line, and skip / regression-in rates per word.
    • Per reader (one reader, many trials): measure distribution vs the cohort
      (violin/box), a reading-speed summary card with cohort percentiles, fixation
      duration over time, the saccade-amplitude × fixation-duration density scatter,
      progressive vs regressive saccades per trial, the landing-position (PVL) curve,
      and this reader's per-trial trend.
    • Per group (a cohort): pooled distributions, the group word profile, a
      per-reader summary table, and the group trend (optionally with per-reader lines).
    • Group comparison (two cohorts): overlaid distributions, the per-word A−B
      difference profile (diverging colormap + zero line), paired summary bars with
      error bars, an effect size + significance test (Cohen's d, Welch t-test /
      Mann–Whitney; exploratory), and a stacked two-group word heatmap.
    • Cross-cutting controls every section reads: a shared measure picker
      (TFD/FFD/FPRT/RPD/n_fixations/skip/regression-in/out + fixation duration /
      saccade amplitude), mean/median/sum aggregation and SD/SEM/IQR/bootstrap-CI
      spread, a z-score within reader normalization toggle, a min-readers/min-trials
      guard, and a per-view tidy-table CSV download. Groups are defined either by
      splitting a categorical field or by two independent filter sets. The per-text
      stimulus view now honours the active global_* visualization settings instead
      of hard-coded display options (AN-28). Adds scipy for the group tests.
  • Saccade line width — a width slider (0.5–10 px, default 2) in the Saccade-style
    popover, threaded through every plot, bulk export, save/restore, and deep links
    (per-scanpath in comparisons); plus headless --saccade-color/--saccade-style/
    --saccade-width CLI flags and a plot_scanpath(saccade_width=…) kwarg.
  • Show full monitor toggle — frame the plot to the whole presentation monitor
    instead of cropping to the data extent (single, animated, comparison, bulk export).
  • MultiplEYE corpus supportload_multipleye(), the in-app Public datasets
    picker, and the Add dataset wizard (browser upload) load the multilingual
    reading corpus (identity parsed from folder/file names, one trial per stimulus
    page, character AOIs aggregated to word boxes), with its comprehension questions,
    pre-aggregated reading measures (IA_*), reader metadata, and a true-to-scale
    stimulus-page background image.
  • OneStop public dataset — the Public datasets picker now offers the
    OneStop 360-participant
    English corpus, downloading the paragraph-level interest-area + fixation
    reports from OSF on demand (regime-selectable:
    ordinary / information seeking / repeated / information-seeking-repeated),
    rendered true-to-scale on OneStop's 2560×1440 monitor. Distinct from the
    env-var $ONESTOP_DATA_DIR server bundle. See docs.
  • Public datasets (PoTeC + MultiplEYE) shown by default (SCANPATH_PUBLIC_DATASETS=0
    to hide). Schema auto-detection now recognizes MultiplEYE columns.
  • MultiplEYE server-bundle source — a URL-addressable multipleye data
    source (?source=multipleye) for deep-linking a review app straight into the
    viewer at a given participant + trial. Gated on $MULTIPLEYE_DATA_DIR pointing
    at a raw export root, it reuses the native MultiplEYE loader (same raw frames,
    schema auto-detection, and authoritative 1920×1080 monitor) as the public
    source — so it renders identically — and fast-paths to a single session for
    ?participant (resolved case-insensitively). Exposed on every surface: the
    sidebar source list, the Share/deep-link round-trip, and headless
    render --source multipleye [--export DIR]. Mirrors the OneStop server
    bundle.
  • Upload-wizard helpers — derive trial/participant ids from the filename
    (delimiter split or regex) and aggregate character AOIs into word boxes.
  • Fixation classification (visual only) — under the Fixation controls, flag
    short / long / out-of-bounds fixations and either highlight them (chosen
    marker + colour) or discard them from the plot, with editable short/long
    duration thresholds. Affects only what's drawn — measures and exports are
    unchanged. Replaces the old out-of-text marker toggle.
  • Drag-to-reorder trial chips — an inline ✏️ Edit chips popover beside the
    chip strip (replaces the sidebar picker): drag fields between Shown and
    Available and reorder within Shown. The chip strip's More dropdown now
    holds the full chip list (so any chip clipped at the line edge is always
    reachable) alongside the summary stats.
  • Column mapping surfaces auto-detected columns per field (and flags when
    you've overridden the detected default).
  • Fixation marker opacity — an opacity slider (global + per-scanpath, default
    0.7) replaces the Hollow circles toggle, so overlapping fixations show through;
    threaded through every plot, animation, comparison, bulk export, save/restore and
    deep links.
  • Fixation-index window on the main plot — a range slider in the Fixation popover
    draws only fixations (and their saccades) within the chosen order_in_trial range,
    applied to the single, animated and comparison views; chips/panels keep the full trial.

Changed

  • Public-datasets picker reworked (DATA-4…7) — the corpus list is now a
    searchable selectbox (shows each corpus' short name + a language · size
    caption, one-line description, and home link) that scales as more datasets are
    added; local/private upload stays the primary path. Each loader now shows
    an Expected files layout for its data directory and a found vs. Download
    status — a one-click ⬇ Download (PoTeC, OneStop) replaces the always-on
    Download if missing checkbox, so an already-downloaded corpus never re-checks
    the network. The per-source participant/text narrowing (PoTeC Texts/Readers,
    MultiplEYE Sessions/Stimuli) is gone — each source loads the whole corpus and
    the global Narrow by trial filters scope it. (The headless load_potec /
    load_multipleye keep their readers/texts/sessions/stimuli args.)
  • Internal: split app.py (4087 → ~1640 lines) into focused modules —
    deep-link/share/config → url_state.py, the upload wizard → wizard.py — and
    factored plot overlay layers into helpers. No behavior change.
  • Navigation streamlined — Corpus Analysis is a header toggle; Data Inspection
    and Share are Scanpath subtabs; the sidebar view-nav is gone.
  • Trial selection reworked into Filter → Pick — Text/Participant/condition
    filters narrow the pool, then one row picks the trial (dropdown + scrubbing
    slider + ◀ ▶); Browse-by modes removed.
  • Comparison styling moved into the per-layer Fixation/Saccade popovers, beside
    the single-trial controls.
  • Compare mode reworked. The second-trial selector sits above the chips and
    mirrors the main picker — trial id + ★ same-text / 👤 same-participant
    markers in the dropdown (ordered stars → same-participant → rest), index/N · id
    slider, ◀ ▶. The overlay/layout + show-A/B-legend config moved into a rail
    ⚙️ Compare popover; the A/B legend (static and animated overlay) is
    optional and hidden by default; the figure title is removed; each chip strip's
    trial id is coloured to its scanpath (replacing the A/B legend line). Color
    fixations by
    now works in compare too — it colours both scanpaths by the metric
    (shared scale), with the per-scanpath flat colour as the A/B marker outline; the
    redundant global saccade controls stay hidden.
  • Welcome tour walks the whole Scanpath screen in reading order (plot →
    selection → chips → rail → panels → sidebar); the redundant Exit button is
    gone (the ✕ closes it).
  • Styling & chrome polish — saccade arrows off by default, span-border colour,
    horizontal/rotatable colour bars, tighter control rail, less heading clutter,
    a dismiss ✕ on the welcome tour.

Fixed

  • MultiplEYE reading text now aligns with the stimulus image (BUG-3). The
    loader reads the real FONT_SIZE + font from the stimulus config and stamps
    them onto the data (stimulus_font_px / stimulus_font_family); on a dataset
    switch the app snaps its font controls to the exact size and CJK typeface (and
    off "scale text to boxes", since the precise px is known), so the word labels
    land on the printed text instead of being inferred ~3× too small in a generic
    font. The scale-text-to-boxes path also improved: the font is budgeted from
    the line pitch (not the glyph-tight box height) and the box-width cap is
    script-aware (full-width CJK vs half-width Latin, per word), so CJK corpora and
    mixed CJK+Latin lines size sensibly. OneStop sizing is unchanged.
  • Compare-mode fixations no longer turn black. The per-scanpa...
Read more

v0.22.0

Choose a tag to compare

@github-actions github-actions released this 18 Jun 22:48
002c1b3

Changed

  • Scanpath screen reworked for sidebar-closed use. Visualization controls
    moved out of the sidebar into a control rail beside the plot (per-layer
    styling in popovers; Animate / Compare as toggle + popover; quick views
    trimmed and stacked). Selection is a one-line row above the plot — Browse
    by
    pills · trial selectbox · a Filter trials popover — with the scrubbing
    slider (showing the trial id) below. The view nav is sidebar menu buttons.
  • Browse-by always offers Trial / Text / Participant: Text = one selectbox
    • a participant slider; Participant = the participant selector + a Pick by
      pill row.
  • Trial info → chips. The Trial Info subtab is folded into a configurable,
    trial-level Field = Value chip strip above the plot (identity, conditions,
    and summary stats — reading time, word / fixation counts, in-box fixations),
    including the participant id and the compared trial when comparing. Per-trial
    subtabs are now Annotations · Stimulus & questions · Export.

Fixed

  • Mark border span overlay draws even when Bounding boxes is off.
  • Animation starts paused at the configured speed instead of autoplaying.
  • CITATION.cff version kept in sync with the package.

Docs

  • README, docs site, AGENTS, the welcome tour, and in-code comments updated for the
    three-tab layout + control rail; headless API docstrings clarified (it renders
    the full figure by default; the app opens on a minimal first view).

Install/upgrade: pip install -U scanpath-studio

v0.21.0

Choose a tag to compare

@OmerShubi OmerShubi released this 18 Jun 07:37
14ac374

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 an st.toggle with 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_width migrated to the width= 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.toggle that 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 --potec load 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=1 to 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 slide...
Read more

v0.20.0

Choose a tag to compare

@OmerShubi OmerShubi released this 17 Jun 15:49

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.
  • 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

  • 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 use redraw=False (updating just those traces). The
    replay now actually runs at reading time ÷ speed.
  • Uploading a large EyeLink report no longer crashes the app. Reports with
    sentinel values (e.g. . in the CURRENT_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 a...
Read more

v0.19.1

Choose a tag to compare

@github-actions github-actions released this 14 Jun 10:37

Added

  • Zipped tables. Upload boxes now accept .zip archives (e.g.
    data.csv.zip) wrapping any supported format (csv/tsv/parquet/feather); a
    multi-member zip is concatenated like a multi-file upload.

Changed

  • Raised the max upload size from 500 MB to 5000 MB.

Fixed

  • Save & restore no longer crashes when files are uploaded — the upload
    widgets were being swept into the config's column mapping, which isn't
    JSON-serializable.
  • Highlighted text in Trial metadata and Paragraph & question (critical
    / distractor spans, difficulty / preview rows) is now readable in dark mode —
    the light highlight backgrounds now pin a dark text color instead of
    inheriting the theme's light one.

Install/upgrade: pip install -U scanpath-studio

v0.19.0

Choose a tag to compare

@github-actions github-actions released this 13 Jun 08:12

Added

  • Dark mode. Ships a polished dark theme for the app chrome (☰ →
    Settings → Appearance, or follows your OS). The scanpath plot stays light
    in both themes, so it always reproduces the experiment's stimulus faithfully.
  • Raw-gaze-only datasets. Upload just a raw-gaze table (no words or
    fixations) and visualize the gaze trace — the Scanpath Visualization tab draws
    the time-coloured gaze scatter, the trial picker and Data Statistics work off
    the raw gaze, and the fixation-only views (animation, Generations) show a
    "needs a fixations table" note.
  • Upload a config to restore it. The sidebar 💾 Save & restore panel gains a
    JSON uploader that re-applies a previously downloaded config — layers, coloring,
    sizing, text/highlighting, canvas, axes, trial selection, and annotations —
    silently skipping anything that doesn't fit the loaded data.

Changed

  • Reorganized layout & usability pass. The Animated Scanpath tab folds
    into the main tab (now Scanpath Visualization) as an Animate checkbox;
    bulk export moves to its own Bulk Export tab (with an export the whole
    dataset
    option); Multiple Comparison is renamed Generations (WIP).
    In the side panel: a Trial Info header (showing the compared trial's info
    too), the trial selectors below it, annotations above a collapsible metadata
    table, and an Export toggle. Participant-mode selection now offers trial
    index / text / trial id. Defaults flip to Fixation index off, saccade
    arrows on
    ; "Color fixations by line" is now a line option in Color
    fixations by
    ; Text-highlighting and Heatmap-style options grey out when their
    layer is off. The animation's playback speed, info box, and play / pause /
    restart + scrub controls all move into one place (speed + info under the
    Animate toggle, transport below the plot); default playback is now ×4. The
    monitor/font controls (renamed Experimental Setup) move under 📂 Data.
  • Plot configuration + Annotations merged into 💾 Save & restore. One sidebar
    panel saves the full figure configuration, all annotations, and the data
    source + column mapping + app version to a single JSON file (and restores the
    settings + annotations) — capturing more state than before (text sizing,
    highlighting, background).

Fixed

  • Animated scanpath text is now true-to-scale. Its transport controls used
    to shrink the equal-aspect plot, leaving the word labels oversized relative to
    the boxes; the figure now reserves the control space without shrinking the
    plot, so the animation matches the static view exactly.
  • The tutorial is now a guided spotlight tour. The welcome opens centered
    like a modal over a closed sidebar — appearing as soon as the page opens,
    not after the first full render; the following steps open the sidebar and
    drop to a corner card that scrolls the relevant panel into view and pulses
    an outline around it. The previous all-dialog style remains one constant
    away (tour.TOUR_STYLE = "dialog").
  • README trimmed and refreshed — a concise rewrite (264 → 157 lines)
    reflecting the current five-tab app, with a regenerated hero GIF and
    screenshot.
  • Simpler, more general column mapping. The Words/IA word-box mapping is now
    a single coordinate-format selector (edges ↔ origin+size) plus four fields
    instead of eight, and column auto-detection matches names case- and
    separator-insensitively (IA_LEFT, ia_left and Participant ID all
    resolve). Required-field markers now match what the loader actually needs.
  • Search-engine discoverability. Keyword-rich page title and tagline, so the
    <title> and the social/search description Streamlit Cloud serves to crawlers
    are no longer brand-only.
  • Mapping panels grouped under each upload box. On the Upload source each
    table's column-mapping panel now sits directly beneath its own upload box
    (Words/IA, Fixations, Raw gaze), raw-gaze mapping is a first-class peer, and
    every field has a ? tooltip describing what it is and how it's used.

Fixed

  • Animated scanpath order numbers no longer glide in from the top-left corner —
    they now snap on at their fixation. The labels render in a constant-length
    text trace, so a new number turns on in place instead of a fresh node
    flashing at the (0,0) origin before placement.
  • The tutorial's Skip/Done buttons now close the dialog instantly instead of
    leaving it on screen for the ~10 s full-app rerun.

CI

  • Leaner AppTest suite. Data-independent integration tests now boot the tiny
    synthetic trial instead of the bundled demo (~10x cheaper per boot, in a
    single run), cutting the AppTest file ~4x. The bundled-demo render still gets
    guardrail coverage.
  • Parallel test runs. pytest -n auto (via pytest-xdist) fans the suite
    across the runner's cores, roughly cutting the AppTest-dominated wall-clock to
    a third.
  • Faster dependency install. The test job installs with uv (cached)
    instead of pip, trimming the install step that now dominates each run.
  • Test on Python 3.14 (the version Streamlit Cloud runs); CI now runs on pull
    requests only. Added a supported-Python-versions badge to the README.
  • Added a pull request template (.github/pull_request_template.md) with a
    summary/verification prompt and a checklist mirroring the CONTRIBUTING and CI
    checks (tests, ruff, [Unreleased] changelog, dependency manifests).
  • The publish workflow now creates a GitHub release (with the matching CHANGELOG
    section as the body) on every v* tag, alongside the PyPI publish and Slack
    post; scripts/changelog_notes.py gained a --format markdown mode for it.

Install/upgrade: pip install -U scanpath-studio

v0.18.0 — Flexible dataset support + first-visit tutorial

Choose a tag to compare

@OmerShubi OmerShubi released this 12 Jun 23:08
eb3292b

Added

  • Flexible dataset support. Load multi-file datasets (several files, a list,
    or a glob — concatenated with a source_file tag), single-report datasets
    (words-only or fixations-only), stimulus-level word boxes (broadcast across
    participants), and AOI-sequence fixations (placed at word/character-box
    centers). TSV inputs are now read directly. The upload panel takes several
    files per table, and either table alone.
  • First-visit tutorial. A welcome dialog walks through the app's main
    surfaces on first entry (suppressed for embeds and deep links); replay it
    anytime via 🎓 Show tutorial at the bottom of the sidebar.

Changed

  • Raw data is shown while the column mapping is incomplete. A missing
    required column no longer halts the whole app — the uploaded tables render in
    the Raw Data tab so you can see the columns and finish the mapping.
  • About popover in the header. The LaCC Lab / Code pill links are replaced
    by a single ℹ️ About toggle with credits, the code link, citation guidance,
    and more from the lab.

Fixed

  • The animated scanpath now honours the fixation colour options (Color
    fixations by / by line, colorscale, colour range, colour bar) like the static
    plot; previously they only affected the image. Colours are pinned to the full
    trial's range so they stay stable during playback. Dual-overlay replays keep
    the flat A/B colours.

Install/upgrade: pip install -U scanpath-studio

Full notes: see CHANGELOG.md.

v0.17.0 — Headless CLI + Python API

Choose a tag to compare

@OmerShubi OmerShubi released this 12 Jun 23:08
7b26a84

Added

  • Headless CLI: scanpath-studio render builds one trial's figure straight
    to .html/.png/.svg/.pdf (or --animate for the HTML replay) without
    launching the app — --sample or --words/--fixations, --list-trials,
    per-layer --no-* toggles. Bare scanpath-studio still launches the app.
  • Public Python API: import scanpath_studio as sps
    load_scanpath_data, load_sample_data, list_trials,
    compute_word_metrics, plot_scanpath, animate_scanpath, save_figure
    the app's canonical figures, programmatically.

Install/upgrade: pip install -U scanpath-studio

Full notes: see CHANGELOG.md.