Skip to content

Pull request for HRF Toolbox and RSA Toolbox#88

Open
Michael-Sun wants to merge 138 commits into
canlab:masterfrom
Michael-Sun:master
Open

Pull request for HRF Toolbox and RSA Toolbox#88
Michael-Sun wants to merge 138 commits into
canlab:masterfrom
Michael-Sun:master

Conversation

@Michael-Sun

Copy link
Copy Markdown
Contributor

No description provided.

Michael-Sun added 30 commits May 4, 2026 12:52
…pipeline-for-usability

Refactor HRF_Est_Toolbox2 with simple end-to-end pipeline API
…pipeline-for-usability-xttmq9

HRF estimation: bug fixes, robustness improvements, and new end-to-end HRF_Est_Toolbox2 pipeline
…pipeline-for-usability-fqntqa

Fix HRF entrypoints and plotting; add HRF_Est_Toolbox2 end-to-end pipeline and helpers
…pipeline-for-usability-vy57ks

HRF estimation: bug fixes, robustness improvements, and new HRF_Est_Toolbox2 pipeline
…pipeline-for-usability-8jw8bf

HRF estimation: bug fixes, plotting/indexing fixes, and new end-to-end HRF pipeline
…pipeline-for-usability-mpelg5

Add HRF_Est_Toolbox2 end-to-end pipeline and fix multiple HRF function bugs
…pipeline-for-usability-6u4wev

