Skip to content

Add fmri_surface_data object for CIFTI/GIFTI surface & grayordinate data#86

Open
torwager wants to merge 7 commits into
masterfrom
canlab_fmri_surface_object
Open

Add fmri_surface_data object for CIFTI/GIFTI surface & grayordinate data#86
torwager wants to merge 7 commits into
masterfrom
canlab_fmri_surface_object

Conversation

@torwager

@torwager torwager commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

New CANlab object fmri_surface_data (subclass of image_vector) — the surface/grayordinate analogue of fmri_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

  • Native I/O: CIFTI-2 + GIFTI readers/writers (CanlabCore/Surface_tools/canlab_*), bit-exact vs cifti_read/gifti; verified to work with those tools removed from the path.
  • Object model: brain_model replaces volInfo (populated for the subcortical sub-block); .dat always full — no empty-squeezing (remove_empty/replace_empty no-ops).
  • Interop: reconstruct_image, to_fmri_data, compare_space, write.
  • Volume↔surface: vol2surf/surf2vol via the vendored CBIG RF warps (vol→surf→vol r≈1.0), fully native.
  • Analysis: cat/horzcat, mean, apply_mask, threshold (+cluster-extent k), ttest, regress, predict, ica (predict/ttest/ica delegate to fmri_data + remap).
  • Rendering: surface (native + any addbrain/MNI surface via resampling), render_on_surface, plot; reparse_contiguous, apply_parcellation, surface_region.
  • Docs: docs/fmri_surface_data_methods.md (integrated into Object_methods.md/Workflows.md), docs/workflows/fmri_surface_data_howto.md (with figures), plus developer docs + runnable walkthrough under CanlabCore/docs/.
  • Sample data: one small HCP Open Access group myelin map in Sample_datasets/CIFTI_surface_examples/; other atlases resolve from Neuroimaging_Pattern_Masks.
  • Tests: 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 made ica error for all image_vector subclasses.
  • addbrain.m help: documented the fs_LR/fsaverage standard-mesh correspondence.
  • Deprecation pointers in the external-dependent Cifti_plotting readers.

Notes / deferred (see design plan)

  • vol2surf/surf2vol use a fixed group MNI152↔fsaverage correspondence (not a per-subject ribbon mapper); fsaverage↔fs_LR deformation is a planned enhancement.
  • Optional future polish: dedicated fmri_surface_statistic_image/fmri_surface_atlas subclasses; CC0 TemplateFlow meshes.

🤖 Generated with Claude Code

torwager and others added 3 commits July 9, 2026 00:39
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>
Verified the whole object end-to-end (41 tests pass; walkthrough runs both with
and without Neuroimaging_Pattern_Masks). Fixes from the review:

- apply_mask: now falls back to the object's .mask property when no mask arg is
  passed (matching the documented behavior), with a clear error if neither is
  set. Added a unit test.
- Walkthrough (CanlabCore/docs/fmri_surface_data_walkthrough.m): use the bundled
  HCP myelin map as the primary object so it runs with only CanlabCore; guard the
  subcortex / atlas / parcellation sections on NPM availability; fix the
  parcellation demo (previously skipped because spaces never matched).
- How-to (docs/workflows/fmri_surface_data_howto.md): fix Section E/F snippets that
  referenced undefined variables (mydata, subj1..3, scores) and called regress
  before setting the design; they now match the runnable walkthrough.
- Docs accuracy: regress is native OLS (not "delegated"); cluster-extent threshold
  is implemented (not "planned"); ica is a class override (not inherited);
  canlab_surface_vertexcolors signature includes graycolor.
- Method help examples (vol2surf, surface, surf2vol, canlab_read_cifti): use the
  bundled emotionreg / myelin sample data instead of a private-repo image.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@torwager torwager force-pushed the canlab_fmri_surface_object branch from 32b80e6 to f178d11 Compare July 9, 2026 04:41
torwager and others added 4 commits July 9, 2026 00:52
…ge/slices; doc links

- Volume-only image_vector methods (flip, isosurface, interpolate, resample_space,
  extract_gray_white_csf, searchlight, slice_movie, trim_mask, read_from_file,
  extract_roi_averages, ...) are overridden in a methods(Hidden) block: they no
  longer clutter methods(obj)/tab-completion, and calling one raises a clear
  fmri_surface_data:unsupportedMethod error pointing to the surface equivalent.
  The class stays a full image_vector subclass.
- orthviews / montage / slices now route the subcortical grayordinates through
  to_fmri_data and call the fmri_data method (meaningful subcortex display);
  cortex-only objects get a clear "use surface(obj)" error.
- Added test_volume_only_methods_hidden; documented in the methods page
  ("Volume-only methods (redirected or masked)").
- Made the walkthrough / design-plan references in the docs into links.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ow a MATLAB table

- Object property `intent` renamed to `imagetype` (holds
  dscalar/dtseries/dlabel/func/shape/label). The CIFTI/GIFTI reader & writer
  structs keep the faithful `intent`/`intents` field names at the I/O boundary;
  the constructor/write map between `obj.imagetype` and the CIFTI intent.
- `label_table` property is now a MATLAB `table` (variables key, name, rgba)
  instead of a struct array — nicer to view/query. Boundary converters
  (private struct2labeltable / labeltable2struct) translate to/from the native
  readers' struct arrays; apply_parcellation accepts either format.
- Updated tests (assert imagetype + istable(label_table)) and the methods docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ization pipeline

surface() / render_on_surface() now accept the same colour vocabulary as the
master visualization pipeline (addblobs / set_colormap): clim / cmaprange,
colormap / colormapname (single sequential map), pos_colormap / neg_colormap,
splitcolor, maxcolor / mincolor, and color (solid). surface() forwards any colour
option straight through to render_on_surface, and the via-volume path forwards
the compatible options to image_vector/render_on_surface. So the same options
colour surface data and volume blobs. Added test_harmonized_color_options; updated
surface() help and the methods page. (Level 1 of the visualization harmonization;
the stateful fmridisplay-layer integration is the next step.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tive layers)

Level 2 of the visualization harmonization: an fmri_surface_data can now be added
to a managed fmridisplay and driven by the same controls as volume data.

- @fmridisplay/addblobs: detects an fmri_surface_data and dispatches to a new
  @fmridisplay/add_surface_blobs, which registers it as a SURFACE-NATIVE layer
  (source_surface) rather than converting to a volume region.
- @fmridisplay/render_layer_surfaces: paints surface-native layers by colouring
  the per-vertex data DIRECTLY on any registered mesh whose vertex count matches
  the object's space (fs_LR-32k / fsaverage-164k), at full fidelity, using the
  same central canlab_colormap value->colour map as montages (so colours match).
  set_colormap / set_opacity / removeblobs / refresh / the controller act on the
  layer like a volume layer. Non-matching meshes are skipped; a surface layer has
  no montage representation (use to_fmri_data / surf2vol for that).
- Fix @fmri_surface_data/isempty: image_vector/isempty treats an empty volInfo as
  empty, but a cortex-only surface object legitimately has an empty volInfo, so a
  fully-populated cortical map wrongly reported empty. Now empty iff .dat has no rows.
- Added canlab_test_surface_fmridisplay (addblobs paints, set_colormap/removeblobs
  propagate, non-matching/no-surface handled). Full surface suite: 47 passing.
- Documented the managed-display integration in the methods page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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