diff --git a/R/EntropyMatrix.R b/R/EntropyMatrix.R index b434026..6cdeca2 100644 --- a/R/EntropyMatrix.R +++ b/R/EntropyMatrix.R @@ -5,7 +5,7 @@ #' #' @param me A Molecule Experiment object. #' @param featureTypes A character string specifying the feature type. Supported values include -#' "sub_sector", "sub_concentric", "super_sector", and "super_concentric". +#' "subsector", "subconcentric", "supersector", and "superconcentric". #' @param nCores Number of cores #' @param ... arguments passing to CountsMatrix #' @@ -14,11 +14,11 @@ #' @examples #' data(example_me) #' me <- loadBoundaries(me) -#' ent <- EntropyMatrix(me, c("sub_sector", "sub_concentric", "super_sector", "super_concentric"), nCores = 1) +#' ent <- EntropyMatrix(me, c("subsector", "subconcentric", "supersector", "superconcentric"), nCores = 1) #' lapply(ent, head, n = 4) EntropyMatrix <- function(me, featureTypes, nCores = 1, ...) { # Ensure featureTypes are valid - # if (!all(featureTypes %in% c("sub_sector", "sub_concentric", 'sub_combo', "super_sector", "super_concentric", "super_combo"))) { + # if (!all(featureTypes %in% c("subsector", "subconcentric", 'subcombo', "supersector", "superconcentric", "supercombo"))) { # stop("Invalid assayName(s) provided!") # } diff --git a/R/EntropyMatrix_utils.R b/R/EntropyMatrix_utils.R index 0b83287..911c22c 100644 --- a/R/EntropyMatrix_utils.R +++ b/R/EntropyMatrix_utils.R @@ -38,11 +38,11 @@ annuli_counts = function(mat) { CountsMatrix <- function(me, assayName, nCores = 1, ...) { counts_matrix = MoleculeExperiment::countMolecules(me, moleculesAssay = "detected", boundariesAssay = assayName, matrixOnly = TRUE, nCores = nCores, ...) - if (assayName %in% c("sub_sector", "super_sector")) { + if (assayName %in% c("subsector", "supersector")) { return(counts_matrix) } - if (assayName %in% c("sub_concentric", "super_concentric")) { + if (assayName %in% c("subconcentric", "superconcentric")) { return(annuli_counts(counts_matrix)) } diff --git a/R/EntropySummarizedExperiment.R b/R/EntropySummarizedExperiment.R index 19c6c67..279152a 100644 --- a/R/EntropySummarizedExperiment.R +++ b/R/EntropySummarizedExperiment.R @@ -6,6 +6,8 @@ #' @param df_list A list of data frames, each containing assay data. #' @param me A Molecule Experiment object. #' @param includeCounts logical (default FALSE) whether to include gene counts as features +#' @param concatenateFeatures logical whether to concatenate all the features +#' into a single assay (default FALSE). If FALSE the output SE object has multiple assays #' @param nCores Number of cores (default 1) #' #' @return A SummarizedExperiment object. @@ -17,40 +19,54 @@ #' @examples #' data(example_me) #' me <- loadBoundaries(me) -#' ent <- EntropyMatrix(me, c("sub_sector", "sub_concentric", "super_sector", "super_concentric"), nCores = 1) +#' ent <- EntropyMatrix(me, c("subsector", "subconcentric", "supersector", "superconcentric"), nCores = 1) #' se <- EntropySummarizedExperiment(ent, me) #' se -EntropySummarizedExperiment <- function(df_list, me, includeCounts = FALSE, nCores = 1) { +EntropySummarizedExperiment <- function(df_list, me, includeCounts = FALSE, concatenateFeatures = FALSE, nCores = 1) { # 1. Assay Data: Using countMolecules function to get assay data. # Creating the assay_data - assay_data <- make_assay_data(df_list) + assay_data <- make_assay_data(df_list, concatenateFeatures = concatenateFeatures) if (includeCounts) { - # Generating the genecount - genecount <- as.data.frame(as.matrix(MoleculeExperiment::countMolecules(me, - moleculesAssay = "detected", - boundariesAssay = "cell", - matrixOnly = TRUE, - nCores = nCores))) - - # Adding a prefix to the row names of genecount to differentiate it - rownames(genecount) <- paste("genecount", rownames(genecount), sep="_") - - # Rbinding the assay_data and genecount together - assay_data <- rbind(assay_data, genecount) + # Generating the genecount + genecount <- as.data.frame(as.matrix(MoleculeExperiment::countMolecules(me, + moleculesAssay = "detected", + boundariesAssay = "cell", + matrixOnly = TRUE, + nCores = nCores))) + + # Adding a prefix to the row names of genecount to differentiate it + rownames(genecount) <- paste("genecount", rownames(genecount), sep="_") + + if (concatenateFeatures) { + + # Rbinding the assay_data and genecount together + assay_data <- rbind(assay_data, genecount) + + } else { + + assay_data[["genecount"]] <- genecount + + } } - # 2. Row Data - rowData <- data.frame( - FeatureCategory = gsub("_.*", "", rownames(assay_data)), - FeatureGene = gsub(".*_", "", rownames(assay_data)) - ) + if (concatenateFeatures) { - # Translate "sub" and "super" prefixes to "Subcellular" and "Supercellular" respectively - rowData$FeatureCategory <- gsub("^sub", "Subcellular", rowData$FeatureCategory) - rowData$FeatureCategory <- gsub("^super", "Supercellular", rowData$FeatureCategory) - rowData$FeatureCategory <- gsub("^genecount", "Genecount", rowData$FeatureCategory) + # 2. Row Data + rowData <- data.frame( + FeatureCategory = gsub("_.*", "", rownames(assay_data)), + FeatureGene = gsub(".*_", "", rownames(assay_data)) + ) + + # Translate "sub" and "super" prefixes to "Subcellular" and "Supercellular" respectively + # rowData$FeatureCategory <- gsub("^sub", "Subcellular", rowData$FeatureCategory) + # rowData$FeatureCategory <- gsub("^super", "Supercellular", rowData$FeatureCategory) + # rowData$FeatureCategory <- gsub("^genecount", "Genecount", rowData$FeatureCategory) + + } else { + rowData = NULL + } # 3. Column Data cell_df <- extract_boundaries_and_centroids(me)[[2]] @@ -65,12 +81,27 @@ EntropySummarizedExperiment <- function(df_list, me, includeCounts = FALSE, nCor # Convert Cell column to a format compatible with the columns in assay_data colData$Cell <- paste0(colData$Sample_id, ".", colData$Cell) - # Create the SummarizedExperiment object - se <- SummarizedExperiment::SummarizedExperiment( - assays = list(spatialFeatures = as.matrix(assay_data)), - rowData = rowData, - colData = colData - ) + if (concatenateFeatures) { + # Create the SummarizedExperiment object + se <- SummarizedExperiment::SummarizedExperiment( + assays = list(spatialFeatures = as.matrix(assay_data)), + rowData = rowData, + colData = colData + ) + } else { + + rnames = gsub(".*_", "", rownames(assay_data[[1]])) + assay_data <- lapply(assay_data, function(x){ + rownames(x) <- rnames + return(x) + }) + + se <- SummarizedExperiment::SummarizedExperiment( + assays = assay_data, + rowData = rowData, + colData = colData + ) + } return(se) } diff --git a/R/EntropySummarizedExperiment_utils.R b/R/EntropySummarizedExperiment_utils.R index 52bba7f..33b3321 100644 --- a/R/EntropySummarizedExperiment_utils.R +++ b/R/EntropySummarizedExperiment_utils.R @@ -1,11 +1,22 @@ #' make assay data #' #' @param df_list A list of data frames -#' @return A single data frame -make_assay_data = function(df_list) { - do.call(rbind, lapply(names(df_list), function(assayName) { +#' @param concatenateFeatures logical whether to concatenate features (default FALSE) +#' @return if concatenateFeatures == TRUE, A single data frame, otherwise a list +#' containing data frames +make_assay_data = function(df_list, concatenateFeatures = FALSE) { + + assay_data_list = lapply(names(df_list), function(assayName) { df <- df_list[[assayName]] rownames(df) <- paste(assayName, rownames(df), sep="_") return(df) - })) + }) + names(assay_data_list) <- names(df_list) + + if (concatenateFeatures) { + return(do.call(rbind, assay_data_list)) + } else { + return(assay_data_list) + } + } diff --git a/R/loadBoundaries_utils.R b/R/loadBoundaries_utils.R index e497218..7328a6d 100644 --- a/R/loadBoundaries_utils.R +++ b/R/loadBoundaries_utils.R @@ -21,24 +21,23 @@ #' @param k A numeric value indicating the scaling factor for concentric polygons. #' Defaults to 5. #' @return A list containing dataframes for each assay type: -#' - `sub_sector`: Feature data for sub-sector polygons. -#' - `sub_concentric`: Feature data for sub-concentric polygons. -#' - `sub_combo`: Feature data for sub-combo polygons. -#' - `super_concentric`: Feature data for super-concentric polygons. -#' - `super_combo`: Feature data for super-combo polygons. +#' - `subsector`: Feature data for sub-sector polygons. +#' - `subconcentric`: Feature data for sub-concentric polygons. +#' - `supersector`: Feature data for super-sector polygons. +#' - `superconcentric`: Feature data for super-concentric polygons. #' @importFrom dplyr group_by mutate arrange select ungroup rowwise distinct %>% bind_rows #' @importFrom purrr map_dfr #' @importFrom parallel mclapply -GenerateFeatureData <- function(me, featureTypes = c("sub_sector", "sub_concentric", - "super_sector", "super_concentric"), k = 5) { +GenerateFeatureData <- function(me, featureTypes = c("subsector", "subconcentric", + "supersector", "superconcentric"), k = 5) { results <- extract_boundaries_and_centroids(me) df_circle = results$df_circle featureTypes <- match.arg(featureTypes, several.ok = TRUE) - if ("sub_sector" %in% featureTypes) { - # For sub-sector - sub_sector <- df_circle %>% + if ("subsector" %in% featureTypes) { + # For subsector + subsector <- df_circle %>% distinct(segment_id, x_location, y_location, .keep_all = TRUE) %>% mutate(angle = atan2(y_location - y_central, x_location - x_central) + pi) %>% split(.$segment_id) %>% @@ -46,47 +45,46 @@ GenerateFeatureData <- function(me, featureTypes = c("sub_sector", "sub_concentr bind_rows() %>% dplyr::rename(x_section = x_location_sector, y_section = y_location_sector, area_id = sector_id) } else { - sub_sector <- NULL + subsector <- NULL } - if ("super_sector" %in% featureTypes) { - # For super-sector - super_sector <- create_sector_df(df_circle) + if ("supersector" %in% featureTypes) { + # For supersector + supersector <- create_sector_df(df_circle) } else { - super_sector <- NULL + supersector <- NULL } - if ("sub_concentric" %in% featureTypes) { - # Common for sub-concentric + if ("subconcentric" %in% featureTypes) { + # Common for subconcentric common_scale_factors <- generate_scale_factors_all(k) common_scaled_df <- common_scale_factors %>% map_dfr(~create_scaled_df_sub(.x, df_circle, k)) - # For sub-concentric - sub_concentric <- common_scaled_df %>% + # For subconcentric + subconcentric <- common_scaled_df %>% select(x_section = x_scaled, y_section = y_scaled, segment_id, sample_id, area_id = concentric_id) # modify the area_id column - sub_concentric <- sub_concentric %>% mutate(area_id = sapply(area_id, modify_area_id)) + subconcentric <- subconcentric %>% mutate(area_id = sapply(area_id, modify_area_id)) } else { - sub_concentric <- NULL + subconcentric <- NULL } - if ("super_concentric" %in% featureTypes) { - # For super-concentric + if ("superconcentric" %in% featureTypes) { + # For superconcentric super_scale_factors <- generate_scale_factors_all_outside(k) super_scaled_df <- super_scale_factors %>% map_dfr(~create_scaled_df_super(.x, df_circle, k)) - super_concentric <- super_scaled_df %>% + superconcentric <- super_scaled_df %>% select(x_section = x_scaled, y_section = y_scaled, segment_id, sample_id, area_id = concentric_id) # Modify the area_id column for each table - super_concentric <- super_concentric %>% mutate(area_id = sapply(area_id, modify_area_id)) + superconcentric <- superconcentric %>% mutate(area_id = sapply(area_id, modify_area_id)) } else { - super_concentric <- NULL + superconcentric <- NULL } featureData = sapply(featureTypes, get, simplify = FALSE, envir = environment()) return(featureData) - # return(list(sub_sector = sub_sector, sub_concentric = sub_concentric, super_sector = super_sector, super_concentric = super_concentric)) } #' Create sectors from a given data frame diff --git a/R/spatialFeatures.R b/R/spatialFeatures.R index dbd06e5..1c7dc20 100644 --- a/R/spatialFeatures.R +++ b/R/spatialFeatures.R @@ -15,10 +15,13 @@ #' the entropy values into a SummarizedExperiment object. #' #' @param me A MoleculeExperiment (ME) object -#' @param featureTypes a character vector listing the types of featureTypes to include +#' @param featureTypes A character string specifying the feature type. Supported values include +#' "subsector", "subconcentric", "supersector", and "superconcentric". #' @param k A numeric value indicating the number of polygons to calculate entropy (default 5) #' @param nCores number of cores for parallel processing (default 1) #' @param includeCounts logical (default FALSE) whether to include gene counts as features +#' @param concatenateFeatures logical whether to concatenate all the features +#' into a single assay (default FALSE). If FALSE the output SE object has multiple assays #' @param ... arguments passed to loadBoundaries and EntropyMatrix #' @return A SummarizedExperiment object containing a spatialFeatures assay and cell-level colData #' @export @@ -27,11 +30,12 @@ #' se <- spatialFeatures(me) #' se spatialFeatures <- function(me, - featureTypes = c("sub_sector", "sub_concentric", - "super_sector", "super_concentric"), + featureTypes = c("subsector", "subconcentric", + "supersector", "superconcentric"), k = 5, nCores = 1, includeCounts = FALSE, + concatenateFeatures = FALSE, ...) { # step 1 load new boundaries @@ -41,7 +45,7 @@ spatialFeatures <- function(me, ent = EntropyMatrix(me, nCores = nCores, featureTypes = featureTypes, ...) # step 3 create SummarizedExperiment - se = EntropySummarizedExperiment(ent, me, includeCounts = includeCounts, nCores = nCores) + se = EntropySummarizedExperiment(ent, me, includeCounts = includeCounts, concatenateFeatures = concatenateFeatures, nCores = nCores) return(se) } diff --git a/man/EntropyMatrix.Rd b/man/EntropyMatrix.Rd index f369c1d..a020805 100644 --- a/man/EntropyMatrix.Rd +++ b/man/EntropyMatrix.Rd @@ -10,7 +10,7 @@ EntropyMatrix(me, featureTypes, nCores = 1, ...) \item{me}{A Molecule Experiment object.} \item{featureTypes}{A character string specifying the feature type. Supported values include -"sub_sector", "sub_concentric", "super_sector", and "super_concentric".} +"subsector", "subconcentric", "supersector", and "superconcentric".} \item{nCores}{Number of cores} @@ -25,6 +25,6 @@ This function computes the entropy of a counts matrix from a Molecule Experiment \examples{ data(example_me) me <- loadBoundaries(me) -ent <- EntropyMatrix(me, c("sub_sector", "sub_concentric", "super_sector", "super_concentric"), nCores = 1) +ent <- EntropyMatrix(me, c("subsector", "subconcentric", "supersector", "superconcentric"), nCores = 1) lapply(ent, head, n = 4) } diff --git a/man/EntropySummarizedExperiment.Rd b/man/EntropySummarizedExperiment.Rd index 92c0d8d..4b505cd 100644 --- a/man/EntropySummarizedExperiment.Rd +++ b/man/EntropySummarizedExperiment.Rd @@ -4,7 +4,13 @@ \alias{EntropySummarizedExperiment} \title{Create a SummarizedExperiment Object from a List of Data Frames} \usage{ -EntropySummarizedExperiment(df_list, me, includeCounts = FALSE, nCores = 1) +EntropySummarizedExperiment( + df_list, + me, + includeCounts = FALSE, + concatenateFeatures = FALSE, + nCores = 1 +) } \arguments{ \item{df_list}{A list of data frames, each containing assay data.} @@ -13,6 +19,9 @@ EntropySummarizedExperiment(df_list, me, includeCounts = FALSE, nCores = 1) \item{includeCounts}{logical (default FALSE) whether to include gene counts as features} +\item{concatenateFeatures}{logical whether to concatenate all the features +into a single assay (default FALSE). If FALSE the output SE object has multiple assays} + \item{nCores}{Number of cores (default 1)} } \value{ @@ -25,7 +34,7 @@ constructs a SummarizedExperiment object with the specified data structure. \examples{ data(example_me) me <- loadBoundaries(me) -ent <- EntropyMatrix(me, c("sub_sector", "sub_concentric", "super_sector", "super_concentric"), nCores = 1) +ent <- EntropyMatrix(me, c("subsector", "subconcentric", "supersector", "superconcentric"), nCores = 1) se <- EntropySummarizedExperiment(ent, me) se } diff --git a/man/GenerateFeatureData.Rd b/man/GenerateFeatureData.Rd index 0d954a3..1754b1a 100644 --- a/man/GenerateFeatureData.Rd +++ b/man/GenerateFeatureData.Rd @@ -6,7 +6,7 @@ \usage{ GenerateFeatureData( me, - featureTypes = c("sub_sector", "sub_concentric", "super_sector", "super_concentric"), + featureTypes = c("subsector", "subconcentric", "supersector", "superconcentric"), k = 5 ) } @@ -22,11 +22,10 @@ Defaults to 5.} \value{ A list containing dataframes for each assay type: \itemize{ -\item \code{sub_sector}: Feature data for sub-sector polygons. -\item \code{sub_concentric}: Feature data for sub-concentric polygons. -\item \code{sub_combo}: Feature data for sub-combo polygons. -\item \code{super_concentric}: Feature data for super-concentric polygons. -\item \code{super_combo}: Feature data for super-combo polygons. +\item \code{subsector}: Feature data for sub-sector polygons. +\item \code{subconcentric}: Feature data for sub-concentric polygons. +\item \code{supersector}: Feature data for super-sector polygons. +\item \code{superconcentric}: Feature data for super-concentric polygons. } } \description{ diff --git a/man/make_assay_data.Rd b/man/make_assay_data.Rd index 71b13fa..ff46f31 100644 --- a/man/make_assay_data.Rd +++ b/man/make_assay_data.Rd @@ -4,13 +4,16 @@ \alias{make_assay_data} \title{make assay data} \usage{ -make_assay_data(df_list) +make_assay_data(df_list, concatenateFeatures = FALSE) } \arguments{ \item{df_list}{A list of data frames} + +\item{concatenateFeatures}{logical whether to concatenate features (default FALSE)} } \value{ -A single data frame +if concatenateFeatures == TRUE, A single data frame, otherwise a list +containing data frames } \description{ make assay data diff --git a/man/spatialFeatures.Rd b/man/spatialFeatures.Rd index 59ca87a..82379bc 100644 --- a/man/spatialFeatures.Rd +++ b/man/spatialFeatures.Rd @@ -6,17 +6,19 @@ \usage{ spatialFeatures( me, - featureTypes = c("sub_sector", "sub_concentric", "super_sector", "super_concentric"), + featureTypes = c("subsector", "subconcentric", "supersector", "superconcentric"), k = 5, nCores = 1, includeCounts = FALSE, + concatenateFeatures = FALSE, ... ) } \arguments{ \item{me}{A MoleculeExperiment (ME) object} -\item{featureTypes}{a character vector listing the types of featureTypes to include} +\item{featureTypes}{A character string specifying the feature type. Supported values include +"subsector", "subconcentric", "supersector", and "superconcentric".} \item{k}{A numeric value indicating the number of polygons to calculate entropy (default 5)} @@ -24,6 +26,9 @@ spatialFeatures( \item{includeCounts}{logical (default FALSE) whether to include gene counts as features} +\item{concatenateFeatures}{logical whether to concatenate all the features +into a single assay (default FALSE). If FALSE the output SE object has multiple assays} + \item{...}{arguments passed to loadBoundaries and EntropyMatrix} } \value{ diff --git a/vignettes/SpatialFeatures.Rmd b/vignettes/SpatialFeatures.Rmd index 285a435..5d18c29 100644 --- a/vignettes/SpatialFeatures.Rmd +++ b/vignettes/SpatialFeatures.Rmd @@ -80,7 +80,7 @@ ggplot_me() + # add molecule points and colour by feature name geom_point_me(me, byColour = "feature_id", size = 0.1) + # add nuclei segments and colour the border with red - geom_polygon_me(me, assayName = "sub_sector", fill = NA, colour = "red") + + geom_polygon_me(me, assayName = "subsector", fill = NA, colour = "red") + # add cell segments and colour by cell id geom_polygon_me(me, byFill = "segment_id", colour = "black", alpha = 0.1) + # zoom in to selected patch area @@ -90,7 +90,7 @@ ggplot_me() + # add molecule points and colour by feature name geom_point_me(me, byColour = "feature_id", size = 0.1) + # add nuclei segments and colour the border with red - geom_polygon_me(me, assayName = "sub_concentric", fill = NA, colour = "red") + + geom_polygon_me(me, assayName = "subconcentric", fill = NA, colour = "red") + # add cell segments and colour by cell id geom_polygon_me(me, byFill = "segment_id", colour = "black", alpha = 0.1) + # zoom in to selected patch area @@ -100,7 +100,7 @@ ggplot_me() + # add molecule points and colour by feature name geom_point_me(me, byColour = "feature_id", size = 0.1) + # add nuclei segments and colour the border with red - geom_polygon_me(me, assayName = "super_sector", fill = NA, colour = "blue") + + geom_polygon_me(me, assayName = "supersector", fill = NA, colour = "blue") + # add cell segments and colour by cell id geom_polygon_me(me, byFill = "segment_id", colour = "black", alpha = 0.1) + # zoom in to selected patch area @@ -110,7 +110,7 @@ ggplot_me() + # add molecule points and colour by feature name geom_point_me(me, byColour = "feature_id", size = 0.1) + # add nuclei segments and colour the border with red - geom_polygon_me(me, assayName = "super_concentric", fill = NA, colour = "blue") + + geom_polygon_me(me, assayName = "superconcentric", fill = NA, colour = "blue") + # add cell segments and colour by cell id geom_polygon_me(me, byFill = "segment_id", colour = "black", alpha = 0.1) + # zoom in to selected patch area @@ -121,7 +121,7 @@ ggplot_me() + This function `EntropyMatrix()` computes the entropy of a counts matrix from a `MoleculeExperiment` object based on the given assay type. ```{r} -ent = SpatialFeatures::EntropyMatrix(me, c("sub_sector", "sub_concentric", "super_sector", "super_concentric"), nCores = 1) +ent = SpatialFeatures::EntropyMatrix(me, c("subsector", "subconcentric", "supersector", "superconcentric"), nCores = 1) lapply(ent, head, n = 4) ```