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.
Arguments
- maps
A data.frame (or tibble) with at least a
filecolumn of NIfTI paths. Optionalsubjectandcontrastcolumns 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 aneuroim2::NeuroVol, matching the NIfTI adapter contract.- ...
Additional arguments forwarded to
gds()when building the NIfTI-backed plan.
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"