R/sce_to_spe.R

Defines functions sce_to_spe

Documented in sce_to_spe

#' Convert a SCE object to a SPE one
#'
#' This function converts a spot-level
#' [SingleCellExperiment-class][SingleCellExperiment::SingleCellExperiment-class]
#' (SCE) object as generated by `fetch_data()` to a
#' [SpatialExperiment-class][SpatialExperiment::SpatialExperiment-class] (SPE)
#' object.
#'
#' Note that the resulting object is a bit more complex than a regular SPE
#' because it contains the data from the spatialLIBD project which you might
#' otherwise have to generate for your own data.
#'
#' @param sce Defaults to the output of
#' `fetch_data(type = 'sce')`. This is a
#' \linkS4class{SingleCellExperiment}
#' object with the spot-level Visium data and information required for
#' visualizing the histology. See [fetch_data()] for more details.
#' @param imageData A `DataFrame()` with image data. Will be used with
#' [SpatialExperiment::imgData][SpatialExperiment::SpatialExperiment-methods].
#' If `NULL`, then this will be constructed for you assuming that you are
#' working with the original data from `spatialLIBD::fetch_data("sce")`.
#'
#' @return A a
#' [SpatialExperiment-class][SpatialExperiment::SpatialExperiment-class]  object.
#' @export
#' @importFrom SpatialExperiment "imgData<-" "spatialCoordsNames<-"
#' "colData<-" SpatialImage
#' @importFrom jsonlite read_json
#' @importFrom methods new
#' @family SpatialExperiment-related functions
#' @author
#' Brenda Pardo, Leonardo Collado-Torres
#'
#' @examples
#'
#' if (enough_ram()) {
#'     ## Download the sce data
#'     sce <- fetch_data("sce")
#'     ## Transform it to a SpatialExperiment object
#'     spe <- sce_to_spe(sce)
#' }
sce_to_spe <- function(sce = fetch_data("sce"), imageData = NULL) {
    sce <- check_sce(sce)

    # Load assays
    assays_visium <- SummarizedExperiment::assays(sce)

    # Load rowData
    rowData_visium <- SummarizedExperiment::rowData(sce)

    ## Re-case tissue
    if (is.factor(sce$tissue)) sce$tissue <- sce$tissue == "1"

    # Load colData
    cols_to_drop <-
        c(
            "tissue",
            "row",
            "col",
            "imagerow",
            "imagecol"
        )
    colData_visium <-
        SummarizedExperiment::colData(sce)[, !colnames(SummarizedExperiment::colData(sce)) %in% c(cols_to_drop, "height", "width", "barcode"), drop = FALSE]

    names(colData_visium)[names(colData_visium) == "sample_name"] <- "sample_id"

    # Load spatialCoords
    spatialCoords_visium <-
        SummarizedExperiment::colData(sce)[, colnames(SummarizedExperiment::colData(sce)) %in% cols_to_drop, drop = FALSE]
    names(spatialCoords_visium) <-
        c(
            "in_tissue",
            "array_row",
            "array_col",
            "pxl_row_in_fullres",
            "pxl_col_in_fullres"
        )

    ## Use the official sample id name
    colnames(colData_visium)[colnames(colData_visium) == "sample_name"] <- "sample_id"
    colData_visium$sample_id <- as.character(colData_visium$sample_id)

    # Load reducedDim
    reducedDimNames_visium <-
        SingleCellExperiment::reducedDims(sce)

    # Load images from the web for our data
    if (is.null(imageData)) {
        sample_id <- unique(colData_visium$sample_id)

        url_images <-
            paste0(
                "https://spatial-dlpfc.s3.us-east-2.amazonaws.com/images/",
                sample_id,
                "_tissue_lowres_image.png"
            )

        # Load scaleFactors
        url_scaleFactors <- paste0(
            "https://raw.githubusercontent.com/LieberInstitute/",
            "HumanPilot/master/10X/",
            sample_id,
            "/scalefactors_json.json"
        )
        names(url_scaleFactors) <- sample_id
        scaleFactors_visium <-
            lapply(url_scaleFactors, jsonlite::read_json)

        ## Create a list of images

        spatial_img_list <- mapply(function(url) {
            SpatialExperiment::SpatialImage(
                url
            )
        }, url_images)


        img_dat <- DataFrame(
            sample_id = as.character(sample_id),
            image_id = rep("lowres", length(sample_id)),
            data = I(spatial_img_list),
            scaleFactor = vapply(
                scaleFactors_visium,
                "[[",
                numeric(1),
                "tissue_lowres_scalef",
                USE.NAMES = FALSE
            )
        )
        imageData <- img_dat

        ## Fix things we had done that are not default:
        # Scaling for lowres image: https://github.com/LieberInstitute/HumanPilot/blob/master/Analysis/Layer_Notebook.R#L118-L119
        spatialCoords_visium$pxl_col_in_fullres <- spatialCoords_visium$pxl_col_in_fullres / img_dat$scaleFactor[match(colData_visium$sample_id, img_dat$sample_id)]
        spatialCoords_visium$pxl_row_in_fullres <- spatialCoords_visium$pxl_row_in_fullres / img_dat$scaleFactor[match(colData_visium$sample_id, img_dat$sample_id)]
        ## Names of the columns is flipped at https://github.com/LieberInstitute/HumanPilot/blob/master/Analysis/Layer_Notebook.R#L116 compared to what
        ## SpatialExperiment does at https://github.com/drighelli/SpatialExperiment/blob/bf1b18b559ea2785d52db4e39a85f1d584aede45/R/read10xVisium.R#L170
        # tmp <- spatialCoords_visium$pxl_row_in_fullres
        # spatialCoords_visium$pxl_row_in_fullres <- spatialCoords_visium$pxl_col_in_fullres
        # spatialCoords_visium$pxl_col_in_fullres <- tmp
        ## The above is no longer necessary thanks to https://github.com/drighelli/SpatialExperiment/commit/6710fe8b0a7919191ecce989bb6831647385ef5f
    }

    # ## Create object manually
    # spe <- new("SpatialExperiment", SingleCellExperiment::SingleCellExperiment(
    #     rowData = rowData_visium,
    #     colData = colData_visium,
    #     assays = assays_visium,
    #     reducedDims = reducedDimNames_visium
    # ))
    #
    # ## Add missing spatial info
    # colData(spe) <- spatialCoords_visium
    # SpatialExperiment::spatialCoordsNames(spe) <- c("pxl_col_in_fullres", "pxl_row_in_fullres")
    # SpatialExperiment::imgData(spe) <- imageData
    #

    ## This works now in SpatialExperiment version 1.1.701, so we no longer
    ## need the manual code from above

    ## The following code ultimately fails due to the current lack of support
    ## for multiple `sample_id`s, as in
    ## https://github.com/drighelli/SpatialExperiment/blob/a9e54fbd5af7fe676f8a5b29e4cfe113402070d4/R/SpatialExperiment.R#L143-L144
    ## or in
    ## https://github.com/drighelli/SpatialExperiment/blob/a9e54fbd5af7fe676f8a5b29e4cfe113402070d4/R/SpatialExperiment.R#L164

    spe <- SpatialExperiment::SpatialExperiment(
        rowData = rowData_visium,
        colData = cbind(colData_visium, spatialCoords_visium),
        assays = assays_visium,
        reducedDims = reducedDimNames_visium,
        sample_id = NULL,
        spatialCoordsNames = c("pxl_col_in_fullres", "pxl_row_in_fullres"),
        scaleFactors = img_dat$scaleFactor,
        imgData = img_dat,
        imageSources = url_images,
        loadImage = FALSE
    )
    return(spe)
}
LieberInstitute/spatialLIBD documentation built on Nov. 4, 2024, 11:57 a.m.