Add fmri_surface_data object for CIFTI/GIFTI surface & grayordinate data#86
Open
torwager wants to merge 6 commits into
Open
Add fmri_surface_data object for CIFTI/GIFTI surface & grayordinate data#86torwager wants to merge 6 commits into
torwager wants to merge 6 commits into
Conversation
Convert two quarantined standalone scripts into real matlab.unittest tests and move them into the discovered suite, and make the runner robust against non-test files that match the canlab_test_*.m glob. - image_vector/canlab_test_check_roi_extraction.m: converts old_to_integrate/check_roi_extraction.m. The original printed PASS/FAIL but never asserted. Now asserts multi-region 'unique_mask_values' extraction and invariance of the region averages across a write->reload round-trip (RelTol 1e-3 / AbsTol 1e-2 absorbs single-precision NIfTI rounding). Complements canlab_test_extract_roi (single-mask only). - image_vector/canlab_test_resampling_pattern_expression.m: converts old_to_integrate/resampling_pattern_expression_unit_test1.m, which only plotted. Now asserts SIIPS pattern expression is stable (corr > 0.99) across default/nearest/spline resampling; skips if SIIPS is unavailable. - helpers/canlab_safe_suite_from_file.m + canlab_run_all_tests.m: wrap TestSuite.fromFile so a stray non-test canlab_test_*.m is warn-skipped instead of throwing NonTestFile and aborting discovery of the whole suite. - canlab_test_runner_robustness.m: pins that behavior (non-test file -> warn + empty + ok=false; valid file -> loads). Old originals removed from old_to_integrate (jackknife_similarity_unit_test.m stays - it is a characterization/figure script, not a unit test). Full default suite after: 147 passed, 0 failed, 2 incomplete (pre-existing environment skips). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The five xval_*_unit_test.m files at the Unit_tests root were genuine tests (real assertions, no graphics, deterministic, bundled DPSP / synthetic data) but were plain-assert functions named outside the canlab_test_* convention, so the runner never discovered them. Convert each into a functiontests file under a new predictive_model/ subdir: the model is fit once in setupOnce (skipped via assumeTrue if the DPSP sample data is absent) and cached, and the assertions are split into focused test functions using tc.verify* for granular reporting. Behavior preserved. - predictive_model/canlab_test_xval_SVM.m - predictive_model/canlab_test_xval_SVR.m - predictive_model/canlab_test_xval_regression_multisubject.m - predictive_model/canlab_test_xval_regression_multisubject_featureselect.m - predictive_model/canlab_test_xval_discriminant_classifier.m - helpers/canlab_get_dpsp_hot_warm.m: shared DPSP Hot/Warm loader. Old xval_*_unit_test.m removed. New suite: 25 test points, all pass, ~7.5s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nperm) predictive_model_unit_test.m exercised the @predictive_model object's own public API (fit/predict/score/crossval/bootstrap/weight_map_object/ permutation_test/calibrate/select_features/grid_search/stability_selection/ pipeline/newapi routing/regression+report/summary). This is non-redundant with the xval_* tests, which cover the legacy wrapper functions rather than the object methods - so it is worth keeping. Convert to predictive_model/canlab_test_predictive_model_api.m: the shared fit -> crossval -> bootstrap chain is computed once in setupOnce and cached; the rest are focused test functions using tc.verify*; visualisation methods (plot/confusionchart/montage) are smoke-tested and skipped on a headless runner via canlab_classify_environment_error. Drop the bootstrap/permutation/stability counts to minimum-viable values (nboot 25->5, nperm 10->3, stability nboot 20->5) since this is a smoke test, not real inference; assertions are structural (shapes/ranges/p-floor), so the counts only need to exercise the code paths. Runtime 131s -> 73s locally; the residual cost is the high-dimensional (194,676-feature) cross-validation, not the resampling counts. Skipped if DPSP_hotwarm is not on the path. Old predictive_model_unit_test.m removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dominant cost was cross-validating on the full ~195k-voxel volume. In setupOnce, restrict hw_obj to gray matter (gray_matter_mask.img) and then deterministically thin to every 8th voxel (~20k features). hw_obj and X stay in lockstep, so weight_map_object / montage back-project consistently, and all assertions are structural so masking does not change them. Falls back to the full volume if the mask is not on the path. Runtime: 131s (original) -> 73s (minimal nboot/nperm) -> ~20s now. All 17 test points still pass; model behaviour unchanged (AUC ~0.83). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New CANlab object `fmri_surface_data` (subclass of image_vector), the surface/
grayordinate analogue of fmri_data. Wraps the HCP CIFTI grayordinate standard as
a true CANlab object with full fmri_data-style method parity, running natively in
MATLAB with no external toolbox (sole exception: ica, which needs GIFT/icatb like
the base class).
Highlights:
- Native CIFTI-2 + GIFTI readers/writers (Surface_tools/canlab_read|write_cifti|
gifti), bit-exact vs cifti_read/gifti oracles; proven to work with those tools
removed from the path.
- Object: construction from CIFTI/GIFTI/struct/key-value; brain_model replaces
volInfo (volInfo populated for the subcortical sub-block); no empty-squeezing
(.dat always full; remove_empty/replace_empty are no-ops).
- Interop: reconstruct_image, to_fmri_data, compare_space (0/1/2/3), write.
- Volume<->surface: vol2surf / surf2vol via vendored CBIG RF warps (vol->surf->
vol r~1.0), fully native.
- Data/analysis: cat/horzcat, mean, apply_mask, threshold (+cluster-extent 'k'),
ttest, regress, predict, ica (predict/ttest/ica delegate to fmri_data via a
proxy and remap results).
- Rendering: surface (native 4-panel + on any addbrain/MNI surface via volume
resampling), render_on_surface, plot; reparse_contiguous (mesh graph),
apply_parcellation, surface_region.
- Docs: docs/fmri_surface_data_{design_plan,methods}.md + runnable walkthrough.m.
- Tests: Unit_tests/surface_data/ (7 files, 41 tests passing).
Also: fix a stray non-functional debug line in @image_vector/ica.m that errored
ica() for all image_vector subclasses; document the fs_LR/fsaverage standard-mesh
correspondence in addbrain.m; add deprecation pointers in the external-dependent
Cifti_plotting readers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- docs/fmri_surface_data_methods.md: per-class methods page (properties + methods grouped by area), integrated into docs/Object_methods.md (class hierarchy + object-classes table) and docs/Workflows.md. - docs/workflows/fmri_surface_data_howto.md: intro workflow — load surface data and render it natively; map volumetric data to the surface (vol2surf) and back (surf2vol / to_fmri_data); parcellation, thresholding, and group analysis. Includes three rendered example figures. - Methods page includes a summarized inventory of surface atlases / maps available in the companion Neuroimaging_Pattern_Masks repository. - Sample data: bundle one small HCP Open Access group myelin map (Sample_datasets/CIFTI_surface_examples/) with a provenance README; additional surface atlases are resolved from Neuroimaging_Pattern_Masks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
New CANlab object
fmri_surface_data(subclass ofimage_vector) — the surface/grayordinate analogue offmri_data, wrapping the HCP CIFTI grayordinate standard as a true CANlab object. Runs natively in MATLAB with no external toolbox (sole exception:ica, which needs GIFT/icatb like the base class).What's included
CanlabCore/Surface_tools/canlab_*), bit-exact vscifti_read/gifti; verified to work with those tools removed from the path.brain_modelreplacesvolInfo(populated for the subcortical sub-block);.datalways full — no empty-squeezing (remove_empty/replace_emptyno-ops).reconstruct_image,to_fmri_data,compare_space,write.vol2surf/surf2volvia the vendored CBIG RF warps (vol→surf→vol r≈1.0), fully native.cat/horzcat,mean,apply_mask,threshold(+cluster-extentk),ttest,regress,predict,ica(predict/ttest/ica delegate tofmri_data+ remap).surface(native + any addbrain/MNI surface via resampling),render_on_surface,plot;reparse_contiguous,apply_parcellation,surface_region.docs/fmri_surface_data_methods.md(integrated intoObject_methods.md/Workflows.md),docs/workflows/fmri_surface_data_howto.md(with figures), plus developer docs + runnable walkthrough underCanlabCore/docs/.Sample_datasets/CIFTI_surface_examples/; other atlases resolve fromNeuroimaging_Pattern_Masks.CanlabCore/Unit_tests/surface_data/— 7 files, 41 tests passing (ica skipped when its toolbox is absent).Incidental fixes
@image_vector/ica.m: removed a stray non-functional debug line that madeicaerror for allimage_vectorsubclasses.addbrain.mhelp: documented the fs_LR/fsaverage standard-mesh correspondence.Cifti_plottingreaders.Notes / deferred (see design plan)
vol2surf/surf2voluse a fixed group MNI152↔fsaverage correspondence (not a per-subject ribbon mapper); fsaverage↔fs_LR deformation is a planned enhancement.fmri_surface_statistic_image/fmri_surface_atlassubclasses; CC0 TemplateFlow meshes.🤖 Generated with Claude Code