Advanced NeuroVec Patterns

if (requireNamespace("ggplot2", quietly = TRUE) && requireNamespace("albersdown", quietly = TRUE)) ggplot2::theme_set(albersdown::theme_albers(family = params$family, preset = params$preset))
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE)
suppressPackageStartupMessages({
  library(purrr)
  library(neuroim2)
})
options(mc.cores = 1)

This article is now the deeper companion to vignette("VolumesAndVectors"). Read that first if you want the compact introduction to NeuroVec. Stay here when you want more detail on multi-file reads, manual construction, matrix views, and dense/sparse conversions for 4D data.

Working with neuroimaging time-series data

This vignette focuses on the parts of the 4D workflow that remain useful after you already understand the basic container model:

Reading multiple four-dimensional images

file_name <- system.file("extdata", "global_mask_v4.nii", package = "neuroim2")
vec <- read_vec(file_name)
vec_multi <- read_vec(c(file_name, file_name, file_name))
dim(vec_multi)

vec2 <- read_vec(rep(file_name, 10))
vec2

Creating a NeuroVec from an in-memory array

You can build a NeuroVec directly from arrays or matrices:

set.seed(1)
dims <- c(24, 24, 24, 5)
arr  <- array(rnorm(prod(dims)), dims)
sp4  <- NeuroSpace(dims, spacing = c(2,2,2))
dvec <- NeuroVec(arr, sp4)
dim(dvec)

You can also start from a matrix (voxels × time or time × voxels) using DenseNeuroVec:

mat  <- matrix(rnorm(prod(dims)), nrow = prod(dims[1:3]), ncol = dims[4])
dvec2 <- DenseNeuroVec(mat, sp4)
all.equal(dim(dvec), dim(dvec2))

Time-series transforms: z-scoring and summary volumes

Z-score each voxel’s time-series (center and scale across time):

vec_z <- scale_series(dvec, center = TRUE, scale = TRUE)
dim(vec_z)

Compute a mean volume across time and return a 3D NeuroVol:

M      <- as.matrix(dvec)              # voxels × time
vmean  <- rowMeans(M)                  # per-voxel mean
mean3d <- NeuroVol(vmean, drop_dim(space(dvec)))
mean3d

Concatenating along time

Append time points by concatenating vectors or volumes:

dvec_more <- concat(dvec, dvec)        # doubles the time dimension
dim(dvec_more)

Dense ↔ sparse workflows

Sparse representations store only voxels within a mask. This is handy for large ROIs or brain masks.

# Build a random mask and convert a dense vec to sparse
mask_arr <- array(runif(prod(dims[1:3])) > 0.7, dims[1:3])
mask_vol <- LogicalNeuroVol(mask_arr, drop_dim(sp4))

svec <- as.sparse(dvec, mask_vol)     # SparseNeuroVec with explicit mask
svec                                 # note the stored mask and cardinality

# Convert back to dense if needed
dense_again <- as.dense(svec)
all.equal(dim(dense_again), dim(dvec))

Tip: For file-backed or memory-mapped vectors, convert to DenseNeuroVec via a matrix if you need dense-only operations:

dv_dense <- DenseNeuroVec(as.matrix(vec), space(vec))

Writing vectors to disk

You can write NeuroVec and NeuroVol objects as NIfTI files:

tmp_vec <- tempfile(fileext = ".nii.gz")
write_vec(sub_vector(vec, 1:3), tmp_vec)
file.exists(tmp_vec)
unlink(tmp_vec)

Putting it together with an ROI

Combine ROI extraction with time-series transforms:

vol3d <- read_vol(system.file("extdata", "global_mask_v4.nii", package="neuroim2"))
roi   <- spherical_roi(vol3d, c(12,12,12), radius = 6)
rts   <- series_roi(vec, roi)          # ROIVec (T × N with coords)

# z-score each column (voxel) across time, then average within ROI
mat_roi  <- values(rts)                # T × N
mat_z    <- base::scale(mat_roi, center=TRUE, scale=TRUE)
roi_mean <- rowMeans(mat_z)
length(roi_mean)                       # matches time dimension

This article now complements the core path rather than replacing it. Use vignette("VolumesAndVectors") for the basic 4D container model and come back here when you need denser transformation and conversion patterns.



Try the neuroim2 package in your browser

Any scripts or data that you put into this service are public.

neuroim2 documentation built on April 16, 2026, 5:07 p.m.