Skip to contents

Constructs the neighbourhood-interaction design matrix for a single niche bandwidth and tags each covariate by type ("CellType", "Niche", "Response", "ResponseNiche", or "Other"). The scientifically important covariates are the three-way CellType:condition:niche interactions ("ResponseNiche"), which capture how expression within an index cell type changes with the condition as a function of a niche cell type's local density. Self interactions — an index cell type against its own niche density — are dropped; when niches have been merged with mergeNiches(), this extends to any index that is a member of the merged niche's group. This is an escape hatch for custom fits; most users should call fitSpiDE().

Usage

nicheDesign(
  spe,
  condition = NULL,
  sigma,
  index = NULL,
  niche = NULL,
  covariates = character(),
  cell_type = "cell_type",
  name = "Niche",
  sample_id = "sample_id",
  random = c("none", "intercept", "slope"),
  re.celltype = FALSE,
  ...
)

Arguments

spe

a SpatialExperiment with a niche reducedDim for sigma.

condition

a character, the colData column of the tested condition, or NULL (default) for a condition-free design. With NULL the condition terms are omitted and the two-way CellType:niche interactions (tagged "Niche") become the tested effects; no Response columns are produced.

sigma

a numeric, the bandwidth (a single value).

index, niche

character vectors restricting index / niche cell types (NULL = all).

covariates

a character vector of nuisance colData columns.

cell_type

a character, the colData column of cell type labels.

name

a character, the niche reducedDim prefix.

sample_id

a character, the colData column identifying samples (patients); used only when random != "none".

random

one of "none" (the default), "intercept" (add a per-sample random intercept) or "slope" (also add per-sample random slopes on the niche covariates). The random-effect columns are penalised at fit time to implement a mixed model via ridge (see the vignette).

This defaults to "none" even though fitSpiDE() defaults to "intercept". The asymmetry is deliberate: the random-effect columns are collinear with the cell-type block and are identified only by the penalty applied at fit time, so a design returned with them included is rank-deficient. That is correct for fitting and surprising for a constructor whose job is to hand back a design matrix to inspect.

re.celltype

logical; add a nested (sample x cell type) random intercept alongside the per-sample one, so that every tested niche slope is a within-(sample, cell type) slope. Without it the slopes also carry the between-sample composition effect (a patient-level association between a cell type's mean niche density and its mean expression in that type), which is not neighbourhood-dependent differential expression. Ignored when random = "none". Defaults to FALSE here and TRUE in fitSpiDE(), for the same reason random does: a design returned with penalty-identified columns is rank-deficient, which is correct for fitting and surprising from a constructor.

...

ignored.

Value

a list with W (the design matrix), covtype (a factor of column types), coefmap (a data.frame mapping columns to index/niche cells), and mode ("condition" or "niche").

Details

With condition = NULL the condition terms are omitted and the two-way CellType:niche interactions ("Niche") become the tested effects. That design also omits the bare niche main effects, so the interaction block is cell-means coded: each coefficient is directly the slope of expression on that niche cell type's log density within the index cell type, rather than a contrast against a reference cell type.

Examples

data(toySpiDE)
spe <- toySpiDE
spe <- buildNiches(spe, sigma = 20)
des <- nicheDesign(spe, condition = "condition", sigma = 20)
table(des$covtype)
#> 
#>         CellType            Niche         Response    ResponseNiche 
#>                3                4                0                6 
#> ResponseCellType            Other 
#>                3                3 

des0 <- nicheDesign(spe, condition = NULL, sigma = 20)
table(des0$covtype)
#> 
#>         CellType            Niche         Response    ResponseNiche 
#>                3                6                0                0 
#> ResponseCellType            Other 
#>                0                0