# ROIs, Searchlights, and Pipelines

Most analysis work in `neuroim2` reduces to the same pattern: define a spatial support, extract values from it, then summarize or map those values into a new result. This article shows the three main ways to do that.

## Extract a time series from one ROI

Start with a 4D image and define one spherical region of interest.

    vec_file <- system.file("extdata", "global_mask_v4.nii", package = "neuroim2")
    vol <- read_vol(vec_file)
    vec <- read_vec(vec_file)

    roi <- spherical_roi(vol, c(12, 12, 12), radius = 6)
    roi_ts <- series_roi(vec, roi)

    dim(values(roi_ts))
    #> [1]  4 19

    stopifnot(length(roi) > 0L)
    stopifnot(nrow(values(roi_ts)) == dim(vec)[4])

That gives you one compact object containing the time series from every voxel inside the ROI.

## Split a masked volume into parcels

When you already have a parcellation or cluster assignment, `split_clusters()` turns one `NeuroVec` into a list of region-wise objects.

    set.seed(1)

    mask_vol <- vol > 0
    cluster_ids <- sample(1:4, sum(mask_vol), replace = TRUE)
    clustered <- ClusteredNeuroVol(mask_vol, cluster_ids)
    parts <- split_clusters(vec, clustered)

    length(parts)
    #> [1] 4

    part_means <- map_dbl(parts, ~ mean(values(.)))
    part_means
    #> 1 2 3 4
    #> 1 1 1 1

    stopifnot(length(parts) == 4L)
    stopifnot(all(is.finite(part_means)))

This is the right pattern when the support is fixed in advance by an atlas, parcel map, or clustering step.

## Build searchlights lazily

Searchlights define many overlapping ROIs, one centered at each voxel in a mask. The lazy form is useful because you only realize the neighborhoods you actually touch.

    sl <- searchlight(mask_vol, radius = 4, eager = FALSE, nonzero = FALSE)
    first_sl <- sl[[1]]

    nrow(coords(first_sl))
    #> [1] 6

    stopifnot(nrow(coords(first_sl)) > 0L)

The eager form is better when you want to iterate repeatedly over the full set and can afford the up-front construction cost.

## Map a simple statistic over the first few searchlights

You do not need a specialized pipeline framework to use split-map-reduce style workflows. A small list of ROIs plus `purrr::map_*()` is often enough.

    first_five <- lapply(seq_len(5), function(i) sl[[i]])
    first_five_means <- map_dbl(first_five, ~ mean(values(.)))

    first_five_means
    #> [1] 0.5000000 0.8333333 0.8333333 0.5000000 0.5000000

    stopifnot(length(first_five_means) == 5L)
    stopifnot(all(is.finite(first_five_means)))

The pattern is the same whether the pieces come from parcels, ROIs, connected components, or searchlights:

1. define the spatial pieces
2. extract the values you need
3. reduce them into a scalar, vector, or model result

## Where to go next

- `vignette("VolumesAndVectors")` for the core data containers
- `vignette("regionOfInterest")` for the full ROI API surface
- `vignette("pipelines")` for older split-map-reduce examples
- `vignette("clustered-neurovec")` for parcel-based data structures