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.
This vignette focuses on the parts of the 4D workflow that remain useful after you already understand the basic container model:
NeuroVecSeqNeuroVec objects from arrays or matricesfile_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)
#> [1] 64 64 25 12
vec2 <- read_vec(rep(file_name, 10))
vec2
#> <NeuroVecSeq> [10 vectors]
#> ── Sequence ────────────────────────────────────────────────────────────────────
#> [1] : DenseNeuroVec 64x64x25 x 4t
#> [2] : DenseNeuroVec 64x64x25 x 4t
#> [3] : DenseNeuroVec 64x64x25 x 4t
#> [4] : DenseNeuroVec 64x64x25 x 4t
#> [5] : DenseNeuroVec 64x64x25 x 4t
#> ... and 5 moreYou 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)
#> [1] 24 24 24 5You can also start from a matrix (voxels × time or time × voxels)
using DenseNeuroVec:
Z-score each voxel’s time-series (center and scale across time):
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
#> <DenseNeuroVol> [114.6 Kb]
#> ── Spatial ─────────────────────────────────────────────────────────────────────
#> Dimensions : 24 x 24 x 24
#> Spacing : 2 x 2 x 2 mm
#> Origin : 0, 0, 0
#> Orientation : RAS
#> ── Data ────────────────────────────────────────────────────────────────────────
#> Range : [-1.643, 1.756]Append time points by concatenating vectors or volumes:
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
#> <SparseNeuroVec> [306.2 Kb]
#> ── Spatial ─────────────────────────────────────────────────────────────────────
#> Dimensions : 24 x 24 x 24
#> Time Points : 5
#> Spacing : 2 x 2 x 2
#> Origin : 0, 0, 0
#> ── Sparse ──────────────────────────────────────────────────────────────────────
#> Cardinality : 4128
# Convert back to dense if needed
dense_again <- as.dense(svec)
all.equal(dim(dense_again), dim(dvec))
#> [1] TRUETip: For file-backed or memory-mapped vectors, convert to
DenseNeuroVec via a matrix if you need dense-only
operations:
You can write NeuroVec and NeuroVol objects
as NIfTI files:
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
#> [1] 4This 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.