Epoch reviewer Phase 1: interactive rejection + live ERP + apply/save#224
Open
jdpigeon wants to merge 1 commit into
Open
Epoch reviewer Phase 1: interactive rejection + live ERP + apply/save#224jdpigeon wants to merge 1 commit into
jdpigeon wants to merge 1 commit into
Conversation
Second half of the epoch-review UI (docs/epoch-review-ui-plan.md §0/§9) —
turns the static Phase 0 viewer into a working, teach-as-you-go cleaner.
Interaction (EpochReviewer, Canvas 2D + DOM overlay, OQ1):
- Click an epoch column to toggle it rejected (greyed trace + wash + ✕).
- Prev/Next navigation through epoch windows; column→ABSOLUTE index math is
offset-aware so the right epochs are dropped after paging.
- Amplitude gain control (clamped, traces can't bleed across lanes).
Live ERP preview (OQ6, client-side — the teaching payoff):
- LiveErpPane averages NON-rejected epochs per condition via the pure
meanTrace() over the Phase-0 buffer and redraws on every toggle. ZERO worker
round-trips (OQ2=2A, no runPython RPC); empty selection → flat line, no NaN.
Apply at "Clean Data":
- apply_rejection(epochs, drop_indices, bad_channels) in utils.py (epochs.drop
+ info['bads']), native-tested BIT-IDENTICAL to a manual MNE drop/bads.
- CleanEpochs carries {dropIndices, badChannels}; cleanEpochsEpic posts
apply_rejection (trailing ';' suppresses the Epochs PyProxy) → saves via the
existing write-back bridge (PR #222) → re-fetches arrays + stats. Local
selection clears after commit (fresh 0-based indices next round).
Bad-channel UI is Phase 2 — apply_rejection takes the param but the UI wires
badChannels: [] for now.
typecheck 0 · eslint 0 errors · vitest 44/44 · native pytest 14/14 · build green
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Phase 1 of the Interactive Epoch Review UI (
docs/epoch-review-ui-plan.md) — this is the phase that makes it a fully working, interactive epoch cleaner and delivers the onboarding payoff: click bad epochs and watch the ERP clean up live.Builds on Phase 0 (static reviewer, PR #223) and the write-back bridge (PR #222). Locked decisions implemented: OQ1 = Canvas 2D, OQ2 = extend dataKey / no RPC, OQ6 = live ERP computed client-side.
What you can now do (QA flow)
-cleaned-epo.fifto disk (via the PR Fix broken Clean→Analyze round-trip: persist cleaned epochs to host disk #222 bridge), refreshes stats.How it works
Changes
utils.py—apply_rejection(epochs, drop_indices, bad_channels)(epochs.drop+info['bads']), native-tested bit-identical to a manual MNE drop/bads.epochArrays.ts— puremeanTrace(buffer, meta, epochIndices, channel)ERP primitive (unit-tested vs manual mean, empty → zeros).EpochReviewer.tsx— now interactive/controlled: click-to-reject (grey wash + ✕), offset-aware navigation, amplitude gain (clamped, no lane bleed).LiveErpPane.tsx(new) — per-condition live ERP over non-rejected epochs; redraws on every toggle; NaN-guarded empty state.applyRejection()(trailing;),CleanEpochs({dropIndices, badChannels}),cleanEpochsEpicrewritten to apply → save → refresh.Out of scope (later phases)
Bad-channel flagging UI (Phase 2 —
apply_rejectiontakes the param, UI wires[]), auto-flag fromdrop_log(Phase 2), onboarding/guided mode (Phase 3).Verification
npm run typecheck— 0 errorseslint— 0 errors (2 benign warnings, incl. one pre-existing sidebar warning)npx vitest run— 44/44 (new:meanTrace, EpochReviewer overlay-click →onToggleEpoch)pytest tests/analysis/— 14/14 (4 newapply_rejectionbit-identical/drop-count/no-op/identity)npm run build— greenStacked on
epoch-reviewer-phase0(PR #223). 🤖 Generated with Claude Code