R/spatialDE.R
d8aca211
 #' Find spatially variable genes with **SpatialDE**
 #'
 #' Identify genes that significantly depend on spatial coordinates with the
 #' [**SpatialDE**](https://github.com/Teichlab/SpatialDE) Python package.
 #'
 #' @param x A numeric `matrix` of counts where genes are rows and cells are columns.
 #'
 #'    Alternatively, a \linkS4class{SpatialExperiment} object.
 #'
 #' @param ... For the generic, arguments to pass to specific methods.
36086cd8
 #' @param coordinates A `data.frame` with sample coordinates. Each row is a
 #'   sample, the columns with coordinates should be named 'x' and 'y'.
 #'
 #'   For the *SpatialExperiment* method, coordinates are taken from
 #'   `spatialCoords(x)`.
 #'
d8aca211
 #' @param assay_type A `character` string specifying the assay from `x` to use
 #'   as input. Defaults to `"counts"`.
 #' @param verbose A `logical` controlling the display of a progress bar from the
 #'   Python package.
 #'
 #' @return A `data.frame` with DE results where each row is a gene and columns
 #'   contain relevant statistics.
 #'
 #'   The most important columns are:
 #'
 #'   * `g`: the name of the gene
 #'   * `pval`: the p-value for spatial differential expression
 #'   * `qval`: the q-value, indicating significance after correcting for
 #'   multiple testing
 #'   * `l`: A parameter indicating the distance scale a gene changes expression
 #'   over
 #'
 #' @examples
6b99d290
 #' ## Mock up a SpatialExperiment object wit 400 cells and 3 genes
d8aca211
 #' set.seed(42)
6b99d290
 #' spe <- mockSVG(size = 20, tot_genes = 3, de_genes = 1, return_SPE = TRUE)
d8aca211
 #'
 #' ## Run spatialDE
 #' de_results <- spatialDE(spe)
 #'
1e1b0d81
 #' head(de_results)
 #'
d8aca211
 #' @seealso
 #' The individual steps performed by this function: [stabilize()],
 #' [regress_out()] and [run()].
 #'
 #' For further analysis of the DE results:
 #' [model_search()] and [spatial_patterns()].
 #'
 #' @references
 #' Svensson, V., Teichmann, S. & Stegle, O. SpatialDE: identification of
 #' spatially variable genes. Nat Methods 15, 343–346 (2018).
 #' \url{https://doi.org/10.1038/nmeth.4636}
 #'
 #' [**SpatialDE 1.1.3**](https://pypi.org/project/SpatialDE/1.1.3/): the version
 #' of the Python package used under the hood.
 #'
f9403c31
 #' @author Davide Corso, Milan Malfait, Lambda Moses
d8aca211
 #' @name spatialDE
 NULL
9867332a
 
 ## Run spatialDE pipeline on any matrix-like object
 #' @importFrom Matrix colSums
f2ee8aa8
 #' @importFrom basilisk basiliskStart basiliskRun
9867332a
 .spatialDE <- function(x, coordinates, verbose = FALSE) {
     sample_info <- data.frame(coordinates, total_counts = colSums(x))
f2ee8aa8
     coords <- sample_info[, c("x", "y")]
     
     proc <- basiliskStart(spatialDE_env, testload="scipy.optimize")
     
     # Stabilize
     assert_matrix(x, any.missing = FALSE)
     .naiveDE_stabilize(proc, x)
     stabilized <- basiliskRun(proc, function(store) {
         as.matrix(store$stabilized)
     }, persist=TRUE)
     
     # Regress_out
     assert_data_frame(sample_info, any.missing = FALSE)
     assert_names(colnames(sample_info),
                  must.include = "total_counts"
9867332a
     )
f2ee8aa8
     assert_matrix(stabilized, any.missing = FALSE)
     .naiveDE_regress_out(proc, stabilized, sample_info)
     regressed <- basiliskRun(proc, function(store) {
         as.matrix(store$regressed)
     }, persist=TRUE)
     
     # SpatialDE.run()
     assert_data_frame(coords, any.missing = FALSE)
     assert_names(colnames(coords), identical.to = c("x", "y"))
     assert_matrix(regressed, any.missing = FALSE)
     assert_flag(verbose)
353bd6f2
     .importPyModule(proc, verbose)
f2ee8aa8
     .spatialDE_run(proc, regressed, coords)
     
     # results
     out <- basiliskRun(proc, function(store) {
         store$de_results
     }, persist=TRUE)
     
9867332a
     out
 }
 
 
 #' @import methods
 #' @export
 #' @rdname spatialDE
 setGeneric("spatialDE", function(x, ...) standardGeneric("spatialDE"))
 
 #' @export
 #' @rdname spatialDE
1715bdd0
 setMethod("spatialDE", "matrix", .spatialDE)
9867332a
 
 #' @export
 #' @rdname spatialDE
 #' @importFrom SummarizedExperiment assay
 #' @importFrom SpatialExperiment spatialCoords spatialCoordsNames<-
 setMethod("spatialDE", "SpatialExperiment",
1715bdd0
     function(x, assay_type = "counts", verbose = FALSE) {
9867332a
         ## Rename spatialCoords columns to "x", "y"
         spatialCoordsNames(x) <- c("x", "y")
beda0cbe
         coordinates <- as.data.frame(spatialCoords(x))
9867332a
 
1715bdd0
         .spatialDE(
             x = assay(x, assay_type),
             coordinates = coordinates,
             verbose = verbose
         )
9867332a
     }
 )