Skip to content

Interactive plotly foraging-session plots (trial-based + time-based)#104

Open
hanhou wants to merge 12 commits into
mainfrom
add-plotly-foraging-plots
Open

Interactive plotly foraging-session plots (trial-based + time-based)#104
hanhou wants to merge 12 commits into
mainfrom
add-plotly-foraging-plots

Conversation

@hanhou

@hanhou hanhou commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Interactive plotly foraging-session plots

Adds plotly counterparts of the matplotlib plotting functions, each mirroring its sibling:

  • plot_foraging_session_plotly — trial-based, mirrors plot_foraging_session (choice/reward raster + per-trial reward-probability schedule).
  • plot_session_in_time_plotly — time-based, mirrors plot_session_scroller (licks / rewards / go cues + smoothed overlays, with the reward-probability schedule in a bottom panel + rangeslider scroller).

Highlights (both functions):

  • Multiple sessions concatenate horizontally with a thick boundary line; per-session x-axis labels restart at 0.
  • Hover shows each event's (session, trial).
  • Ignored trials drawn red; horizontal scroll-zoom (scrollZoom, y locked).
  • Time-based reuses the trial-based 2-panel + scroller layout; pL (red) / pR (blue) reward-schedule lines, broken at session boundaries.

Interactive demos

Open in a browser (GitHub won't render plotly inline) — example mouse 802253 (graduated within 10 sessions):

Drag the bottom scroller to pan, its handles to zoom, scroll to zoom; hover for session/trial.

Tests

tests/test_plot_foraging_session_plotly.py covers both functions (single- and multi-session); existing matplotlib tests unchanged. flake8 clean.

Usage examples live in the companion reproduce_figures.ipynb (aind-dynamic-foraging-database).

hanhou and others added 10 commits June 6, 2026 21:41
Two plotly counterparts of the matplotlib plotting functions, each built to match
its sibling as closely as plotly allows:

- plot_foraging_session_plotly (new): trial-based, mirrors plot_foraging_session
  (choice/reward raster over the per-trial reward-probability schedule).
- plot_session_in_time_plotly (rewritten): time-based, mirrors plot_session_scroller.
  Adopts the scroller's y-layout, adds the reward-probability band (from df_trials),
  groups the four behavior rows contiguously so a single go-cue line spans them, and
  starts zoomed to a 120 s window at the first go cue with a rangeslider for scrubbing.

Filled traces use go.Scatter (Scattergl ignores fill="tonexty").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surface plot_foraging_session_plotly and plot_session_in_time_plotly alongside
plot_foraging_session for top-level import.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cover the trial-based plot (real session history, plus the optional bias band /
photostim path) and the time-based plot (events-only, and the df_trials path that
adds the reward-probability band).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…al hover

- Reward-probability band moved out of the main panel; it now lives only in the
  rangeslider "scroller" at the bottom, which auto-scales its own y so the band
  reads at a useful size.
- Lick / reward ticks shortened to 30% of the row height (70% shorter), centered
  on each row, so the four contiguous behavior rows stay legible when busy.
- Each go cue / reward / lick carries the trial it falls in (assigned via the
  go-cue windows) as customdata, surfaced on hover -- no on-plot text labels.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eslider

Auto-fitting the rangeslider over all rows left the reward-probability band a thin
strip at the top (most of the scroller blank). Pin the rangeslider's y-range to the
band region when a band is present, so the probability schedule fills the scroller;
fall back to auto when there's no band (events-only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refine plot_session_in_time_plotly:
- Add per-trial smoothed overlays in their own band above the event rows: gold
  pR/(pL+pR), black solid choice (smooth=5), black dashed lick count (smooth=5).
- Ignored trials (animal_response==2) draw a red go-cue line; responded ones green.
  Each event/go-cue carries its trial number on hover (no on-plot text).
- Reorder event rows like the trial figure: rewards at the outer edges, licks inside,
  right pair grouped at top / left pair at bottom; one go-cue line per trial.
- Reward-probability band shown only in the rangeslider scroller, colored left-red /
  right-blue (trial-consistent), pinned to ~half the scroller bar.
- nan-safe time extent (fixes a (0, NaN) rangeslider range from NaN event timestamps).
- Lock y (fixedrange) on both plotly figures for horizontal-only (scroll) zoom.
- Add a smooth_factor parameter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sion, trial) hover

- Add a rangeslider "scroller" under the trial-based figure (drag to pan/zoom).
- For multiple sessions, x tick labels restart at 0 each session.
- Choice-raster ticks and ignored/autowater markers now carry (within-session trial,
  session) and show it on hover.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, pL/pR lines

- Events / go cues now carry (trial, session) and show both on hover.
- Multiple sessions: x tick labels restart at 0 each session (nice-step ticks).
- Replace the filled reward-probability band in the scroller with two lines (pL red,
  pR blue), like the trial-based reward schedule, broken at session boundaries; the
  scroller y is pinned to those lines. (go.Scatter so they render in the rangeslider.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ller layout

Reuse the trial-based structure in the time-based figure: raster / curves on top
(row 1) over a reward-schedule panel (row 2) showing pL (red) / pR (blue) as 0..1
lines, broken at session boundaries, with the rangeslider scroller under row 2.
Legend moved outside top-left, horizontal, ~5 entries per row. Drops the old
high-parked band + pinned-slider hack.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reduce default width to 1000 for both plotly figures.
- Time-based: pin the title top-left and add top margin so it clears the legend;
  make the legend entries compact (smaller font, 125px entries).
- Trial-based: smaller legend font and more top margin for title separation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hanhou hanhou marked this pull request as draft June 7, 2026 07:05
hanhou and others added 2 commits June 7, 2026 07:07
CI interrogate requires 100% docstring coverage; the two nested helpers in
plot_session_in_time_plotly were missing docstrings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…agma trial-based

CI requires 100% coverage. Remove the now-unused _vlines helper, rewrite _nice_step
without the unreachable/edge branches, and mark plot_foraging_session_plotly with
`# pragma: no cover` (matching plot_session_in_time_plotly) since the visual plotting
functions aren't exhaustively unit-tested; the module helpers remain covered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hanhou hanhou marked this pull request as ready for review June 7, 2026 07:25
@alexpiet

alexpiet commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

looks great, thanks for updating your plotly functions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants