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 many 4D files into a
NeuroVecSeq - creating
NeuroVecobjects from arrays or matrices - time-series transforms and concatenation
- dense/sparse conversion patterns
- writing vectors back to disk
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)
#> [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 moreCreating 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)
#> [1] 24 24 24 5You can also start from a matrix (voxels × time or time × voxels)
using DenseNeuroVec:
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)
#> [1] 24 24 24 5Compute 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]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
#> <SparseNeuroVec> [306 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:
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)
#> [1] TRUE
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
#> [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.