Add HRF_Est_Toolbox2 pipeline and bugfixes across HRF fitters
Fix typo
Michael-Sun and others added 30 commits June 26, 2026 16:47
Compute core of the causality pipeline (IO-free, unit-testable). Takes
per-run node timeseries + per-node HRF kernels, deconvolves each run,
optionally removes the task-evoked component, runs Granger per subject
(pooling that subject's runs), and aggregates directed net-flow across
subjects with a one-sample t-test + BH-FDR.

EvokedMode = both|remove|keep implements the "compute both and compare"
choice: 'remove' regresses neural-level task regressors out of the proxy
(endogenous coupling), 'keep' uses the full proxy. Validated on synthetic
ground truth (A->B, shared task drive, C independent): true A->B is
strongly significant in both modes; the comparison exposes that removal
trades common-drive robustness for SNR. Stats-toolbox-free (betainc tcdf).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
End-to-end driver over a study output directory:
- builds each node's deconvolution kernel from the sFIR score CSVs
  (group-mean curve, condition-averaged by default);
- extracts the matching node timeseries from each run's 4-D BOLD --
  signatures via hrf_apply_maps_to_wholebrain (same loader used in
  scoring, one row per volume), atlas regions via apply_parcellation;
- builds an unconvolved per-condition task design from the BIDS events
  for the evoked-mean removal;
- prunes nodes missing/constant in any run to keep kernels and every
  run's timeseries column-aligned;
- calls hrf_causality_analyze (deconv -> per-subject Granger -> group
  one-sample t + FDR), EvokedMode 'both' by default.

Unit = signature | atlas; Nodes/Atlas selectors; MaxRuns for smoke tests.
Kernel-building verified on the real acceptmap score CSVs (44 sig nodes,
21 conditions); the IO calls (apply_parcellation [T x regions];
hrf_apply_maps_to_wholebrain accepts plain fmri_data) verified against
source. Full real-BOLD run pending a faster-than-UNC connection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Heatmap (net flow, significant cells boxed) + directed circular graph
(arrow i->j for each significant positive net edge, width/colour by
magnitude; falls back to top-N by |net| dashed when nothing is sig) +
net-drive ranking bar (row-sum of net = source vs sink). Accepts an
hrf_causality/_analyze struct (Mode selects evoked mode, PField p_fdr/p)
or a bare net matrix. Diverging colormap + F/t significance via the
struct's p fields; no toolbox deps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
One wordcloud frame per peristimulus lag from map_<set>_<term> score
columns (built for Neurosynth term maps): each term sized by its score
at that lag, coloured by sign (red +, blue -). Terms sit at FIXED spiral
positions ordered by overall importance, so only size/colour animate --
you see associations grow and fade as the HRF unfolds, no layout jitter.

Input: a score CSV, an input_table (pooled group-mean across subjects),
or a direct struct(scores,terms,lags). Set/Condition/Model/Object/TopN/
SizeBy selectors; writes .mp4/.avi/.gif (MPEG-4 with Motion-JPEG-AVI
fallback). Validated on synthetic terms with staggered lag peaks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three coupled additions so directed connectivity is computed where it is
scientifically meaningful -- within a task state, pooled across bodysites:

- hrf_causality now accepts a CELL of output dirs and pools their subjects
  (same subject id across dirs combines that subject's runs), e.g.
  {lf_distractmap, obs_distractmap}. Kernels are pooled across dirs.
- 'Condition' restricts Granger to the event blocks of a trial_type
  (glob; e.g. 'rest_stim', 'nback-stimblock'). Per-run condition masks are
  built from the BIDS events and passed to analyze, which splits each run's
  proxy into the contiguous blocks (>= MinSegLen) and treats each as a
  separate GC realization -- no autoregression across block gaps.
  hrf_causality_analyze gains 'Segments'/'MinSegLen' and now records
  .subjects; per-subject GC is wrapped in try/catch.
- hrf_causality_contrast(R1,R2) compares two results' per-subject net flow:
  auto PAIRED one-sample t on shared subjects (within-subject design),
  else unpaired Welch two-sample; aligns on shared nodes; output plugs
  straight into hrf_plot_causality. Handles BOTH rest_stim-vs-nback
  (within-data) and acceptance-vs-experience (between-dir) contrasts.

Validated on synthetic ground truth: block-restricted GC recovers a
condition-specific A->B far better than whole-run (t 6.6 vs 3.9); the
paired contrast of coupled-vs-none recovers the difference (t=5.8,
p_fdr=.002) and the unpaired fallback triggers on disjoint subjects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Thin wrapper over hrf_make_average_montage_animations that pools the
whole-brain HRF maps of one OR MORE output directories before averaging:
collects each dir (hrf_collect_wholebrain_outputs), concatenates on common
columns (same subject id across dirs pools that subject's runs -- e.g. both
bodysite dirs of distractmap), and renders per-condition group (and optional
subject) montage animations over the peristimulus lags. All rendering /
stat options pass straight through. Conditions are the FIT-condition labels
in the map metadata (e.g. rest_stim_ttl_1, nback-stimblock_ttl_1).

Pooling validated on lf+obs distractmap (66+78 records -> 7 shared subjects,
144 records). Map loading/rendering runs where BOLD access is fast.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the mediation method alongside Granger, as scoped (flexible outcome).

- hrf_mediation_analyze: IO-free core. Per-subject OLS paths (a, b, c, c',
  ab) then a one-sample group t on each (standard two-level mediation);
  single-subject/pooled falls back to a trial bootstrap of the indirect
  effect ab. Stats-toolbox-free. Validated on ground truth (true ab
  recovered p=1e-6, null ab ns, bootstrap CI excludes 0).
- hrf_causality_mediation: driver. Reuses hrf_causality's BOLD->proxy
  extraction (new 'ReturnData' early-exit, so no second 4-D load),
  deconvolves each run, takes per-trial node amplitudes over each event's
  window, and resolves X/M/Y from a node name, a BIDS events column
  (temp/rating), or 'condition:<glob>' -- so stimulus->region->rating,
  node->node, and condition-effect mediation all use one API. Accepts dirs
  (pooled) or a prep struct.
- hrf_causality: 'ReturnData' returns per-run tsRuns/kernels/nodes/subjects/
  events_files/TR for reuse; tracks the per-run events file.

End-to-end validated on synthetic stim->med->rating through deconvolution:
ab=0.63 p=1.3e-5, 84% mediated, direct effect collapses; null mediator ns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Third causality method: estimates a deterministic bilinear DCM (SPM) on a
small user-specified node set and returns posterior endogenous connectivity
as a directed net-flow result that plugs into hrf_plot_causality /
hrf_causality_contrast.

- Uses the RAW node timeseries (DCM has its own hemodynamic model) via
  hrf_causality 'ReturnData'; builds DCM.U box inputs from the BIDS event
  onsets at microtime (TR/Bins); A=full / C=all / B=none|all|<condition>
  configurable; per-run spm_dcm_estimate -> Ep.A.
- Converts SPM's A(target<-source) to i->j and reports net = A - A'; group
  one-sample t across subjects + FDR. Returns .gcm (cell of estimated DCMs)
  for spm_dcm_peb group inference.
- MaxNodes guard (DCM doesn't scale); EXPERIMENTAL at study scale.

VALIDATED on synthetic ground truth: spm_dcm_estimate converges on the
constructed struct and recovers an injected node1->node2 influence
(net=+0.59 Hz, group p=0.012, correct sign); output renders via
hrf_plot_causality. Completes the Granger/mediation/DCM method trio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
source can now be an output directory or a CELL of directories/input
tables, collected (hrf_collect_wholebrain_outputs) and concatenated on
common columns into one group-mean over every subject of every dir --
same multi-dir convention as hrf_pooled_wholebrain_animation / hrf_causality.
Previously only a single CSV / input_table / struct was accepted.

Validated on real distractmap data (lf+obs pooled, Set='neurosynth',
condition nback-stimblock_ttl_1): 30 terms x 64 lags, sensible profile
(working/executive/phonological + heat/noxious/faces) animating over the HRF.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Term selection is now significance-based instead of an arbitrary top-N:
a one-sample t across SUBJECTS is computed at each (term,lag) from the
per-subject means, and a term is shown at the lags where its association
is significant (it lights up over the HRF), selected only if significant
at >=1 lag.

- New params: Threshold (default 0.05), Correction ('fdr' BH across terms
  within each lag | 'none'), Persist (false: draw a term only where
  significant; true: always draw, greyed sub-threshold). TopN is now a
  legibility CAP (default 60) applied after the statistical selection.
- Pooling reworked: per-SUBJECT term matrices (average that subject's
  runs/files) are stacked for the group t (was a flat average over files).
- Single CSV / struct (no group) -> warns and falls back to top-N by
  |score|; "none significant" also falls back so the movie isn't empty.
- Output gains .t/.p/.sig/.nsubj/.selection.
- GIF fix: build ONE global colormap from all frames at close, so colours
  survive when the first frame is near-blank (no sig terms yet) -- the new
  gating exposed that per-frame palettes collapsed reds/blues to grey.

Validated on synthetic 8-subject data: only the planted signal terms are
selected, per-lag sig counts track the bump (0 at early/late lags), and
peak-frame text renders red.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the naive Archimedean-spiral placement (words centred on spiral
points, ignoring their size -> overlap) with a greedy collision-avoidance
packing like a static wordcloud: each word's bounding box is measured at
its MAXIMUM font (peak over lags), then placed largest-first, spiralling
outward to the first slot that overlaps nothing already placed. Because the
layout reserves max size, later frames only shrink words -> positions stay
fixed and the packing never overlaps (tight at each term's peak lag,
breathing open in troughs). Matches the wordcloud_stat look while keeping
the animation stable. Bigger canvas (1000x760) for headroom.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes "No subject had usable trials" when Y (or X) lives on a DIFFERENT
event than the trial anchor. In the WASABI paradigm the pain 'rating' is
recorded on 'intensity_rating_start' events, not on the heat blocks, so
Y='rating' was all-NaN for stimblock trials and every trial was dropped.

Now every numeric events column is resolved per trial with nearest-event
PAIRING: the trial row's own value if finite, else the nearest event that
has a finite value (preferring the next one within 'PairWindow' seconds,
default 90). So a heat trial links to its subsequent rating. New PairWindow
param; docstring steers TrialType to the block ('nback-stimblock'/'rest_stim')
rather than '*stimblock*' (which also grabs zero-duration *_ttl_* markers).

Validated on real distractmap events + synthetic proxy: trials now usable,
temp->NPS a-path recovered (0.83, p=.004); previously errored out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signature extraction applied ALL maps in the config (44 signatures + 38
imageset maps) to every run, then kept the wanted columns -- so a mediation
with M='NPS' still did 82 pattern-expressions per 4-D BOLD. Now a one-time
subset image_vector is built holding just the requested node maps (searched
across the signature sets AND imagesets, named by node) and only those are
applied per run; falls back to the full apply if it can't be assembled.
hrf_causality_mediation passes just its X/M/Y node specs as Nodes (events
columns like temp/rating and 'condition:' specs are resolved later, not
extracted), so 'X','temp','M','NPS','Y','rating' extracts ONE map/run.

The 841 MB BOLD load per run is unchanged (inherent); this removes the
~82x-redundant apply. Validated: subset for {temp,NPS,rating} -> 1 map
(NPS), column map_imageset_NPS matches node NPS; checkcode clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per-lag FDR under-corrects the lag family and relies on a t-distribution
untrustworthy at n~7-11. Adds sign-flip permutation correction over the
WHOLE term x lag surface, now the default:

- Correction='permutation' (default): max-t FWER (Nichols & Holmes 2002),
  exact by enumerating all 2^n flips for n<=13; each subject's whole matrix
  is flipped so lag/term correlations are preserved under the null.
- Correction='cluster': temporal cluster-mass sign-flip (Maris & Oostenveld
  2007) for sustained effects.
- Also 'fdr' (per-lag, prior default), 'fdr_all' (whole-surface BH), 'none'.
- Nperm (random flips when 2^n too large), ClusterFormP.
- Group stats keep the per-subject stack; output gains .p_corr/.correction.
  No group -> per-lag FDR -> top-N fallback (honest 'none survived' label).

Validated (8-subj synthetic, 5 signal + 15 noise): permutation and cluster
select 5/5 signal with 0 false positives; per-lag FDR leaks 2, uncorrected 8.
Pure-null data: nothing survives (FWER controlled). Recommend the 54
Ke-Bo-2024 topic maps (Set='neurosynth_topics_fi') to shrink the 525-term
family and regain power at small n.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… API

Adds one canonical group-inference engine and routes every group-stats
site through it, so the whole API shares small-n-appropriate correction
instead of ad-hoc parametric t + FDR.

hrf_group_stats(stack,...): per-subject stack [dims... x nSubj] ->
est/t/p/p_corr/sig. Correction = 'permutation' (sign-flip one-sample /
label two-sample, FWER via max-|t| over a Mask'd family, exact by
enumerating all 2^n flips for n<=13), 'cluster' (temporal cluster-mass
along ClusterDim), 'fdr', 'fdr_all', 'none'. Design one/two-sample.
Validated: connectivity edge FWER, term x lag cluster, two-sample.

Wired in (new Correction/GroupNperm params, default 'fdr' = prior BH so
behavior is unchanged unless opted in):
- hrf_causality_analyze + hrf_causality: net-flow edges, off-diagonal family
- hrf_dcm: same
- hrf_causality_contrast: paired -> one-sample sign-flip; unpaired -> label
  permutation
- hrf_mediation_analyze (+ driver): per-path sign-flip (Correction default
  'none' parametric; 'permutation' opts in), no cross-path family
- hrf_plot_causality unchanged (its p_fdr field now carries the chosen
  corrected p)

Validated end-to-end: analyze A->B perm p_corr=.0078 (=1/128 floor at n=8);
mediation ab perm p=.0005 (n=12); paired contrast perm p_corr=.0078.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t terms

Add a 'Unit' selector so the animation can visualize any score family, not
only Neurosynth map_ columns:
  - 'imageset' (default): map_<Set>_* -- Neurosynth terms/topics, hansen22,
    bucknerlab networks, etc. (unchanged default behaviour)
  - 'signature': sig_<Set>_* (e.g. Set='all' -> NPS, SIIPS, ...)
  - 'atlas': atlas_<Set>_<region>_<Suffix> -- the words are region names;
    'Suffix' (mean|meanL1|sum, default mean) picks the summary and is stripped
    from the label.
Set is now interpreted per Unit (imageset name / signature set / atlas token).
Default Title adapts ("<Set> regions/signatures/maps over the HRF"). Networks
and imageset image names already worked via Set (they are map_ columns).

Validated on a synthetic CSV mixing all three families: atlas -> region
names (strips _mean, excludes _meanL1/_se), signature -> NPS/SIIPS (excludes
_se), imageset -> terms; no-Unit default unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hrf_animate_wordcloud:
- PrettyLabels (default true): display names undo makeValidName-style
  sanitization for the words -- camelCase / underscores / hyphens -> spaces
  ('SensoryStimulation'->'Sensory Stimulation', 'Ctx_V1_L'->'Ctx V1 L',
  'RegionA'->'Region A'). Raw tokens kept in out.terms; pretty in out.labels.
- ReturnFrames option -> out.frames (RGB per lag), out.title/.condition, so
  the montage can composite frames without a file round-trip.

hrf_animate_montage (new): render several per-lag animations side by side,
advanced TOGETHER so every tile shows the same peristimulus lag. Panels:
'wordcloud' (any Unit/Set -- terms, topics, networks, signatures, atlas
regions, via ReturnFrames), 'movie'/'brain' (per-lag frames read from an
existing montage movie/gif, e.g. hrf_pooled_wholebrain_animation output), or
'frames' (given). Pads tiles (no distortion), auto grid, per-tile + super
titles. Toolbox-light: local uint8 conversion; labels via insertText only if
present. Validated: 3 synced wordcloud panels (terms/signatures/regions),
1x3 grid, one movie.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
For a subject-stacked rsm (.dat k x k x N) counts, in each RSM cell /
grouping-block / contrast, how many subjects meet a criterion -- the
paper-ready "in 9/11 subjects hot patterns were more self-similar than to
warm" summary. Returns BOTH a count-MAP (matrix to imagesc) and a
count-TABLE (one row per cell) with count/proportion AND the group effect +
group p (via the shared hrf_group_stats permutation engine).

All the options requested are available:
- Granularity: 'blocks' (groupings -> GxG), 'full' (k x k conditions),
  'contrasts' (a list; supports within-vs-between DIFFERENCE contrasts, the
  core RSA claim).
- Criterion: 'sign', 'threshold', or 'permutation' (per-subject within-RSM
  label-permutation significance).
- Table content: count + proportion + group_mean/t/p/p_corr/sig; group
  Correction fdr|permutation|none. RDMs auto-oriented so 'more similar' is
  consistent; Fisher-z auto for correlation RSMs; mean/median/sum reduction.

Validated on synthetic blocked RSM (hot/warm/imagine, N=8): within>between
contrasts 8/8 with group p=2.6e-9; sign/threshold/permutation criteria and
blocks/full/contrasts granularities all correct.

Next (index over brain regions / model RDMs) will be companion functions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes the subject-consistency count family across all three RSA indices
the user asked to have available -- RSM cells (count_map), candidate MODEL
RDMs (count_models), and brain REGIONS (count_regions):

- @rsm/count_models: per-subject fit of a data RSM to candidate model RDMs
  (rsm array, numeric, or metadata column -> same-vs-different). Counts how
  many subjects each model WINS (argmax) and is significantly related
  ('sign'/'threshold'/'permutation' per-subject label-perm). Orients data and
  models to a common similarity space; group effect via rsm_group_stats. The
  count analogue of @rsm/compare's Nili-2014 group RFX.

- @rsm/count_regions: takes an ARRAY of per-region rsm's (e.g. rsa_parcelwise
  .per_parcel_rsms), runs count_map per region for a contrast/cell, and
  assembles a region count-table with group p FDR-corrected ACROSS REGIONS
  (rsa_parcelwise scope). With an atlas it paints statistic_image count-maps
  via assign_vals_to_atlas so threshold/montage/table just work.

- count_map: adds 'doplot' (imagesc heatmap w/ counts, or bar for contrasts)
  and routes group stats through new @rsm/private/rsm_group_stats -- uses the
  shared hrf_group_stats engine when present, else a built-in one-sample
  t+FDR, so the RSA toolbox no longer hard-depends on the HRF pipeline.

Validated on synthetic subject-stacked RSMs (N=8): count_models picks the
condition model 8/8 wins (r=0.77) over a random RDM (0 wins); count_regions
flags the 2 structured parcels (8/8, p~1e-8, sig) and rejects the 2 noise
parcels; all doplot paths render.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rsa_oo_demo walks through how the RSA/RSM tools extend the CANlab object model:
fmri_data --compute_rsm--> rsm (new first-class object with its own method
surface) and fmri_data --rsa_parcelwise--> statistic_image maps that flow back
into the standard threshold/region/montage/table chain.

Upgrades over the prior draft:
- New section 7: the subject-consistency reporting layer -- count_map (per-cell/
  contrast counts + group p) and count_models (which model RDM wins per subject).
- Section 8 now runs a REAL rsa_parcelwise + count_regions: it borrows a sample
  dataset's brain geometry (emotionreg volInfo), plants a condition x bodysite
  structure, parcellates with a canlab2024 subset, and paints statistic_image
  maps + an atlas count-map -- replacing the earlier random-value stand-in.
- Header diagram/requirements updated to include the count_* methods.

Runs end-to-end in R2025b (verified): count_map hot>warm 9/9 (p=3.6e-14),
count_models condition wins 9/9 over bodysite, rsa_parcelwise -> statistic_image
-> montage, count_regions -> FDR-corrected region count-table. .mlx regenerated
from the .m so the two stay in sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The n~7-11 per-lag HRF summaries reported uncorrected per-timepoint t-tests.
Add a small adapter, hrf_time_correction(D, 'Correction',...), over the shared
hrf_group_stats engine and wire it into the three timecourse tests so per-lag
inference gets a consistent, small-n-appropriate multiple-comparison
correction -- sign-flip / label max-|t| FWER, temporal cluster-mass, or FDR:

- hrf_time_unfolding_stats: 'Correction'/'Nperm' params; adds .p_corrected /
  .significant_corrected (one-sample), and .group_p_corrected /
  .group_significant_corrected for the two-group case.
- hrf_2x2_study_score_stats: 'Correction'/'Nperm'; each simple/main/
  interaction contrast gains .p_corrected / .significant_corrected, and the
  contrast_table gains an n_significant_corrected column.
- hrf_compare_conditions: 'Correction'/'Nperm'; two-sample correction across
  the A-vs-B timepoints, adds .p_corrected / .significant_corrected.

All default to 'none' (original per-timepoint behavior preserved; corrected
fields are additive). Validated on planted-bump synthetic timecourses: cluster
and permutation recover exactly the true lag window where uncorrected leaks an
adjacent lag; two-sample and 2x2 interaction paths confirmed.

Deferred (documented): hrf_curve_summary_groupstats (metric table already has
FDR/Bonferroni; per-subject identities not retained post-collapse, so max-t
FWER would need re-pivoting the raw table) and hrf_make_average_montage_animations
(operates on group mean/sem/n, not the per-subject stack, so sign-flip
permutation would require replumbing the cached-wholebrain pipeline; keeps
parametric + FDR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hrf_oo_demo walks through how the HRF pipeline plugs into CanlabCore's object
model, mirroring rsa_oo_demo for the HRF side:

- hrf_fit_all_models: fit fir/sfir/canonical HRF curves (+ model SE) to a
  timeseries; recovered shapes plotted against the ground-truth HRF.
- fmri_hrf: HRF condition x lag beta maps as a first-class fmri_data SUBCLASS
  (built in real brain space); HRF-aware disp, and inherited fmri_data methods
  (get_wh_image slicing, apply_parcellation) just work.
- statistic_hrf: the paired t-side via make_fmri_stat_hrf, a statistic_image
  SUBCLASS -> threshold/region/montage on a sliced condition x lag t-map.
- hrf_time_unfolding_stats with 'Correction','cluster': corrected per-lag group
  inference through the shared hrf_group_stats engine (the new wiring).
- Pointers to deconvolution->Granger causality, misspecification metrics, and
  whole-brain condition x lag animation.

Runs end-to-end in R2025b (verified): sfir recovers peak lag 6; fmri_hrf /
statistic_hrf construct and subclass correctly; threshold->region works; per-lag
cluster correction recovers the planted 8-14 s window (8 uncorrected -> 7
corrected). .mlx generated from the .m; README links both.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first draft under-sold the toolbox. Rebuilt hrf_oo_demo to mirror the actual
WASABI DistractMap "HRF Estimation Animations and Atlas Regions" workflow, with
each headline feature driven off the objects:

- S4 HRF ANIMATION straight off the object: hrf_make_montage_animation takes an
  fmri_hrf slice (get_wh_image of a condition's lag volumes) -> condition x lag
  brain movie (the "animations" half), no NIfTI path needed.
- S5 ATLAS REGIONS via inherited apply_parcellation: fmri_hrf -> [volumes x
  regions] -> per-region HRF curves + |peak| ranking (the object-level version
  of plot_hrf_atlas_curves' RankBy summaries). Recovers the planted HRF per
  region at r=1.00.
- S6 group statistic_hrf: stack subjects' condition x lag betas, one-sample t
  per volume -> a statistic_hrf of group t-maps (the object core of
  hrf_make_average_montage_animations' .group_t) -> threshold/region/montage.
- S7 corrected per-lag inference (hrf_time_unfolding_stats 'Correction') kept.
- S8 documents the full on-disk study API with the ACTUAL DistractMap calls:
  plot_hrf_atlas_curves / plot_hrf_curves (RankBy hrf_match|auc_abs|peak_t|
  n_sig|snr|shape_r2, atlas/signature/imageset sources, condition contrasts),
  hrf_curve_summaries + hrf_curve_summary_groupstats, hrf_make_average_montage_
  animations, hrf_animate_wordcloud (FWE), hrf_causality/_contrast/_mediation.

Runs end-to-end in R2025b (SHOW gates the brain movies): region curves r=1.00,
focal group t-map (5693/6000 planted voxels), per-lag cluster correction
recovers exactly the planted 8-14 s window (7 vs 7). .mlx regenerated from .m.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge with current CANLab Core
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.

1 participant