iEEG Toolkit: Goals & Specifications (Pre-Implementation)
This document turns the “Future directions” in ieeg-toolkit.md into a concrete, testable set of goals and specifications for evolving the iEEG GUI toolkit.
Scope
Interactive exploration of iEEG recorded from a 2D electrode grid, using:
Panel for app composition
Bokeh/HoloViews for plotting
cogpy.plot.*as the implementation home
The core UX is: select electrodes on a grid, inspect time series, and link into richer views (spectrogram/topomap) without losing interactivity on large recordings.
Goals
Deterministic dev fixtures: every viewer has a “known-good” example dataset for quick debugging and for responsiveness checks on large inputs.
Explicit schemas: GUIs consume a small number of named entities with stable dims/coords/attrs (no hidden transposes).
Composable widgets: selection, transforms, and viewers remain modular and are linkable via shared state (e.g. time cursor).
Performance by construction:
render budgets (downsampling),
avoid full materialization where possible (windowed compute),
predictable latency during selection changes.
Minimal IO assumptions: GUIs operate on in-memory
xarray/numpyobjects; IO belongs elsewhere.
Non-goals
Full Neuroscope2 parity (spike sorting, complete annotation systems, file browsing).
A universal viewer for all electrode layouts (start with 2D grids + multichannel).
Making decisions about canonical storage formats (this is GUI/data-model oriented).
Inputs: expected entities (summary)
This toolkit should standardize on a small set of entities (schemas defined in the datasets docs):
IEEGGridTimeSeries:xr.DataArraywith dims("time","AP","ML")(canonical target).MultichannelTimeSeries:xr.DataArraywith dims("channel","time").Optional:
GridSpectrogram4D+BurstPeaksTablefor linked time–frequency views.
For GUI development, these are expected to come from bundle constructors (see explanation/datasets/gui-bundles.md).
Component responsibilities (current + planned)
Current components (implemented)
ChannelGrid: selection state + modes; no rendering.ChannelGridWidget: electrode grid visualization + interaction; optional atlas image and background scalar.MultichannelViewer: stacked time series viewer with overview strip and downsampling.IEEGViewer: wiring layer: xarray → numpy, z-score, optional grid-driven selection + apply button.
Planned cross-cutting components (spec only)
TimeCursor(shared state):single “current time” and/or
(t0, t1)window shared by traces/spectrogram/topomap.
SelectionPolicy(pure compute):converts raw metrics and user intents (“top-N variance”) into a
ChannelGrid.selectedset.
TransformPipeline(view-time transforms):optional reref/filter/standardization applied as a view (not necessarily written back).
Feature specifications derived from “Future directions”
Each feature below includes a minimal contract and acceptance criteria.
1) Signal-driven selection
User story
“Given the current visible time window, select the top-N channels by variance (or by correlation to a seed channel).”
Inputs
sig_tcasxr.DataArrayor numpy view of shape(channel, time)(canonical for compute).Current time window
(t0, t1)from viewer state.Strategy parameters:
metric:"variance"|"correlation"n: intseed_channel: optional (for correlation)
Outputs
A set of
(ap, ml)pairs (or flat channel indices) that can be applied toChannelGrid.
Acceptance criteria
Deterministic on fixed input + seed (if randomness is used at all).
Uses only the current window (no full-recording scan unless explicitly requested).
If
nexceeds available channels, clamps gracefully.
2) Sorting (reordering displayed channels)
User story
“Reorder the stacked traces by AP, ML, variance, or correlation.”
Inputs
Current selected channel set.
Sorting key:
"AP","ML","variance","correlation_to_seed"
Outputs
Ordered list of flat channel indices passed to
MultichannelViewer.show_channels(...).
Acceptance criteria
Sorting does not change which channels are selected, only their display order.
Sorting is stable (ties deterministic).
3) Atlas placement improvements (atlas_mode="full")
User story
“Show the full atlas image and place the electrode grid in correct physical location, including asymmetric AP extent.”
Inputs
ap_coords,ml_coords(physical coords) and atlas placement metadata.
Outputs
Correct placement parameters (image origin + extent) used by
ChannelGridWidget.
Acceptance criteria
The same physical coordinate at two places (grid tick labels and hover labels) maps consistently.
Documented coordinate conventions: which direction is positive AP/ML, and image orientation assumptions.
4) Bad channel detection overlay (grid widget)
User story
“Flag likely bad channels on the grid (e.g., high kurtosis) and allow quick exclusion.”
Inputs
Metric computed per channel from the current window or full data:
e.g. kurtosis, RMS, line noise power proxy.
Outputs
A per-cell flag and/or scalar displayed on the grid:
color outline, hatch, or icon-like overlay (implementation-dependent).
Acceptance criteria
Bad-channel flags do not break selection interaction.
“Exclude bads” is reversible and does not destroy the underlying selection state.
6) Lazy loading / windowed materialization
User story
“Long recordings should not require full
.compute()to be viewable.”
Inputs
Potentially Dask-backed xarray arrays.
Current visible time window and rendering budgets (
detail_px,overview_px).
Outputs
View-time window extraction and downsampling.
Acceptance criteria
Large mode can run without materializing the full array in memory.
Window changes only compute what is needed for the view.
Explicitly document any “overview strip” assumptions (e.g., precomputed mean trace vs streaming).
Performance targets (guidance)
“Small mode”: viewer construction + first render should be near-instant.
“Large mode”: interactions should remain bounded:
selection changes should not rebuild the entire HoloViews object graph,
time window changes should not allocate full-resolution traces.
Bundle sizing guidance is specified in explanation/datasets/modes.md.
Compatibility notes / known tensions
Current examples and some code paths use
("time","ML","AP")in places. The spec target is("time","AP","ML")for grid-aware signals.The flattening convention (AP-major vs ML-major) must be defined once and tested because it affects:
ChannelGrid.flat_indicesstack(channel=("AP","ML"))orderingwiring between grid selection and trace display
Proposed roadmap (phased)
Schema hardening: choose canonical grid dims/flattening; add validation helpers.
Selection improvements: signal-driven selection + sorting + presets.
QC overlays: bad-channel metrics and grid overlays.
Linked views: shared time cursor + spectrogram + topomap.
Scalability: windowed compute + optional Dask-friendly paths.