Skip to contents

This helper builds on the NIfTI adapter to materialise a realised GDS from a set of NIfTI map files, typically obtained via find_maps(). The heavy lifting (reading NIfTI, spatial metadata, masking) is delegated to the existing NIfTI adapter and the neuroim2 package.

Usage

gds_from_nifti_maps(maps, mask = NULL, ...)

Arguments

maps

A data.frame (or tibble) with at least a file column of NIfTI paths. Optional subject and contrast columns can be used to relabel the realised GDS.

mask

Optional mask passed through to gds() when constructing the NIfTI plan. Can be a NIfTI file path or a neuroim2::NeuroVol, matching the NIfTI adapter contract.

...

Additional arguments forwarded to gds() when building the NIfTI-backed plan.

Value

A realised GDS object.

Details

Subject and contrast labels can be injected post-hoc using the subject and contrast columns when available in maps. This avoids hard-coding any filename convention while still allowing callers to impose semantics via hooks.

This helper is single-contrast: every file in maps$file is loaded as one map per subject along a single contrast axis. A contrast column is used only to label that one contrast (all non-missing values must agree); it does not pivot a long subject x contrast table into a grid. For multi-contrast workflows, call gds_from_nifti_maps() once per contrast and combine the results, or assemble the source manually with nifti_source().

Beta-only raw maps are accepted. When no variance or standard-error maps are available, the realised GDS contains a synthetic var assay filled with 1 and a warning is emitted. This placeholder variance is useful for satisfying the GDS assay contract, but it is not meaningful subject-level uncertainty. For group analyses over subject-level searchlight or stat-map metrics, prefer an unweighted reducer such as method = "ols:voxelwise" instead of fixed/random-effects meta-analysis.

Examples

if (requireNamespace("neuroim2", quietly = TRUE) &&
    requireNamespace("RNifti", quietly = TRUE)) {
  # Write tiny 4x4x2 subject-level maps for four subjects
  dir <- tempfile("maps_")
  dir.create(dir)
  subj <- c("1001", "1002", "1003", "1004")
  files <- file.path(dir, paste0(subj, "_naive_diag_mean.nii.gz"))
  for (f in files) RNifti::writeNifti(array(rnorm(32), c(4, 4, 2)), f)

  # NOTE: `contrast` is a single label here. gds_from_nifti_maps() is
  # single-contrast; to analyse several contrasts, subset `maps` and call
  # once per contrast (a multi-valued `contrast` column triggers a warning).
  maps <- data.frame(
    file = files,
    subject = subj,
    contrast = "naive_diag_mean"
  )

  group_info <- data.frame(
    group = c("control", "control", "patient", "patient"),
    row.names = maps$subject
  )

  # Beta-only maps: a unit-variance placeholder is added (with a warning)
  g <- gds_from_nifti_maps(maps) |>
    with_col_data(group_info)

  fit <- reduce(g, method = "ols:voxelwise", formula = ~ group) |>
    compute()
  print(names(assays(fit)))

  unlink(dir, recursive = TRUE)
}
#> Warning: No variance or SE provided; using unit variance as a synthetic placeholder. This is only valid for unweighted reducers such as method = "ols:voxelwise" (e.g. one_sample()/group_ols()); variance-weighted reducers (fixed/random/meta:*) will refuse it. Supply real SE (e.g. nifti_source(se = ...)) for meta-analysis.
#>  [1] "sigma2"               "df_res"               "n_obs"               
#>  [4] "cov_tri"              "coef:(Intercept)"     "coef:grouppatient"   
#>  [7] "se_coef:(Intercept)"  "se_coef:grouppatient" "t_coef:(Intercept)"  
#> [10] "t_coef:grouppatient"  "p_coef:(Intercept)"   "p_coef:grouppatient"