| Title: | Spatially Typed Annotated fMRI Datasets |
|---|---|
| Description: | Provides spatially typed, annotated observation-by-feature containers for functional magnetic resonance imaging (fMRI) data. The package aligns lazy numerical assays with observation metadata, feature metadata, experimental entities, and explicit neuroimaging spaces while retaining compatibility with NIfTI, HDF5, BIDS, and in-memory sources. |
| Authors: | Bradley Buchsbaum [aut, cre] (ORCID: <https://orcid.org/0000-0001-5800-9890>) |
| Maintainer: | Bradley Buchsbaum <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.11.0.9000 |
| Built: | 2026-10-16 13:35:28 UTC |
| Source: | https://github.com/bbuchsbaum/fmridataset |
Construct a strictly aligned assay set
aligned_assay_set(assays, observations, features)aligned_assay_set(assays, observations, features)
assays |
Named matrices or |
observations |
Observation axis. |
features |
Feature axis. |
An aligned_assay_set.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) obs <- axis_frame(data.frame(.obs_id = sprintf("vol-%d", 1:4)), axis = "observation") feat <- feature_axis(feature_data(sp), space = sp) bold <- matrix(rnorm(4 * n_features(sp)), nrow = 4) aligned_assay_set(list(bold = bold), obs, feat)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) obs <- axis_frame(data.frame(.obs_id = sprintf("vol-%d", 1:4)), axis = "observation") feat <- feature_axis(feature_data(sp), space = sp) bold <- matrix(rnorm(4 * n_features(sp)), nrow = 4) aligned_assay_set(list(bold = bold), obs, feat)
Append immutable source shards
append_source_shards(x, sources, shard_ids = NULL, shard_data = NULL)append_source_shards(x, sources, shard_ids = NULL, shard_data = NULL)
x |
An existing |
sources |
New compatible child sources. |
shard_ids |
Stable IDs for the new shards. |
shard_data |
Optional metadata for the new shards. Its columns must match existing shard metadata. |
A new row_sharded_source; x and its child descriptors are not
modified.
src <- row_sharded_source(list(memory_source(matrix(1:4, nrow = 2)))) grown <- append_source_shards(src, list(memory_source(matrix(5:8, nrow = 2)))) source_shape(grown)src <- row_sharded_source(list(memory_source(matrix(1:4, nrow = 2)))) grown <- append_source_shards(src, list(memory_source(matrix(5:8, nrow = 2)))) source_shape(grown)
Apply one validity relation lazily to frame assays
apply_feature_validity(x, name = NULL, assays = NULL)apply_feature_validity(x, name = NULL, assays = NULL)
x |
An |
name |
Validity relation name. |
assays |
Assay names to mask. Defaults to all assays. |
A new frame with lazy NA masking and derivation provenance.
space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") subjects <- entity_frame( data.frame(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) frame <- fmri_frame( assays = list(signal = matrix(1:8, nrow = 2)), observations = data.frame(.obs_id = c("o1", "o2"), subject_id = c("sub-1", "sub-2")), space = space, entities = list(subject = subjects), relations = list( observation_subject = key_relation("subject_id"), subject_feature_validity = validity ) ) masked_frame <- apply_feature_validity(frame) collect_assay(masked_frame)space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") subjects <- entity_frame( data.frame(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) frame <- fmri_frame( assays = list(signal = matrix(1:8, nrow = 2)), observations = data.frame(.obs_id = c("o1", "o2"), subject_id = c("sub-1", "sub-2")), space = space, entities = list(subject = subjects), relations = list( observation_subject = key_relation("subject_id"), subject_feature_validity = validity ) ) masked_frame <- apply_feature_validity(frame) collect_assay(masked_frame)
The estimate distinguishes source storage from the R object returned by a read. Numeric source dtypes, including float16 and float32, are realized as R doubles. The conservative peak estimate adds selection, conversion, and compressed-input buffers to the retained output. It covers numerical payloads; fixed R object headers and selector metadata are outside the estimate.
as_array_source(x, ...) source_shape(x, ...) source_dtype(x, ...) source_chunks(x, ...) source_capabilities(x, ...) source_fingerprint(x, ...) source_open(x, ...) source_read(x, observations = NULL, features = NULL, ...) source_read_native(x, observations = NULL, ...) source_close(x, ...) source_realization_cost(x, observations = NULL, features = NULL)as_array_source(x, ...) source_shape(x, ...) source_dtype(x, ...) source_chunks(x, ...) source_capabilities(x, ...) source_fingerprint(x, ...) source_open(x, ...) source_read(x, observations = NULL, features = NULL, ...) source_read_native(x, observations = NULL, ...) source_close(x, ...) source_realization_cost(x, observations = NULL, features = NULL)
x |
An array source or object coercible to one. |
... |
Additional method arguments. |
observations |
Optional observation selector: |
features |
Optional feature selector, under the same law. |
Fingerprint policy.
source_fingerprint() returns the revision fingerprint of a descriptor:
one SHA-256 string over the serializable descriptor and the physical
revision evidence a backend can observe without reading values (file sizes
and modification times, store metadata, or a per-object identity token for
in-memory sources), combined with selectors and shard composition for
wrappers. It never hashes array values, it is computed once at
construction and cached in the descriptor, and it survives serialization.
Equal fingerprints mean "the same descriptor of the same revision"; they
never mean equal values, and different fingerprints never mean different
values. Two independently constructed memory_source() objects with equal
payloads have different fingerprints by design.
Value identity is a separate, explicit, O(n) operation: content_hash().
File-backed sources compare their captured revision evidence with the
physical state before every open and read and raise
fmridataset_error_source_stale when it differs; genuine backend failures
raise fmridataset_error_backend_io. The policy is recorded in
inst/architecture/ADR-009-source-fingerprints-and-content-hashes.md.
A source_realization_cost list containing storage and realized
dtypes, storage and output bytes, temporary buffer components, and the
estimated peak bytes.
src <- memory_source(matrix(seq_len(6), nrow = 2)) source_shape(src) source_dtype(src) handle <- source_open(src) source_read(handle, observations = 1) source_close(handle)src <- memory_source(matrix(seq_len(6), nrow = 2)) source_shape(src) source_dtype(src) handle <- source_open(src) source_read(handle, observations = 1) source_close(handle)
as_delarr() wraps a serializable array source as a
delarr provider so that bounded, chunk-aware execution can be delegated
to delarr without materializing the assay. The realization budget bounds
each provider pull, not the whole source, so a lazy array may describe more
data than the budget allows; every pull is checked before it reads.
as_delarr(x, memory_budget = Inf, ...) ## Default S3 method: as_delarr(x, memory_budget = Inf, ...)as_delarr(x, memory_budget = Inf, ...) ## Default S3 method: as_delarr(x, memory_budget = Inf, ...)
x |
An array source, or another object with an |
memory_budget |
Maximum realized bytes permitted for a single pull.
|
... |
Additional arguments passed to methods. |
A delarr lazy array whose pulls route through source_read().
array-source for the source protocol.
src <- memory_source(matrix(seq_len(6), nrow = 2)) lazy <- as_delarr(src) dim(lazy)src <- memory_source(matrix(seq_len(6), nrow = 2)) lazy <- as_delarr(src) dim(lazy)
Companion packages implement methods for legacy or domain-specific objects.
The generic is owned by fmridataset so conversions have one canonical
destination and do not introduce competing frame classes.
as_fmri_frame(x, ...)as_fmri_frame(x, ...)
x |
An object convertible to an |
... |
Method-specific arguments. |
An fmri_frame.
src <- memory_source(matrix(seq_len(6), nrow = 2)) obs <- tibble::tibble(.obs_id = c("o1", "o2")) fr <- fmri_frame(list(beta = src), obs) identical(as_fmri_frame(fr), fr)src <- memory_source(matrix(seq_len(6), nrow = 2)) obs <- tibble::tibble(.obs_id = c("o1", "o2")) fr <- fmri_frame(list(beta = src), obs) identical(as_fmri_frame(fr), fr)
Construct a typed auxiliary table
auxiliary_table(data, key = NULL, role = "auxiliary", metadata = list())auxiliary_table(data, key = NULL, role = "auxiliary", metadata = list())
data |
Scalar tabular data. |
key |
Optional stable unique-key column. |
role |
Stable table role such as |
metadata |
Unaligned table-level metadata. |
An fmri_auxiliary_table.
at <- auxiliary_table( data.frame(contrast = c("A-B", "B-A"), stat = c(2.1, -2.1)), key = "contrast", role = "contrasts" ) table_data(at)at <- auxiliary_table( data.frame(contrast = c("A-B", "B-A"), stat = c(2.1, -2.1)), key = "contrast", role = "contrasts" ) table_data(at)
Validate and inspect a typed auxiliary table
validate_auxiliary_table(x) table_data(x) table_key(x) table_role(x)validate_auxiliary_table(x) table_data(x) table_key(x) table_role(x)
x |
An |
validate_auxiliary_table() returns x invisibly; other functions
return table data, key, or role.
at <- auxiliary_table( data.frame(contrast = c("A-B", "B-A"), stat = c(2.1, -2.1)), key = "contrast", role = "contrasts" ) validate_auxiliary_table(at) table_key(at) table_role(at)at <- auxiliary_table( data.frame(contrast = c("A-B", "B-A"), stat = c(2.1, -2.1)), key = "contrast", role = "contrasts" ) validate_auxiliary_table(at) table_key(at) table_role(at)
A block is two-dimensional: rows are the elements of the owning axis and columns are named components. Arrays with more than two dimensions are rejected because a trailing axis without typed metadata would be an anonymous semantic dimension; represent higher-order structure as named components, as several blocks, or as an assay.
axis_block( data, components = NULL, role = "continuous", units = NULL, metadata = list() ) axis_block_data(x) block_components(x) block_component_ids(x)axis_block( data, components = NULL, role = "continuous", units = NULL, metadata = list() ) axis_block_data(x) block_components(x) block_component_ids(x)
data |
A matrix, two-dimensional lazy array, or serializable array
source. Its first dimension is aligned with the owning axis and its second
dimension indexes |
components |
Component metadata. The |
role |
Semantic role such as |
units |
Optional units applying to the block as a whole. |
metadata |
Additional serializable metadata. |
x |
An |
An axis_block.
b <- axis_block( matrix(1:6, 3, 2), components = data.frame(.component_id = c("x", "y")), role = "continuous" ) dim(axis_block_data(b)) block_component_ids(b)b <- axis_block( matrix(1:6, 3, 2), components = data.frame(.component_id = c("x", "y")), role = "continuous" ) dim(axis_block_data(b)) block_component_ids(b)
Construct an annotated axis
axis_frame( data, blocks = list(), id = NULL, axis = c("observation", "feature", "entity", "component"), id_col = NULL, metadata = list(), id_policy = c("require", "deterministic", "ephemeral"), id_keys = NULL, id_namespace = NULL ) axis_data(x) axis_blocks(x) axis_ids(x)axis_frame( data, blocks = list(), id = NULL, axis = c("observation", "feature", "entity", "component"), id_col = NULL, metadata = list(), id_policy = c("require", "deterministic", "ephemeral"), id_keys = NULL, id_namespace = NULL ) axis_data(x) axis_blocks(x) axis_ids(x)
data |
A data frame with one row per axis element. |
blocks |
Named |
id |
Optional stable IDs. |
axis |
Axis role. Observation is the public default. |
id_col |
Name of the ID column. |
metadata |
Additional serializable metadata. |
id_policy |
ID policy. |
id_keys |
Columns that uniquely identify rows under deterministic policy. |
id_namespace |
Stable namespace under deterministic policy. |
x |
An |
An axis_frame.
x <- axis_frame(data.frame(value = 1:3), id_policy = "ephemeral") axis_ids(x) axis_data(x)x <- axis_frame(data.frame(value = 1:3), id_policy = "ephemeral") axis_ids(x) axis_data(x)
A basis_space is a representational feature axis linked to one parent
spatial space. Its encoder maps parent features to component coefficients;
its optional decoder maps coefficients back to the parent. Fitting and
model-specific offsets remain the responsibility of packages such as
fmrilatent.
basis_space( parent, component_ids, encoder, decoder = NULL, data = NULL, basis_type = "linear_basis", provenance = list(), tolerance = 1e-08, metadata = list() )basis_space( parent, component_ids, encoder, decoder = NULL, data = NULL, basis_type = "linear_basis", provenance = list(), tolerance = 1e-08, metadata = list() )
parent |
Parent |
component_ids |
Stable component identifiers. |
encoder |
Component-by-parent analysis operator. |
decoder |
Optional parent-by-component synthesis operator. |
data |
One metadata row per component. |
basis_type |
Stable basis-family label. |
provenance |
Serializable derivation metadata. |
tolerance |
Maximum absolute error permitted when validating that
|
metadata |
Additional serializable metadata. |
A basis_space.
parent <- volume_space(c(2, 1, 1), support = 1:2) x <- basis_space(parent, c("c1", "c2"), diag(2), diag(2)) n_features(x)parent <- volume_space(c(2, 1, 1), support = 1:2) x <- basis_space(parent, c("c1", "c2"), diag(2), diag(2)) n_features(x)
Computes the exact unregularized least-squares encoder
(D' D)^{-1} D' for a full-column-rank decoder D.
basis_space_from_decoder( parent, component_ids, decoder, data = NULL, basis_type = "linear_basis", provenance = list(), tolerance = 1e-08, metadata = list(), encoder = c("least_squares", "none") )basis_space_from_decoder( parent, component_ids, decoder, data = NULL, basis_type = "linear_basis", provenance = list(), tolerance = 1e-08, metadata = list(), encoder = c("least_squares", "none") )
parent, component_ids, decoder, data, basis_type, provenance, tolerance, metadata
|
Passed to |
encoder |
Either |
A basis_space.
parent <- volume_space(c(2, 1, 1), support = 1:2) x <- basis_space_from_decoder(parent, c("c1", "c2"), diag(2)) basis_synthesis(x)parent <- volume_space(c(2, 1, 1), support = 1:2) x <- basis_space_from_decoder(parent, c("c1", "c2"), diag(2)) basis_synthesis(x)
fmrilatent remains the owner of latent fitting, temporal scores, handles,
and offsets. This adapter extracts only its spatial synthesis dictionary and
constructs the corresponding least-squares feature-space algebra.
basis_space_from_fmrilatent( x, parent, component_ids = NULL, data = NULL, provenance = list(), tolerance = 1e-08 )basis_space_from_fmrilatent( x, parent, component_ids = NULL, data = NULL, provenance = list(), tolerance = 1e-08 )
x |
An explicit |
parent |
Parent feature space aligned to the loading rows. |
component_ids |
Optional stable component IDs. |
data |
Optional component metadata. |
provenance |
Additional serializable provenance. |
tolerance |
Left-inverse validation tolerance. |
A basis_space.
# Loading fmrilatent itself takes several seconds, so this full # integration example is wrapped in \donttest{}. if (requireNamespace("fmrilatent", quietly = TRUE)) { parent <- volume_space(c(2, 2, 1), support = 1:4, template = "toy-native") decoder <- Matrix::Matrix( matrix(c(1, 0, 0, 1, 1, 1, 2, -1), nrow = 4, byrow = TRUE), sparse = TRUE ) scores <- Matrix::Matrix(matrix(c(1, 0, 0, 1, 2, -1), nrow = 3, byrow = TRUE)) mask <- neuroim2::LogicalNeuroVol( array(TRUE, dim = c(2, 2, 1)), neuroim2::NeuroSpace(c(2, 2, 1)) ) latent <- fmrilatent::LatentNeuroVec( basis = scores, loadings = decoder, space = neuroim2::NeuroSpace(c(2, 2, 1, 3)), mask = mask, offset = rep(10, 4), meta = list(family = "toy_pca") ) x <- basis_space_from_fmrilatent(latent, parent = parent) basis_projection_info(x) }# Loading fmrilatent itself takes several seconds, so this full # integration example is wrapped in \donttest{}. if (requireNamespace("fmrilatent", quietly = TRUE)) { parent <- volume_space(c(2, 2, 1), support = 1:4, template = "toy-native") decoder <- Matrix::Matrix( matrix(c(1, 0, 0, 1, 1, 1, 2, -1), nrow = 4, byrow = TRUE), sparse = TRUE ) scores <- Matrix::Matrix(matrix(c(1, 0, 0, 1, 2, -1), nrow = 3, byrow = TRUE)) mask <- neuroim2::LogicalNeuroVol( array(TRUE, dim = c(2, 2, 1)), neuroim2::NeuroSpace(c(2, 2, 1)) ) latent <- fmrilatent::LatentNeuroVec( basis = scores, loadings = decoder, space = neuroim2::NeuroSpace(c(2, 2, 1, 3)), mask = mask, offset = rep(10, 4), meta = list(family = "toy_pca") ) x <- basis_space_from_fmrilatent(latent, parent = parent) basis_projection_info(x) }
Inspect basis-space operators
basis_analysis(x) basis_synthesis(x) basis_projection_info(x)basis_analysis(x) basis_synthesis(x) basis_projection_info(x)
x |
A |
basis_analysis() returns the parent-to-component analysis
operator; basis_synthesis() returns the optional component-to-parent
synthesis operator; basis_projection_info() returns validation metadata.
These names deliberately avoid colliding with
fmrilatent::basis_decoder(), which constructs model-level decoders.
parent <- volume_space(c(2, 1, 1), support = 1:2) x <- basis_space(parent, c("c1", "c2"), diag(2), diag(2)) basis_analysis(x) basis_synthesis(x) basis_projection_info(x)parent <- volume_space(c(2, 1, 1), support = 1:2) x <- basis_space(parent, c("c1", "c2"), diag(2), diag(2)) basis_analysis(x) basis_synthesis(x) basis_projection_info(x)
Bind frames along observations
bind_observations( ..., metadata_policy = c("identical", "merge"), active_assay = NULL )bind_observations( ..., metadata_policy = c("identical", "merge"), active_assay = NULL )
... |
Frames with identical feature IDs, spaces, and assay semantics. |
metadata_policy |
Frame-metadata reconciliation. |
active_assay |
Optional active assay for the result. Required when operands have different active assays. |
A lazily row-bound fmri_frame.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) make <- function(prefix) { fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("%s-%d", prefix, 1:4)), space = sp ) } bound <- bind_observations(make("a"), make("b")) dim(bound)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) make <- function(prefix) { fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("%s-%d", prefix, 1:4)), space = sp ) } bound <- bind_observations(make("a"), make("b")) dim(bound)
Apply a function to bounded feature blocks
block_apply(x, FUN, block_size = 4096L, assay = active_assay(x), ...)block_apply(x, FUN, block_size = 4096L, assay = active_assay(x), ...)
x |
An |
FUN |
Function receiving an observation-by-feature matrix and feature IDs. |
block_size |
Number of features per block. |
assay |
Assay name. |
... |
Additional arguments passed to |
A list of block results.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) block_apply(frame, function(mat, ids) colMeans(mat), block_size = 4L)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) block_apply(frame, function(mat, ids) colMeans(mat), block_size = 4L)
Inspect a frame block plan
block_manifest(plan)block_manifest(plan)
plan |
A |
A data frame containing logical block bounds and byte estimates.
frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(20), 5, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:5)), active_assay = "signal" ) plan <- plan_blocks(frame, memory_budget = 10 * 1024^2) block_manifest(plan)frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(20), 5, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:5)), active_assay = "signal" ) plan <- plan_blocks(frame, memory_budget = 10 * 1024^2) block_manifest(plan)
Canonicalization version 1 normalizes semantic R values and writes a tagged,
length-prefixed package binary format. It is an explicitly R-only format.
Named lists and attributes use lexicographic field
order; unnamed list order is preserved. Strings are UTF-8 NFC, sparse matrix
storage layouts are normalized, and NaN payloads use one R value while
remaining distinct from NA_real_. Negative zero remains distinct from zero.
canonical_bytes(x) canonical_sha256(x)canonical_bytes(x) canonical_sha256(x)
x |
A serializable R value. |
canonical_bytes() returns a raw vector. canonical_sha256() returns
its lowercase SHA-256 hexadecimal digest.
canonical_bytes(list(b = 2, a = 1)) canonical_sha256(list(b = 2, a = 1))canonical_bytes(list(b = 2, a = 1)) canonical_sha256(list(b = 2, a = 1))
Canonicalization version 1 hashes normalized R objects with SHA-256 over a package-owned tagged binary encoding. It is stable for supported package operations and round trips, but is deliberately R-only rather than a cross-language wire encoding.
canonicalization_contract()canonicalization_contract()
A serializable canonicalization descriptor.
contract <- canonicalization_contract() contract$algorithmcontract <- canonicalization_contract() contract$algorithm
Collect one frame assay under an explicit memory budget
collect_assay( x, assay = active_assay(x), memory_budget = getOption("fmridataset.collect_budget", 2 * 1024^3), force = FALSE )collect_assay( x, assay = active_assay(x), memory_budget = getOption("fmridataset.collect_budget", 2 * 1024^3), force = FALSE )
x |
An |
assay |
One assay name; defaults to the active assay. |
memory_budget |
Maximum estimated peak bytes, including the retained output and source conversion or decompression buffers. |
force |
Allow collection above the estimated peak budget. |
A dense matrix.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) collect_assay(frame)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) collect_assay(frame)
Collect spatial maps through native or reconstructed reads
collect_spatial_maps( x, observations = NULL, assay = active_assay(x), path = c("auto", "native", "reconstruct"), memory_budget = getOption("fmridataset.spatial_budget", 512 * 1024^2) )collect_spatial_maps( x, observations = NULL, assay = active_assay(x), path = c("auto", "native", "reconstruct"), memory_budget = getOption("fmridataset.spatial_budget", 512 * 1024^2) )
x |
An |
observations |
Observation IDs or integer positions. The requested order is preserved. Duplicated selectors are rejected, as they are on every other frame axis selection. |
assay |
Assay name. |
path |
One of |
memory_budget |
Maximum estimated peak bytes for all returned native maps plus the current packed read, conversion, and reconstruction buffers. |
A named list with one native spatial object per observation.
sp <- volume_space(dim = c(2L, 2L, 1L), affine = diag(4), support = 1:4) frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(12), 3, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:3)), space = sp, active_assay = "signal" ) maps <- collect_spatial_maps(frame, observations = c(1L, 2L)) names(maps)sp <- volume_space(dim = c(2L, 2L, 1L), affine = diag(4), support = 1:4) frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(12), 3, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:3)), space = sp, active_assay = "signal" ) maps <- collect_spatial_maps(frame, observations = c(1L, 2L)) names(maps)
Compute a deterministic collection digest
collection_digest(x)collection_digest(x)
x |
An |
A SHA-256 digest computed without reading numerical arrays.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_digest(collection)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_digest(collection)
Access frames in an fMRI collection
collection_frames(x) collection_frame(x, id) collection_ids(x)collection_frames(x) collection_frame(x, id) collection_ids(x)
x |
An |
id |
One stable frame ID. |
The named frame list, one frame, or the stable frame IDs.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_ids(collection) collection_frame(collection, "sub01")voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_ids(collection) collection_frame(collection, "sub01")
Summarize collection feature spaces
collection_space_data(x) collection_common_space(x)collection_space_data(x) collection_common_space(x)
x |
An |
collection_space_data() returns one metadata row per frame;
collection_common_space() returns whether every feature space is exactly
compatible with the first.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_space_data(collection) collection_common_space(collection)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_space_data(collection) collection_common_space(collection)
The target of first must be the source of second, and their addressed
axes must agree. Explicit ID maps are joined through the intermediate IDs.
Feature operators are composed as second %*% first without changing link
direction.
compose_frame_links(first, second, type = NULL, metadata = list())compose_frame_links(first, second, type = NULL, metadata = list())
first |
A canonical source-to-intermediate |
second |
A canonical intermediate-to-target |
type |
Result link type. It may be omitted when both inputs have the same type. |
metadata |
Unaligned result-link metadata. |
A canonical source-to-target frame_link.
first <- frame_link("bold", "beta", type = "derivation") second <- frame_link("beta", "summary", type = "derivation") composed <- compose_frame_links(first, second) composed$source composed$targetfirst <- frame_link("bold", "beta", type = "derivation") second <- frame_link("beta", "summary", type = "derivation") composed <- compose_frame_links(first, second) composed$source composed$target
A composite_space forms one feature axis from heterogeneous child spaces,
such as left cortex, right cortex, and subcortical volume. It owns only the
ordered routing between that axis and its named parts; each child remains the
authority for spatial identity, vectorization, and reconstruction.
composite_space( parts, composite_type = "composite", metadata = list(), route = NULL )composite_space( parts, composite_type = "composite", metadata = list(), route = NULL )
parts |
A named list of non-empty |
composite_type |
A stable semantic label, such as
|
metadata |
Additional serializable metadata. |
route |
Optional internal routing table with |
A composite_space.
parts <- list( left = index_space(2, ids = c("l1", "l2")), right = index_space(2, ids = c("r1", "r2")) ) x <- composite_space(parts, composite_type = "bilateral") feature_ids(x)parts <- list( left = index_space(2, ids = c("l1", "l2")), right = index_space(2, ids = c("r1", "r2")) ) x <- composite_space(parts, composite_type = "bilateral") feature_ids(x)
Inspect composite feature-space parts
composite_parts(x) composite_part_names(x) composite_part(x, name)composite_parts(x) composite_part_names(x) composite_part(x, name)
x |
A |
name |
One child part name. |
composite_parts() returns the ordered named child spaces;
composite_part_names() returns their names; and composite_part()
returns one child space.
parts <- list( left = index_space(2, ids = c("l1", "l2")), right = index_space(2, ids = c("r1", "r2")) ) x <- composite_space(parts) composite_part_names(x) composite_part(x, "left")parts <- list( left = index_space(2, ids = c("l1", "l2")), right = index_space(2, ids = c("r1", "r2")) ) x <- composite_space(parts) composite_part_names(x) composite_part(x, "left")
content_hash() is the one operation in the package that identifies an
array by its values. It is the content domain of the identity contract
(see identity_descriptor()) and it is always explicit: nothing in the
package computes it for you. Ordinary construction, inspection,
fingerprinting, planning, and persistence never call it.
content_hash(x, ...) ## Default S3 method: content_hash(x, ...) ## S3 method for class 'array_source' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) ) ## S3 method for class 'memory_source' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) ) ## S3 method for class 'source_view' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) ) ## S3 method for class 'row_sharded_source' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) )content_hash(x, ...) ## Default S3 method: content_hash(x, ...) ## S3 method for class 'array_source' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) ) ## S3 method for class 'memory_source' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) ) ## S3 method for class 'source_view' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) ) ## S3 method for class 'row_sharded_source' content_hash( x, ..., block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) )
x |
An array source, a handle, or a matrix coercible to a memory source. |
... |
Passed to methods. |
block_bytes |
Upper bound on the realized bytes of one read. The
default reuses the block-planning option
|
The digest is O(n) in the number of values. The default method streams:
it opens one handle, reads bounded row blocks through the source protocol
aligned to the source chunk grid, and hashes each block into a running
state, so no source is materialized whole. block_bytes bounds the
realized size of one read and affects only I/O; every block size produces
the same digest. Blocks cover whole rows when a row fits the bound and
consecutive feature ranges of one row otherwise.
Two sources hash equal exactly when they have the same shape, realize to the
same R mode (double, logical, or complex), and hold equal values. Storage
dtype, chunking, wrappers, views, and shard composition do not enter the
digest, so an in-memory copy and a row-bound composition of the same values
agree. NaN payloads and NA are normalized to one representation each and
remain distinct; negative zero stays distinct from zero.
The digest describes the values at the moment they were read. It is a
receipt, not a live property: a later in-memory mutation of a memory
source's payload is not detected by source_fingerprint() and shows only
when a fresh content_hash() is compared with the earlier one.
One lowercase SHA-256 hexadecimal string.
source_fingerprint() for the cheap revision identity of a
descriptor, identity_descriptor() for typed identity domains, and
inst/architecture/ADR-009-source-fingerprints-and-content-hashes.md
for the policy.
a <- memory_source(matrix(1:6, 2, 3)) b <- memory_source(matrix(as.double(1:6), 2, 3), chunks = c(1, 1)) identical(source_fingerprint(a), source_fingerprint(b)) identical(content_hash(a), content_hash(b))a <- memory_source(matrix(1:6, 2, 3)) b <- memory_source(matrix(as.double(1:6), 2, 3), chunks = c(1, 1)) identical(source_fingerprint(a), source_fingerprint(b)) identical(content_hash(a), content_hash(b))
Content hashing version 1 is a chained SHA-256 over fixed-size leaves of the realized values in row-major order. The digest depends on the shape, the realized R mode, and every value, and on nothing else: not on the storage dtype, the chunk grid, the read block size, or the composition of sources that produced the values.
content_hash_contract()content_hash_contract()
A serializable content-hash contract descriptor.
content_hash_contract()content_hash_contract()
counting_source() records numerical reads without placing a mutable
environment inside the source descriptor. It is exported for backend and
downstream conformance suites, not as an application data source.
counting_source(source) source_counts(x) reset_source_counts(x)counting_source(source) source_counts(x) reset_source_counts(x)
source |
An array source. |
x |
A counting source. |
This is developer-only test instrumentation. The counter registry is process-local, is not persisted with the descriptor, and must not be used as provenance or as an execution receipt.
A serializable instrumented source.
src <- counting_source(memory_source(matrix(seq_len(6), nrow = 2))) source_read(src, observations = 1) source_counts(src)$readssrc <- counting_source(memory_source(matrix(seq_len(6), nrow = 2))) source_read(src, observations = 1) source_counts(src)$reads
Describe compressed entity-by-feature validity
entity_feature_validity(entity, entity_ids, masks, space, metadata = list())entity_feature_validity(entity, entity_ids, masks, space, metadata = list())
entity |
Entity registry name. |
entity_ids |
Stable entity IDs aligned to mask rows. |
masks |
Logical entity-by-feature matrix or a |
space |
Exact feature space addressed by validity columns. |
metadata |
Serializable relation metadata. |
An entity_feature_validity relation descriptor.
space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) validity_entity(validity)space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) validity_entity(validity)
An entity frame stores one row per subject, session, run, stimulus, item, or
other study entity. Scalar annotations live in data; multivariate values
live in named, first-axis-aligned axis_block objects.
entity_frame(data, key, blocks = list(), entity_type = NULL, metadata = list())entity_frame(data, key, blocks = list(), entity_type = NULL, metadata = list())
data |
Scalar entity annotations with one row per entity. |
key |
Name of the stable primary-key column. |
blocks |
Named entity-aligned |
entity_type |
Optional semantic type such as |
metadata |
Additional serializable metadata. |
An entity_frame, also implementing the axis_frame contract.
x <- entity_frame( data = tibble::tibble( stimulus_id = c("stim-1", "stim-2", "stim-3"), category = c("face", "scene", "object") ), key = "stimulus_id" ) entity_ids(x)x <- entity_frame( data = tibble::tibble( stimulus_id = c("stim-1", "stim-2", "stim-3"), category = c("face", "scene", "object") ), key = "stimulus_id" ) entity_ids(x)
Construct and validate an entity registry
entity_registry(entities = list(), ...) validate_entity_registry(x)entity_registry(entities = list(), ...) validate_entity_registry(x)
entities |
A named list of |
... |
Alternatively, named |
x |
An entity registry. |
A named entity_registry.
subjects <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) registry <- entity_registry(subject = subjects) entity_names(registry)subjects <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) registry <- entity_registry(subject = subjects) entity_names(registry)
Compute a stable entity-registry digest
entity_registry_digest(x)entity_registry_digest(x)
x |
A frame, view, or entity registry. |
A hexadecimal digest over the normalized registry.
subjects <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) registry <- entity_registry(subject = subjects) entity_registry_digest(registry)subjects <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) registry <- entity_registry(subject = subjects) entity_registry_digest(registry)
Access entities from a frame or registry
entities(x, ...) entity(x, name, ...) entity_names(x)entities(x, ...) entity(x, name, ...) entity_names(x)
x |
An |
... |
Additional method arguments. |
name |
One registered entity name. |
entities() returns the registry; entity() returns one
entity_frame; entity_names() returns registry names.
subjects <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) registry <- entity_registry(subject = subjects) entities(registry) entity(registry, "subject") entity_names(registry)subjects <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) registry <- entity_registry(subject = subjects) entities(registry) entity(registry, "subject") entity_names(registry)
Entity-frame accessors
entity_key(x) entity_ids(x) entity_data(x) entity_blocks(x)entity_key(x) entity_ids(x) entity_data(x) entity_blocks(x)
x |
An |
The stable key name, entity IDs, scalar data, or aligned blocks.
embedding <- axis_block(matrix(as.double(1:8), 2, 4), role = "embedding") x <- entity_frame( data = tibble::tibble(stimulus_id = c("stim-1", "stim-2")), key = "stimulus_id", blocks = list(semantic = embedding) ) entity_key(x) entity_ids(x) entity_data(x) entity_blocks(x)embedding <- axis_block(matrix(as.double(1:8), 2, 4), role = "embedding") x <- entity_frame( data = tibble::tibble(stimulus_id = c("stim-1", "stim-2")), key = "stimulus_id", blocks = list(semantic = embedding) ) entity_key(x) entity_ids(x) entity_data(x) entity_blocks(x)
Event rows retain their natural cardinality and are not expanded to acquired volumes. Entity-key columns are validated against a study when attached.
event_table(data, key = "event_id", metadata = list())event_table(data, key = "event_id", metadata = list())
data |
Scalar event annotations. |
key |
Stable event-key column. |
metadata |
Serializable event-table metadata. |
An fmri_event_table.
et <- event_table( data.frame(event_id = c("e1", "e2"), onset = c(0, 10), duration = c(2, 2)), key = "event_id" ) event_data(et) event_key(et)et <- event_table( data.frame(event_id = c("e1", "e2"), onset = c(0, 10), duration = c(2, 2)), key = "event_id" ) event_data(et) event_key(et)
Event-table accessors
event_data(x) event_key(x)event_data(x) event_key(x)
x |
An |
Event scalar data or the stable key name.
et <- event_table( data.frame(event_id = c("e1", "e2"), onset = c(0, 10)), key = "event_id" ) event_data(et) event_key(et)et <- event_table( data.frame(event_id = c("e1", "e2"), onset = c(0, 10)), key = "event_id" ) event_data(et) event_key(et)
Execute a bounded frame block plan
execute_block_plan(x, plan, FUN, ..., assay = plan$assay)execute_block_plan(x, plan, FUN, ..., assay = plan$assay)
x |
The same frame or view used to construct |
plan |
A |
FUN |
Function receiving |
... |
Additional arguments passed to |
assay |
Assay name; defaults to the planned assay. |
A list containing one result per planned block.
frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(20), 5, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:5)), active_assay = "signal" ) plan <- plan_blocks(frame, memory_budget = 10 * 1024^2) execute_block_plan(frame, plan, function(values, observation_ids, feature_ids, block) { sum(values) })frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(20), 5, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:5)), active_assay = "signal" ) plan <- plan_blocks(frame, memory_budget = 10 * 1024^2) execute_block_plan(frame, plan, function(values, observation_ids, feature_ids, block) { sum(values) })
Unlike collect_spatial_maps(), execute_spatial() holds only one input
map at a time. The callback result is retained, so callers remain
responsible for keeping returned values appropriately small.
execute_spatial( x, observations = NULL, FUN, ..., assay = active_assay(x), path = c("auto", "native", "reconstruct"), memory_budget = getOption("fmridataset.spatial_budget", 512 * 1024^2) )execute_spatial( x, observations = NULL, FUN, ..., assay = active_assay(x), path = c("auto", "native", "reconstruct"), memory_budget = getOption("fmridataset.spatial_budget", 512 * 1024^2) )
x |
An |
observations |
Observation IDs or integer positions. |
FUN |
Function receiving |
... |
Additional arguments passed to |
assay |
Assay name. |
path |
One of |
memory_budget |
Maximum estimated peak bytes for one input spatial map plus its packed read, conversion, and reconstruction buffers. |
A list of callback results in requested observation order.
sp <- volume_space(dim = c(2L, 2L, 1L), affine = diag(4), support = 1:4) frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(12), 3, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:3)), space = sp, active_assay = "signal" ) execute_spatial(frame, c(1L, 2L), function(map, observation_id) observation_id)sp <- volume_space(dim = c(2L, 2L, 1L), affine = diag(4), support = 1:4) frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(12), 3, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:3)), space = sp, active_assay = "signal" ) execute_spatial(frame, c(1L, 2L), function(map, observation_id) observation_id)
Matrix operations always use bounded observation-by-feature blocks. Spatial operations use a source's native-image capability only when the frame view retains the complete feature domain; otherwise they reconstruct maps from packed assay values through the frame's feature space.
execution_path( x, operation = c("matrix", "spatial"), assay = active_assay(x), path = c("auto", "native", "reconstruct") )execution_path( x, operation = c("matrix", "spatial"), assay = active_assay(x), path = c("auto", "native", "reconstruct") )
x |
An |
operation |
Either |
assay |
Assay name. |
path |
For spatial operations, one of |
One of "matrix", "native", or "reconstruct".
sp <- volume_space(dim = c(2L, 2L, 1L), affine = diag(4), support = 1:4) frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(12), 3, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:3)), space = sp, active_assay = "signal" ) execution_path(frame, operation = "matrix") execution_path(frame, operation = "spatial")sp <- volume_space(dim = c(2L, 2L, 1L), affine = diag(4), support = 1:4) frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(12), 3, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:3)), space = sp, active_assay = "signal" ) execution_path(frame, operation = "matrix") execution_path(frame, operation = "spatial")
explain() returns a bounded, serializable summary of the visible frame.
Axis IDs are sampled by default so inspecting a large study does not create
another large object. Set ids = "complete" only when every visible ID is
required.
explain(x, ids = c("sample", "none", "complete"), sample_size = 3L)explain(x, ids = c("sample", "none", "complete"), sample_size = 3L)
x |
An |
ids |
One of |
sample_size |
Number of IDs sampled from each end of each axis. |
The schema digest describes column, block, assay, relation, entity, table, and space contracts. The semantic digest covers the complete source-free FDS manifest. Physical source fingerprints are reported separately.
A bounded serializable execution summary. No assay or aligned-block
values are read. ids_durable reports whether the observation axis and
the feature space carry durable IDs; when it is FALSE the semantic
digest is NULL because ephemeral IDs cannot enter an FDS manifest.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) summary <- explain(frame) summary$shapesp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) summary <- explain(frame) summary$shape
This source is exported solely for deterministic backend, codec, cleanup, and recovery conformance tests.
fault_source( source, stage = c("read", "open", "native_read", "close"), message = NULL )fault_source( source, stage = c("read", "open", "native_read", "close"), message = NULL )
source |
An array source. |
stage |
One of |
message |
Failure message. |
This is developer-only test instrumentation. Never persist a fault_source
as study data or use one in an analysis plan.
A serializable fault-injecting source.
src <- fault_source(memory_source(matrix(seq_len(6), nrow = 2)), stage = "read") tryCatch(source_read(src), error = function(e) conditionMessage(e))src <- fault_source(memory_source(matrix(seq_len(6), nrow = 2)), stage = "read") tryCatch(source_read(src), error = function(e) conditionMessage(e))
Storage codecs use this helper to pair each source-free FDS array declaration
with its current physical or in-memory array_source.
fds_frame_bindings(x)fds_frame_bindings(x)
x |
An |
A named list of array_source descriptors keyed exactly like the
manifest arrays registry.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) bindings <- fds_frame_bindings(frame) names(bindings)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) bindings <- fds_frame_bindings(frame) names(bindings)
The manifest owns semantic alignment but deliberately excludes physical
source descriptors. Storage packages bind assay names to physical array
locations separately and reconstruct frames with frame_from_fds_manifest().
fds_frame_manifest(x) validate_fds_manifest(manifest)fds_frame_manifest(x) validate_fds_manifest(manifest)
x |
An |
manifest |
An FDS manifest. |
A serializable backend-neutral manifest.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) manifest <- fds_frame_manifest(frame) manifest$shape validate_fds_manifest(manifest)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) manifest <- fds_frame_manifest(frame) manifest$shape validate_fds_manifest(manifest)
Compute a canonical FDS manifest digest
fds_manifest_digest(manifest)fds_manifest_digest(manifest)
manifest |
A valid FDS manifest. |
A stable hexadecimal digest over semantic manifest content.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) manifest <- fds_frame_manifest(frame) fds_manifest_digest(manifest)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) manifest <- fds_frame_manifest(frame) fds_manifest_digest(manifest)
FDS version 1 is the backend-neutral semantic contract for persisted
fmri_frame objects. Physical codecs may add locations, chunks, compression,
and checksums outside this manifest, but cannot change its field meanings.
fds_schema() fds_schema_version()fds_schema() fds_schema_version()
fds_schema() returns the immutable schema identity;
fds_schema_version() returns its integer major version.
fds_schema() fds_schema_version()fds_schema() fds_schema_version()
Extract shared study-level physical bindings
fds_study_bindings(x)fds_study_bindings(x)
x |
An |
A named list of shared entity-block payloads. Representation arrays remain owned by their individual frame bindings.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) fds_study_bindings(study)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) fds_study_bindings(study)
Study manifests retain shared entities, typed links, relational tables, and the semantic manifests of every frame or collection member. Numerical sources remain separate bindings so physical storage packages do not own or reinterpret study semantics.
fds_study_manifest(x) validate_fds_study_manifest(manifest)fds_study_manifest(x) validate_fds_study_manifest(manifest)
x |
An |
manifest |
An FDS study manifest. |
fds_study_manifest() returns a serializable source-free manifest;
validate_fds_study_manifest() returns manifest invisibly.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) manifest <- fds_study_manifest(study) names(manifest$representations)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) manifest <- fds_study_manifest(study) names(manifest$representations)
Compute a canonical FDS study-manifest digest
fds_study_manifest_digest(manifest)fds_study_manifest_digest(manifest)
manifest |
A valid FDS study manifest. |
A stable hexadecimal digest over source-free study semantics.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) manifest <- fds_study_manifest(study) fds_study_manifest_digest(manifest)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) manifest <- fds_study_manifest(study) fds_study_manifest_digest(manifest)
Extract canonical study representations for persistence
fds_study_representations(x)fds_study_representations(x)
x |
An |
Named frames and collections matching fds_study_manifest(x).
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) names(fds_study_representations(study))voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) names(fds_study_representations(study))
Construct a spatial feature axis
feature_axis(data, space = NULL, blocks = list(), metadata = list(), ...)feature_axis(data, space = NULL, blocks = list(), metadata = list(), ...)
data |
Feature metadata or an |
space |
A |
blocks |
Feature-aligned blocks. |
metadata |
Additional metadata. |
... |
Additional arguments for methods. |
A feature axis_frame carrying its space.
sp <- index_space(3, ids = sprintf("f%d", 1:3), namespace = "ex") fx <- feature_axis(data.frame(.feature_id = sprintf("f%d", 1:3)), space = sp) axis_ids(fx)sp <- index_space(3, ids = sprintf("f%d", 1:3), namespace = "ex") fx <- feature_axis(data.frame(.feature_id = sprintf("f%d", 1:3)), space = sp) axis_ids(fx)
A feature map owns a target-by-source linear operator and the complete
spatial identity of both axes. Equal dimensions are never treated as
evidence of spatial compatibility. Statistical execution plans and
covariance models remain the responsibility of packages such as
fmrigds.
feature_map( from, to, operator, map_type = "linear", traits = list(linear = TRUE), provenance = list(), metadata = list() )feature_map( from, to, operator, map_type = "linear", traits = list(linear = TRUE), provenance = list(), metadata = list() )
from |
Source |
to |
Target |
operator |
Target-by-source matrix, sparse |
map_type |
Stable map-family label. |
traits |
Named serializable semantic traits. |
provenance |
Serializable derivation metadata for the map itself. |
metadata |
Additional serializable metadata. |
A serializable feature_map descriptor.
src <- index_space(4, ids = paste0("v", 1:4), namespace = "map-source") tgt <- index_space(2, ids = paste0("p", 1:2), namespace = "map-target") op <- matrix(c(0.5, 0.5, 0, 0, 0, 0, 0.5, 0.5), nrow = 2, byrow = TRUE) m <- feature_map(src, tgt, op, map_type = "toy_aggregation") feature_map_operator(m)src <- index_space(4, ids = paste0("v", 1:4), namespace = "map-source") tgt <- index_space(2, ids = paste0("p", 1:2), namespace = "map-target") op <- matrix(c(0.5, 0.5, 0, 0, 0, 0, 0.5, 0.5), nrow = 2, byrow = TRUE) m <- feature_map(src, tgt, op, map_type = "toy_aggregation") feature_map_operator(m)
Parcel spaces contribute their aggregation operator and basis spaces their
analysis operator. Other transformations require an explicit
feature_map().
feature_map_from_target(target)feature_map_from_target(target)
target |
A parent-linked |
A feature_map from parent_space(target) to target.
parent <- volume_space(c(2, 2, 1), support = 1:4, template = "toy") membership <- Matrix::sparseMatrix( i = 1:4, j = c(1L, 1L, 2L, 2L), x = 1, dims = c(4L, 2L) ) target <- parcel_space(parent, c("left", "right"), membership, atlas = "toy") m <- feature_map_from_target(target) feature_map_target_space(m)parent <- volume_space(c(2, 2, 1), support = 1:4, template = "toy") membership <- Matrix::sparseMatrix( i = 1:4, j = c(1L, 1L, 2L, 2L), x = 1, dims = c(4L, 2L) ) target <- parcel_space(parent, c("left", "right"), membership, atlas = "toy") m <- feature_map_from_target(target) feature_map_target_space(m)
Construct a lazy source transformed through a feature map
feature_mapped_source(source, map, rule = c("linear", "independent_variance"))feature_mapped_source(source, map, rule = c("linear", "independent_variance"))
source |
Observation-by-source-feature |
map |
A compatible |
rule |
Transformation rule. |
A serializable feature_mapped_source.
src <- index_space(4, ids = paste0("v", 1:4), namespace = "map-source") tgt <- index_space(2, ids = paste0("p", 1:2), namespace = "map-target") op <- matrix(c(0.5, 0.5, 0, 0, 0, 0, 0.5, 0.5), nrow = 2, byrow = TRUE) m <- feature_map(src, tgt, op, map_type = "toy_aggregation") fs <- feature_mapped_source(memory_source(matrix(1:12, nrow = 3)), m) dim(source_read(fs))src <- index_space(4, ids = paste0("v", 1:4), namespace = "map-source") tgt <- index_space(2, ids = paste0("p", 1:2), namespace = "map-target") op <- matrix(c(0.5, 0.5, 0, 0, 0, 0, 0.5, 0.5), nrow = 2, byrow = TRUE) m <- feature_map(src, tgt, op, map_type = "toy_aggregation") fs <- feature_mapped_source(memory_source(matrix(1:12, nrow = 3)), m) dim(source_read(fs))
Validate and inspect feature maps
validate_feature_map(x) feature_map_source_space(x) feature_map_target_space(x) feature_map_operator(x) feature_map_digest(x)validate_feature_map(x) feature_map_source_space(x) feature_map_target_space(x) feature_map_operator(x) feature_map_digest(x)
x |
A |
validate_feature_map() returns x invisibly. The accessors return
the source space, target space, linear operator, or deterministic digest.
src <- index_space(4, ids = paste0("v", 1:4), namespace = "map-source") tgt <- index_space(2, ids = paste0("p", 1:2), namespace = "map-target") op <- matrix(c(0.5, 0.5, 0, 0, 0, 0, 0.5, 0.5), nrow = 2, byrow = TRUE) m <- feature_map(src, tgt, op, map_type = "toy_aggregation") feature_map_source_space(m) feature_map_target_space(m) feature_map_digest(m)src <- index_space(4, ids = paste0("v", 1:4), namespace = "map-source") tgt <- index_space(2, ids = paste0("p", 1:2), namespace = "map-target") op <- matrix(c(0.5, 0.5, 0, 0, 0, 0, 0.5, 0.5), nrow = 2, byrow = TRUE) m <- feature_map(src, tgt, op, map_type = "toy_aggregation") feature_map_source_space(m) feature_map_target_space(m) feature_map_digest(m)
Every feature-space class (such as volume_space(), surface_space(),
parcel_space(), basis_space(), composite_space(), and
index_space()) implements this shared generic contract for feature
count, stable identity, restriction, vectorization, and reconstruction.
n_features(x, ...) feature_ids(x, ...) native_shape(x, ...) feature_data(x, ...) space_digest(x, ...) restrict_space(x, index, ...) vectorize_space(x, spatial_object, ...) reconstruct_space(x, vector, ...) adjacency(x, ...) same_space(x, y, ...) assert_same_space(x, y, ...) ## S3 method for class 'surface_space' reconstruct_space(x, vector, format = c("surface_map", "neurosurf"), ...)n_features(x, ...) feature_ids(x, ...) native_shape(x, ...) feature_data(x, ...) space_digest(x, ...) restrict_space(x, index, ...) vectorize_space(x, spatial_object, ...) reconstruct_space(x, vector, ...) adjacency(x, ...) same_space(x, y, ...) assert_same_space(x, y, ...) ## S3 method for class 'surface_space' reconstruct_space(x, vector, format = c("surface_map", "neurosurf"), ...)
x |
A feature-space object. |
... |
Additional arguments for methods. |
index |
Features to keep, in order: positive or negative positions, a logical mask over the features, or character feature IDs. Every built-in space resolves these by the same selection law and rejects out-of-bounds, duplicated, or unknown selectors with structured errors. |
spatial_object |
A native spatial object to vectorize. For a
|
vector |
A feature vector to reconstruct. An unnamed vector is positional; a named vector must name every feature ID exactly once and is reordered to the space's feature order. |
y |
A second feature-space object. |
format |
Surface reconstruction format. The backend-neutral default is
|
n_features() returns a single integer; feature_ids() returns a
character vector of stable feature identifiers; native_shape() returns
the class-specific native dimensions; feature_data() returns a tibble
of per-feature metadata; space_digest() returns a content digest
string; restrict_space() and reconstruct_space() return an object of
the same feature-space class; vectorize_space() returns a numeric
vector; adjacency() returns a sparse adjacency matrix or NULL;
same_space() returns a space_comparison list whose same field is
TRUE only when class, digest, and ordered feature IDs all agree;
assert_same_space() returns that report invisibly and signals an
fmridataset_error_space_mismatch error otherwise.
x <- index_space(3, ids = c("a", "b", "c")) n_features(x) feature_ids(x) y <- restrict_space(x, 1:2) same_space(x, x)$samex <- index_space(3, ids = c("a", "b", "c")) n_features(x) feature_ids(x) y <- restrict_space(x, 1:2) same_space(x, x)$same
Validate and inspect entity-feature validity
validate_entity_feature_validity(x) validity_entity(x, name = NULL) validity_entity_ids(x, name = NULL) validity_mask_bank(x, name = NULL) validity_space(x, name = NULL) validity_matrix(x, name = NULL)validate_entity_feature_validity(x) validity_entity(x, name = NULL) validity_entity_ids(x, name = NULL) validity_mask_bank(x, name = NULL) validity_space(x, name = NULL) validity_matrix(x, name = NULL)
x |
An |
name |
Relation name when |
The validated descriptor, entity name/IDs, mask bank, feature space, or expanded entity-by-feature logical matrix.
space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) validity_entity_ids(validity) validity_matrix(validity)space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) validity_entity_ids(validity) validity_matrix(validity)
Dropping entity records cascades: child entities whose key relation references a dropped record are dropped too, observations reaching a dropped record are removed, and sparse edges, validity rows, link maps, and table rows are restricted to the surviving IDs. Table rows without a key value are kept.
filter_entities(x, entity, predicate)filter_entities(x, entity, predicate)
x |
An |
entity |
Bare or quoted shared entity name. |
predicate |
A scalar-metadata predicate evaluated on that entity table. |
A self-contained fmri_study whose numerical sources remain lazy.
subject_entity <- entity_frame( data.frame(subject_id = c("s1", "s2"), age = c(20, 60)), key = "subject_id" ) obs <- data.frame( .obs_id = paste0("o", 1:4), subject_id = c("s1", "s1", "s2", "s2") ) frame <- fmri_frame( assays = list(bold = matrix(rnorm(16), nrow = 4)), observations = obs, space = index_space(4, ids = paste0("f", 1:4)), entities = list(subject = subject_entity), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) study <- fmri_study(list(main = frame), entities = list(subject = subject_entity)) older <- filter_entities(study, subject, age > 30) observation_ids(study_frame(older, "main"))subject_entity <- entity_frame( data.frame(subject_id = c("s1", "s2"), age = c(20, 60)), key = "subject_id" ) obs <- data.frame( .obs_id = paste0("o", 1:4), subject_id = c("s1", "s1", "s2", "s2") ) frame <- fmri_frame( assays = list(bold = matrix(rnorm(16), nrow = 4)), observations = obs, space = index_space(4, ids = paste0("f", 1:4)), entities = list(subject = subject_entity), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) study <- fmri_study(list(main = frame), entities = list(subject = subject_entity)) older <- filter_entities(study, subject, age > 30) observation_ids(study_frame(older, "main"))
Filter frame observations using scalar metadata
filter_obs(x, predicate, resolve = TRUE)filter_obs(x, predicate, resolve = TRUE)
x |
An |
predicate |
A metadata expression returning one logical value per observation. |
resolve |
Whether the predicate may use namespaced entity metadata. |
An fmri_view.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame( .obs_id = sprintf("vol-%d", 1:4), run_id = rep(c("run-1", "run-2"), each = 2) ), space = sp ) filter_obs(frame, run_id == "run-1")sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame( .obs_id = sprintf("vol-%d", 1:4), run_id = rep(c("run-1", "run-2"), each = 2) ), space = sp ) filter_obs(frame, run_id == "run-1")
A collection keeps frames separate when they share an observational and assay contract but cannot share a feature axis, as with participant-native volume or surface spaces. Equal feature dimensions or IDs are not required; feature-space type and annotation semantics are validated explicitly.
fmri_collection(frames, metadata = list(), provenance = NULL)fmri_collection(frames, metadata = list(), provenance = NULL)
frames |
A non-empty named list of |
metadata |
Unaligned collection-level metadata. |
provenance |
|
An fmri_collection.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_ids(collection)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) collection_ids(collection)
Construct a spatially typed annotated matrix
fmri_frame( assays, observations, features = NULL, space = NULL, entities = list(), relations = list(), tables = list(), active_assay = NULL, metadata = list(), provenance = NULL )fmri_frame( assays, observations, features = NULL, space = NULL, entities = list(), relations = list(), tables = list(), active_assay = NULL, metadata = list(), provenance = NULL )
assays |
Named matrices or serializable array sources. |
observations |
Observation metadata or an observation |
features |
Feature metadata or a spatial feature axis. |
space |
Feature space used when |
entities |
A named |
relations |
Named relation registry. |
tables |
Named typed tables created by |
active_assay |
Active assay name. |
metadata |
Unaligned frame-level record. Aligned values belong on an axis, entity, block, assay, relation, typed table, or linked frame. |
provenance |
|
An fmri_frame.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) framesp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) frame
Construct a linked fMRI study
fmri_study( frames, entities = list(), links = list(), tables = list(), metadata = list(), provenance = NULL )fmri_study( frames, entities = list(), links = list(), tables = list(), metadata = list(), provenance = NULL )
frames |
Named |
entities |
Shared authoritative entity registry. |
links |
Named |
tables |
Named typed relational tables. |
metadata |
Unaligned study-level metadata. |
provenance |
|
An fmri_study.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_ids(study)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_ids(study)
Reconstruct a frame from an FDS manifest and physical sources
frame_from_fds_manifest(manifest, bindings)frame_from_fds_manifest(manifest, bindings)
manifest |
A valid FDS v1 frame manifest. |
bindings |
Named physical array payloads or |
An fmri_frame whose semantic state comes from manifest and whose
lazy arrays come from bindings.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) manifest <- fds_frame_manifest(frame) bindings <- fds_frame_bindings(frame) rebuilt <- frame_from_fds_manifest(manifest, bindings) identical(feature_ids(rebuilt), feature_ids(frame))voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) manifest <- fds_frame_manifest(frame) bindings <- fds_frame_bindings(frame) rebuilt <- frame_from_fds_manifest(manifest, bindings) identical(feature_ids(rebuilt), feature_ids(frame))
Describe a typed link between study representations
frame_link( source, target, type = c("derivation", "mapping", "correspondence", "alignment"), map = NULL, source_axis = c("observation", "feature"), target_axis = c("observation", "feature"), metadata = list(), operator = NULL )frame_link( source, target, type = c("derivation", "mapping", "correspondence", "alignment"), map = NULL, source_axis = c("observation", "feature"), target_axis = c("observation", "feature"), metadata = list(), operator = NULL )
source |
Source representation name. |
target |
Target representation name. |
type |
Link type: derivation, feature mapping, correspondence, or alignment. |
map |
Optional scalar table with |
source_axis |
Axis addressed by |
target_axis |
Axis addressed by |
metadata |
Serializable link metadata. |
operator |
Optional typed feature operator. This is valid only for a feature-to-feature mapping or alignment and remains a first-class field. |
A frame_link descriptor.
link <- frame_link("bold", "surface", type = "derivation") link$source link$targetlink <- frame_link("bold", "surface", type = "derivation") link$source link$target
The schema describes aligned assay annotations, scalar column types and factor levels, multivariate block trailing axes and components, spatial identity, entities, relations, auxiliary tables, and active-assay policy. It inspects descriptors and metadata only and never reads numerical values.
frame_schema(x)frame_schema(x)
x |
An |
A serializable fmri_frame_schema.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) schema <- frame_schema(frame) schema$active_assaysp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) schema <- frame_schema(frame) schema$active_assay
Generic accessors for the components of an fmri_frame or fmri_view:
its assays, active assay, observation and feature axes and IDs, block
registries, and dimensions.
assays(x, ...) assay(x, name = active_assay(x), ...) active_assay(x, ...) observation_axis(x, ...) observations(x, resolve = FALSE, ...) features(x, ...) observation_ids(x, ...) obs_blocks(x, resolve = FALSE, ...) feature_blocks(x, ...) ## S3 method for class 'fmri_frame' dim(x) ## S3 method for class 'fmri_view' dim(x)assays(x, ...) assay(x, name = active_assay(x), ...) active_assay(x, ...) observation_axis(x, ...) observations(x, resolve = FALSE, ...) features(x, ...) observation_ids(x, ...) obs_blocks(x, resolve = FALSE, ...) feature_blocks(x, ...) ## S3 method for class 'fmri_frame' dim(x) ## S3 method for class 'fmri_view' dim(x)
x |
An |
... |
Additional method arguments. |
name |
One assay name; defaults to the active assay. Positions, vectors, and missing values are refused. |
resolve |
Whether to append reachable, namespaced entity annotations or lazily lifted entity blocks. |
assays() returns a named aligned_assay_set list and assay()
one aligned_assay from it. active_assay() returns a single assay
name. observation_axis() returns an axis_frame; observations() and
features() return a data frame of the corresponding metadata.
observation_ids() and feature_ids() return character vectors of
stable IDs. obs_blocks() and feature_blocks() return named lists of
axis_blocks. dim() returns a length-2 integer vector, and nrow()
and ncol() return single integers.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) names(assays(frame)) active_assay(frame) dim(frame)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) names(assays(frame)) active_assay(frame) dim(frame)
Validate and compare canonical frame schemas
validate_frame_schema(schema) compare_frame_schema(x, reference, mode = c("same", "collection", "bind")) validate_against_schema(x, reference, mode = c("same", "collection", "bind")) frame_schema_digest(x)validate_frame_schema(schema) compare_frame_schema(x, reference, mode = c("same", "collection", "bind")) validate_against_schema(x, reference, mode = c("same", "collection", "bind")) frame_schema_digest(x)
schema |
A canonical frame schema. |
x |
A frame, view, or schema to validate. |
reference |
A frame, view, or schema used as the reference contract. |
mode |
Comparison mode. |
compare_frame_schema() treats named records, such as column
descriptors and the assay, entity, relation, and table registries, as
unordered: column order and assay registry order are not semantic. This
matches frame_schema_digest(), whose canonical encoding sorts record
fields by name. Unnamed sequences such as feature and component IDs remain
order-sensitive. validate_frame_schema() checks the shape of every
section and rejects missing or unknown top-level fields.
Validators return their input invisibly. compare_frame_schema()
returns a structured frame_schema_compatibility report.
frame_schema_digest() returns a single hex digest string.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) schema <- frame_schema(frame) validate_frame_schema(schema) compare_frame_schema(frame, frame)$compatible frame_schema_digest(frame)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) schema <- frame_schema(frame) validate_frame_schema(schema) compare_frame_schema(frame, frame)$compatible frame_schema_digest(frame)
Compute the deterministic digest of a hierarchy index
hierarchy_digest(x)hierarchy_digest(x)
x |
An |
A SHA-256 digest.
subject <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) observations <- tibble::tibble( .obs_id = paste0("obs-", 1:4), subject_id = c("sub-1", "sub-1", "sub-2", "sub-2") ) frame <- fmri_frame( assays = list(beta = memory_source(matrix(as.double(1:12), 4, 3))), observations = observations, entities = list(subject = subject), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) idx <- hierarchy_index(frame, levels = "subject") hierarchy_digest(idx)subject <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) observations <- tibble::tibble( .obs_id = paste0("obs-", 1:4), subject_id = c("sub-1", "sub-1", "sub-2", "sub-2") ) frame <- fmri_frame( assays = list(beta = memory_source(matrix(as.double(1:12), 4, 3))), observations = observations, entities = list(subject = subject), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) idx <- hierarchy_index(frame, levels = "subject") hierarchy_digest(idx)
A hierarchy index is an immutable, assay-free cache derived from validated
key relations. levels are supplied root-to-leaf. Each adjacent edge must
form a strict chain from observations to the deepest entity and then through
its parents. Crossed relations are therefore never mistaken for containment.
hierarchy_index(x, levels, relations = NULL)hierarchy_index(x, levels, relations = NULL)
x |
An |
levels |
Unique entity names in root-to-leaf order. |
relations |
Optional named character vector mapping every level to the key-relation name used for its incoming edge. This is required when an edge is ambiguous. |
Integer group codes use entity-registry order, so they remain stable when a frame is filtered or reordered.
An fmri_hierarchy_index.
subject <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) observations <- tibble::tibble( .obs_id = paste0("obs-", 1:4), subject_id = c("sub-1", "sub-1", "sub-2", "sub-2") ) frame <- fmri_frame( assays = list(beta = memory_source(matrix(as.double(1:12), 4, 3))), observations = observations, entities = list(subject = subject), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) idx <- hierarchy_index(frame, levels = "subject") hierarchy_ids(idx)subject <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) observations <- tibble::tibble( .obs_id = paste0("obs-", 1:4), subject_id = c("sub-1", "sub-1", "sub-2", "sub-2") ) frame <- fmri_frame( assays = list(beta = memory_source(matrix(as.double(1:12), 4, 3))), observations = observations, entities = list(subject = subject), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) idx <- hierarchy_index(frame, levels = "subject") hierarchy_ids(idx)
Access derived hierarchy index data
hierarchy_ids(x) hierarchy_groups(x) hierarchy_levels(x) hierarchy_relations(x) hierarchy_complete(x)hierarchy_ids(x) hierarchy_groups(x) hierarchy_levels(x) hierarchy_relations(x) hierarchy_complete(x)
x |
An |
hierarchy_ids() returns stable entity IDs; hierarchy_groups()
returns stable integer grouping codes; hierarchy_levels() and
hierarchy_relations() return named character vectors;
hierarchy_complete() returns a logical vector.
subject <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) observations <- tibble::tibble( .obs_id = paste0("obs-", 1:4), subject_id = c("sub-1", "sub-1", "sub-2", "sub-2") ) frame <- fmri_frame( assays = list(beta = memory_source(matrix(as.double(1:12), 4, 3))), observations = observations, entities = list(subject = subject), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) idx <- hierarchy_index(frame, levels = "subject") hierarchy_ids(idx) hierarchy_groups(idx) hierarchy_levels(idx) hierarchy_relations(idx) hierarchy_complete(idx)subject <- entity_frame( data = tibble::tibble(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) observations <- tibble::tibble( .obs_id = paste0("obs-", 1:4), subject_id = c("sub-1", "sub-1", "sub-2", "sub-2") ) frame <- fmri_frame( assays = list(beta = memory_source(matrix(as.double(1:12), 4, 3))), observations = observations, entities = list(subject = subject), relations = list( observation_subject = key_relation("subject_id", target = "subject") ) ) idx <- hierarchy_index(frame, levels = "subject") hierarchy_ids(idx) hierarchy_groups(idx) hierarchy_levels(idx) hierarchy_relations(idx) hierarchy_complete(idx)
Inspect axis ID durability
axis_id_policy(x) ids_are_durable(x)axis_id_policy(x) ids_are_durable(x)
x |
An axis, feature space, frame, or view. |
axis_id_policy() returns the versioned ID-policy descriptor;
ids_are_durable() returns one logical value.
x <- axis_frame(data.frame(value = 1:3), id_policy = "ephemeral") axis_id_policy(x) ids_are_durable(x)x <- axis_frame(data.frame(value = 1:3), id_policy = "ephemeral") axis_id_policy(x) ids_are_durable(x)
Semantic and schema identities are independent of physical locations.
Source fingerprints identify descriptors and selectors, not array contents.
Content digests are optional receipts computed explicitly by
content_hash() or supplied by a backend; this function never reads data
to infer one, so the content domain always requires content_digest.
identity_descriptor( x, domain = c("auto", "semantic", "schema", "space", "source", "provenance", "content"), content_digest = NULL )identity_descriptor( x, domain = c("auto", "semantic", "schema", "space", "source", "provenance", "content"), content_digest = NULL )
x |
A frame, frame schema, feature space, array source, FDS manifest, provenance graph, collection, or study. |
domain |
Identity domain. Usually inferred from |
content_digest |
Externally computed content digest, such as
the value of |
A serializable typed identity descriptor.
src <- memory_source(matrix(seq_len(6), nrow = 2)) identity_descriptor(src)$domainsrc <- memory_source(matrix(seq_len(6), nrow = 2)) identity_descriptor(src)$domain
Construct a generic indexed feature space
index_space( n, ids = NULL, namespace = NULL, data = NULL, id_policy = c("require", "deterministic", "ephemeral") )index_space( n, ids = NULL, namespace = NULL, data = NULL, id_policy = c("require", "deterministic", "ephemeral") )
n |
Number of features. |
ids |
Optional stable feature IDs. |
namespace |
Stable namespace used for deterministic IDs. |
data |
Optional feature metadata. |
id_policy |
ID policy used when |
An index_space.
index_space(3, ids = c("a", "b", "c")) index_space(2, namespace = "roi", id_policy = "deterministic")index_space(3, ids = c("a", "b", "c")) index_space(2, namespace = "roi", id_policy = "deterministic")
A key relation does not duplicate a mapping. It declares that one scalar column on an observation, feature, or entity table references the stable IDs of one entity frame.
key_relation( key, target = NULL, source = "observation", allow_missing = FALSE, metadata = list() )key_relation( key, target = NULL, source = "observation", allow_missing = FALSE, metadata = list() )
key |
Foreign-key column on the source domain. |
target |
Target entity name. When |
source |
Source domain: |
allow_missing |
Whether missing foreign-key values are permitted. |
metadata |
Additional serializable metadata. |
A serializable key_relation descriptor.
rel <- key_relation("stimulus_id", target = "stimulus", source = "observation") rel$keyrel <- key_relation("stimulus_id", target = "stimulus", source = "observation") rel$key
Resolve logical observation rows to shards
locate_source_rows(x, observations = NULL)locate_source_rows(x, observations = NULL)
x |
A |
observations |
Logical observation positions in requested order. |
A data frame mapping each request position to a shard and local row.
shards <- list(memory_source(matrix(1:4, nrow = 2)), memory_source(matrix(5:8, nrow = 2))) locate_source_rows(row_sharded_source(shards), observations = c(1, 3))shards <- list(memory_source(matrix(1:4, nrow = 2)), memory_source(matrix(5:8, nrow = 2))) locate_source_rows(row_sharded_source(shards), observations = c(1, 3))
Lazily transform a frame into a new feature domain
map_features(x, target = NULL, map = NULL, assay_rules = "linear")map_features(x, target = NULL, map = NULL, assay_rules = "linear")
x |
An |
target |
Optional parent-linked target space from which a canonical map can be derived. |
map |
Optional explicit |
assay_rules |
Named rules for every assay: |
A new linked-domain fmri_frame whose assays remain lazy.
parent <- volume_space(c(2, 2, 1), support = 1:4, template = "toy") frame <- fmri_frame( assays = list(signal = matrix(1:12, nrow = 3)), observations = data.frame(.obs_id = paste0("o", 1:3)), space = parent ) parcels <- parcel_space( parent, parcel_ids = c("left", "right"), membership = Matrix::sparseMatrix( i = 1:4, j = c(1L, 1L, 2L, 2L), x = 1, dims = c(4L, 2L) ), atlas = "toy-atlas" ) parcel_frame <- map_features(frame, target = parcels) dim(collect_assay(parcel_frame))parent <- volume_space(c(2, 2, 1), support = 1:4, template = "toy") frame <- fmri_frame( assays = list(signal = matrix(1:12, nrow = 3)), observations = data.frame(.obs_id = paste0("o", 1:3)), space = parent ) parcels <- parcel_space( parent, parcel_ids = c("left", "right"), membership = Matrix::sparseMatrix( i = 1:4, j = c(1L, 1L, 2L, 2L), x = 1, dims = c(4L, 2L) ), atlas = "toy-atlas" ) parcel_frame <- map_features(frame, target = parcels) dim(collect_assay(parcel_frame))
Construct a deduplicated, bit-packed bank of feature masks
mask_bank(masks, space, metadata = list())mask_bank(masks, space, metadata = list())
masks |
Logical mask-by-feature matrix. Duplicate rows are stored once. |
space |
Exact feature space addressed by mask columns. |
metadata |
Serializable metadata. |
A serializable mask_bank.
space <- index_space(6, ids = paste0("f", 1:6), namespace = "validity-ex") masks <- rbind( c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) ) bank <- mask_bank(masks, space) n_masks(bank)space <- index_space(6, ids = paste0("f", 1:6), namespace = "validity-ex") masks <- rbind( c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) ) bank <- mask_bank(masks, space) n_masks(bank)
Validate and inspect a mask bank
validate_mask_bank(x) n_masks(x) mask_values(x, mask = NULL) mask_bank_digest(x)validate_mask_bank(x) n_masks(x) mask_values(x, mask = NULL) mask_bank_digest(x)
x |
A |
mask |
Optional mask ID or integer position. |
The validated bank, number of masks, unpacked logical masks, or deterministic digest.
space <- index_space(6, ids = paste0("f", 1:6), namespace = "validity-ex") masks <- rbind( c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) ) bank <- mask_bank(masks, space) mask_values(bank) mask_bank_digest(bank)space <- index_space(6, ids = paste0("f", 1:6), namespace = "validity-ex") masks <- rbind( c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) ) bank <- mask_bank(masks, space) mask_values(bank) mask_bank_digest(bank)
A memory source holds its values in the descriptor, so its revision
fingerprint cannot be derived from a file state. It is instead derived from
the shape, dtype, chunk grid, and a per-object identity token assigned once
at construction, plus the optional caller-supplied revision. Construction
therefore never hashes the payload, whatever its size. It reads values only
when dtype narrows the data's natural type (for example "logical" or an
integer width over doubles), to verify once that every value is
representable; incompatible data raise fmridataset_error_source_contract.
Reads return the R storage mode the dtype realizes to: doubles for every
numeric dtype, logical for "logical", complex for complex dtypes.
memory_source( data, dtype = NULL, chunks = NULL, revision = NULL, identity = c("object", "content") )memory_source( data, dtype = NULL, chunks = NULL, revision = NULL, identity = c("object", "content") )
data |
A two-dimensional matrix or array. |
dtype |
Logical storage dtype. Numeric R matrices default to
|
chunks |
Optional logical chunk shape. |
revision |
Optional single string naming the revision of |
identity |
|
Two independently constructed memory sources with equal values have
different fingerprints by design, and fingerprint equality is never value
equality. A serialization round trip preserves the token, so a descriptor
and its copies agree. Values compared across objects require
content_hash(). Set identity = "content" to opt into a content-derived
token: the payload is hashed once at construction and equal-valued sources
then share a fingerprint at O(n) cost.
A serializable memory_source.
source_fingerprint() and content_hash() for the fingerprint
policy.
src <- memory_source(matrix(seq_len(6), nrow = 2)) source_shape(src) source_dtype(src)src <- memory_source(matrix(seq_len(6), nrow = 2)) source_shape(src) source_dtype(src)
The descriptor reads headers and one mask at construction, but no fMRI
volumes. Numerical reads split requested global observations by file, pass
local volume indices into neuroim2::read_vec(), and restrict the mask to
requested packed features before materialization. Native reads return
full-volume NeuroVec objects in requested observation order.
nifti_array_source(paths, mask, chunks = NULL)nifti_array_source(paths, mask, chunks = NULL)
paths |
One or more NIfTI files with a common spatial grid. |
mask |
A NIfTI mask path or a compatible |
chunks |
Optional logical observation-by-feature chunk hint. |
The fingerprint covers the descriptor and the size and modification time of
every file captured at construction, never the voxel values. Every open,
read, and native read re-observes those files first and raises
fmridataset_error_source_stale (with source, expected, actual, and
changed fields) if any differ; genuine read failures remain
fmridataset_error_backend_io. See content_hash() to identify values.
A serializable nifti_array_source.
# A small NIfTI fixture shipped with neuroim2 stands in for real data. path <- system.file("extdata", "global_mask_v4.nii", package = "neuroim2") if (nzchar(path)) { src <- nifti_array_source(path, path) source_shape(src) source_dtype(src) }# A small NIfTI fixture shipped with neuroim2 stands in for real data. path <- system.file("extdata", "global_mask_v4.nii", package = "neuroim2") if (nzchar(path)) { src <- nifti_array_source(path, path) source_shape(src) source_dtype(src) }
Recover the spatial domain of a NIfTI source
nifti_source_space(x, template = NULL)nifti_source_space(x, template = NULL)
x |
A |
template |
Optional template or native-space label. |
A compatible volume_space.
path <- system.file("extdata", "global_mask_v4.nii", package = "neuroim2") if (nzchar(path)) { src <- nifti_array_source(path, path) spatial <- nifti_source_space(src, template = "fixture") n_features(spatial) }path <- system.file("extdata", "global_mask_v4.nii", package = "neuroim2") if (nzchar(path)) { src <- nifti_array_source(path, path) spatial <- nifti_source_space(src, template = "fixture") n_features(spatial) }
Resolve validity onto frame observations
observation_validity(x, name = NULL)observation_validity(x, name = NULL)
x |
An |
name |
Validity relation name. |
Observation-by-feature logical validity matrix.
space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") subjects <- entity_frame( data.frame(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) frame <- fmri_frame( assays = list(signal = matrix(1:8, nrow = 2)), observations = data.frame(.obs_id = c("o1", "o2"), subject_id = c("sub-1", "sub-2")), space = space, entities = list(subject = subjects), relations = list( observation_subject = key_relation("subject_id"), subject_feature_validity = validity ) ) observation_validity(frame)space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") subjects <- entity_frame( data.frame(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) frame <- fmri_frame( assays = list(signal = matrix(1:8, nrow = 2)), observations = data.frame(.obs_id = c("o1", "o2"), subject_id = c("sub-1", "sub-2")), space = space, entities = list(subject = subjects), relations = list( observation_subject = key_relation("subject_id"), subject_feature_validity = validity ) ) observation_validity(frame)
A parcel_space owns only the feature-axis algebra required by
fmridataset: stable parcel identity, a parent feature space, and explicit
parent-to-parcel operators. Atlas discovery, labels, and provenance remain
owned by neuroatlas and can be imported with parcel_space_from_atlas().
parcel_space( parent, parcel_ids, membership, data = NULL, atlas, aggregation = c("mean", "sum"), decoder = NULL, metadata = list() )parcel_space( parent, parcel_ids, membership, data = NULL, atlas, aggregation = c("mean", "sum"), decoder = NULL, metadata = list() )
parent |
Parent |
parcel_ids |
Stable atlas-native parcel identifiers. |
membership |
Non-negative parent-feature by parcel membership weights. |
data |
One metadata row per parcel. The |
atlas |
Atlas identity list containing at least |
aggregation |
Either weighted |
decoder |
Optional parent-feature by parcel reconstruction operator.
The default blends overlapping parcel values by row-normalized membership;
|
metadata |
Additional serializable metadata. |
A parcel_space.
parent <- volume_space(c(3, 2, 1), support = 1:6) membership <- Matrix::sparseMatrix( i = 1:6, j = c(1, 1, 1, 2, 2, 2), x = 1, dims = c(6L, 2L) ) x <- parcel_space(parent, c(10L, 20L), membership, atlas = "toy-atlas") n_features(x)parent <- volume_space(c(3, 2, 1), support = 1:6) membership <- Matrix::sparseMatrix( i = 1:6, j = c(1, 1, 1, 2, 2, 2), x = 1, dims = c(6L, 2L) ) x <- parcel_space(parent, c(10L, 20L), membership, atlas = "toy-atlas") n_features(x)
The adapter delegates atlas identity and label interpretation to
neuroatlas. For surface atlases it uses get_roi() so atlas-specific
hemisphere-local coding is not duplicated here.
parcel_space_from_atlas( atlas, parent, aggregation = c("mean", "sum"), metadata = list() )parcel_space_from_atlas( atlas, parent, aggregation = c("mean", "sum"), metadata = list() )
atlas |
A |
parent |
The aligned parent |
aggregation |
Aggregation method passed to |
metadata |
Serializable metadata passed to |
A parcel_space aligned to parent.
# Loading neuroatlas and neurosurf alone takes several seconds, so this # example runs under --run-donttest rather than on every check. if (requireNamespace("neuroatlas", quietly = TRUE) && requireNamespace("neurosurf", quietly = TRUE)) { old_rgl <- Sys.getenv("RGL_USE_NULL", unset = NA) Sys.setenv(RGL_USE_NULL = "TRUE") left <- matrix(c(0, 0, 0, 1, 0, 0, 0, 1, 0), ncol = 3, byrow = TRUE) right <- sweep(left, 2, c(0, 0, 1), "+") faces <- matrix(c(0, 1, 2), nrow = 1) lh <- neurosurf::SurfaceGeometry(left, faces, "lh") rh <- neurosurf::SurfaceGeometry(right, faces, "rh") atlas <- list( name = "toy-surface", lh_atlas = neurosurf::NeuroSurface(lh, 1:3, c(1, 1, 0)), rh_atlas = neurosurf::NeuroSurface(rh, 1:3, c(2, 2, 0)), ids = 1:2, labels = c("A", "B"), orig_labels = c("A", "B"), hemi = c("left", "right"), network = NULL, cmap = NULL, surf_type = "pial", surface_space = "toy" ) class(atlas) <- c("toy", "surfatlas", "atlas") parent <- surface_space( vertex_ids = c(paste0("L-", 1:3), paste0("R-", 1:3)), hemisphere = rep(c("left", "right"), each = 3), topology = rbind(c(1, 2, 3), c(4, 5, 6)), geometry = rbind(left, right), template = "toy" ) x <- parcel_space_from_atlas(atlas, parent) feature_ids(x) if (is.na(old_rgl)) Sys.unsetenv("RGL_USE_NULL") else Sys.setenv(RGL_USE_NULL = old_rgl) }# Loading neuroatlas and neurosurf alone takes several seconds, so this # example runs under --run-donttest rather than on every check. if (requireNamespace("neuroatlas", quietly = TRUE) && requireNamespace("neurosurf", quietly = TRUE)) { old_rgl <- Sys.getenv("RGL_USE_NULL", unset = NA) Sys.setenv(RGL_USE_NULL = "TRUE") left <- matrix(c(0, 0, 0, 1, 0, 0, 0, 1, 0), ncol = 3, byrow = TRUE) right <- sweep(left, 2, c(0, 0, 1), "+") faces <- matrix(c(0, 1, 2), nrow = 1) lh <- neurosurf::SurfaceGeometry(left, faces, "lh") rh <- neurosurf::SurfaceGeometry(right, faces, "rh") atlas <- list( name = "toy-surface", lh_atlas = neurosurf::NeuroSurface(lh, 1:3, c(1, 1, 0)), rh_atlas = neurosurf::NeuroSurface(rh, 1:3, c(2, 2, 0)), ids = 1:2, labels = c("A", "B"), orig_labels = c("A", "B"), hemi = c("left", "right"), network = NULL, cmap = NULL, surf_type = "pial", surface_space = "toy" ) class(atlas) <- c("toy", "surfatlas", "atlas") parent <- surface_space( vertex_ids = c(paste0("L-", 1:3), paste0("R-", 1:3)), hemisphere = rep(c("left", "right"), each = 3), topology = rbind(c(1, 2, 3), c(4, 5, 6)), geometry = rbind(left, right), template = "toy" ) x <- parcel_space_from_atlas(atlas, parent) feature_ids(x) if (is.na(old_rgl)) Sys.unsetenv("RGL_USE_NULL") else Sys.setenv(RGL_USE_NULL = old_rgl) }
Inspect parent-linked feature spaces and parcel-space operators
parent_space(x) parcel_membership(x) parcel_aggregation(x)parent_space(x) parcel_membership(x) parcel_aggregation(x)
x |
A parent-linked feature space such as a |
parent_space() returns the parent feature space;
parcel_membership() and parcel_aggregation() return sparse operators.
parent <- volume_space(c(3, 2, 1), support = 1:6) membership <- Matrix::sparseMatrix( i = 1:6, j = c(1, 1, 1, 2, 2, 2), x = 1, dims = c(6L, 2L) ) x <- parcel_space(parent, c(10L, 20L), membership, atlas = "toy-atlas") parent_space(x) parcel_membership(x)parent <- volume_space(c(3, 2, 1), support = 1:6) membership <- Matrix::sparseMatrix( i = 1:6, j = c(1, 1, 1, 2, 2, 2), x = 1, dims = c(6L, 2L) ) x <- parcel_space(parent, c(10L, 20L), membership, atlas = "toy-atlas") parent_space(x) parcel_membership(x)
plan_blocks() uses source chunk hints and an explicit byte budget to build
a serializable, metadata-only execution plan. "imagewise" blocks retain
complete feature rows, "featurewise" blocks retain complete observation
columns, and "balanced" blocks scale both axes in the source chunk ratio.
plan_blocks( x, assay = active_assay(x), layout = c("balanced", "imagewise", "featurewise"), memory_budget = getOption("fmridataset.block_budget", 512 * 1024^2), target_block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) )plan_blocks( x, assay = active_assay(x), layout = c("balanced", "imagewise", "featurewise"), memory_budget = getOption("fmridataset.block_budget", 512 * 1024^2), target_block_bytes = getOption("fmridataset.target_block_bytes", 4 * 1024^2) )
x |
An |
assay |
Assay name. |
layout |
One of |
memory_budget |
Hard maximum estimated peak bytes for one input block. |
target_block_bytes |
Preferred block size, capped by |
A serializable frame_block_plan.
frame <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(20), 5, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:5)), active_assay = "signal" ) plan <- plan_blocks(frame, memory_budget = 10 * 1024^2) planframe <- fmri_frame( assays = list(signal = memory_source(matrix(seq_len(20), 5, 4))), observations = data.frame(.obs_id = sprintf("obs-%d", 1:5)), active_assay = "signal" ) plan <- plan_blocks(frame, memory_budget = 10 * 1024^2) plan
Create a content-addressed provenance record
provenance_record( operation, parents = character(), inputs = list(), parameters = list(), outputs = list(), software = list(package = "fmridataset"), metadata = list() )provenance_record( operation, parents = character(), inputs = list(), parameters = list(), outputs = list(), software = list(package = "fmridataset"), metadata = list() )
operation |
Stable operation name. |
parents |
IDs of direct parent records. |
inputs, parameters, outputs, software, metadata
|
Serializable record data. |
A provenance_record.
r <- provenance_record("normalize", inputs = list(method = "zscore")) r$operation r$idr <- provenance_record("normalize", inputs = list(method = "zscore")) r$operation r$id
Construct and inspect an immutable provenance graph
provenance_graph(...) validate_provenance_graph(x) provenance_records(x) provenance_tips(x) provenance_digest(x) append_provenance(x, records)provenance_graph(...) validate_provenance_graph(x) provenance_records(x) provenance_tips(x) provenance_digest(x) append_provenance(x, records)
... |
|
x |
A |
records |
One or more records appended to |
A validated provenance_graph, its records, tips, or digest.
r1 <- provenance_record("load", inputs = list(path = "toy.nii")) g <- provenance_graph(r1) r2 <- provenance_record("normalize", parents = r1$id) g <- append_provenance(g, r2) provenance_tips(g)r1 <- provenance_record("load", inputs = list(path = "toy.nii")) g <- provenance_graph(r1) r2 <- provenance_record("normalize", parents = r1$id) g <- append_provenance(g, r2) provenance_tips(g)
read_bids_bold() is the narrow BIDS on-ramp to the canonical frame API. It
discovers fMRIPrep desc-preproc BOLD runs, creates deterministic volume
IDs, resolves one common volume space, and returns a lazy NIfTI-backed frame.
BOLD values are not read until an assay or spatial map is explicitly
collected.
read_bids_bold( path, subject, task = NULL, session = NULL, run = NULL, space = NULL, derivative = "fmriprep", mask = "intersection", events = TRUE, chunks = NULL )read_bids_bold( path, subject, task = NULL, session = NULL, run = NULL, space = NULL, derivative = "fmriprep", mask = "intersection", events = TRUE, chunks = NULL )
path |
Path to a BIDS dataset containing fMRIPrep derivatives. |
subject |
One exact subject label, with or without the |
task, session, run, space
|
Optional exact BIDS entity selectors. |
derivative |
Currently only |
mask |
|
events |
Whether to attach matching BIDS events as a keyed event table. |
chunks |
Optional observation-by-feature chunk hint passed to
|
Runs are ordered by session, task, and run number. Numeric run labels are
compared as integers, so unpadded run-2 precedes run-10.
Each observation carries scan_id, subject_id, session_id, task_id,
run_id, volume_index (1-based position within its run), run_time, and
TR. run_time is the acquisition onset of the volume relative to the start
of its run, (volume_index - 1) * TR. No start_time column is emitted, so
as_sampling_frame() uses fmrihrf::sampling_frame()'s default offset of
TR/2 and its sample times are run_time + TR/2. This is deliberate: it
keeps fmrihrf's modelling default. For onset-aligned sampling, set a zero
offset on the schema before converting:
schema <- temporal_schema(bold) schema$start_time <- stats::setNames(rep(0, schema$n_runs), names(schema$run_lengths)) sf <- as_sampling_frame(schema)
or build the frame with a start_time = 0 observation column.
A lazy fmri_frame with a signal assay.
## Not run: bold <- read_bids_bold( "/data/my-study", subject = "01", task = "memory", space = "MNI152NLin2009cAsym" ) first_run <- filter_obs(bold, run_id == "run-1") map <- spatial_map(bold, observation = 1) ## End(Not run)## Not run: bold <- read_bids_bold( "/data/my-study", subject = "01", task = "memory", space = "MNI152NLin2009cAsym" ) first_run <- filter_obs(bold, run_id == "run-1") map <- spatial_map(bold, observation = 1) ## End(Not run)
Construct a relation registry
relation_registry(relations = list(), ...)relation_registry(relations = list(), ...)
relations |
A named list of |
... |
Alternatively, named relation descriptors. |
A named relation_registry.
registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) relation_names(registry)registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) relation_names(registry)
Compute a stable relation-registry digest
relation_registry_digest(x)relation_registry_digest(x)
x |
A frame, view, or relation registry. |
A hexadecimal digest over the normalized registry.
registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) relation_registry_digest(registry)registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) relation_registry_digest(registry)
Access frame relations
relations(x, ...) relation(x, name, ...) relation_names(x)relations(x, ...) relation(x, name, ...) relation_names(x)
x |
An |
... |
Additional method arguments. |
name |
One registered relation name. |
relations() returns the registry; relation() returns one
descriptor; relation_names() returns registry names.
registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) relations(registry) relation(registry, "observation_stimulus") relation_names(registry)registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) relations(registry) relation(registry, "observation_stimulus") relation_names(registry)
row_sharded_source() presents compatible child sources as one logical
observation-by-feature array. Stable shard IDs and explicit boundaries make
global-to-local row routing inspectable and serializable. Reads are grouped
by touched shard, so an arbitrary ordered selector is issued at most once to
each selected child.
row_sharded_source(sources, shard_ids = NULL, shard_data = NULL)row_sharded_source(sources, shard_ids = NULL, shard_data = NULL)
sources |
A non-empty list of compatible two-dimensional array sources. |
shard_ids |
Stable, unique shard identifiers. |
shard_data |
Optional scalar metadata with one row per shard. Names used by the shard manifest are reserved. |
A serializable row_sharded_source.
shards <- list( memory_source(matrix(1:4, nrow = 2)), memory_source(matrix(5:8, nrow = 2)) ) src <- row_sharded_source(shards) source_shape(src)shards <- list( memory_source(matrix(1:4, nrow = 2)), memory_source(matrix(5:8, nrow = 2)) ) src <- row_sharded_source(shards) source_shape(src)
Select frame features using feature metadata
select_features(x, predicate)select_features(x, predicate)
x |
An |
predicate |
A metadata expression returning one logical value per feature. |
An fmri_view.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) select_features(frame, i == 1)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) select_features(frame, i == 1)
Inspect a row-sharded source manifest
shard_manifest(x)shard_manifest(x)
x |
A |
A data frame describing stable IDs, logical row ranges, source fingerprints, and user-supplied shard metadata.
shards <- list(memory_source(matrix(1:4, nrow = 2)), memory_source(matrix(5:8, nrow = 2))) shard_manifest(row_sharded_source(shards))shards <- list(memory_source(matrix(1:4, nrow = 2)), memory_source(matrix(5:8, nrow = 2))) shard_manifest(row_sharded_source(shards))
A valid canonical source is two-dimensional, has an explicit supported dtype and chunk grid, advertises serializable block slicing, provides a stable non-empty fingerprint, and contains no runtime handles or closures.
source_descriptor(x) validate_array_source(x)source_descriptor(x) validate_array_source(x)
x |
An |
source_descriptor() returns a plain serializable contract list.
validate_array_source() invisibly returns x or raises a structured
source-contract error.
src <- memory_source(matrix(seq_len(6), nrow = 2)) source_descriptor(src) validate_array_source(src)src <- memory_source(matrix(seq_len(6), nrow = 2)) source_descriptor(src) validate_array_source(src)
Storage packages implement the array source protocol and
must fail the way built-in sources fail, so that callers can handle every
source alike. source_error() builds the condition object for the three
failure kinds the protocol defines; signal it with stop().
source_error(message, type = c("stale", "io", "contract"), ...)source_error(message, type = c("stale", "io", "contract"), ...)
message |
One-sentence description of the failure. |
type |
One of |
... |
Named fields stored on the condition, such as |
"stale" (fmridataset_error_source_stale): the physical store no longer
matches the descriptor's revision evidence (a file was rewritten, a store
was replaced). Supply source, expected, and actual so the caller can
report what changed.
"io" (fmridataset_error_backend_io): a genuine read, open, or close
failure. Supply file and operation where known.
"contract" (fmridataset_error_source_contract): the descriptor or a
method violates the protocol. Supply field.
Every condition also carries the fmridataset_error class, so a single
handler can catch all package errors.
A condition object inheriting from the type-specific class,
fmridataset_error, error, and condition.
cond <- source_error( "Store was rewritten after the descriptor was built.", type = "stale", source = "example.h5", expected = "abc", actual = "def" ) inherits(cond, "fmridataset_error_source_stale") tryCatch(stop(cond), fmridataset_error_source_stale = function(e) e$actual)cond <- source_error( "Store was rewritten after the descriptor was built.", type = "stale", source = "example.h5", expected = "abc", actual = "def" ) inherits(cond, "fmridataset_error_source_stale") tryCatch(stop(cond), fmridataset_error_source_stale = function(e) e$actual)
A view stores its selectors in the package's normalized selection form
rather than as expanded position vectors: a select-all axis stores no
vector, one contiguous run stores its bounds, and only an arbitrary subset
stores positions. A view over a view composes into one view over the root
source. Selectors follow the package-wide normalization law: logical masks
must match the axis length without NA; numeric positions must be whole
numbers, may reorder, may be negative (but not mixed with positive), drop
zero, must be in bounds, and may not repeat an element; an empty selection
is legal. Fingerprints hash the normalized form, so equal selections agree
however they were expressed and a select-all view fingerprints in constant
time.
source_view(source, observations = NULL, features = NULL)source_view(source, observations = NULL, features = NULL)
source |
An |
observations |
Stored observation selector. |
features |
Stored feature selector. |
A serializable source view.
src <- memory_source(matrix(seq_len(6), nrow = 2)) view <- source_view(src, observations = 1) source_shape(view)src <- memory_source(matrix(seq_len(6), nrow = 2)) view <- source_view(src, observations = 1) source_shape(view)
Feature-space accessor
space(x, ...)space(x, ...)
x |
An object with spatial identity. |
... |
Additional arguments. |
A FeatureSpace.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) space(frame)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) space(frame)
Describe an explicit sparse or many-to-many relation
sparse_relation( data, from, to, from_col = ".from_id", to_col = ".to_id", weight = NULL, directed = TRUE, metadata = list() )sparse_relation( data, from, to, from_col = ".from_id", to_col = ".to_id", weight = NULL, directed = TRUE, metadata = list() )
data |
Scalar edge table. |
from |
Source domain. |
to |
Target domain. |
from_col |
Column containing source stable IDs. |
to_col |
Column containing target stable IDs. |
weight |
Optional numeric weight column. |
directed |
Whether edge direction is semantically meaningful. |
metadata |
Additional serializable metadata. |
A serializable sparse_relation descriptor.
edges <- sparse_relation( data = tibble::tibble( .from_id = c("obs-1", "obs-2"), .to_id = c("stim-1", "stim-2"), weight = c(0.7, 0.3) ), from = "observation", to = "entity:stimulus", weight = "weight" ) edges$fromedges <- sparse_relation( data = tibble::tibble( .from_id = c("obs-1", "obs-2"), .to_id = c("stim-1", "stim-2"), weight = c(0.7, 0.3) ), from = "observation", to = "entity:stimulus", weight = "weight" ) edges$from
Recover a spatial map for one observation
spatial_map(x, observation, assay = active_assay(x))spatial_map(x, observation, assay = active_assay(x))
x |
An |
observation |
Observation ID or one integer position. |
assay |
Assay name. |
A reconstructed spatial object.
sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) spatial_map(frame, observation = 1L)sp <- volume_space(dim = c(2, 2, 2), affine = diag(4)) frame <- fmri_frame( assays = list(bold = matrix(rnorm(4 * n_features(sp)), nrow = 4)), observations = data.frame(.obs_id = sprintf("vol-%d", 1:4)), space = sp ) spatial_map(frame, observation = 1L)
Compute a deterministic study digest
study_digest(x)study_digest(x)
x |
An |
A SHA-256 digest computed without numerical reads.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_digest(study)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_digest(study)
Reconstruct a study from semantic and physical components
study_from_fds_manifest(manifest, representations, bindings = list())study_from_fds_manifest(manifest, representations, bindings = list())
manifest |
A valid FDS v2 study manifest. |
representations |
Named lazy frames or collections matching the representation manifests. |
bindings |
Named physical bindings for shared study arrays. |
An fmri_study.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) manifest <- fds_study_manifest(study) rebuilt <- study_from_fds_manifest( manifest, list(main = frame), fds_study_bindings(study) ) study_ids(rebuilt)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) manifest <- fds_study_manifest(study) rebuilt <- study_from_fds_manifest( manifest, list(main = frame), fds_study_bindings(study) ) study_ids(rebuilt)
Study representation accessors
study_frames(x, contextual = TRUE) study_frame(x, name, contextual = TRUE) study_ids(x)study_frames(x, contextual = TRUE) study_frame(x, name, contextual = TRUE) study_ids(x)
x |
An |
contextual |
Replace frame-local entity stubs with shared study entities. |
name |
Stable representation name. |
Named representations, one representation, or representation IDs.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_ids(study) study_frame(study, "main")voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_ids(study) study_frame(study, "main")
Study link and table accessors
study_links(x) study_link(x, name) study_tables(x) study_table(x, name)study_links(x) study_link(x, name) study_tables(x) study_table(x, name)
x |
An |
name |
Stable link or table name. |
A registry or one descriptor/table.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_links(study) study_tables(study)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) study_links(study) study_tables(study)
Construct a packed cortical surface feature space
surface_space( vertex_ids, hemisphere, support = NULL, topology = NULL, geometry = NULL, medial_wall = NULL, template = NULL, units = "mm", surf_to_world = diag(4), metadata = list() )surface_space( vertex_ids, hemisphere, support = NULL, topology = NULL, geometry = NULL, medial_wall = NULL, template = NULL, units = "mm", surf_to_world = diag(4), metadata = list() )
vertex_ids |
Stable IDs for every vertex in the full mesh. |
hemisphere |
One |
support |
Active vertex positions or IDs. By default, all non-medial-wall vertices are active. |
topology |
A three-column face matrix or asset descriptor with
|
geometry |
A vertex-by-three coordinate matrix or asset descriptor with
|
medial_wall |
Logical full-mesh medial-wall mask. |
template |
Optional template identity such as |
units |
Coordinate units. |
surf_to_world |
A finite 4 by 4 surface-to-world transform, following
the |
metadata |
Additional serializable metadata. |
A surface_space.
surface_space( vertex_ids = c("L-1", "L-2", "L-3"), hemisphere = rep("left", 3) )surface_space( vertex_ids = c("L-1", "L-2", "L-3"), hemisphere = rep("left", 3) )
neurosurf remains the owner of mesh geometry and algorithms. This adapter
extracts its stable topology, coordinates, hemisphere, and world transform
into the backend-neutral identity required by an fmri_frame.
surface_space_from_neurosurf( geometry, vertex_ids = NULL, support = NULL, medial_wall = NULL, template = NULL, units = "mm", metadata = list() )surface_space_from_neurosurf( geometry, vertex_ids = NULL, support = NULL, medial_wall = NULL, template = NULL, units = "mm", metadata = list() )
geometry |
A |
vertex_ids |
Optional stable full-mesh vertex IDs. |
support, medial_wall, template, units, metadata
|
Passed to |
A surface_space.
if (requireNamespace("neurosurf", quietly = TRUE)) { old_rgl <- Sys.getenv("RGL_USE_NULL", unset = NA) Sys.setenv(RGL_USE_NULL = "TRUE") vertices <- matrix(c(0, 0, 0, 1, 0, 0, 0, 1, 0), ncol = 3, byrow = TRUE) geom <- neurosurf::SurfaceGeometry( vertices, matrix(c(0, 1, 2), nrow = 1), hemi = "lh", label = "pial" ) x <- surface_space_from_neurosurf(geom, template = "toy-surface") feature_ids(x) if (is.na(old_rgl)) Sys.unsetenv("RGL_USE_NULL") else Sys.setenv(RGL_USE_NULL = old_rgl) }if (requireNamespace("neurosurf", quietly = TRUE)) { old_rgl <- Sys.getenv("RGL_USE_NULL", unset = NA) Sys.setenv(RGL_USE_NULL = "TRUE") vertices <- matrix(c(0, 0, 0, 1, 0, 0, 0, 1, 0), ncol = 3, byrow = TRUE) geom <- neurosurf::SurfaceGeometry( vertices, matrix(c(0, 1, 2), nrow = 1), hemi = "lh", label = "pial" ) x <- surface_space_from_neurosurf(geom, template = "toy-surface") feature_ids(x) if (is.na(old_rgl)) Sys.unsetenv("RGL_USE_NULL") else Sys.setenv(RGL_USE_NULL = old_rgl) }
The canonical frame model carries no acquisition timing of its own: an
fmri_frame is observations by features, and when the observations happen to
be volumes acquired in runs, that fact is ordinary observation metadata. The
package already writes it that way – read_bids_bold() emits run_id and
TR columns – but nothing validated the convention, so every consumer
reinvented it and none could rely on it.
temporal_schema( x, run_col = NULL, tr_col = "TR", start_time_col = "start_time", censor_col = "censor", order_col = NULL ) has_temporal_schema(x, ...) as_sampling_frame(x, ...)temporal_schema( x, run_col = NULL, tr_col = "TR", start_time_col = "start_time", censor_col = "censor", order_col = NULL ) has_temporal_schema(x, ...) as_sampling_frame(x, ...)
x |
An |
run_col, tr_col, start_time_col, censor_col
|
Observation metadata columns
holding the run label, repetition time, first-volume offset, and censoring
indicator. Each is a single column name; |
order_col |
|
... |
Passed to |
These functions make it a contract. temporal_schema() derives a validated
description from the observation metadata; as_sampling_frame() reconstructs
the fmrihrf::sampling_frame that design and HRF modelling code expects.
The schema is derived, never stored. The columns are the truth, so the schema cannot go stale, needs no serialization of its own, and follows subsetting, reordering, and binding for free.
temporal_schema() returns a frame_temporal_schema.
has_temporal_schema() returns a scalar logical.
as_sampling_frame() returns an fmrihrf::sampling_frame.
run_idRequired. One value per observation naming the acquisition run it belongs to. Any type; compared as character. No missing values.
TROptional. Repetition time in seconds, positive and finite, and
constant within each run (compared with a relative tolerance of
sqrt(.Machine$double.eps), so floating-point noise is not a second
value). Runs may differ from one another, matching
fmrihrf::sampling_frame().
start_timeOptional. Non-negative finite offset in seconds of the
first volume of each run (the slice-time-correction reference, or any
other first-volume acquisition time). Constant within each run; runs may
differ. When absent, as_sampling_frame() leaves the offset to
fmrihrf::sampling_frame()'s default of TR/2.
censorOptional. Logical, one value per observation, TRUE where
the observation is to be excluded. No missing values.
Optional. A numeric within-run acquisition index or
time, such as volume_index or run_time from read_bids_bold(). No
missing values.
read_bids_bold() emits run_time, the acquisition onset of each volume
relative to its run ((volume_index - 1) * TR). The sampling frame built by
as_sampling_frame() places samples at start_time + (volume_index - 1) * TR, and when no start_time column is supplied fmrihrf's default
start_time = TR/2 applies, so sample times are run_time + TR/2. This
modelling default is kept on purpose. For onset-aligned sampling, add a
start_time column of 0 when constructing the frame, or set it on the
schema before converting:
schema <- temporal_schema(frame) schema$start_time <- stats::setNames(rep(0, schema$n_runs), names(schema$run_lengths)) as_sampling_frame(schema)
Runs are numbered in order of first appearance, not by sorting, so
block_ids is stable under any operation that preserves observation order.
A frame is contiguous when each run occupies one unbroken stretch of
observations. Frames are not required to be contiguous – filter_obs() and
ID-based reordering both produce legal interleaved views – but a
sampling_frame is a run-length encoding and cannot represent one, so
as_sampling_frame() refuses a non-contiguous frame rather than silently
reordering it.
Contiguity says nothing about order within a run. When an order column is
present (order_col, by default the first of volume_index and run_time
found), the schema records in ordered whether it increases strictly within
every run, and as_sampling_frame() refuses a frame whose volumes are out of
acquisition order. Without such a column the order within a run cannot be
checked: ordered is NA, and the observation order is taken as acquisition
order.
A zero-observation frame has an empty schema but no sampling frame;
as_sampling_frame() refuses it.
frame <- fmri_frame( assays = list(bold = matrix(rnorm(12), 6, 2)), observations = data.frame( .obs_id = sprintf("t%02d", 1:6), run_id = rep(c("run-1", "run-2"), each = 3), TR = 2 ) ) schema <- temporal_schema(frame) schema$run_lengths if (requireNamespace("fmrihrf", quietly = TRUE)) { as_sampling_frame(frame) }frame <- fmri_frame( assays = list(bold = matrix(rnorm(12), 6, 2)), observations = data.frame( .obs_id = sprintf("t%02d", 1:6), run_id = rep(c("run-1", "run-2"), each = 3), TR = 2 ) ) schema <- temporal_schema(frame) schema$run_lengths if (requireNamespace("fmrihrf", quietly = TRUE)) { as_sampling_frame(frame) }
Container metadata is deliberately unaligned. Array- or table-valued data belong in assays, axis blocks, relations, typed tables, or linked frames. A vector field is an unaligned value whatever its length; a length that coincides with an axis or entity size is not treated as alignment.
unaligned_record(x = list())unaligned_record(x = list())
x |
A named serializable list. |
An unaligned_record.
rec <- unaligned_record(list(task = "rest", tr = 2)) rec$taskrec <- unaligned_record(list(task = "rest", tr = 2)) rec$task
Validate a keyed event table
validate_event_table(x)validate_event_table(x)
x |
An |
x, invisibly.
et <- event_table( data.frame(event_id = c("e1", "e2"), onset = c(0, 10)), key = "event_id" ) validate_event_table(et)et <- event_table( data.frame(event_id = c("e1", "e2"), onset = c(0, 10)), key = "event_id" ) validate_event_table(et)
Validate an fMRI collection
validate_fmri_collection(x)validate_fmri_collection(x)
x |
An |
x, invisibly, or a structured collection error.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) validate_fmri_collection(collection)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) collection <- fmri_collection(list(sub01 = frame, sub02 = frame)) validate_fmri_collection(collection)
Validate a study
validate_fmri_study(x)validate_fmri_study(x)
x |
An |
x, invisibly.
voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) validate_fmri_study(study)voxels <- volume_space(dim = c(2, 2, 1), affine = diag(4), template = "toy") frame <- fmri_frame( assays = list(bold = matrix(rnorm(3 * n_features(voxels)), nrow = 3)), observations = data.frame(.obs_id = paste0("vol-", 1:3)), space = voxels ) study <- fmri_study(list(main = frame)) validate_fmri_study(study)
Validate a relation registry
validate_relation_registry( x, observations = NULL, features = NULL, entities = NULL )validate_relation_registry( x, observations = NULL, features = NULL, entities = NULL )
x |
A |
observations |
Optional observation |
features |
Optional feature |
entities |
Optional |
Invisibly returns x; contextual validation also enforces all
foreign-key and edge identities.
registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) validate_relation_registry(registry)registry <- relation_registry( observation_stimulus = key_relation("stimulus_id", target = "stimulus") ) validate_relation_registry(registry)
Validate a typed unaligned metadata record
validate_unaligned_record(x)validate_unaligned_record(x)
x |
An |
x, invisibly.
rec <- unaligned_record(list(task = "rest", tr = 2)) validate_unaligned_record(rec)rec <- unaligned_record(list(task = "rest", tr = 2)) validate_unaligned_record(rec)
Summarize feature coverage without imposing an analysis policy
validity_coverage(x, name = NULL, domain = c("entity", "observation"))validity_coverage(x, name = NULL, domain = c("entity", "observation"))
x |
An |
name |
Validity relation name. |
domain |
Weight unique entities or frame observations. |
Named fraction-valid vector over frame features.
space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") subjects <- entity_frame( data.frame(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) frame <- fmri_frame( assays = list(signal = matrix(1:8, nrow = 2)), observations = data.frame(.obs_id = c("o1", "o2"), subject_id = c("sub-1", "sub-2")), space = space, entities = list(subject = subjects), relations = list( observation_subject = key_relation("subject_id"), subject_feature_validity = validity ) ) validity_coverage(frame)space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") subjects <- entity_frame( data.frame(subject_id = c("sub-1", "sub-2")), key = "subject_id" ) validity <- entity_feature_validity( entity = "subject", entity_ids = c("sub-1", "sub-2"), masks = rbind( c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE) ), space = space ) frame <- fmri_frame( assays = list(signal = matrix(1:8, nrow = 2)), observations = data.frame(.obs_id = c("o1", "o2"), subject_id = c("sub-1", "sub-2")), space = space, entities = list(subject = subjects), relations = list( observation_subject = key_relation("subject_id"), subject_feature_validity = validity ) ) validity_coverage(frame)
Lazily mask invalid observation-feature cells with missing values
validity_masked_source(source, observation_mask_id, bank)validity_masked_source(source, observation_mask_id, bank)
source |
Observation-by-feature array source. |
observation_mask_id |
One mask-bank ID per source row. |
bank |
Compatible |
A serializable validity_masked_source.
space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") bank <- mask_bank( rbind(c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE)), space ) src <- memory_source(matrix(1:8, nrow = 2)) masked <- validity_masked_source(src, bank$mask_ids[c(1, 2)], bank) source_read(masked)space <- index_space(4, ids = paste0("f", 1:4), namespace = "validity-ex") bank <- mask_bank( rbind(c(TRUE, TRUE, FALSE, TRUE), c(TRUE, FALSE, FALSE, TRUE)), space ) src <- memory_source(matrix(1:8, nrow = 2)) masked <- validity_masked_source(src, bank$mask_ids[c(1, 2)], bank) source_read(masked)
Construct a packed volumetric feature space
volume_space( dim, affine = diag(4), support = NULL, template = NULL, units = "mm", metadata = list() )volume_space( dim, affine = diag(4), support = NULL, template = NULL, units = "mm", metadata = list() )
dim |
Three spatial dimensions. |
affine |
A 4 by 4 voxel-to-world affine. |
support |
Logical full-volume support or packed linear indices. |
template |
Optional template/native-space identity. |
units |
Spatial units. |
metadata |
Additional serializable metadata. |
A volume_space.
volume_space(c(2, 2, 2), affine = diag(4), support = 1:4)volume_space(c(2, 2, 2), affine = diag(4), support = 1:4)
write_frame() writes an fmri_frame to an HDF5 file and open_frame()
reopens one. Both require the fmristore package, which performs the
physical HDF5 work. fmristore is not on CRAN; install it from
https://bbuchsbaum.r-universe.dev, for example with
install.packages("fmristore", repos = c("https://bbuchsbaum.r-universe.dev", getOption("repos"))). Without it, or with a version that lacks frame
support, both functions fail with an error of class
fmridataset_error_backend_io.
write_frame(x, path, format = "hdf5", ...) open_frame(path, format = "hdf5", ...)write_frame(x, path, format = "hdf5", ...) open_frame(path, format = "hdf5", ...)
x |
An |
path |
Destination or source path. |
format |
Storage format. Only |
... |
Arguments passed to the physical store implementation. |
Reopened assays are lazy sources: opening a frame does not read assay values.
Neither function computes a content hash. Persistence records semantic
manifest digests and source fingerprints only; a caller who wants a value
receipt for the written or reopened arrays requests it explicitly with
content_hash() and records the result where it is needed.
write_frame() invisibly returns the committed path, normalized
with forward slashes on every platform. open_frame() returns an
fmri_frame.
if (requireNamespace("fmristore", quietly = TRUE)) { src <- memory_source(matrix(seq_len(6), nrow = 2)) obs <- tibble::tibble(.obs_id = c("o1", "o2")) space <- index_space(3, id_policy = "deterministic", namespace = "demo") frame <- fmri_frame(list(beta = src), obs, space = space) path <- tempfile(fileext = ".h5") committed <- write_frame(frame, path) reopened <- open_frame(committed) collect_assay(reopened, "beta") }if (requireNamespace("fmristore", quietly = TRUE)) { src <- memory_source(matrix(seq_len(6), nrow = 2)) obs <- tibble::tibble(.obs_id = c("o1", "o2")) space <- index_space(3, id_policy = "deterministic", namespace = "demo") frame <- fmri_frame(list(beta = src), obs, space = space) path <- tempfile(fileext = ".h5") committed <- write_frame(frame, path) reopened <- open_frame(committed) collect_assay(reopened, "beta") }
zarr_array_source() describes one two-dimensional Zarr array whose logical
axes are observations and features. The descriptor contains no open store,
R6 object, external pointer, or loader function. Runtime handles are opened
only for metadata discovery and numerical reads.
zarr_array_source( uri, array_path = "/", shape = NULL, dtype = NULL, chunks = NULL, physical_axes = c("observation", "feature") )zarr_array_source( uri, array_path = "/", shape = NULL, dtype = NULL, chunks = NULL, physical_axes = c("observation", "feature") )
uri |
One local path, file URI, or HTTP(S) location understood by
|
array_path |
Absolute path of the array within the Zarr hierarchy. The
default |
shape |
Optional logical observation-by-feature shape. |
dtype |
Optional logical storage dtype supported by |
chunks |
Optional logical observation-by-feature chunk shape. |
physical_axes |
Names of the two physical Zarr dimensions, permitting either observation-first or feature-first storage. |
The optional zarr package is needed only when metadata
must be discovered or data are read. Supplying shape, dtype, and chunks
together therefore permits metadata-only construction and serialization on
workers where Zarr is not installed.
The fingerprint covers the descriptor: URI, array path, logical shape,
dtype, chunks, and axis order, never the stored values. Opening a handle
re-reads the store metadata and raises fmridataset_error_source_stale
(with source, expected, and actual fields) if shape, chunks, or dtype
changed; a store that cannot be opened is fmridataset_error_backend_io.
See content_hash() to identify values.
A serializable zarr_array_source descriptor.
# Metadata-only construction needs no Zarr store and no zarr package. src <- zarr_array_source( "fixture.zarr", shape = c(5L, 6L), dtype = "float64", chunks = c(2L, 3L) ) source_shape(src) source_chunks(src)# Metadata-only construction needs no Zarr store and no zarr package. src <- zarr_array_source( "fixture.zarr", shape = c(5L, 6L), dtype = "float64", chunks = c(2L, 3L) ) source_shape(src) source_chunks(src)