Diff of /R/deconvolution.R [000000] .. [413088]

Switch to unified view

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
}