|
a |
|
b/R/deconvolution.R |
|
|
1 |
#### |
|
|
2 |
# Spot Deconvolution #### |
|
|
3 |
#### |
|
|
4 |
|
|
|
5 |
#' getDeconvolution |
|
|
6 |
#' |
|
|
7 |
#' Calculate deconvolution of spots and ROIs |
|
|
8 |
#' |
|
|
9 |
#' @param object a VoltRon object |
|
|
10 |
#' @param assay assay name (exp: Assay1) or assay class (exp: Visium, Xenium), see \link{SampleMetadata}. |
|
|
11 |
#' if NULL, the default assay will be used, see \link{vrMainAssay}. |
|
|
12 |
#' @param features features |
|
|
13 |
#' @param sc.object Seurat Object |
|
|
14 |
#' @param sc.assay assay of the Seurat Object used for the single cell data reference |
|
|
15 |
#' @param sc.cluster metadata column variable used for the single cell data reference |
|
|
16 |
#' @param method Deconvolution method, RCTD (spot), SPOTlight (spot), MuSiC (ROI) |
|
|
17 |
#' @param ... additional parameters passed to method specific functions, e.g. RCTD, MuSiC. |
|
|
18 |
#' |
|
|
19 |
#' @export |
|
|
20 |
getDeconvolution <- function(object, assay = NULL, features = NULL, sc.object, sc.assay = "RNA", sc.cluster = "seurat_clusters", method = "RCTD", ...){ |
|
|
21 |
|
|
|
22 |
# sample metadata |
|
|
23 |
sample.metadata <- SampleMetadata(object) |
|
|
24 |
|
|
|
25 |
# get assay names |
|
|
26 |
assay_names <- vrAssayNames(object, assay = assay) |
|
|
27 |
|
|
|
28 |
# check assay type |
|
|
29 |
assay.types <- unique(vrAssayTypes(object, assay = assay)) |
|
|
30 |
|
|
|
31 |
if(length(assay.types) > 1){ |
|
|
32 |
stop("Please make sure that only assays of one assay type (cell/spot/ROI) are being deconvoluted at a time!") |
|
|
33 |
} else { |
|
|
34 |
|
|
|
35 |
# make single cell reference |
|
|
36 |
reference <- getDeconReference(sc.object = sc.object, sc.assay = sc.assay, sc.cluster = sc.cluster, |
|
|
37 |
method = method, assay.type = assay.types) |
|
|
38 |
|
|
|
39 |
# run a list of assays |
|
|
40 |
for(assy in assay_names){ |
|
|
41 |
|
|
|
42 |
# get assay |
|
|
43 |
cur_assay <- object[[assy]] |
|
|
44 |
|
|
|
45 |
# RCTD |
|
|
46 |
rawdata <- getDeconSingle(object = cur_assay, features = features, reference = reference, method = method, ...) |
|
|
47 |
|
|
|
48 |
# add cell type mixtures as new featureset |
|
|
49 |
object <- addFeature(object, assay = assy, data = rawdata, feature_name = "Decon") |
|
|
50 |
} |
|
|
51 |
} |
|
|
52 |
|
|
|
53 |
return(object) |
|
|
54 |
} |
|
|
55 |
|
|
|
56 |
#' getDeconReference |
|
|
57 |
#' |
|
|
58 |
#' Establish and produce the single cell reference for deconvolution |
|
|
59 |
#' |
|
|
60 |
#' @param sc.object Seurat Object |
|
|
61 |
#' @param sc.assay assay of the Seurat Object used for the single cell data reference |
|
|
62 |
#' @param sc.cluster metadata column variable used for the single cell data reference |
|
|
63 |
#' @param method Deconvolution method, RCTD (spot), SPOTlight (spot), MuSiC (ROI) |
|
|
64 |
#' @param assay.type the assay type associated with the single cell deconvolution reference |
|
|
65 |
#' |
|
|
66 |
#' @noRd |
|
|
67 |
getDeconReference <- function(sc.object, sc.assay = "RNA", sc.cluster = "seurat_clusters", method = "RCTD", assay.type = NULL){ |
|
|
68 |
|
|
|
69 |
# Deconvolute for spots |
|
|
70 |
if(assay.type == "spot"){ |
|
|
71 |
|
|
|
72 |
# check method |
|
|
73 |
if(!method %in% c("RCTD")){ |
|
|
74 |
message("The selected method is not provided for spot deconvolution. Switching to RCTD") |
|
|
75 |
method <- "RCTD" |
|
|
76 |
} |
|
|
77 |
|
|
|
78 |
# deconvolution with RCTD |
|
|
79 |
if(method == "RCTD"){ |
|
|
80 |
|
|
|
81 |
if (!requireNamespace('spacexr')) |
|
|
82 |
stop("Please install spacexr package to use the RCTD algorithm") |
|
|
83 |
if (!requireNamespace('Seurat')) |
|
|
84 |
stop("Please install Seurat package for using Seurat objects") |
|
|
85 |
|
|
|
86 |
message("Configuring Single Cell Assay (reference) ...\n") |
|
|
87 |
sccounts <- Seurat::GetAssayData(sc.object[[sc.assay]], slot = "counts") |
|
|
88 |
# sccounts <- as.matrix(apply(sccounts,2,ceiling)) |
|
|
89 |
rownames(sccounts) <- rownames(sc.object[[sc.assay]]) |
|
|
90 |
cell_types <- as.factor(sc.object@meta.data[[sc.cluster]]) |
|
|
91 |
names(cell_types) <- colnames(sc.object) |
|
|
92 |
sc.nUMI <- colSums(sccounts) |
|
|
93 |
names(sc.nUMI) <- colnames(sc.object) |
|
|
94 |
reference <- spacexr::Reference(sccounts, cell_types, sc.nUMI) |
|
|
95 |
} |
|
|
96 |
|
|
|
97 |
# Deconvolute for ROIs |
|
|
98 |
} else if(assay.type == "ROI"){ |
|
|
99 |
|
|
|
100 |
# check method |
|
|
101 |
if(!method %in% c("MuSiC")){ |
|
|
102 |
message("The selected method is not provided for ROI deconvolution. Switching to MuSiC") |
|
|
103 |
method <- "MuSiC" |
|
|
104 |
} |
|
|
105 |
|
|
|
106 |
# deconvolution with MuSiC |
|
|
107 |
if(method == "MuSiC"){ |
|
|
108 |
|
|
|
109 |
message("Configuring Single Cell Assay (reference) ...\n") |
|
|
110 |
if(inherits(sc.object, "SingleCellExperiment")){ |
|
|
111 |
sc.object$music_decon_clusters <- sc.object[[sc.cluster]] |
|
|
112 |
reference <- sc.object |
|
|
113 |
} else if(inherits(sc.object, "Seurat")){ |
|
|
114 |
sc.object$music_decon_clusters <- sc.object@meta.data[[sc.cluster]] |
|
|
115 |
sccounts <- Seurat::GetAssayData(sc.object[[sc.assay]], slot = "counts") |
|
|
116 |
sccounts <- as.matrix(apply(sccounts,2,ceiling)) |
|
|
117 |
rownames(sccounts) <- rownames(sc.object[[sc.assay]]) |
|
|
118 |
reference <- Seurat::as.SingleCellExperiment(Seurat::CreateSeuratObject(sccounts, meta.data = sc.object@meta.data)) |
|
|
119 |
} else{ |
|
|
120 |
stop("'sc.object' should either be of a Seurat or SingleCellExperiment class!") |
|
|
121 |
} |
|
|
122 |
|
|
|
123 |
} |
|
|
124 |
} |
|
|
125 |
|
|
|
126 |
# return |
|
|
127 |
return(reference) |
|
|
128 |
} |
|
|
129 |
|
|
|
130 |
#' getDeconSingle |
|
|
131 |
#' |
|
|
132 |
#' Calculate deconvolution of spots and ROIs of a single vrAssay object |
|
|
133 |
#' |
|
|
134 |
#' @param object a vrAssay object |
|
|
135 |
#' @param features features |
|
|
136 |
#' @param reference the single cell deconvolution reference, generated by \code{getDeconReference} |
|
|
137 |
#' @param method Deconvolution method, RCTD (spot), SPOTlight (spot), MuSiC (ROI) |
|
|
138 |
#' @param ... additional parameters passed to method specific functions |
|
|
139 |
#' |
|
|
140 |
#' @noRd |
|
|
141 |
getDeconSingle <- function(object, features = features, reference, method = "RCTD", ...){ |
|
|
142 |
|
|
|
143 |
# get assay type |
|
|
144 |
assay.type <- vrAssayTypes(object) |
|
|
145 |
|
|
|
146 |
if(assay.type == "spot"){ |
|
|
147 |
|
|
|
148 |
# check method |
|
|
149 |
if(!method %in% c("RCTD")){ |
|
|
150 |
message("The selected method is not provided for spot deconvolution. Switching to RCTD") |
|
|
151 |
method <- "RCTD" |
|
|
152 |
} |
|
|
153 |
|
|
|
154 |
if(method == "RCTD"){ |
|
|
155 |
message("Running RCTD for spot deconvolution ...\n") |
|
|
156 |
rawdata <- getRCTD(object = object, features = features, reference = reference, ...) |
|
|
157 |
} |
|
|
158 |
|
|
|
159 |
} else if(assay.type == "ROI"){ |
|
|
160 |
|
|
|
161 |
# check method |
|
|
162 |
if(!method %in% c("MuSiC")){ |
|
|
163 |
message("The selected method is not provided for ROI deconvolution. Switching to MuSiC") |
|
|
164 |
method <- "MuSiC" |
|
|
165 |
} |
|
|
166 |
|
|
|
167 |
if(method == "MuSiC"){ |
|
|
168 |
message("Running MuSiC for ROI deconvolution ...\n") |
|
|
169 |
rawdata <- getMuSiC(object = object, features = features, reference = reference, ...) |
|
|
170 |
} |
|
|
171 |
|
|
|
172 |
} |
|
|
173 |
|
|
|
174 |
# return |
|
|
175 |
return(rawdata) |
|
|
176 |
} |
|
|
177 |
|
|
|
178 |
#' getRCTD |
|
|
179 |
#' |
|
|
180 |
#' Calculate RCTD deconvolution for spot transcriptomics |
|
|
181 |
#' |
|
|
182 |
#' @param object a VoltRon object |
|
|
183 |
#' @param features features |
|
|
184 |
#' @param reference the single cell deconvolution reference, generated \code{getDeconReference} |
|
|
185 |
#' @param ... additional parameters passed to \code{create.RCTD} function |
|
|
186 |
#' |
|
|
187 |
#' @noRd |
|
|
188 |
getRCTD <- function(object, features = NULL, reference, ...){ |
|
|
189 |
|
|
|
190 |
if (!requireNamespace('spacexr')) |
|
|
191 |
stop("Please install spacexr package to use the RCTD algorithm: devtools::install_github('dmcable/spacexr')") |
|
|
192 |
if (!requireNamespace('Seurat')) |
|
|
193 |
stop("Please install Seurat package for using Seurat objects: install.packages('Seurat')") |
|
|
194 |
|
|
|
195 |
# create spatial data |
|
|
196 |
message("Configuring Spatial Assay ...\n") |
|
|
197 |
spatialcounts <- vrData(object, norm = FALSE) |
|
|
198 |
coords <- as.data.frame(as(vrCoordinates(object), "dgCMatrix"))[,c("x", "y")] |
|
|
199 |
spatialnUMI <- colSums(spatialcounts) |
|
|
200 |
spatialdata <- spacexr::SpatialRNA(coords, spatialcounts, spatialnUMI) |
|
|
201 |
|
|
|
202 |
# Run RCTD |
|
|
203 |
myRCTD <- spacexr::create.RCTD(spatialdata, reference, ...) |
|
|
204 |
message("Calculating Cell Type Compositions of spots with RCTD ...\n") |
|
|
205 |
myRCTD <- quiet(spacexr::run.RCTD(myRCTD, doublet_mode = 'full')) |
|
|
206 |
results <- as.matrix(myRCTD@results$weights) |
|
|
207 |
norm_weights <- t(sweep(results, 1, rowSums(results), "/")) |
|
|
208 |
|
|
|
209 |
# return |
|
|
210 |
return(norm_weights) |
|
|
211 |
} |
|
|
212 |
|
|
|
213 |
#' getMuSiC |
|
|
214 |
#' |
|
|
215 |
#' Calculate MuSiC deconvolution for ROIs |
|
|
216 |
#' |
|
|
217 |
#' @param object a vrAssay object |
|
|
218 |
#' @param features features |
|
|
219 |
#' @param reference the single cell deconvolution reference, generated \code{getDeconReference} |
|
|
220 |
#' @param sc.samples metadata column in Seurat that provides the samples in the single cell data |
|
|
221 |
#' |
|
|
222 |
#' @noRd |
|
|
223 |
getMuSiC <- function(object, features = NULL, reference, sc.samples = NULL){ |
|
|
224 |
|
|
|
225 |
if (!requireNamespace('Seurat')) |
|
|
226 |
stop("Please install Seurat package for using Seurat objects: install.packages('Seurat')") |
|
|
227 |
if (!requireNamespace('MuSiC')) |
|
|
228 |
stop("Please install MuSiC package for ROI deconvolution: devtools::install_github('xuranw/MuSiC')") |
|
|
229 |
if (!requireNamespace('SingleCellExperiment')) |
|
|
230 |
stop("Please install SingleCellExperiment package for ROI deconvolution: BiocManager::install('SingleCellExperiment')") |
|
|
231 |
|
|
|
232 |
if(is.null(sc.samples)) |
|
|
233 |
stop("Please provide a metadata column for samples for MuSiC algorithm to work, e.g. sc.samples = Sample") |
|
|
234 |
|
|
|
235 |
if(is.null(features)) { |
|
|
236 |
features <- vrFeatures(object) |
|
|
237 |
} |
|
|
238 |
|
|
|
239 |
# Single cell reference data |
|
|
240 |
reference <- reference[rownames(reference) %in% features,] |
|
|
241 |
|
|
|
242 |
# data |
|
|
243 |
datax <- as.matrix(vrData(object)) |
|
|
244 |
|
|
|
245 |
# common features |
|
|
246 |
common_features <- intersect(rownames(reference), rownames(datax)) |
|
|
247 |
common_features <- intersect(common_features, features) |
|
|
248 |
if(length(common_features) < 5) |
|
|
249 |
stop("The number of common or selected features are less than 5!") |
|
|
250 |
reference <- reference[rownames(reference) %in% common_features,] |
|
|
251 |
datax <- datax[common_features,] |
|
|
252 |
|
|
|
253 |
# deconvolute |
|
|
254 |
message("Calculating Cell Type Compositions of ROIs with MuSiC ...\n") |
|
|
255 |
results <- MuSiC::music_prop(bulk.mtx = datax, |
|
|
256 |
sc.sce = reference, |
|
|
257 |
clusters = "music_decon_clusters", |
|
|
258 |
samples = sc.samples, |
|
|
259 |
verbose = T) |
|
|
260 |
t(results$Est.prop.weighted) |
|
|
261 |
} |