Commit cc8664b
feat: Show component counts in accepted/rejected toggle (#123)
* fix: Prevent backpressure deadlock in NIfTI header decompression
- Fix: Changed decompressHeader to use fire-and-forget write so reading starts immediately, preventing deadlock when large NIfTI files (100+ MB) buffer in DecompressionStream
- Enhancement: Added "registry.json" to RICA_FILE_PATTERNS so rica_server discovers RepetitionTime for frequency axis calculations
- Progress: Updated session log documenting the backpressure deadlock bug and fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: Narrow ICA components NIfTI filter to exclude echo-specific and derived files
Previously the filter matched any *_components.nii.gz containing "ica", which
caught echo-specific files (echo-1..5) and derived maps (ICAAccepted,
ICAAveragingWeights). These were all fetched unnecessarily — wasting bandwidth
and causing the last one to overwrite the correct niftiBuffer.
New pattern: must contain _desc-ICA_components.nii.gz and must not contain _echo-,
matching only the main ICA component map. Same logic applied to both the React
file filter/processing blocks and the rica_server.py discovery filter.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: Extract TR from NIfTI header before full file load
For very large NIfTI files that exceed browser memory limits, the full
arrayBuffer() call may fail, leaving repetitionTime null and causing the
power spectrum to display cycles/TR instead of Hz.
Fix by reading just the first 4096 bytes of the file/response to extract
the TR from the header, independently of loading the full file:
- File upload: use file.slice(0, 4096).arrayBuffer() before readFileAsArrayBuffer
- Server load: try a Range: bytes=0-4095 request before fetching the full file
4KB is sufficient to decompress the gzip stream enough to reach the NIfTI-1
(348 bytes) or NIfTI-2 (540 bytes) header containing pixdim[4] (TR).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: Load NIfTI via URL to avoid OOM errors with large files
Previously, Rica loaded the entire ICA components NIfTI into a JavaScript
ArrayBuffer before passing it to Niivue. For very large 4D NIfTI files
(hundreds of MB compressed, gigabytes uncompressed), this caused the browser
to run out of heap memory even when the local machine has plenty of RAM.
Fix by passing a URL directly to Niivue instead of an ArrayBuffer:
- Server mode: store '/' + filepath; Niivue fetches from localhost directly
- File upload mode: use URL.createObjectURL(file) to create a blob URL
that Niivue can load without a full ArrayBuffer copy in the JS heap
BrainViewer now accepts a niftiUrl prop (alongside the existing niftiBuffer
for backwards compatibility) and uses it directly in loadVolumes when present.
The same change is threaded through Plots, DecisionTree, and DecisionTreeTab.
This allows the local server to load maps for files that previously caused
OOM errors in the browser, since Niivue's internal (WebAssembly) decompression
is significantly more memory-efficient than the JS heap allocation path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: Decouple interactive views from NIfTI availability
Time series and FFT spectrum only require the mixing matrix TSV —
they don't need the NIfTI file at all. Previously, hasInteractiveViews
gated all three components on NIfTI availability, so any failure in
niftiUrl/niftiBuffer propagation would hide time series and FFT too.
Fix by separating the two checks:
- hasInteractiveViews: !!mixingMatrix?.data?.length (mixing matrix only)
- hasBrainViewer: !!(niftiBuffer || niftiUrl) (NIfTI required)
Time series + FFT always show when mixing matrix is loaded.
BrainViewer only renders when the NIfTI is also available.
This also improves UX for datasets where only TSV files are uploaded
(no NIfTI), which previously showed the static PNG fallback even though
the interactive time series and FFT could work perfectly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* revert: Restore niftiBuffer loading to fix missing brain viewer
The URL-based NIfTI loading optimization (niftiUrl) caused the brain
viewer to disappear because niftiUrl wasn't propagating correctly through
the component tree. Revert to the reliable niftiBuffer (ArrayBuffer) approach
which was working before.
The TR extraction from 4KB header slice is kept (previous commit) so the
power spectrum frequency axis still shows Hz correctly regardless of whether
the full NIfTI loads successfully.
URL-based loading for large files can be revisited separately once the
propagation issue is diagnosed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: Always set niftiUrl so brain viewer loads for large files
For very large NIfTI files, response.arrayBuffer() / readFileAsArrayBuffer()
can fail with OOM. Previously this left niftiBuffer null and caused the
brain viewer to not render.
Fix by always setting niftiUrl first (zero memory cost), then attempting
to load niftiBuffer. If the buffer load fails, niftiUrl is still set so
hasBrainViewer is true and BrainViewer can load directly from the URL
(server HTTP path or blob: URL from File object).
BrainViewer already prefers niftiUrl when present (previous commit).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: Restore original NIfTI filename filter (too narrow after previous change)
The filter was changed to _desc-ICA_components.nii.gz which is too strict
and misses files that don't follow exact BIDS naming (e.g. ICA_components.nii.gz).
Restore the original condition:
_components.nii.gz + ica in name + no stat-z + no echo-
This is identical to upstream/master except we added !echo- to keep the
echo-specific file exclusion that was added to rica_server.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: Show accepted/rejected component counts in toggle tabs
Display the number of currently accepted and rejected components
next to each label in the classification toggle switch (e.g.,
"Accepted (12)" / "Rejected (5)"). Counts update in real-time
as components are reclassified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Address PR review comments for component counter tabs
- Guard against indexOf returning -1 in ToggleSwitch highlight
- Default missing count keys to 0 with nullish coalescing
- Use single reduce pass instead of two filter calls for counts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>1 parent ad48bf5 commit cc8664b
2 files changed
Lines changed: 23 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
238 | 238 | | |
239 | 239 | | |
240 | 240 | | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
241 | 255 | | |
242 | 256 | | |
243 | 257 | | |
| |||
385 | 399 | | |
386 | 400 | | |
387 | 401 | | |
| 402 | + | |
388 | 403 | | |
389 | 404 | | |
390 | 405 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
| 13 | + | |
12 | 14 | | |
13 | | - | |
| 15 | + | |
14 | 16 | | |
15 | 17 | | |
16 | | - | |
| 18 | + | |
17 | 19 | | |
18 | 20 | | |
19 | 21 | | |
| |||
39 | 41 | | |
40 | 42 | | |
41 | 43 | | |
42 | | - | |
| 44 | + | |
43 | 45 | | |
44 | 46 | | |
45 | 47 | | |
| |||
49 | 51 | | |
50 | 52 | | |
51 | 53 | | |
52 | | - | |
| 54 | + | |
53 | 55 | | |
54 | 56 | | |
55 | 57 | | |
| |||
61 | 63 | | |
62 | 64 | | |
63 | 65 | | |
64 | | - | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
| |||
0 commit comments