| Title: | Lazy, Format-Agnostic Group Analysis for fMRI |
|---|---|
| Description: | Provides lazy, spatially typed group-analysis plans for observation-by-feature functional magnetic resonance imaging (fMRI) frames together with compatibility workflows for first-level statistical outputs represented as sample by subject by contrast Group Data Sets (GDS). Supports bounded feature-block reducers, tabular, 'NIfTI', 'HDF5', and 'fmristore' inputs, space-aware transformations, provenance tracking, and reproducible export. |
| Authors: | Brad Buchsbaum [aut, cre] |
| Maintainer: | Brad Buchsbaum <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-10 22:47:59 UTC |
| Source: | https://github.com/bbuchsbaum/fmrigds |
Lazy, format-agnostic group analysis for fMRI.
fmrigds provides a common Group Data Set (GDS) abstraction for first-level
fMRI outputs together with a lazy, plan-based workflow for group analysis.
The package centers on a compact public grammar:
gds() to open supported sources and create a plan
subset(), derive(), align(), mask(), map_to(), reduce(),
posthoc(), and write_out() to describe analysis steps
compute() to execute the plan and return a realised GDS
Core capabilities include:
Constructors for GDS objects and spaces
Storage adapters (tabular, NIfTI, HDF5, fmristore)
Statistical derivations and variance propagation helpers
Reducer and post-hoc registries for group and meta-analytic workflows
Provenance-aware export and inspection helpers
See the package reference and vignettes for supported workflows and release guidance.
Maintainer: Brad Buchsbaum [email protected]
Useful links:
Align subjects into a consensus space
align(x, family)align(x, family)
x |
A plan, source, or realised GDS |
family |
A |
Updated plan
Syntactic sugar around the map-family registry helpers.
register_alignment(x, family, overwrite = FALSE) list_alignments(x) get_alignment(x, name)register_alignment(x, family, overwrite = FALSE) list_alignments(x) get_alignment(x, name)
x |
A |
family |
A |
overwrite |
Logical; overwrite existing family with the same name |
name |
Alignment family name |
The updated object with the family registered
A character vector of registered alignment family names
The MapFamily entry or NULL if not found
Apply a common mask to two realised GDS objects
apply_common_mask(g1, g2, rule = c("intersection", "union"))apply_common_mask(g1, g2, rule = c("intersection", "union"))
g1 |
First GDS |
g2 |
Second GDS |
rule |
Mask rule ("intersection" or "union") |
A list with subsetted g1, g2, and indices idx1, idx2
Convert a legacy rectangular GDS cube to a canonical frame
as_fmri_frame.gds( x, subject = NULL, contrast = NULL, assay_map = c(var = "variance", se = "std_error"), ... )as_fmri_frame.gds( x, subject = NULL, contrast = NULL, assay_map = c(var = "variance", se = "std_error"), ... )
x |
A realized legacy |
subject, contrast
|
Names for the generated observation key columns.
|
assay_map |
Named character vector mapping legacy GDS assay names to canonical frame names. |
... |
Reserved for future use. |
An fmri_frame with one row per subject-contrast cell.
Provides a lightweight front door for external packages holding data in memory (lists, arrays, data.frames) to construct a validated GDS without going through on-disk adapters.
as_gds(x, ...) ## S3 method for class 'list' as_gds( x, space = NULL, subjects = NULL, contrasts = NULL, col_data = NULL, row_data = NULL, metadata = list(), ... ) ## S3 method for class 'array' as_gds( x, space = NULL, subjects = NULL, contrasts = NULL, assay_name = "beta", col_data = NULL, row_data = NULL, metadata = list(), ... ) ## S3 method for class 'data.frame' as_gds( x, mapping = NULL, space = NULL, col_data = NULL, row_data = NULL, contrast_data = NULL, metadata = list(), ... ) ## S3 method for class 'nftab' as_gds(x, feature = NULL, ...)as_gds(x, ...) ## S3 method for class 'list' as_gds( x, space = NULL, subjects = NULL, contrasts = NULL, col_data = NULL, row_data = NULL, metadata = list(), ... ) ## S3 method for class 'array' as_gds( x, space = NULL, subjects = NULL, contrasts = NULL, assay_name = "beta", col_data = NULL, row_data = NULL, metadata = list(), ... ) ## S3 method for class 'data.frame' as_gds( x, mapping = NULL, space = NULL, col_data = NULL, row_data = NULL, contrast_data = NULL, metadata = list(), ... ) ## S3 method for class 'nftab' as_gds(x, feature = NULL, ...)
x |
Object to coerce (list/array/data.frame) |
... |
Additional arguments passed to methods |
space |
Optional space for sample axis; defaults to sample labels from data |
subjects |
Optional subject identifiers |
contrasts |
Optional contrast identifiers |
col_data |
Optional subject-level covariates |
row_data |
Optional sample-level metadata |
metadata |
Optional metadata list merged into |
assay_name |
Name to use for the single-array input (default: "beta") |
mapping |
Optional list mapping column names for axes and assays. Default: list(sample="sample", subject="subject", contrast="contrast", assays=list(beta="beta", var="var"), contrast_data=NULL) |
contrast_data |
Optional contrast-level metadata. When omitted,
|
feature |
Name of the neurotabs feature to use as the primary assay |
A gds object
This compatibility projection is deliberately strict. The selected observation annotations must define one complete, unique Cartesian product of subject and contrast keys. Ragged frames remain frames and are rejected rather than padded with implicit slabs.
## S3 method for class 'fmri_frame' as_gds( x, subject = "subject_id", contrast = "contrast_id", subjects = NULL, contrasts = NULL, assay_names = names(fmridataset::assays(x)), assay_map = NULL, memory_budget = 2 * 1024^3, metadata = list(), ... )## S3 method for class 'fmri_frame' as_gds( x, subject = "subject_id", contrast = "contrast_id", subjects = NULL, contrasts = NULL, assay_names = names(fmridataset::assays(x)), assay_map = NULL, memory_budget = 2 * 1024^3, metadata = list(), ... )
x |
An |
subject, contrast
|
Observation columns defining the rectangular axes.
Either may be |
subjects, contrasts
|
Optional explicit axis order or singleton label.
A |
assay_names |
Assays to realize into the cube. |
assay_map |
Named character vector mapping frame assay names to GDS
assay names. By default |
memory_budget |
Maximum total bytes realized across projected assays. |
metadata |
Additional GDS metadata. |
... |
Reserved for future use. |
A realized legacy gds compatibility projection.
Create a GDS plan from an image catalog. The catalog's assay mappings
determine which files are used for the beta assay and, optionally, one
uncertainty assay (se or var); mapping any other assay is an error.
When the catalog has a subject column, its values become the GDS subject
labels and uncertainty files are paired with beta files by subject;
subject-level metadata from the catalog is attached as col_data.
## S3 method for class 'image_catalog' as_gds(x, mask = NULL, ...)## S3 method for class 'image_catalog' as_gds(x, mask = NULL, ...)
x |
An image_catalog object with assay mappings set via |
mask |
Optional mask file path or NeuroVol object. |
... |
Additional arguments passed to |
A gds_plan object.
if (requireNamespace("neuroim2", quietly = TRUE) && requireNamespace("RNifti", quietly = TRUE)) { # Write tiny 4x4x2 beta and SE maps for three subjects root <- tempfile("study_") for (s in c("01", "02", "03")) { d <- file.path(root, paste0("sub-", s), "stats") dir.create(d, recursive = TRUE) RNifti::writeNifti(array(rnorm(32), c(4, 4, 2)), file.path(d, paste0("sub-", s, "_beta.nii.gz"))) RNifti::writeNifti(array(0.5, c(4, 4, 2)), file.path(d, paste0("sub-", s, "_se.nii.gz"))) } catalog <- image_catalog(root, "sub-*/stats/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") |> map_assays(beta = "_beta", se = "_se") plan <- as_gds(catalog) result <- compute(plan) print(result) unlink(root, recursive = TRUE) }if (requireNamespace("neuroim2", quietly = TRUE) && requireNamespace("RNifti", quietly = TRUE)) { # Write tiny 4x4x2 beta and SE maps for three subjects root <- tempfile("study_") for (s in c("01", "02", "03")) { d <- file.path(root, paste0("sub-", s), "stats") dir.create(d, recursive = TRUE) RNifti::writeNifti(array(rnorm(32), c(4, 4, 2)), file.path(d, paste0("sub-", s, "_beta.nii.gz"))) RNifti::writeNifti(array(0.5, c(4, 4, 2)), file.path(d, paste0("sub-", s, "_se.nii.gz"))) } catalog <- image_catalog(root, "sub-*/stats/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") |> map_assays(beta = "_beta", se = "_se") plan <- as_gds(catalog) result <- compute(plan) print(result) unlink(root, recursive = TRUE) }
Import a neuroim2::NeuroVec (4D brain volume) as a GDS object.
The 4th dimension can represent subjects OR contrasts.
## S3 method for class 'NeuroVec' as_gds( x, assay_name = "beta", along = c("subject", "contrast"), subjects = NULL, contrasts = NULL, mask = NULL, ... ) ## S3 method for class 'DenseNeuroVec' as_gds( x, assay_name = "beta", along = c("subject", "contrast"), subjects = NULL, contrasts = NULL, mask = NULL, ... )## S3 method for class 'NeuroVec' as_gds( x, assay_name = "beta", along = c("subject", "contrast"), subjects = NULL, contrasts = NULL, mask = NULL, ... ) ## S3 method for class 'DenseNeuroVec' as_gds( x, assay_name = "beta", along = c("subject", "contrast"), subjects = NULL, contrasts = NULL, mask = NULL, ... )
x |
A |
assay_name |
Name for the assay (default: |
along |
What does the 4th dimension represent? One of:
|
subjects |
Character vector of subject IDs. Length must match the 4th
dimension when |
contrasts |
Character vector of contrast names. Length must match the 4th
dimension when |
mask |
Optional mask. See |
... |
Additional arguments passed to |
A gds object with voxel space.
if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 3), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(96), c(4, 4, 2, 3)), sp4) # 4D volume where each volume is a subject gds_obj <- as_gds(vec4d, along = "subject", subjects = c("sub-01", "sub-02", "sub-03")) print(subjects(gds_obj)) # 4D volume where each volume is a contrast gds_obj <- as_gds(vec4d, along = "contrast", contrasts = c("faces", "places", "objects")) print(contrasts(gds_obj)) }if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 3), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(96), c(4, 4, 2, 3)), sp4) # 4D volume where each volume is a subject gds_obj <- as_gds(vec4d, along = "subject", subjects = c("sub-01", "sub-02", "sub-03")) print(subjects(gds_obj)) # 4D volume where each volume is a contrast gds_obj <- as_gds(vec4d, along = "contrast", contrasts = c("faces", "places", "objects")) print(contrasts(gds_obj)) }
Import a single neuroim2::NeuroVol (3D brain volume) as a GDS object.
The volume becomes a single subject with a single contrast.
## S3 method for class 'NeuroVol' as_gds( x, assay_name = "beta", subject = "subject1", contrast = "contrast1", mask = NULL, ... ) ## S3 method for class 'DenseNeuroVol' as_gds( x, assay_name = "beta", subject = "subject1", contrast = "contrast1", mask = NULL, ... )## S3 method for class 'NeuroVol' as_gds( x, assay_name = "beta", subject = "subject1", contrast = "contrast1", mask = NULL, ... ) ## S3 method for class 'DenseNeuroVol' as_gds( x, assay_name = "beta", subject = "subject1", contrast = "contrast1", mask = NULL, ... )
x |
A |
assay_name |
Name for the assay (default: |
subject |
Subject identifier (default: |
contrast |
Contrast identifier (default: |
mask |
Optional mask. Can be:
|
... |
Additional arguments passed to |
A gds object with voxel space.
if (requireNamespace("neuroim2", quietly = TRUE)) { sp <- neuroim2::NeuroSpace(c(4, 4, 2), spacing = c(2, 2, 2)) vol <- neuroim2::NeuroVol(array(rnorm(32), c(4, 4, 2)), sp) gds_obj <- as_gds(vol, subject = "sub-01", contrast = "faces") print(gds_obj) }if (requireNamespace("neuroim2", quietly = TRUE)) { sp <- neuroim2::NeuroSpace(c(4, 4, 2), spacing = c(2, 2, 2)) vol <- neuroim2::NeuroVol(array(rnorm(32), c(4, 4, 2)), sp) gds_obj <- as_gds(vol, subject = "sub-01", contrast = "faces") print(gds_obj) }
Extract a single assay from a GDS object and return it as a
neuroim2::NeuroVec (4D neuroimaging array), stacking along the 4th
dimension.
as_neurovec( x, assay = "beta", along = c("subject", "contrast", "both"), subset_subjects = NULL, subset_contrasts = NULL )as_neurovec( x, assay = "beta", along = c("subject", "contrast", "both"), subset_subjects = NULL, subset_contrasts = NULL )
x |
A GDS object with a voxel space. |
assay |
Name of the assay to extract (default: |
along |
Which dimension to stack along the 4th dimension. One of:
|
subset_subjects |
Optional character vector of subject IDs to include. |
subset_contrasts |
Optional character vector of contrast names to include |
A neuroim2::NeuroVec object with dimensions [x, y, z, n] where
n depends on the along parameter.
if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 4), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(128), c(4, 4, 2, 4)), sp4) gds <- as_gds(vec4d, along = "subject", subjects = paste0("sub0", 1:4)) # Stack all subjects into a 4D volume vec <- as_neurovec(gds, assay = "beta", along = "subject") print(dim(vec)) # Stack specific subjects vec <- as_neurovec(gds, assay = "beta", along = "subject", subset_subjects = c("sub01", "sub02")) print(dim(vec)) }if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 4), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(128), c(4, 4, 2, 4)), sp4) gds <- as_gds(vec4d, along = "subject", subjects = paste0("sub0", 1:4)) # Stack all subjects into a 4D volume vec <- as_neurovec(gds, assay = "beta", along = "subject") print(dim(vec)) # Stack specific subjects vec <- as_neurovec(gds, assay = "beta", along = "subject", subset_subjects = c("sub01", "sub02")) print(dim(vec)) }
Extract a single assay from a GDS object and return it as a list of
neuroim2::NeuroVol objects, one per subject/contrast combination.
as_neurovol_list( x, assay = "beta", by = c("subject", "contrast"), drop_dim = TRUE )as_neurovol_list( x, assay = "beta", by = c("subject", "contrast"), drop_dim = TRUE )
x |
A GDS object with a voxel space. |
assay |
Name of the assay to extract (default: |
by |
How to organize the output list. One of:
|
drop_dim |
If |
A named list of neuroim2::NeuroVol objects. The structure depends
on the by parameter and the dimensions of the data:
Single contrast, by = "subject": list of NeuroVol named by subject
Single subject, by = "contrast": list of NeuroVol named by contrast
Multiple of both: nested list [[subject]][[contrast]]
if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 4), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(128), c(4, 4, 2, 4)), sp4) gds <- as_gds(vec4d, along = "subject", subjects = paste0("sub0", 1:4)) # Extract beta maps as list of NeuroVols (one per subject) vols <- as_neurovol_list(gds, assay = "beta") print(names(vols)) print(vols$sub01) # NeuroVol for subject "sub01" # Extract by contrast (here: one subject with three contrasts) sp3 <- neuroim2::NeuroSpace(c(4, 4, 2, 3), spacing = c(2, 2, 2)) vec_con <- neuroim2::NeuroVec(array(rnorm(96), c(4, 4, 2, 3)), sp3) gds_con <- as_gds(vec_con, along = "contrast", contrasts = c("faces", "places", "objects")) vols_by_con <- as_neurovol_list(gds_con, assay = "beta", by = "contrast") print(names(vols_by_con)) }if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 4), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(128), c(4, 4, 2, 4)), sp4) gds <- as_gds(vec4d, along = "subject", subjects = paste0("sub0", 1:4)) # Extract beta maps as list of NeuroVols (one per subject) vols <- as_neurovol_list(gds, assay = "beta") print(names(vols)) print(vols$sub01) # NeuroVol for subject "sub01" # Extract by contrast (here: one subject with three contrasts) sp3 <- neuroim2::NeuroSpace(c(4, 4, 2, 3), spacing = c(2, 2, 2)) vec_con <- neuroim2::NeuroVec(array(rnorm(96), c(4, 4, 2, 3)), sp3) gds_con <- as_gds(vec_con, along = "contrast", contrasts = c("faces", "places", "objects")) vols_by_con <- as_neurovol_list(gds_con, assay = "beta", by = "contrast") print(names(vols_by_con)) }
Ensure an object is a plan
as_plan(x)as_plan(x)
x |
Plan, source, or realized GDS |
A plan object
Extract a single assay from a GDS object
assay(x, name = "beta", ...)assay(x, name = "beta", ...)
x |
A GDS object |
name |
Assay name (default: "beta") |
... |
Additional arguments |
A 3D array
Retrieve assay metadata
assay_info(name)assay_info(name)
name |
Assay name |
Assay metadata list or NULL if not found
Extract assays from a GDS object
assays(x)assays(x)
x |
A GDS object |
Named list of 3D arrays
Assert compatibility between two spaces
assert_compatible_spaces(g1, g2, fields = c("type", "dim", "template_id"))assert_compatible_spaces(g1, g2, fields = c("type", "dim", "template_id"))
g1 |
First GDS or space |
g2 |
Second GDS or space |
fields |
Fields to compare (subset of c("type","dim","template_id")) |
TRUE if compatible; otherwise errors
sp1 <- space_voxel(c(2,2,2), diag(4), storage = "dense") sp2 <- space_voxel(c(2,2,2), diag(4), storage = "dense") assert_compatible_spaces(sp1, sp2)sp1 <- space_voxel(c(2,2,2), diag(4), storage = "dense") sp2 <- space_voxel(c(2,2,2), diag(4), storage = "dense") assert_compatible_spaces(sp1, sp2)
Apply regex patterns to filenames or paths to extract values for new metadata columns.
assign_meta( catalog, column, pattern, source = "basename", replacement = "\\1" )assign_meta( catalog, column, pattern, source = "basename", replacement = "\\1" )
catalog |
An image_catalog object. |
column |
Name of new column to create. |
pattern |
Regex pattern to match (should contain a capture group). |
source |
Which existing column to match against. Default |
replacement |
Replacement string using backreferences. Default |
Updated image_catalog.
root <- tempfile("study_") d <- file.path(root, "sub-01") dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("run-1_faces.nii", "run-2_faces.nii", "run-1_houses.nii")))) catalog <- image_catalog(root, "sub-*/*.nii") catalog <- assign_meta(catalog, "run", "run-([0-9]+)", source = "basename") catalog <- assign_meta(catalog, "contrast", "_([^_]+)\\.nii", replacement = "\\1") catalog$metadata[, c("basename", "run", "contrast")] unlink(root, recursive = TRUE)root <- tempfile("study_") d <- file.path(root, "sub-01") dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("run-1_faces.nii", "run-2_faces.nii", "run-1_houses.nii")))) catalog <- image_catalog(root, "sub-*/*.nii") catalog <- assign_meta(catalog, "run", "run-([0-9]+)", source = "basename") catalog <- assign_meta(catalog, "contrast", "_([^_]+)\\.nii", replacement = "\\1") catalog$metadata[, c("basename", "run", "contrast")] unlink(root, recursive = TRUE)
Stores a weight array as an assay. Note that none of the built-in registered
reducers currently consume custom weight assays: reduce() refuses
weights = "custom" (and "n_eff") unless the selected reducer declares
support for that scheme, rather than silently ignoring it.
attach_weight(g, name, array)attach_weight(g, name, array)
g |
A realised GDS |
name |
Assay-like name for the weights (e.g., "n_eff" or "w_custom") |
array |
Numeric 3D array matching |
Updated GDS with weights stored in assays
beta <- array(0, dim = c(2,2,1)); var <- array(1, dim = c(2,2,1)) g <- new_gds(list(beta = beta, var = var), space_sample_labels(c("a","b")), c("s1","s2"), "c1") w <- array(1, dim = c(2,2,1)) g2 <- attach_weight(g, "w_custom", w)beta <- array(0, dim = c(2,2,1)); var <- array(1, dim = c(2,2,1)) g <- new_gds(list(beta = beta, var = var), space_sample_labels(c("a","b")), c("s1","s2"), "c1") w <- array(1, dim = c(2,2,1)) g2 <- attach_weight(g, "w_custom", w)
Returns a samples x terms x contrasts array by stacking per-term coefficient assays (e.g., coef:(Intercept), coef:age, ...) along a new terms dimension.
coef_array(gds, prefix = "coef:")coef_array(gds, prefix = "coef:")
gds |
A realised GDS |
prefix |
Assay name prefix to stack (default: "coef:") |
A 3D numeric array samples x terms x contrasts
Retrieve packed covariance triangles for OLS coefficients
coef_cov_tri(gds, method = "ols:voxelwise", contrast)coef_cov_tri(gds, method = "ols:voxelwise", contrast)
gds |
A realised GDS |
method |
Reducer method key (default: "ols:voxelwise") |
contrast |
Contrast name to retrieve |
A list with fields type, terms, pack, and cov_tri (L x samples)
Extract column (subject) metadata from a GDS object
col_data(x)col_data(x)
x |
A GDS object |
Data frame with subject-level metadata
Compute a common mask between two spaces
common_mask(g1, g2, rule = c("intersection", "union"))common_mask(g1, g2, rule = c("intersection", "union"))
g1 |
First GDS or space |
g2 |
Second GDS or space |
rule |
Either "intersection" or "union" |
A list with integer indices idx1 and idx2 for subsetting each
m1 <- array(c(TRUE, FALSE, TRUE, TRUE), c(2, 2, 1)) m2 <- array(c(TRUE, TRUE, FALSE, TRUE), c(2, 2, 1)) sp1 <- space_voxel(c(2,2,1), diag(4), mask_bitmap = m1, storage = "packed") sp2 <- space_voxel(c(2,2,1), diag(4), mask_bitmap = m2, storage = "packed") common_mask(sp1, sp2, rule = "intersection")m1 <- array(c(TRUE, FALSE, TRUE, TRUE), c(2, 2, 1)) m2 <- array(c(TRUE, TRUE, FALSE, TRUE), c(2, 2, 1)) sp1 <- space_voxel(c(2,2,1), diag(4), mask_bitmap = m1, storage = "packed") sp2 <- space_voxel(c(2,2,1), diag(4), mask_bitmap = m2, storage = "packed") common_mask(sp1, sp2, rule = "intersection")
Materialise a plan into a realised GDS
compute( x, sink = c("memory", "h5"), path = NULL, sink_options = list(), block = NULL, assays = NULL, ... )compute( x, sink = c("memory", "h5"), path = NULL, sink_options = list(), block = NULL, assays = NULL, ... )
x |
Plan or source |
sink |
Storage sink ("memory" for in-memory data, "h5" to write a GDS HDF5 store) |
path |
Output path when |
sink_options |
Optional list of sink-specific options |
block |
Optional list specifying block indices to request from the adapter |
assays |
Optional character vector to return raw arrays instead of GDS object |
... |
Reserved for future use |
A realised gds object
Extract contrast-level metadata from a GDS object
contrast_data(x)contrast_data(x)
x |
A GDS object or plan |
Data frame with one row per contrast/repeated-measure level
For objects that are not GDS objects or plans (for example factors), the
default method delegates to stats::contrasts(), so attaching fmrigds does
not break base model-contrast code.
contrasts(x, ...)contrasts(x, ...)
x |
A GDS object or plan |
... |
Passed to |
Character vector of contrast names
Record a derivation operation in a plan
derive(x, what = c("var", "se", "t", "z"), options = list())derive(x, what = c("var", "se", "t", "z"), options = list())
x |
Plan or source |
what |
Character vector of assays to derive |
options |
Optional named list of options |
Updated plan
Detect the best adapter for a source
detect_adapter(source, prefer = NULL)detect_adapter(source, prefer = NULL)
source |
Source specification (path, list, etc.) |
prefer |
Optional adapter name to prefer when available |
Adapter name
examination_control() validates the bounded execution, residual-geometry,
review, staging, and numerical settings used by examine_group(). Keeping
these settings in a typed object makes defaults visible and reproducible.
examination_control( block_size = 1024L, geometry = list(rank = 32L, oversample = 8L, cap = 8, balance_contrasts = TRUE, stability_replicates = 2L), review = list(surprise = list(energy_threshold = 2.5, tail_threshold = 0.01, residual_threshold = 3), influence = list(energy_threshold = 1, max_abs_threshold = 2), quality = list(coverage_fraction = list(direction = "low", threshold = 0.8)), min_stability = 0.7), exact_refit_n = 5L, retain_n = 5L, staging = list(tempdir = NULL), tolerance = list(rank = sqrt(.Machine$double.eps), leverage = 1e-08, degeneracy = 1e-12) )examination_control( block_size = 1024L, geometry = list(rank = 32L, oversample = 8L, cap = 8, balance_contrasts = TRUE, stability_replicates = 2L), review = list(surprise = list(energy_threshold = 2.5, tail_threshold = 0.01, residual_threshold = 3), influence = list(energy_threshold = 1, max_abs_threshold = 2), quality = list(coverage_fraction = list(direction = "low", threshold = 0.8)), min_stability = 0.7), exact_refit_n = 5L, retain_n = 5L, staging = list(tempdir = NULL), tolerance = list(rank = sqrt(.Machine$double.eps), leverage = 1e-08, degeneracy = 1e-12) )
block_size |
Positive number of samples read per scan block. |
geometry |
Named list controlling the deterministic low-rank residual
representation. Supported entries are |
review |
Named list controlling review status. Supported entries are
|
exact_refit_n |
Maximum number of retained random-effects subjects,
taken in decreasing |
retain_n |
Number of highest-priority subjects retained for localization
when no explicit |
staging |
Named list with optional |
tolerance |
Named list of numerical tolerances: |
An object of class gds_examination_control.
examine_group() branches from subject-level data at a group reducer. It
reports model-conditioned predictive surprise separately from each
subject's exact influence on requested group estimands. It never deletes a
subject or rewrites the source analysis.
examine_group( x, method = NULL, formula = NULL, options = list(), quality = NULL, estimands = NULL, retain = NULL, control = examination_control(), na_action = c("fail", "exclude") )examine_group( x, method = NULL, formula = NULL, options = list(), quality = NULL, estimands = NULL, retain = NULL, control = examination_control(), na_action = c("fail", "exclude") )
x |
A subject-level |
method |
Reducer method when |
formula |
Model formula when |
options |
Reducer options when |
quality |
Optional character vector naming first-level quality columns
in |
estimands |
Named linear estimands or design-column names. See
|
retain |
Optional subject IDs retained for later localization regardless of review rank. |
control |
A validated object from |
na_action |
Missing-covariate policy. The default fails; |
When x already contains one reducer, the examination inherits that
reducer's method, formula, options, and weighting semantics. Supplying model
overrides in that case is an error. When no reducer is present, method is
required and formula-driven reducers default to ~ 1.
A gds_examination object.
The returned object keeps spatial maps in ordinary GDS objects and keeps
subject, contrast, estimand, availability, sensitivity, and provenance data
in tables or named lists. subject_data$review_priority orders inspection;
subject_data$review_status changes to "review" only when an absolute,
stability-aware criterion is met. Random-effects screening is labeled
"tau2_fixed_full"; exact retained-subject refits are labeled
"tau2_refit_exact" and never alter the original review queue.
subject_ids <- paste0("sub-", 1:8) participant_data <- data.frame( group = factor(rep(c("control", "patient"), each = 4)), row.names = subject_ids ) beta <- array(rnorm(12 * 8, sd = 0.2), c(12, 8, 1)) beta[, participant_data$group == "patient", 1] <- beta[, participant_data$group == "patient", 1] + 0.4 variance <- array(0.1, dim(beta)) subject_gds <- new_gds( assays = list(beta = beta, var = variance), space = space_sample_labels(paste0("feature-", 1:12)), subjects = subject_ids, contrasts = "task", col_data = participant_data ) analysis <- as_plan(subject_gds) |> reduce(method = "meta:re_reg", formula = ~ group) exam <- examine_group( analysis, estimands = "grouppatient", control = examination_control(retain_n = 2L) ) summary(exam) if (requireNamespace("ggplot2", quietly = TRUE)) plot(exam)subject_ids <- paste0("sub-", 1:8) participant_data <- data.frame( group = factor(rep(c("control", "patient"), each = 4)), row.names = subject_ids ) beta <- array(rnorm(12 * 8, sd = 0.2), c(12, 8, 1)) beta[, participant_data$group == "patient", 1] <- beta[, participant_data$group == "patient", 1] + 0.4 variance <- array(0.1, dim(beta)) subject_gds <- new_gds( assays = list(beta = beta, var = variance), space = space_sample_labels(paste0("feature-", 1:12)), subjects = subject_ids, contrasts = "task", col_data = participant_data ) analysis <- as_plan(subject_gds) |> reduce(method = "meta:re_reg", formula = ~ group) exam <- examine_group( analysis, estimands = "grouppatient", control = examination_control(retain_n = 2L) ) summary(exam) if (requireNamespace("ggplot2", quietly = TRUE)) plot(exam)
Human-readable summary of a realised GDS or a lazy gds_plan.
explain(x) ## S3 method for class 'gds' print(x, ...) ## S3 method for class 'gds_plan' print(x, ...)explain(x) ## S3 method for class 'gds' print(x, ...) ## S3 method for class 'gds_plan' print(x, ...)
x |
A |
... |
Additional arguments ignored. |
Invisibly returns x (and prints a summary)
Explain a plan's operations in a tidy table
explain_plan(plan)explain_plan(plan)
plan |
A |
A data.frame with one row per node (printed and returned invisibly)
Convenience function that combines split.gds() and as_neurovol_list()
to extract neuroimaging volumes for subjects in a specific group.
extract_group(x, group_var, group_level, assay = "beta", ...)extract_group(x, group_var, group_level, assay = "beta", ...)
x |
A GDS object. |
group_var |
Column name in |
group_level |
The specific group level to extract. |
assay |
Name of the assay to extract (default: |
... |
Additional arguments passed to |
A named list of neuroim2::NeuroVol objects for subjects in the
specified group.
if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 4), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(128), c(4, 4, 2, 4)), sp4) gds <- as_gds(vec4d, along = "subject", subjects = paste0("sub0", 1:4)) gds <- with_col_data(gds, data.frame( diagnosis = c("patient", "control", "patient", "control"), row.names = subjects(gds) )) # Get beta maps for all patients patient_vols <- extract_group(gds, "diagnosis", "patient", assay = "beta") print(names(patient_vols)) # Get beta maps for controls control_vols <- extract_group(gds, "diagnosis", "control", assay = "beta") print(names(control_vols)) }if (requireNamespace("neuroim2", quietly = TRUE)) { sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 4), spacing = c(2, 2, 2)) vec4d <- neuroim2::NeuroVec(array(rnorm(128), c(4, 4, 2, 4)), sp4) gds <- as_gds(vec4d, along = "subject", subjects = paste0("sub0", 1:4)) gds <- with_col_data(gds, data.frame( diagnosis = c("patient", "control", "patient", "control"), row.names = subjects(gds) )) # Get beta maps for all patients patient_vols <- extract_group(gds, "diagnosis", "patient", assay = "beta") print(names(patient_vols)) # Get beta maps for controls control_vols <- extract_group(gds, "diagnosis", "control", assay = "beta") print(names(control_vols)) }
Convenience helper to discover NIfTI map files on disk using a flexible
regular-expression pattern. This is intended for quick "scooping up" of
first-level maps spread across a directory tree (e.g. .*/maps/AUC.nii).
find_maps( root, pattern = "\\.nii(\\.gz)?$", recursive = TRUE, subject_fun = NULL, contrast_fun = NULL )find_maps( root, pattern = "\\.nii(\\.gz)?$", recursive = TRUE, subject_fun = NULL, contrast_fun = NULL )
root |
Root directory to search. |
pattern |
Regular expression passed to |
recursive |
Logical; whether to search subdirectories (default |
subject_fun |
Optional function applied to the character vector of file paths, expected to return a character vector of subject identifiers. |
contrast_fun |
Optional function applied to the character vector of file paths, expected to return a character vector of contrast labels. |
The function does not impose any file naming convention. Instead, callers
can provide optional subject_fun and contrast_fun hooks to derive
subject and contrast labels from file paths.
A data.frame with columns file, subject, and contrast.
fit_group() is the eager convenience wrapper for group_plan() followed
by compute(). The default known-variance random-intercept model is
diag(sampling_variance) + vc_resid I + vc_intercept Z Z'; other registered
frame kernels may use different input and model contracts.
fit_group( frame, estimate = "beta", variance = "variance", design, memory_budget = 256 * 1024^2, block_size = NULL, fit = c("REML", "ML"), method = "lmm:ri_knownvar", options = list() )fit_group( frame, estimate = "beta", variance = "variance", design, memory_budget = 256 * 1024^2, block_size = NULL, fit = c("REML", "ML"), method = "lmm:ri_knownvar", options = list() )
frame |
An |
estimate |
Name of the effect assay. |
variance |
Name of the known sampling-variance assay. |
design |
A |
memory_budget |
Maximum bytes for the two input feature blocks. |
block_size |
Optional explicit feature-block width. |
fit |
Likelihood criterion, |
method |
Registered frame-capable reducer. The default is
|
options |
Named reducer options. |
An fmri_group_fit whose result is an fmri_frame sharing the
input feature IDs and spatial domain.
Create a Group Data Set (GDS)
Adapter front door for building a plan
new_gds( assays, space, subjects, contrasts, col_data = NULL, row_data = NULL, metadata = list() ) gds(source, format = c("auto", ls(.adapter_registry)), prefer = NULL, ...)new_gds( assays, space, subjects, contrasts, col_data = NULL, row_data = NULL, metadata = list() ) gds(source, format = c("auto", ls(.adapter_registry)), prefer = NULL, ...)
assays |
Named list of 3-D arrays (sample x subject x contrast) |
space |
A space object describing the sample axis |
subjects |
Character vector of subject identifiers |
contrasts |
Character vector of contrast identifiers |
col_data |
Optional data frame keyed by subjects |
row_data |
Optional data frame keyed by samples |
metadata |
Optional list merged with |
source |
Source specification (paths, etc.) |
format |
Optional adapter name or "auto" |
prefer |
Optional preferred adapter when multiple match |
... |
Adapter-specific arguments forwarded to |
An object of class c("gds", "group_data")
A gds_plan
The most flexible import function for creating GDS objects from neuroim2 data. Supports multiple subjects and multiple contrasts, with proper variance/SE handling.
gds_from_neurovol_nested( beta, var = NULL, se = NULL, contrasts = NULL, mask = NULL, col_data = NULL, metadata = list(), ... )gds_from_neurovol_nested( beta, var = NULL, se = NULL, contrasts = NULL, mask = NULL, col_data = NULL, metadata = list(), ... )
beta |
A nested list structure for beta/effect estimates. Can be:
|
var |
Optional matching structure for variance estimates. |
se |
Optional matching structure for standard errors (alternative to var). |
contrasts |
Character vector of contrast names. Required when using NeuroVec inputs; inferred from inner list names otherwise. |
mask |
Optional mask. See |
col_data |
Optional data frame of subject-level covariates. |
metadata |
Optional list of additional metadata to attach. |
... |
Additional arguments passed to |
A gds object with dimensions samples x subjects x contrasts.
if (requireNamespace("neuroim2", quietly = TRUE)) { sp <- neuroim2::NeuroSpace(c(4, 4, 2), spacing = c(2, 2, 2)) make_vol <- function(x) neuroim2::NeuroVol(array(x, c(4, 4, 2)), sp) subj <- c("sub-01", "sub-02") # Example 1: Nested list structure (subjects x contrasts) beta <- lapply(stats::setNames(subj, subj), function(s) list(faces = make_vol(rnorm(32)), places = make_vol(rnorm(32)))) var <- lapply(stats::setNames(subj, subj), function(s) list(faces = make_vol(runif(32, 0.5, 1.5)), places = make_vol(runif(32, 0.5, 1.5)))) gds_obj <- gds_from_neurovol_nested(beta, var = var) print(gds_obj) # Example 2: List of 4D NeuroVecs (each subject has a multi-contrast 4D image) sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 3), spacing = c(2, 2, 2)) beta_vecs <- lapply(stats::setNames(subj, subj), function(s) neuroim2::NeuroVec(array(rnorm(96), c(4, 4, 2, 3)), sp4)) # Without variance maps a unit-variance placeholder is used (with a warning) gds_obj <- gds_from_neurovol_nested(beta_vecs, contrasts = c("faces", "places", "objects")) print(contrasts(gds_obj)) }if (requireNamespace("neuroim2", quietly = TRUE)) { sp <- neuroim2::NeuroSpace(c(4, 4, 2), spacing = c(2, 2, 2)) make_vol <- function(x) neuroim2::NeuroVol(array(x, c(4, 4, 2)), sp) subj <- c("sub-01", "sub-02") # Example 1: Nested list structure (subjects x contrasts) beta <- lapply(stats::setNames(subj, subj), function(s) list(faces = make_vol(rnorm(32)), places = make_vol(rnorm(32)))) var <- lapply(stats::setNames(subj, subj), function(s) list(faces = make_vol(runif(32, 0.5, 1.5)), places = make_vol(runif(32, 0.5, 1.5)))) gds_obj <- gds_from_neurovol_nested(beta, var = var) print(gds_obj) # Example 2: List of 4D NeuroVecs (each subject has a multi-contrast 4D image) sp4 <- neuroim2::NeuroSpace(c(4, 4, 2, 3), spacing = c(2, 2, 2)) beta_vecs <- lapply(stats::setNames(subj, subj), function(s) neuroim2::NeuroVec(array(rnorm(96), c(4, 4, 2, 3)), sp4)) # Without variance maps a unit-variance placeholder is used (with a warning) gds_obj <- gds_from_neurovol_nested(beta_vecs, contrasts = c("faces", "places", "objects")) print(contrasts(gds_obj)) }
Import matched lists of NeuroVol objects (e.g., beta and variance maps)
into a GDS. This handles the common case of multiple subjects with a
single contrast. For multiple contrasts, use gds_from_neurovol_nested().
gds_from_neurovols( beta, var = NULL, se = NULL, contrast = "contrast1", mask = NULL, col_data = NULL, ... )gds_from_neurovols( beta, var = NULL, se = NULL, contrast = "contrast1", mask = NULL, col_data = NULL, ... )
beta |
A named list of |
var |
Optional named list of |
se |
Optional named list of |
contrast |
Contrast name (default: |
mask |
Optional mask. See |
col_data |
Optional data frame of subject-level covariates.
Row names must match subject IDs (names of |
... |
Additional arguments passed to |
A gds object.
if (requireNamespace("neuroim2", quietly = TRUE)) { sp <- neuroim2::NeuroSpace(c(4, 4, 2), spacing = c(2, 2, 2)) make_vol <- function(x) neuroim2::NeuroVol(array(x, c(4, 4, 2)), sp) # Beta and variance maps for each subject beta_vols <- list( `sub-01` = make_vol(rnorm(32)), `sub-02` = make_vol(rnorm(32)), `sub-03` = make_vol(rnorm(32)) ) var_vols <- lapply(beta_vols, function(v) make_vol(runif(32, 0.5, 1.5))) gds_obj <- gds_from_neurovols(beta_vols, var = var_vols) print(gds_obj) # With subject covariates covars <- data.frame(age = c(25, 30, 35), group = c("A", "B", "A"), row.names = c("sub-01", "sub-02", "sub-03")) gds_obj <- gds_from_neurovols(beta_vols, var = var_vols, col_data = covars) print(col_data(gds_obj)) }if (requireNamespace("neuroim2", quietly = TRUE)) { sp <- neuroim2::NeuroSpace(c(4, 4, 2), spacing = c(2, 2, 2)) make_vol <- function(x) neuroim2::NeuroVol(array(x, c(4, 4, 2)), sp) # Beta and variance maps for each subject beta_vols <- list( `sub-01` = make_vol(rnorm(32)), `sub-02` = make_vol(rnorm(32)), `sub-03` = make_vol(rnorm(32)) ) var_vols <- lapply(beta_vols, function(v) make_vol(runif(32, 0.5, 1.5))) gds_obj <- gds_from_neurovols(beta_vols, var = var_vols) print(gds_obj) # With subject covariates covars <- data.frame(age = c(25, 30, 35), group = c("A", "B", "A"), row.names = c("sub-01", "sub-02", "sub-03")) gds_obj <- gds_from_neurovols(beta_vols, var = var_vols, col_data = covars) print(col_data(gds_obj)) }
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.
gds_from_nifti_maps(maps, mask = NULL, ...)gds_from_nifti_maps(maps, mask = NULL, ...)
maps |
A data.frame (or tibble) with at least a |
mask |
Optional mask passed through to |
... |
Additional arguments forwarded to |
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.
A realised GDS object.
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) }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) }
gds_from_scalar_maps() is a semantic wrapper for beta-only/stat-map
workflows: each NIfTI is a subject-level metric map rather than a first-level
beta image with meaningful uncertainty. The resulting GDS uses the NIfTI
adapter's unit-variance placeholder behavior for beta-only sources.
gds_from_scalar_maps( files, subject = NULL, contrast = "map", col_data = NULL, mask = NULL, ... ) as_scalar_map_gds( files, subject = NULL, contrast = "map", col_data = NULL, mask = NULL, ... )gds_from_scalar_maps( files, subject = NULL, contrast = "map", col_data = NULL, mask = NULL, ... ) as_scalar_map_gds( files, subject = NULL, contrast = "map", col_data = NULL, mask = NULL, ... )
files |
Character vector of NIfTI paths, a data.frame with a |
subject |
Optional subject identifiers. Required for character |
contrast |
Contrast label(s). A scalar value is recycled across files.
Ignored when |
col_data |
Optional subject-level covariates. If a |
mask |
Optional mask passed to |
... |
Additional arguments forwarded to |
A realised gds object.
if (requireNamespace("neuroim2", quietly = TRUE) && requireNamespace("RNifti", quietly = TRUE)) { # Write tiny 4x4x2 subject-level metric maps for four subjects dir <- tempfile("scalar_maps_") dir.create(dir) subj <- c("sub-01", "sub-02", "sub-03", "sub-04") files <- file.path(dir, paste0(subj, "_auc.nii.gz")) for (f in files) RNifti::writeNifti(array(rnorm(32), c(4, 4, 2)), f) participants <- data.frame(subject = subj, group = c("control", "control", "patient", "patient")) # Beta-only maps: a unit-variance placeholder is added (with a warning) g <- gds_from_scalar_maps( files = files, subject = subj, contrast = "auc", col_data = participants ) print(g) fit <- group_ols(g, ~ group) |> compute() unlink(dir, recursive = TRUE) }if (requireNamespace("neuroim2", quietly = TRUE) && requireNamespace("RNifti", quietly = TRUE)) { # Write tiny 4x4x2 subject-level metric maps for four subjects dir <- tempfile("scalar_maps_") dir.create(dir) subj <- c("sub-01", "sub-02", "sub-03", "sub-04") files <- file.path(dir, paste0(subj, "_auc.nii.gz")) for (f in files) RNifti::writeNifti(array(rnorm(32), c(4, 4, 2)), f) participants <- data.frame(subject = subj, group = c("control", "control", "patient", "patient")) # Beta-only maps: a unit-variance placeholder is added (with a warning) g <- gds_from_scalar_maps( files = files, subject = subj, contrast = "auc", col_data = participants ) print(g) fit <- group_ols(g, ~ group) |> compute() unlink(dir, recursive = TRUE) }
Construct default metadata for a GDS object
gds_metadata( schema_version = "0.1.0", units = list(), provenance = list(graph = list(), log = character(), digest = NULL), software = list(package = "fmrigds", version = .pkg_version(), R_version = getRversion()), alignment = NULL, map_families = list(), mask_info = NULL, contrast_info = NULL, design_mats = NULL, notes = NULL, created = Sys.time() )gds_metadata( schema_version = "0.1.0", units = list(), provenance = list(graph = list(), log = character(), digest = NULL), software = list(package = "fmrigds", version = .pkg_version(), R_version = getRversion()), alignment = NULL, map_families = list(), mask_info = NULL, contrast_info = NULL, design_mats = NULL, notes = NULL, created = Sys.time() )
schema_version |
Schema version string |
units |
Named list of assay units |
provenance |
Provenance structure ( |
software |
Software metadata (package name, version, R version) |
alignment |
Optional alignment metadata |
map_families |
Named list of registered map families |
mask_info |
Optional mask metadata |
contrast_info |
Optional contrast metadata |
design_mats |
Optional design matrices metadata |
notes |
Optional user notes |
created |
Timestamp for when the metadata was created |
Metadata list
Define a plan source (adapter binding)
gds_source(adapter, source_spec, probe_result = NULL)gds_source(adapter, source_spec, probe_result = NULL)
adapter |
Adapter identifier string |
source_spec |
Source specification (paths, handles, etc.) |
probe_result |
Optional probe metadata |
Source descriptor
Public wrapper around the internal tidy frame builder used by CSV/Parquet
exporters. Returns a data.frame; if you prefer a tibble, wrap with
tibble::as_tibble().
gds_to_tibble(gds, assays = NULL, drop_na = FALSE, include_col_data = FALSE)gds_to_tibble(gds, assays = NULL, drop_na = FALSE, include_col_data = FALSE)
gds |
A realised GDS object |
assays |
Character vector of assay names to include (default: all assays in the GDS) |
drop_na |
If TRUE, drop rows with all-NA assays |
include_col_data |
If TRUE, join columns from |
A data.frame in long form with columns sample, subject,
contrast, plus one column per requested assay.
Retrieve a registered adapter
get_adapter(name)get_adapter(name)
name |
Adapter name |
Adapter list
Retrieve a registered map family by name
get_map_family(x, name)get_map_family(x, name)
x |
A plan or realised GDS |
name |
Map family name |
A MapFamily object
Get post-hoc method by name
get_posthoc(name)get_posthoc(name)
name |
Method identifier (e.g., "fdr:bh") |
A list with fields name, fun, requires, provides, or NULL if not found
Get reducer by name
get_reducer(name)get_reducer(name)
name |
Reducer name |
Reducer list or NULL if not found
These helpers wrap reduce(method = "ols:voxelwise") for subject-level map
workflows. They return a lazy GDS plan; call compute() to materialise the
fitted maps.
group_ols(x, formula = ~1, col_data = NULL, options = list(), ...) one_sample(x, subset = NULL, col_data = NULL, options = list(), ...) two_sample( x, group = "group", baseline = NULL, level = NULL, col_data = NULL, options = list(), ... )group_ols(x, formula = ~1, col_data = NULL, options = list(), ...) one_sample(x, subset = NULL, col_data = NULL, options = list(), ...) two_sample( x, group = "group", baseline = NULL, level = NULL, col_data = NULL, options = list(), ... )
x |
|
formula |
One-sided model formula for |
col_data |
Optional subject-level covariates to attach before fitting. |
options |
Reducer options passed to |
... |
Additional arguments passed to |
subset |
Optional expression evaluated in |
group |
Name of the grouping column in |
baseline |
Optional reference level for the grouping factor. |
level |
Optional non-baseline level to compare against |
A gds_plan with an OLS reduce node.
# Synthetic voxel-like data: 5 samples x 4 subjects x 1 contrast beta <- array(rnorm(5 * 4), c(5, 4, 1)) var <- array(1, c(5, 4, 1)) g <- new_gds(list(beta = beta, var = var), space_sample_labels(letters[1:5]), subjects = paste0("s", 1:4), contrasts = "c1", col_data = data.frame(group = c("control", "control", "patient", "patient"), row.names = paste0("s", 1:4))) fit <- group_ols(g, ~ group) |> compute() names(assays(fit)) one <- one_sample(g) |> compute() two <- two_sample(g, group = "group", baseline = "control") |> compute()# Synthetic voxel-like data: 5 samples x 4 subjects x 1 contrast beta <- array(rnorm(5 * 4), c(5, 4, 1)) var <- array(1, c(5, 4, 1)) g <- new_gds(list(beta = beta, var = var), space_sample_labels(letters[1:5]), subjects = paste0("s", 1:4), contrasts = "c1", col_data = data.frame(group = c("control", "control", "patient", "patient"), row.names = paste0("s", 1:4))) fit <- group_ols(g, ~ group) |> compute() names(assays(fit)) one <- one_sample(g) |> compute() two <- two_sample(g, group = "group", baseline = "control") |> compute()
group_plan() compiles design metadata and resolves stable axis IDs without
reading imaging assays. Numerical values are read only by compute(), in
bounded feature blocks, and dispatched through the selected reducer's frame
execution contract.
group_plan( frame, design, method = "lmm:ri_knownvar", estimate = "beta", variance = "variance", memory_budget = 256 * 1024^2, block_size = NULL, options = list() )group_plan( frame, design, method = "lmm:ri_knownvar", estimate = "beta", variance = "variance", memory_budget = 256 * 1024^2, block_size = NULL, options = list() )
frame |
An |
design |
A |
method |
Registered reducer name with frame execution support. |
estimate |
Effect-assay name. |
variance |
Known sampling-variance assay name, or |
memory_budget |
Maximum bytes for input assay blocks. |
block_size |
Optional explicit feature-block width. |
options |
Reducer options. |
A serializable fmri_group_plan.
Harmonise contrast names in a GDS
harmonise_contrasts(g, map)harmonise_contrasts(g, map)
g |
A realised GDS |
map |
Named character vector mapping old -> new contrast names |
Updated GDS with renamed contrasts
beta <- array(0, dim = c(2,1,2), dimnames = list(NULL, "s1", c("a","b"))) var <- beta g <- new_gds(list(beta = beta, var = var), space_sample_labels(c("x","y")), "s1", c("a","b")) harmonise_contrasts(g, c(a = "A", b = "B"))beta <- array(0, dim = c(2,1,2), dimnames = list(NULL, "s1", c("a","b"))) var <- beta g <- new_gds(list(beta = beta, var = var), space_sample_labels(c("x","y")), "s1", c("a","b")) harmonise_contrasts(g, c(a = "A", b = "B"))
Sweeps a directory tree for files matching a glob pattern and extracts metadata from file paths using regex capture groups.
image_catalog(root, pattern = "**/*.nii*", path_regex = NULL, recursive = TRUE)image_catalog(root, pattern = "**/*.nii*", path_regex = NULL, recursive = TRUE)
root |
Root directory to search. |
pattern |
Glob pattern for file discovery (e.g., |
path_regex |
Optional regex with named capture groups for metadata extraction.
Named groups like |
recursive |
Whether to search subdirectories. Default |
An image_catalog object.
# Create a small study tree (empty placeholder files are enough for discovery) root <- tempfile("study_") for (s in c("01", "02", "03")) { d <- file.path(root, paste0("sub-", s), "analysis") dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } # Discover files with subject extraction catalog <- image_catalog( root = root, pattern = "sub-*/analysis/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)" ) catalog catalog$metadata[, c("basename", "subject")] unlink(root, recursive = TRUE)# Create a small study tree (empty placeholder files are enough for discovery) root <- tempfile("study_") for (s in c("01", "02", "03")) { d <- file.path(root, paste0("sub-", s), "analysis") dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } # Discover files with subject extraction catalog <- image_catalog( root = root, pattern = "sub-*/analysis/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)" ) catalog catalog$metadata[, c("basename", "subject")] unlink(root, recursive = TRUE)
Merge a data frame with the catalog metadata by a key column.
join_meta(catalog, data, by, suffix = ".external")join_meta(catalog, data, by, suffix = ".external")
catalog |
An image_catalog object. |
data |
External data.frame to join. |
by |
Column name(s) for joining (must exist in both catalog$metadata and data). |
suffix |
Suffix for duplicate column names from data. Default |
Updated image_catalog.
# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") demographics <- data.frame(subject = c("01", "02"), age = c(25, 30)) catalog <- join_meta(catalog, demographics, by = "subject") catalog$metadata[, c("basename", "subject", "age")] unlink(root, recursive = TRUE)# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") demographics <- data.frame(subject = c("01", "02"), age = c(25, 30)) catalog <- join_meta(catalog, demographics, by = "subject") catalog$metadata[, c("basename", "subject", "age")] unlink(root, recursive = TRUE)
Discoverability helper for finding assay names to pass to assay(),
write_nifti_assays(), or write_out() without having to run a job and
inspect names(assays(fit)). Works on a realised gds, a lazy
gds_plan/gds_source (reporting the input assays the source probed),
or—when reducer is supplied—reports a reducer's declared output stems
without computing anything.
list_assays(x, reducer = NULL, info = TRUE)list_assays(x, reducer = NULL, info = TRUE)
x |
A realised |
reducer |
Optional reducer name (e.g. |
info |
Logical; if |
A data frame (or a character vector when info = FALSE).
assays(), assay(), assay_info(), list_reducers(),
list_posthoc(), write_nifti_assays()
beta <- array(rnorm(5 * 4), c(5, 4, 1)) var <- array(1, c(5, 4, 1)) g <- new_gds(list(beta = beta, var = var), space_sample_labels(letters[1:5]), subjects = paste0("s", 1:4), contrasts = "c1") fit <- one_sample(g) |> compute() list_assays(fit) # names + roles of computed assays list_assays(reducer = "meta:re") # what random-effects would producebeta <- array(rnorm(5 * 4), c(5, 4, 1)) var <- array(1, c(5, 4, 1)) g <- new_gds(list(beta = beta, var = var), space_sample_labels(letters[1:5]), subjects = paste0("s", 1:4), contrasts = "c1") fit <- one_sample(g) |> compute() list_assays(fit) # names + roles of computed assays list_assays(reducer = "meta:re") # what random-effects would produce
List registered map families
list_map_families(x)list_map_families(x)
x |
A plan or realised GDS |
Character vector of family names
List registered post-hoc methods
list_posthoc()list_posthoc()
A sorted character vector of registered post-hoc method names.
posthoc-methods for what each method outputs.
List registered reducers
list_reducers()list_reducers()
A sorted character vector of registered reducer names.
list_assays() to preview a reducer's output assays.
Load a plan from JSON
load_plan(file)load_plan(file)
file |
JSON file produced by save_plan |
A gds_plan. A warning is issued when the digest stored in the file
does not match the reconstructed plan (e.g. the file was edited).
Map families and map_linear operators are restored with
base::unserialize(), which can execute arbitrary code embedded in a
crafted file. Only call load_plan() on files you created or otherwise
trust.
Convenience helpers to create and register alignments
make_linear_family( name, from, to, operators_by_subject, uncertainty = UncertaintyRule("independent") )make_linear_family( name, from, to, operators_by_subject, uncertainty = UncertaintyRule("independent") )
name |
Family name |
from |
Source space |
to |
Target space |
operators_by_subject |
Named list of per-subject linear operators (matrices) |
uncertainty |
Uncertainty rule for variance propagation |
A MapFamily
from <- space_parcels(c("R1","R2")) to <- space_parcels(c("G1","G2")) ops <- list(s1 = diag(2), s2 = diag(2)) fam <- make_linear_family("lin", from, to, ops)from <- space_parcels(c("R1","R2")) to <- space_parcels(c("G1","G2")) ops <- list(s1 = diag(2), s2 = diag(2)) fam <- make_linear_family("lin", from, to, ops)
Create a warp-based alignment family from on-disk paths
make_warp_family( name, from, to, warp_paths, loader, uncertainty = UncertaintyRule("independent") )make_warp_family( name, from, to, warp_paths, loader, uncertainty = UncertaintyRule("independent") )
name |
Family name |
from |
Source space |
to |
Target space |
warp_paths |
Named character vector of file paths per subject |
loader |
Function(path) -> operator (e.g., matrix) for a single subject |
uncertainty |
Uncertainty rule |
A MapFamily (type = deform3d)
loader <- function(path) as.matrix(utils::read.csv(path, header = FALSE)) # paths <- c(s1 = "warp_s1.csv", s2 = "warp_s2.csv") # fam <- make_warp_family("warp", from, to, paths, loader)loader <- function(path) as.matrix(utils::read.csv(path, header = FALSE)) # paths <- c(s1 = "warp_s1.csv", s2 = "warp_s2.csv") # fam <- make_warp_family("warp", from, to, paths, loader)
Specify which files correspond to which statistical assays (beta, se, var, t).
This mapping is used by as_gds.image_catalog() to construct the GDS.
map_assays(catalog, ...)map_assays(catalog, ...)
catalog |
An image_catalog object. |
... |
Named arguments where names are assay types and values are either:
|
Updated image_catalog with assay_map.
# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") # By filename pattern (regex matched against basenames) catalog <- map_assays(catalog, beta = "^cope[0-9]+\\.nii", var = "^varcope[0-9]+\\.nii" ) # By metadata column value catalog <- assign_meta(catalog, "stat_type", "^([a-z]+)[0-9]+") catalog <- map_assays(catalog, beta = list(stat_type = "cope"), var = list(stat_type = "varcope") ) summary(catalog) unlink(root, recursive = TRUE)# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") # By filename pattern (regex matched against basenames) catalog <- map_assays(catalog, beta = "^cope[0-9]+\\.nii", var = "^varcope[0-9]+\\.nii" ) # By metadata column value catalog <- assign_meta(catalog, "stat_type", "^([a-z]+)[0-9]+") catalog <- map_assays(catalog, beta = list(stat_type = "cope"), var = list(stat_type = "varcope") ) summary(catalog) unlink(root, recursive = TRUE)
Create a linear map between spaces
map_linear( from_space, to_space, operator, by_subject = NULL, traits = list(orthogonal = FALSE, mass_preserving = FALSE), uncertainty = UncertaintyRule("independent"), name = NULL )map_linear( from_space, to_space, operator, by_subject = NULL, traits = list(orthogonal = FALSE, mass_preserving = FALSE), uncertainty = UncertaintyRule("independent"), name = NULL )
from_space |
Source space descriptor or name |
to_space |
Target space descriptor or name |
operator |
Mapping operator (matrix/function) |
by_subject |
Optional named list of subject-specific operator descriptors/functions |
traits |
List of map traits (orthogonal, mass_preserving) |
uncertainty |
|
name |
Optional map name |
Object of class c("map_linear", "gds_map")
Add a space transformation to a plan
map_to( x, target_space, map, uncertainty = UncertaintyRule("independent"), combine = NULL )map_to( x, target_space, map, uncertainty = UncertaintyRule("independent"), combine = NULL )
x |
Plan, source, or realised GDS |
target_space |
Target space descriptor or identifier |
map |
Mapping object ( |
uncertainty |
|
combine |
Optional evidence combiner when effect scale absent |
Updated plan
Create a subject-aware map family
MapFamily( name, from_space, to_space, type = c("linear", "orthogonal", "affine3d", "deform3d", "ot"), by_subject, traits = list(orthogonal = FALSE, mass_preserving = FALSE), uncertainty = UncertaintyRule("independent") )MapFamily( name, from_space, to_space, type = c("linear", "orthogonal", "affine3d", "deform3d", "ot"), by_subject, traits = list(orthogonal = FALSE, mass_preserving = FALSE), uncertainty = UncertaintyRule("independent") )
name |
Family name |
from_space |
Source space |
to_space |
Target space |
type |
Map type identifier |
by_subject |
Named list of per-subject operator descriptors |
traits |
Map traits |
uncertainty |
Object of class c("gds_map_family", "gds_map")
Apply a mask policy lazily
mask(x, policy = MaskPolicy())mask(x, policy = MaskPolicy())
x |
Plan, source, or realised GDS |
policy |
Mask policy created by |
Updated plan
Define a mask policy
MaskPolicy( scope = c("group", "subject"), rule = c("intersection", "union", "threshold", "custom"), threshold = 0.95, custom = NULL )MaskPolicy( scope = c("group", "subject"), rule = c("intersection", "union", "threshold", "custom"), threshold = 0.95, custom = NULL )
scope |
Scope of mask computation ("group" or "subject") |
rule |
Mask rule ("intersection", "union", "threshold", "custom") |
threshold |
Fraction for threshold rule |
custom |
Custom function returning logical mask |
A mask policy object
Extract metadata from a GDS object
metadata(x)metadata(x)
x |
A GDS object |
Metadata list
Convenience helper to construct a model matrix using subject-level
covariates already attached to a plan via with_col_data() or stored in a
realised GDS.
model_matrix(x, formula)model_matrix(x, formula)
x |
A |
formula |
Model formula (or string convertible via stats::as.formula) |
A numeric model matrix
Low-level constructor for image_catalog objects. Users should typically
use image_catalog() for file discovery instead.
new_image_catalog( files, metadata = NULL, root_dir = NULL, pattern = NULL, assay_map = list() )new_image_catalog( files, metadata = NULL, root_dir = NULL, pattern = NULL, assay_map = list() )
files |
Character vector of absolute file paths. |
metadata |
Data frame with one row per file containing extracted path components and user-assigned metadata. |
root_dir |
Root directory used for discovery (for relative path display). |
pattern |
Original glob pattern used for discovery. |
assay_map |
Named list mapping assay names to file selection criteria. |
An object of class c("image_catalog", "list").
Build an explicit NIfTI source list for use with gds(..., format = "nifti").
If beta is provided without se, materialising the GDS creates a unit
variance placeholder with a warning. This supports raw beta/stat-map
workflows; the synthetic variance should not be interpreted as subject-level
uncertainty, and variance-weighted reducers will refuse such a GDS.
nifti_source( beta = NULL, se = NULL, subject = NULL, subjects = NULL, contrast = NULL, contrasts = NULL )nifti_source( beta = NULL, se = NULL, subject = NULL, subjects = NULL, contrast = NULL, contrasts = NULL )
beta |
Character vector of NIfTI paths or a directory containing beta/effect images
(optional, can be |
se |
Character vector of NIfTI paths or a directory containing standard error images
(optional, can be |
subject, subjects
|
Optional subject labels. When both |
contrast, contrasts
|
Optional contrast labels. Length must match the number of contrasts in each NIfTI image (one for ordinary 3D maps). |
When both beta and se are supplied, files are paired by subject key unless
explicit subject/subjects labels are supplied. The fallback key is the file
basename (extension removed) with a trailing statistic token stripped,
matching ([_.-](beta|cope|varcope|var|variance|effect|se|stderr|sterr|sigma|std(err)?))+$
(case insensitive). For example sub-01_beta.nii.gz and sub-01_se.nii.gz
both reduce to the key sub-01. Filenames where the statistic token is not
last (e.g. sub-01_stat-beta_sm-2.nii.gz) will fail to pair unless explicit
subject labels are provided. For beta/stat-only maps, prefer
gds_from_scalar_maps(), which takes an explicit subject vector and avoids
filename heuristics entirely.
A list suitable for gds(source = <returned>, format = "nifti")
src <- nifti_source(beta = c("sub-01_beta.nii.gz", "sub-02_beta.nii.gz"), se = c("sub-01_se.nii.gz", "sub-02_se.nii.gz")) str(src)src <- nifti_source(beta = c("sub-01_beta.nii.gz", "sub-02_beta.nii.gz"), se = c("sub-01_se.nii.gz", "sub-02_se.nii.gz")) str(src)
Orthogonal map family helper
OrthogonalFamily( name, from_space, to_space, matrices_by_subject, uncertainty = UncertaintyRule("independent") )OrthogonalFamily( name, from_space, to_space, matrices_by_subject, uncertainty = UncertaintyRule("independent") )
name |
Family name |
from_space |
Source space |
to_space |
Target space |
matrices_by_subject |
Named list of per-subject orthogonal matrices |
uncertainty |
Uncertainty rule (default: independent) |
A MapFamily object with orthogonal traits
Optimal transport family helper
OTFamily( name, from_space, to_space, plans_by_subject, uncertainty = UncertaintyRule("independent") )OTFamily( name, from_space, to_space, plans_by_subject, uncertainty = UncertaintyRule("independent") )
name |
Family name |
from_space |
Source space |
to_space |
Target space |
plans_by_subject |
Named list of per-subject optimal transport plans |
uncertainty |
Uncertainty rule (default: independent) |
A MapFamily object with mass-preserving traits
The default action plane places model surprise on the horizontal axis and
influence on the requested group estimand on the vertical axis. Secondary
views show subject-by-diagnostic summaries or the residual geometry. When
subject is supplied, the retained observed, expected, predictive-residual,
and deletion maps are shown for that subject.
## S3 method for class 'gds_examination' plot( x, subject = NULL, type = c("action", "heatmap", "embedding"), contrast = NULL, estimand = NULL, group_by = NULL, assays = NULL, slice = NULL, ... )## S3 method for class 'gds_examination' plot( x, subject = NULL, type = c("action", "heatmap", "embedding"), contrast = NULL, estimand = NULL, group_by = NULL, assays = NULL, slice = NULL, ... )
x |
A |
subject |
Optional retained subject ID. Supplying it selects the linked
subject view regardless of |
type |
One of |
contrast |
Optional contrast subset. |
estimand |
Optional estimand subset. |
group_by |
Optional column in |
assays |
Optional selected-subject assays to display. |
slice |
Optional one-based axial slice for voxel-space subject maps. |
... |
Reserved for future plot controls. |
A ggplot object.
Add a post-hoc operation to a plan
posthoc(x, method, options = list())posthoc(x, method, options = list())
x |
A plan or object coercible via |
method |
Post-hoc method name (e.g., "fdr:bh", "fdr:by") |
options |
Optional list of method-specific options |
Updated gds_plan
posthoc-methods for the built-in methods and the assays each adds.
df <- data.frame( sample = rep(c("ROI_1","ROI_2"), each = 2), subject = rep(c("s1","s2"), times = 2), contrast = "c1", beta = c(0.5,0.6,0.7,0.8), var = c(0.04,0.05,0.06,0.07) ) tmp <- tempfile(fileext = ".csv"); utils::write.csv(df, tmp, row.names = FALSE) plan <- gds(tmp) |> reduce(method = "fixed") |> posthoc("fdr:bh") # g <- compute(plan) # returns q-valuesdf <- data.frame( sample = rep(c("ROI_1","ROI_2"), each = 2), subject = rep(c("s1","s2"), times = 2), contrast = "c1", beta = c(0.5,0.6,0.7,0.8), var = c(0.04,0.05,0.06,0.07) ) tmp <- tempfile(fileext = ".csv"); utils::write.csv(df, tmp, row.names = FALSE) plan <- gds(tmp) |> reduce(method = "fixed") |> posthoc("fdr:bh") # g <- compute(plan) # returns q-values
Methods are selected by name in posthoc() and add their adjusted-p assays
to the realised GDS. The FDR methods adjust the object's p-value assay(s):
a genuine bare p (from meta/combine reducers or a tabular p column) yields
a single q; a per-term p_coef:<term> family (from regression/LMM reducers
such as ols:voxelwise) yields one q_coef:<term> per term. Pass
options = list(source = "p_coef:<term>") to adjust one specific term.
This is a documentation page (no return value).
"fdr:bh", "fdr:by": add q (or per-term q_coef:<term>),
Benjamini-Hochberg / Benjamini-Yekutieli adjusted p-values, computed
column-wise per subject x contrast.
"fdr:spatial": adds q (or per-term q_coef:<term>), group-wise spatial
FDR. Requires a discrete spatial grouping (one parcel/cluster id per
sample) via options$group or a recognised row_data column
(feature_group, spatial_group, group, parcel, parcel_id).
"nt:tfce_fwer" (needs the optional neurothresh package): adds p_fwer
(TFCE FWER-corrected p-values), sig_mask (1/0 at alpha), and tfce (the
TFCE-enhanced statistic map).
"nt:cluster_fdr_perm" (needs neurothresh): adds q (cluster-FDR q
broadcast to voxels) and sig_mask.
Required input assays are auto-derived (and persisted) when absent: e.g.
fdr:bh on a z-only GDS adds a derived p alongside q.
posthoc(), list_posthoc(), list_assays()
Executes the plan with a small sample block to quickly inspect shapes or
values. If assays is provided, returns raw arrays from the adapter stage
(pre-operations); otherwise returns a realised GDS of the small block after
applying plan nodes.
preview(plan, n = 3, assays = NULL)preview(plan, n = 3, assays = NULL)
plan |
A |
n |
Number of samples to preview (from start) |
assays |
Optional assays to request as raw arrays |
Either a list of arrays (when assays provided) or a small gds
Print validation report
## S3 method for class 'catalog_validation_report' print(x, ...)## S3 method for class 'catalog_validation_report' print(x, ...)
x |
A catalog_validation_report object. |
... |
Additional arguments (ignored). |
Invisibly returns the report.
Print method for image_catalog
## S3 method for class 'image_catalog' print(x, ...)## S3 method for class 'image_catalog' print(x, ...)
x |
An image_catalog object. |
... |
Additional arguments (ignored). |
Invisibly returns the catalog.
Load an image catalog previously saved with write_catalog().
read_catalog(file)read_catalog(file)
file |
Path to catalog JSON file. |
An image_catalog object.
# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") manifest <- tempfile(fileext = ".json") write_catalog(catalog, manifest) catalog2 <- read_catalog(manifest) catalog2 unlink(c(manifest, root), recursive = TRUE)# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") manifest <- tempfile(fileext = ".json") write_catalog(catalog, manifest) catalog2 <- read_catalog(manifest) catalog2 unlink(c(manifest, root), recursive = TRUE)
Reduce across subjects (meta-analysis)
reduce( x, method = c("fixed", "random", "stouffer", "fisher"), weights = c("1/var", "n_eff", "equal", "custom"), by = "contrast", options = list(), formula = NULL, data = NULL )reduce( x, method = c("fixed", "random", "stouffer", "fisher"), weights = c("1/var", "n_eff", "equal", "custom"), by = "contrast", options = list(), formula = NULL, data = NULL )
x |
A |
method |
Reduction method. Built-ins include |
weights |
Weighting scheme ( |
by |
Grouping variable (e.g., |
options |
Additional reducer options. Common examples include
Note: Current grouping is per-contrast. Values other than "contrast" are
not interpreted yet; future versions may extend grouping to other
factors in Restricted repeated-measures LMM contract:
Permutation reducer contract:
|
formula |
Optional model formula. For meta-regression reducers the design
is built from subject-level |
data |
Optional subject-keyed data frame to attach as |
reduce() always works on a lazy plan internally, so x is whichever stage
of the fmrigds workflow you already have:
Start from files or another external source with gds(). That returns a
gds_plan you can pipe directly into reduce().
Start from an in-memory result with a realised gds returned by
compute() or created directly with new_gds(). reduce() will convert
it with as_plan() for you.
You can also pass a low-level gds_source created by gds_source(), but
most users do not need this because gds() creates the source binding
automatically.
If you want that conversion to be explicit, use as_plan()
before calling reduce().
For worked examples, see vignette("fmrigds") for the basic source -> plan
-> compute workflow and vignette("as-plan-and-spatial-fdr") for chaining
verbs on realised GDS objects.
Updated plan
Reducers collapse the subject axis and write group-level assays (named on the
realised GDS, retrievable with assays()/assay()):
"ols:voxelwise": per-term coef:<term>, se_coef:<term>,
t_coef:<term>, p_coef:<term>, plus sigma2, df_res, n_obs
(see reducer-ols-voxelwise).
"fixed"/"meta:fe" and "random"/"meta:re": beta_g, var_g,
se_g, z_g, p_g, Q, I2, n_eff (random-effects also adds
tau2). n_eff is the number of finite subject-level inputs used for
each sample and contrast.
"meta:fe_reg"/"meta:re_reg": per-term coef:<term>,
se_coef:<term>, normal-approximation z_coef:<term> and
p_coef:<term>, plus Q, df_res (random-effects also adds tau2).
"meta:re_reg"
uses the DerSimonian–Laird meta-regression denominator
and excludes rows with
non-finite effects/design values or non-finite, nonpositive variances.
"stouffer"/"combine:stouffer": z_g, p_g.
"fisher"/"combine:fisher" and "combine:lancaster": chi2, df,
p_g.
"perm:onesample"/"perm:twosample": beta_g, se_g, t_g, df,
p_g, p_perm, p_fwer.
gds(), compute(), as_plan(), new_gds(), gds_source()
fmrigds includes four specialized repeated-measures Gaussian mixed-model
reducers that are optimized for the case where every sample shares the same
observation layout and the same fixed/random design.
method = "lmm:ri" fits a random-intercept model.
method = "lmm:ri_slope1" fits a random intercept plus one within-subject
slope supplied through options$slope.
method = "lmm:ri_knownvar" and "lmm:ri_slope1_knownvar" fit the
corresponding variance-aware models using the input var assay as known
diagonal sampling variance.
These reducers operate on the full contrast axis jointly. Repeated-measure
metadata therefore needs to be attached as contrast-level metadata, either
with with_contrast_data() or during tabular ingestion via
gds(..., contrast_data_cols = ...).
Supported contract:
one grouping factor only
Gaussian outcomes only
shared observation layout and shared fixed/random design across samples
unweighted reducers support theta_mode = "pooled" for one shared
random-effect-to-residual covariance shape across samples or
theta_mode = "voxelwise" for sample-specific parameters
known-variance reducers currently support voxelwise covariance estimation only
no crossed random effects and no general lmer() random-effects grammar
This is a documentation page (no return value); these reducers are
invoked via reduce().
The unweighted lmm:ri and lmm:ri_slope1 reducers require beta only. An
input var or se assay is ignored by their likelihood. Their sigma2 and
vc_* outputs are second-level variance components estimated from the
supplied effects.
The *_knownvar reducers require aligned beta and strictly positive var
assays. For each sample, they fit marginal covariance
diag(var) + vc_resid * I + Z G Z'. Thus, var is treated as known sampling
variance, vc_resid (sigma2) is additional observation-level heterogeneity,
and G contains the subject random-effect covariance. Only diagonal sampling
covariance is currently accepted; correlated first-level estimates require a
future full sampling-covariance input rather than pretending their marginal
variances are independent.
Fixed-effect standard errors use the fitted covariance as a plug-in estimate,
and p_coef:* uses per-coefficient containment degrees of freedom
(reported in df_coef:*): coefficients of between-subject columns use
N - rank(X_between), all others the residual df N*K - p. Satterthwaite
and Kenward–Roger corrections are not applied.
Both reducers expand fixed effects per model term (<term> = design-matrix
column names of formula): coef:<term>, se_coef:<term>, t_coef:<term>,
p_coef:<term>. In addition:
lmm:ri provides sigma2, vc_intercept, vc_resid, df_res, logLik,
converged (1/0), and lambda (random-intercept-to-residual variance
ratio).
lmm:ri_slope1 provides sigma2, vc_intercept, vc_slope,
vc_cov_intercept_slope, vc_resid, df_res, logLik, converged,
lambda_intercept, lambda_slope, lambda_cov_intercept_slope, and
corr_intercept_slope.
lmm:ri_knownvar provides sigma2, vc_intercept, vc_resid, and
sampling_var_mean; lmm:ri_slope1_knownvar additionally provides
vc_slope, vc_cov_intercept_slope, and corr_intercept_slope. The
relative lambda_* assays are intentionally omitted because known sampling
variance breaks the single residual-scale parameterization.
Pass these names verbatim (including the colon and any parentheses) to
write_nifti_assays() / write_out().
rm_df <- data.frame(
sample = rep(c("ROI_1", "ROI_2"), each = 12),
subject = rep(paste0("sub-", sprintf("%02d", 1:4)), each = 3, times = 2),
contrast = rep(c("pre", "mid", "post"), times = 8),
time = rep(c(-1, 0, 1), times = 8),
beta = c(
0.40, 0.80, 1.20, 0.55, 0.95, 1.35, 0.65, 1.05, 1.45, 0.85, 1.25, 1.65,
0.70, 1.20, 1.70, 0.85, 1.35, 1.85, 0.95, 1.45, 1.95, 1.15, 1.65, 2.15
)
)
g <- gds(rm_df, contrast_data_cols = "time") |>
reduce(
method = "lmm:ri_slope1",
formula = ~ time,
options = list(
slope = "time",
covariance = "diag",
fit = "REML",
theta_mode = "voxelwise"
)
) |>
compute()
names(assays(g))
assay(g, "coef:time")
rm_df_known <- transform(rm_df, var = 0.04)
g_known <- gds(rm_df_known, contrast_data_cols = "time") |>
reduce(
method = "lmm:ri_slope1_knownvar",
formula = ~ time,
options = list(slope = "time", covariance = "diag", fit = "REML")
) |>
compute()
Fixed-effect tests use per-coefficient degrees of freedom, exposed as
df_coef:<term> assays (the scalar df_res assay is unchanged and still
reports N*K - p). A design column that is constant within every subject
(a between-subject term, including the intercept) uses
df = N - rank(X_between), where X_between holds all between-subject
columns at one row per subject. All other (within-subject) columns use the
residual N*K - p. p_coef:<term> is computed from df_coef:<term>. This
supersedes the single residual-df rule described above for between-subject
terms; it is a containment-style approximation, not Satterthwaite or
Kenward–Roger.
converged reflects the covariance-parameter optimizer: it is 0 when the
optimizer reports failure or a variance parameter is pinned at its upper
search bound (a diverging variance), and 1 otherwise (zero-variance
boundary estimates count as converged).
The reducer identified by method = "ols:voxelwise" performs unweighted
ordinary least squares across subjects independently for each sample and
contrast. It accepts a model formula via reduce(..., formula = ~ 1 + cov)
(design is built from with_col_data() or gds(..., col_data=...)).
Outputs are expanded into per-term assays to preserve the 3-axis invariant:
coef:<term> and se_coef:<term> (one assay per model term)
t_coef:<term> and p_coef:<term> convenience statistics
sigma2 (residual variance) and df_res (residual degrees of freedom)
n_obs (number of finite subjects contributing at each sample)
Optionally, a packed triangular covariance for the coefficient vector can be
attached per contrast using options = list(return_cov = "tri"), which also
promotes per-pair cov:<term_i>:<term_j> assays. Retrieve the packed form
from a realised GDS via coef_cov_tri().
Missing data are handled by per-sample listwise deletion: subjects whose
effect is non-finite at a given sample are dropped for that sample only and
the model is refit on the remaining rows. Samples with fewer than p + 1
finite observations (override with options = list(min_subjects = ...))
cannot be estimated and are returned as NA; n_obs records the effective
sample size and a summary warning is emitted when any sample is reduced.
This is a documentation page (no return value); the reducer is
invoked via reduce(), one_sample(), or group_ols().
For an intercept-only fit (formula = ~ 1):
coef:(Intercept), se_coef:(Intercept), t_coef:(Intercept),
p_coef:(Intercept), plus sigma2, df_res, and n_obs. Each additional
model term adds a matching coef:<term>/se_coef:<term>/t_coef:<term>/
p_coef:<term> quartet. Pass these names verbatim (including the colon and
any parentheses) to write_nifti_assays() / write_out().
# Attach subject-level covariates; build design via formula
plan <- gds("group.csv", col_data = subj_cov) |
reduce(method = "ols:voxelwise", formula = ~ 1 + age + sex,
options = list(return_cov = "tri"))
g <- compute(plan)
# Per-term assays
assay(g, "coef:(Intercept)"); assay(g, "coef:age"); assay(g, "coef:sex")
# Packed covariance for first contrast
cov_info <- coef_cov_tri(g, contrast = contrasts(g)[1])
cov_info$terms # term order
cov_info$cov_tri # L x samples packed upper triangle
# Stack all coefficients into [samples x terms x contrasts]
coef_arr <- coef_array(g)
Register a storage adapter
register_adapter( name, detect, open, probe, read, close, capabilities = NULL, scan = NULL, ... )register_adapter( name, detect, open, probe, read, close, capabilities = NULL, scan = NULL, ... )
name |
Adapter name |
detect |
Function (source) -> score in |
open |
Function (source, ...) -> handle |
probe |
Function (handle, ...) -> list(metadata) |
read |
Function (handle, assays, block = NULL, ...) -> named list of arrays |
close |
Function (handle) -> NULL |
capabilities |
Optional scan-capability declaration. Supported fields
are |
scan |
Optional adapter-specific scan callback. |
... |
Additional elements stored with adapter entry |
Invisibly, the adapter entry
Register an assay type
register_assay( name, role, units = NULL, variance_of = NULL, derive_from = NULL )register_assay( name, role, units = NULL, variance_of = NULL, derive_from = NULL )
name |
Assay name |
role |
Semantic category (e.g., "location", "variance", "stdev", "z", "t", "F", "df", "n_eff", "p", "chi2", "evidence", "log_evidence", "posterior") |
units |
Optional units string/list |
variance_of |
Optional name of the assay whose variance this represents |
derive_from |
Optional character vector of prerequisite assays |
Invisibly, the registered assay definition
Register a map family on a plan or realised GDS
register_map(x, family, overwrite = FALSE)register_map(x, family, overwrite = FALSE)
x |
|
family |
A |
overwrite |
Whether to overwrite an existing family with the same name |
Updated object (gds_plan or gds)
Makes nftab objects from the neurotabs package a first-class
data source for gds(). Called automatically during
.onLoad() when neurotabs is installed; can also be called
manually.
register_nftab_adapter()register_nftab_adapter()
Invisibly, the adapter entry.
Register or replace a post-hoc handler identified by name.
register_posthoc( name, fun, requires, provides, overwrite = TRUE, case_deletion = NULL )register_posthoc( name, fun, requires, provides, overwrite = TRUE, case_deletion = NULL )
name |
String identifier, e.g., "fdr:bh" |
fun |
Function(arrays, opts) -> list of arrays (delta or full arrays) |
requires |
Character vector of required input assays, e.g., c("p") |
provides |
Character vector of output assay names, e.g., c("q") |
overwrite |
Logical; if FALSE and a handler with |
case_deletion |
Optional declaration of whether and how the post-hoc conclusion can be recomputed for selected case deletions. |
The handler fun is called as fun(arrays, opts) where arrays is a
named list of assays shaped sample x subject x contrast. It should return
either (a) a named list of new/updated assays to merge (e.g., list(q = ...)),
or (b) the full arrays list with modifications. Implementations must
preserve the input array dimensions.
Invisibly, the registered post-hoc method name.
posthoc-methods for the built-in methods and their output assays.
Register a reducer kernel
register_reducer( name, fun, requires, provides, options_schema = list(), input_shape = c("contrastwise", "joint_contrast"), model_contract = NULL, diagnostics = NULL, frame_fun = NULL )register_reducer( name, fun, requires, provides, options_schema = list(), input_shape = c("contrastwise", "joint_contrast"), model_contract = NULL, diagnostics = NULL, frame_fun = NULL )
name |
String identifier, e.g., "meta:fe" |
fun |
Function(beta, var, X, z, p, df, df1, df2, opts) -> named list |
requires |
Character vector of required inputs, e.g., c("beta","var") |
provides |
Character vector of outputs to be written |
options_schema |
Optional schema for options |
input_shape |
Reducer execution mode: |
model_contract |
Optional declarative description of the reducer's design, weighting, missingness, variance, estimand, and deletion semantics. Custom reducers may omit this, in which case model-conditioned examination diagnostics are reported as unavailable. |
diagnostics |
Optional diagnostic implementation declaration. This is a
list containing |
frame_fun |
Optional feature-block kernel for |
Invisibly, the registered reducer name.
Relabel subjects in a GDS
relabel_subjects(g, mapping)relabel_subjects(g, mapping)
g |
A realised GDS |
mapping |
Named character vector mapping old -> new subject ids |
Updated GDS with relabeled subjects
beta <- array(0, dim = c(2,2,1), dimnames = list(NULL, c("u1","u2"), "c1")) var <- beta g <- new_gds(list(beta = beta, var = var), space_sample_labels(c("x","y")), c("u1","u2"), "c1") relabel_subjects(g, c(u1 = "s1", u2 = "s2"))beta <- array(0, dim = c(2,2,1), dimnames = list(NULL, c("u1","u2"), "c1")) var <- beta g <- new_gds(list(beta = beta, var = var), space_sample_labels(c("x","y")), c("u1","u2"), "c1") relabel_subjects(g, c(u1 = "s1", u2 = "s2"))
Construct a standardized statistical result frame
result_frame( assays, observations, features, method, diagnostics = list(), term_data = NULL, source_observation_ids = NULL, metadata = list(), provenance = NULL )result_frame( assays, observations, features, method, diagnostics = list(), term_data = NULL, source_observation_ids = NULL, metadata = list(), provenance = NULL )
assays |
Named observation-by-feature result assays. |
observations |
Result-row metadata containing stable |
features |
The aligned spatial feature axis. |
method |
Registered statistical reducer name. |
diagnostics |
Per-feature diagnostics. |
term_data |
Compiled term metadata. |
source_observation_ids |
Stable source observation IDs. |
metadata |
Additional result metadata. |
provenance |
Serializable derivation provenance. |
An fmri_frame marked with a versioned statistical-result schema.
Extract row (sample) metadata from a GDS object
row_data(x)row_data(x)
x |
A GDS object |
Data frame with sample-level metadata
Extract sample-group metadata from a GDS object
sample_groups( x, vars = c("feature_group", "spatial_group", "group", "parcel", "parcel_id") )sample_groups( x, vars = c("feature_group", "spatial_group", "group", "parcel", "parcel_id") )
x |
A GDS object or plan |
vars |
Candidate column names searched in |
A vector of group labels or NULL when unavailable
Extract sample labels from a GDS object
sample_labels(x)sample_labels(x)
x |
A GDS object or plan |
Character vector of sample labels
Writes the plan's source binding, metadata, and operation nodes to a JSON
file. Matrices (including Matrix objects) are stored as numeric data with
their dimensions; map families and map_linear objects are stored as ASCII
R serializations (the same encoding used for alignments in GDS HDF5 stores).
Function-valued components that cannot be represented faithfully, such as a
custom MaskPolicy() function or a covariance provider, cause an error at
save time rather than being silently dropped.
save_plan(plan, file)save_plan(plan, file)
plan |
Plan or object coercible via |
file |
Path to JSON file |
The file records a digest of the serialized plan, which load_plan()
verifies.
Invisibly returns file, the path of the written JSON file. The
file contains the plan's source, metadata, operation nodes and digest
and can be restored with load_plan().
For non-GDS objects (e.g. a neuroim2 NeuroVol/NeuroVec) this
generic falls back to neuroim2::space() when that package is available, so
that attaching fmrigds does not mask neuroim2::space() on the search
path.
space(x, ...)space(x, ...)
x |
A GDS object, or any object with a |
... |
Additional arguments passed to methods. |
A space object
Create a latent basis space descriptor
space_basis(k, basis_name = NULL, projector = NULL, voxel_space = NULL)space_basis(k, basis_name = NULL, projector = NULL, voxel_space = NULL)
k |
Number of components |
basis_name |
Optional name for the basis (e.g., "ICA") |
projector |
Optional matrix/function for voxel projection |
voxel_space |
Optional reference voxel space descriptor |
Space object
Create a voxel space from a NIfTI file
space_from_nifti(path, mask = NULL)space_from_nifti(path, mask = NULL)
path |
Path to a NIfTI file (.nii or .nii.gz) |
mask |
Optional path to a mask NIfTI or a neuroim2::NeuroVol |
A space_voxel object
# if (requireNamespace("neuroim2", quietly = TRUE)) { # sp <- space_from_nifti(system.file("extdata", "tiny.nii", package = "fmrigds")) # }# if (requireNamespace("neuroim2", quietly = TRUE)) { # sp <- space_from_nifti(system.file("extdata", "tiny.nii", package = "fmrigds")) # }
Create a parcels/ROI space descriptor
space_parcels(labels, lookup = NULL, membership = NULL)space_parcels(labels, lookup = NULL, membership = NULL)
labels |
Character vector of parcel labels |
lookup |
Optional lookup information (data frame or list) |
membership |
Optional mapping (list or sparse matrix) from parcels to voxels |
Space object
Classify the portability of a GDS space
space_portability(space)space_portability(space)
space |
A GDS space object. |
One of "portable", "portable_with_external_reference", or
"nonportable_function".
Create a simple label space for tabular samples
space_sample_labels(labels)space_sample_labels(labels)
labels |
Character vector of sample labels |
Space object of type "sample_labels"
Subset a space by sample indices
space_subset(space, idx, pack = FALSE)space_subset(space, idx, pack = FALSE)
space |
A |
idx |
Integer or logical index for the sample axis |
pack |
Logical; when TRUE and |
A new space object with samples restricted
sp <- space_parcels(letters[1:5]) space_subset(sp, 2:4)sp <- space_parcels(letters[1:5]) space_subset(sp, 2:4)
Create a surface space descriptor
space_surface(vertices, faces, hemi, template_id = NULL)space_surface(vertices, faces, hemi, template_id = NULL)
vertices |
Matrix (n x 3) of vertex coordinates |
faces |
Integer matrix (m x 3) of triangle indices (1-based) |
hemi |
Hemisphere identifier ("L", "R", "LR") |
template_id |
Optional template identifier |
Space object
Create a voxel space descriptor
space_voxel( dim, affine, mask_bitmap = NULL, mask_idx = NULL, storage = c("dense", "packed"), template_id = NULL )space_voxel( dim, affine, mask_bitmap = NULL, mask_idx = NULL, storage = c("dense", "packed"), template_id = NULL )
dim |
Integer vector of length 3 (x, y, z) |
affine |
4x4 affine matrix |
mask_bitmap |
Optional logical array matching |
mask_idx |
Optional integer vector of active voxel indices (mask order) |
storage |
Either "dense" or "packed" |
template_id |
Optional template identifier string |
An object of class c("space_voxel", "gds_space")
Divide a GDS object into a list of GDS objects based on a grouping factor
from col_data (subject-level metadata).
## S3 method for class 'gds' split(x, f, drop = TRUE, ...)## S3 method for class 'gds' split(x, f, drop = TRUE, ...)
x |
A GDS object. |
f |
A factor or character vector for splitting, OR a column name
(as a string) from |
drop |
Logical; if |
... |
Additional arguments (ignored). |
A named list of GDS objects, one per level of f.
beta <- array(rnorm(5 * 4), c(5, 4, 1)) var <- array(1, c(5, 4, 1)) gds <- new_gds(list(beta = beta, var = var), space_sample_labels(letters[1:5]), subjects = paste0("s", 1:4), contrasts = "c1", col_data = data.frame(group = c("patients", "controls", "patients", "controls"), row.names = paste0("s", 1:4))) # Split by group column in col_data gds_by_group <- split(gds, "group") gds_by_group$patients # GDS with only patient subjects subjects(gds_by_group$controls) # Or provide a factor directly groups <- factor(c("A", "B", "A", "B")) gds_split <- split(gds, groups) names(gds_split)beta <- array(rnorm(5 * 4), c(5, 4, 1)) var <- array(1, c(5, 4, 1)) gds <- new_gds(list(beta = beta, var = var), space_sample_labels(letters[1:5]), subjects = paste0("s", 1:4), contrasts = "c1", col_data = data.frame(group = c("patients", "controls", "patients", "controls"), row.names = paste0("s", 1:4))) # Split by group column in col_data gds_by_group <- split(gds, "group") gds_by_group$patients # GDS with only patient subjects subjects(gds_by_group$controls) # Or provide a factor directly groups <- factor(c("A", "B", "A", "B")) gds_split <- split(gds, groups) names(gds_split)
Extract subject identifiers from a GDS object
subjects(x)subjects(x)
x |
A GDS object |
Character vector of subject IDs
Adds a subset_axis node to the plan. Realised gds objects and
gds_source bindings are first converted with as_plan(), so the result
is always a lazy gds_plan; call compute() to materialise it.
## S3 method for class 'gds_plan' subset(x, sample = NULL, subject = NULL, contrast = NULL, ...) ## S3 method for class 'gds' subset(x, sample = NULL, subject = NULL, contrast = NULL, ...) ## S3 method for class 'gds_source' subset(x, sample = NULL, subject = NULL, contrast = NULL, ...)## S3 method for class 'gds_plan' subset(x, sample = NULL, subject = NULL, contrast = NULL, ...) ## S3 method for class 'gds' subset(x, sample = NULL, subject = NULL, contrast = NULL, ...) ## S3 method for class 'gds_source' subset(x, sample = NULL, subject = NULL, contrast = NULL, ...)
x |
A |
sample, subject, contrast
|
Optional indices (positional, logical, or names) for the sample, subject, and contrast axes |
... |
Unused |
A gds_plan
Filter catalog files based on metadata conditions.
## S3 method for class 'image_catalog' subset(x, subset, ...)## S3 method for class 'image_catalog' subset(x, subset, ...)
x |
An image_catalog object. |
subset |
Logical expression evaluated in the context of metadata columns. |
... |
Additional arguments (ignored). |
A filtered image_catalog.
# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") catalog <- assign_meta(catalog, "stat_type", "^([a-z]+)[0-9]+") # Keep only files from subject "01" sub_catalog <- subset(catalog, subject == "01") sub_catalog # Multiple conditions sub_catalog <- subset(catalog, subject %in% c("01", "02") & stat_type == "cope") sub_catalog$metadata$basename unlink(root, recursive = TRUE)# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") catalog <- assign_meta(catalog, "stat_type", "^([a-z]+)[0-9]+") # Keep only files from subject "01" sub_catalog <- subset(catalog, subject == "01") sub_catalog # Multiple conditions sub_catalog <- subset(catalog, subject %in% c("01", "02") & stat_type == "cope") sub_catalog$metadata$basename unlink(root, recursive = TRUE)
Summarize a group examination
## S3 method for class 'gds_examination' summary(object, ...)## S3 method for class 'gds_examination' summary(object, ...)
object |
A |
... |
Unused. |
A compact summary.gds_examination object.
Summary method for image_catalog
## S3 method for class 'image_catalog' summary(object, ...)## S3 method for class 'image_catalog' summary(object, ...)
object |
An image_catalog object. |
... |
Additional arguments (ignored). |
Invisibly returns the catalog.
Specify how uncertainty is propagated through a map
UncertaintyRule( mode = c("independent", "cov_provider", "kernel", "none"), df_rule = c("satterthwaite", "none"), cov_provider = NULL, kernel = NULL )UncertaintyRule( mode = c("independent", "cov_provider", "kernel", "none"), df_rule = c("satterthwaite", "none"), cov_provider = NULL, kernel = NULL )
mode |
One of "independent", "cov_provider", "kernel", "none" |
df_rule |
Degrees of freedom aggregation rule |
cov_provider |
Optional covariance provider function |
kernel |
Optional kernel function |
Uncertainty rule descriptor
Get unique values of a metadata column
## S3 method for class 'image_catalog' unique(x, incomparables = FALSE, column = "subject", ...)## S3 method for class 'image_catalog' unique(x, incomparables = FALSE, column = "subject", ...)
x |
An image_catalog object. |
incomparables |
Passed to base unique (ignored for catalog method). |
column |
Name of metadata column to get unique values from. |
... |
Additional arguments (ignored). |
Unique values from the specified column.
Unregister a post-hoc method
unregister_posthoc(name)unregister_posthoc(name)
name |
Method identifier to remove |
Invisibly, TRUE if removed, FALSE if not found
Custom weights are currently unsupported by the built-in registered
reducers; passing the result to reduce() with such a reducer raises an
informative error instead of silently running an inverse-variance analysis.
Only reducers that declare "custom" in options_schema$weights accept it.
use_weight(g, name)use_weight(g, name)
g |
A realised GDS containing the weight assay |
name |
Assay name to use as custom weights |
A list(list) suitable to splice into reduce():
list(weights = "custom", options = list(custom_weights =
# opts <- use_weight(g2, "w_custom")# opts <- use_weight(g2, "w_custom")
Validate a GDS or plan
validate(x, ...)validate(x, ...)
x |
A |
... |
Additional arguments passed to methods |
TRUE if valid; otherwise errors with a descriptive message
Check that the catalog has consistent file coverage across subjects and report any missing or extra files.
## S3 method for class 'image_catalog' validate(x, by = "subject", expect = NULL, ...)## S3 method for class 'image_catalog' validate(x, by = "subject", expect = NULL, ...)
x |
An image_catalog object. |
by |
Column name to group by for consistency check. Default |
expect |
Optional character vector of expected file basenames per subject. |
... |
Additional arguments (ignored). |
A catalog_validation_report object.
# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") report <- validate(catalog) print(report) report <- validate(catalog, expect = c("cope1.nii.gz", "varcope1.nii.gz")) # Remove one file to see an inconsistency being reported invisible(file.remove(file.path(root, "sub-02", "varcope1.nii.gz"))) catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") validate(catalog) unlink(root, recursive = TRUE)# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") report <- validate(catalog) print(report) report <- validate(catalog, expect = c("cope1.nii.gz", "varcope1.nii.gz")) # Remove one file to see an inconsistency being reported invisible(file.remove(file.path(root, "sub-02", "varcope1.nii.gz"))) catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") validate(catalog) unlink(root, recursive = TRUE)
Deformable warp family helper
WarpFamily( name, from_space, to_space, warps_by_subject, uncertainty = UncertaintyRule("independent") )WarpFamily( name, from_space, to_space, warps_by_subject, uncertainty = UncertaintyRule("independent") )
name |
Family name |
from_space |
Source space |
to_space |
Target space |
warps_by_subject |
Named list of per-subject deformation fields |
uncertainty |
Uncertainty rule (default: independent) |
A MapFamily object for deformable warps
Attach subject-level covariates to a plan or GDS
with_col_data(x, col_data)with_col_data(x, col_data)
x |
Plan, source, or realised GDS |
col_data |
Data frame keyed by subject identifiers (rownames) |
A gds_plan (for plans/sources) or a gds (for realised objects)
Attach contrast-level metadata to a plan or GDS
with_contrast_data(x, contrast_data)with_contrast_data(x, contrast_data)
x |
Plan, source, or realised GDS |
contrast_data |
Data frame keyed by contrast identifiers (rownames) |
A gds_plan (for plans/sources) or a gds (for realised objects)
Attach sample-level metadata to a plan or GDS
with_row_data(x, row_data)with_row_data(x, row_data)
x |
Plan, source, or realised GDS |
row_data |
Data frame keyed by sample identifiers (rownames) when available |
A gds_plan (for plans/sources) or a gds (for realised objects)
Save an image catalog to a JSON file for later retrieval with read_catalog().
write_catalog(catalog, file)write_catalog(catalog, file)
catalog |
An image_catalog object. |
file |
Output file path (should end in |
Invisibly returns the file path.
# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") manifest <- tempfile(fileext = ".json") write_catalog(catalog, manifest) file.exists(manifest) unlink(c(manifest, root), recursive = TRUE)# Build a tiny study tree with empty placeholder files root <- tempfile("study_") for (s in c("01", "02")) { d <- file.path(root, paste0("sub-", s)) dir.create(d, recursive = TRUE) invisible(file.create(file.path(d, c("cope1.nii.gz", "varcope1.nii.gz")))) } catalog <- image_catalog(root, "sub-*/*.nii.gz", path_regex = "sub-(?<subject>[^/]+)") manifest <- tempfile(fileext = ".json") write_catalog(catalog, manifest) file.exists(manifest) unlink(c(manifest, root), recursive = TRUE)
Writes each selected assay/subject/contrast image in a voxel-space GDS to a
separate NIfTI file and returns a manifest describing written and skipped
outputs. This is intended for model outputs such as coef:*, t_coef:*,
and p_coef:* assays.
write_nifti_assays( g, out_dir, prefix = NULL, assays = NULL, subjects = NULL, contrasts = NULL, sanitize = TRUE, overwrite = FALSE )write_nifti_assays( g, out_dir, prefix = NULL, assays = NULL, subjects = NULL, contrasts = NULL, sanitize = TRUE, overwrite = FALSE )
g |
A realised |
out_dir |
Output directory. |
prefix |
Optional filename prefix. |
assays |
Character vector of assays to write. Defaults to all assays. |
subjects |
Optional subject labels to write. Defaults to all subjects. |
contrasts |
Optional contrast labels to write. Defaults to all contrasts. |
sanitize |
Logical; if |
overwrite |
Logical; if |
Filenames are [<prefix>_]contrast-<contrast>[_sub-<subject>]_<assay>.nii.gz.
The contrast- token is always included so that writing several contrasts to
the same directory/prefix (e.g. one call per contrast) never silently
overwrites; the sub- token is added when the GDS has more than one subject.
Existing BIDS-style labels are not double-prefixed (a "sub-01" label stays
sub-01, not sub-sub-01). A within-call collision (two distinct outputs
resolving to the same path, e.g. via sanitisation) raises an error.
A data.frame manifest with assay, subject, contrast, path,
written, and skipped_reason columns.
if (requireNamespace("neuroim2", quietly = TRUE) && requireNamespace("RNifti", quietly = TRUE)) { # Write tiny 4x4x2 subject-level metric maps for four subjects dir <- tempfile("scalar_maps_") dir.create(dir) subj <- c("sub-01", "sub-02", "sub-03", "sub-04") files <- file.path(dir, paste0(subj, "_auc.nii.gz")) for (f in files) RNifti::writeNifti(array(rnorm(32), c(4, 4, 2)), f) participants <- data.frame(subject = subj, group = c("control", "control", "patient", "patient")) g <- suppressWarnings(gds_from_scalar_maps(files, subject = subj, contrast = "auc", col_data = participants)) fit <- group_ols(g, ~ group) |> compute() manifest <- write_nifti_assays(fit, file.path(dir, "group_maps"), prefix = "auc", assays = c("coef:grouppatient", "t_coef:grouppatient")) print(manifest[, c("assay", "written")]) print(basename(manifest$path)) unlink(dir, recursive = TRUE) }if (requireNamespace("neuroim2", quietly = TRUE) && requireNamespace("RNifti", quietly = TRUE)) { # Write tiny 4x4x2 subject-level metric maps for four subjects dir <- tempfile("scalar_maps_") dir.create(dir) subj <- c("sub-01", "sub-02", "sub-03", "sub-04") files <- file.path(dir, paste0(subj, "_auc.nii.gz")) for (f in files) RNifti::writeNifti(array(rnorm(32), c(4, 4, 2)), f) participants <- data.frame(subject = subj, group = c("control", "control", "patient", "patient")) g <- suppressWarnings(gds_from_scalar_maps(files, subject = subj, contrast = "auc", col_data = participants)) fit <- group_ols(g, ~ group) |> compute() manifest <- write_nifti_assays(fit, file.path(dir, "group_maps"), prefix = "auc", assays = c("coef:grouppatient", "t_coef:grouppatient")) print(manifest[, c("assay", "written")]) print(basename(manifest$path)) unlink(dir, recursive = TRUE) }
Adds a lazy write operation to the plan. Data are only written when
compute() executes.
write_out( x, path, format = c("h5", "csv", "parquet", "nifti"), options = list() )write_out( x, path, format = c("h5", "csv", "parquet", "nifti"), options = list() )
x |
A plan or object coercible via |
path |
Output file path |
format |
Output format ( |
options |
Optional list of format-specific options |
Updated plan with a write node appended
The report uses inline CSS and SVG only. Its action plane and residual geometry link to retained subject drill-down sections; it has no external JavaScript, font, image, or stylesheet dependency.
write_report( x, file, title = "Group examination", subjects = NULL, overwrite = FALSE, ... )write_report( x, file, title = "Group examination", subjects = NULL, overwrite = FALSE, ... )
x |
A |
file |
Output HTML path. |
title |
Report title. |
subjects |
Optional retained subject IDs to include. By default, all subjects with retained maps are included. |
overwrite |
Whether an existing file may be replaced. |
... |
Reserved for future report controls. |
The normalized output path, invisibly.