From f2424cd0ab6bcce114ebe3eb05b6fc793eb8ac94 Mon Sep 17 00:00:00 2001 From: Eric Siegel Date: Sun, 3 Dec 2023 03:36:56 -0800 Subject: [PATCH 1/3] Add support for assays stored as SeuratObject::Assay5 --- DESCRIPTION | 3 ++- NAMESPACE | 2 ++ R/err.R | 3 ++- R/lib.R | 3 ++- R/util.R | 23 ++++++++++++++++++++++- README.md | 5 ++++- man/counts_matrix_from_assay.Rd | 17 +++++++++++++++++ tests/testthat/test-util.R | 24 +++++++++++++++++++----- 8 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 man/counts_matrix_from_assay.Rd diff --git a/DESCRIPTION b/DESCRIPTION index a1f603d..547aee1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -14,7 +14,8 @@ Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 Suggests: testthat (>= 3.0.0), - Matrix + Matrix, + SeuratObject Config/testthat/edition: 3 Imports: methods, diff --git a/NAMESPACE b/NAMESPACE index 12bc2ec..3f1760a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +export(counts_matrix_from_assay) export(create_bugreport) export(create_bugreport_from_seurat) export(create_loupe) @@ -18,6 +19,7 @@ importFrom(Seurat,Idents) importFrom(Seurat,Reductions) importFrom(hdf5r,H5File) importFrom(hdf5r,H5T_STRING) +importFrom(methods,as) importFrom(methods,is) importFrom(utils,download.file) importFrom(utils,packageVersion) diff --git a/R/err.R b/R/err.R index dd9b50f..5735b55 100644 --- a/R/err.R +++ b/R/err.R @@ -60,9 +60,10 @@ create_bugreport_from_seurat <- function(obj) { assay <- namedAssay[[1]] clusters <- select_clusters(obj) projections <- select_projections(obj) + counts <- counts_matrix_from_assay(assay) create_bugreport( - assay@counts, + counts, clusters, projections, assay_name = assay_name, diff --git a/R/lib.R b/R/lib.R index 6c92fcf..d7645a1 100644 --- a/R/lib.R +++ b/R/lib.R @@ -44,6 +44,7 @@ create_loupe_from_seurat <- function( assay_name <- names(namedAssay) assay <- namedAssay[[1]] + counts <- counts_matrix_from_assay(assay) clusters <- select_clusters(obj, dedup=dedup_clusters) projections <- select_projections(obj) @@ -58,7 +59,7 @@ create_loupe_from_seurat <- function( } success <- create_loupe( - assay@counts, + counts, clusters=clusters, projections=projections, output_dir=output_dir, diff --git a/R/util.R b/R/util.R index 343c93d..fd057ed 100644 --- a/R/util.R +++ b/R/util.R @@ -56,8 +56,9 @@ select_assay <- function(obj) { for (i in seq_along(assay_priority)) { name <- names(assay_priority[i]) assay <- Seurat::GetAssay(obj, assay=name) + counts <- counts_matrix_from_assay(assay) - if (length(assay@counts) > 0) { + if (length(counts) > 0) { result = list() result[[name]] = assay return(result) @@ -67,6 +68,26 @@ select_assay <- function(obj) { NULL } +#' Extract the counts matrix from the Assay +#' +#' @param assay A SeuratObject::Assay or SeuratObject::Assay5 +#' +#' @return A sparse counts matrix + +#' @importFrom methods as +#' +#' @export +counts_matrix_from_assay <- function(assay) { + # convert to older format so that we can consistently access the counts matrix + # Seurat::Assay5 was introduced with Seurat-5.0 and stores the data completely differently + # within the `layers` slot. + if (is(assay, "Assay5")) { + assay <- suppressWarnings(methods::as(object = assay, Class = 'Assay')) + } + + assay@counts +} + #' Select clusters from the assay #' #' @param obj A Seurat Object diff --git a/README.md b/README.md index c99fefa..d901987 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,12 @@ library("loupeR") # Gene Expression RNA assay assay <- seurat_obj[["RNA"]] +# get counts matrix from either the old or newer formats of assay +counts <- counts_matrix_from_assay(assay) + # convert the count matrix, clusters, and projections into a Loupe file create_loupe( - assay@counts, + counts, clusters = select_clusters(seurat_obj), projections = select_projections(seurat_obj) ) diff --git a/man/counts_matrix_from_assay.Rd b/man/counts_matrix_from_assay.Rd new file mode 100644 index 0000000..09d4c76 --- /dev/null +++ b/man/counts_matrix_from_assay.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/util.R +\name{counts_matrix_from_assay} +\alias{counts_matrix_from_assay} +\title{Extract the counts matrix from the Assay} +\usage{ +counts_matrix_from_assay(assay) +} +\arguments{ +\item{assay}{A SeuratObject::Assay or SeuratObject::Assay5} +} +\value{ +A sparse counts matrix +} +\description{ +Extract the counts matrix from the Assay +} diff --git a/tests/testthat/test-util.R b/tests/testthat/test-util.R index 7d72acd..0ba587f 100644 --- a/tests/testthat/test-util.R +++ b/tests/testthat/test-util.R @@ -4,15 +4,29 @@ test_that("select_assay selects active assay", { rna3 <- create_count_mat(5, 5) obj <- Seurat::CreateSeuratObject(rna1, assay="rna1") - obj[["rna2_"]] = Seurat::CreateAssayObject(rna2, key="rna2_") - obj[["rna3_"]] = Seurat::CreateAssayObject(rna3, key="rna3_") + obj[["rna2"]] = Seurat::CreateAssayObject(rna2, key="rna2_") + obj[["rna3"]] = Seurat::CreateAssayObject(rna3, key="rna3_") expect_equal(Seurat::DefaultAssay(object = obj), "rna1") - Seurat::DefaultAssay(object = obj) <- "rna2_" - expect_equal(Seurat::DefaultAssay(object = obj), "rna2_") + Seurat::DefaultAssay(object = obj) <- "rna2" + expect_equal(Seurat::DefaultAssay(object = obj), "rna2") assay <- select_assay(obj) - expect_equal(names(assay), "rna2_") + expect_equal(names(assay), "rna2") +}) + +test_that("counts_matrix_from_assay works on different assay version", { + rna1 <- create_count_mat(5, 5) + rna2 <- create_count_mat(5, 5) + rna3 <- create_count_mat(5, 5) + + obj <- Seurat::CreateSeuratObject(rna1, assay="rna1") + obj[["rna2"]] = Seurat::CreateAssayObject(rna2, key="rna2_") + obj[["rna3"]] = SeuratObject::CreateAssay5Object(rna3, key="rna3_") + + expect_equal(counts_matrix_from_assay(obj[["rna1"]]), rna1) + expect_equal(counts_matrix_from_assay(obj[["rna2"]]), rna2) + expect_equal(counts_matrix_from_assay(obj[["rna3"]]), rna3) }) test_that("select_clusters selects Idents", { From d367b886fdb6b6ff6fad2885ec05a87a9ae5c018 Mon Sep 17 00:00:00 2001 From: Eric Siegel Date: Sun, 3 Dec 2023 04:58:29 -0800 Subject: [PATCH 2/3] converting large assays was too slow --- DESCRIPTION | 4 ++-- NAMESPACE | 2 +- R/util.R | 17 +++++++---------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 547aee1..c46ce40 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -15,9 +15,9 @@ RoxygenNote: 7.2.3 Suggests: testthat (>= 3.0.0), Matrix, - SeuratObject Config/testthat/edition: 3 Imports: methods, - Seurat, + Seurat (>= 5.0.0), + SeuratObject (>= 5.0.0), hdf5r diff --git a/NAMESPACE b/NAMESPACE index 3f1760a..5f4163d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -17,9 +17,9 @@ importFrom(Seurat,Assays) importFrom(Seurat,GetAssay) importFrom(Seurat,Idents) importFrom(Seurat,Reductions) +importFrom(SeuratObject,LayerData) importFrom(hdf5r,H5File) importFrom(hdf5r,H5T_STRING) -importFrom(methods,as) importFrom(methods,is) importFrom(utils,download.file) importFrom(utils,packageVersion) diff --git a/R/util.R b/R/util.R index fd057ed..2400464 100644 --- a/R/util.R +++ b/R/util.R @@ -73,19 +73,16 @@ select_assay <- function(obj) { #' @param assay A SeuratObject::Assay or SeuratObject::Assay5 #' #' @return A sparse counts matrix - -#' @importFrom methods as +#' +#' @importFrom SeuratObject LayerData #' #' @export counts_matrix_from_assay <- function(assay) { - # convert to older format so that we can consistently access the counts matrix - # Seurat::Assay5 was introduced with Seurat-5.0 and stores the data completely differently - # within the `layers` slot. - if (is(assay, "Assay5")) { - assay <- suppressWarnings(methods::as(object = assay, Class = 'Assay')) - } - - assay@counts + # Support both Assay and Assay5 classes + # The same as using the helper `assay$counts` but less indirection. + # With Assay5 it is important to use this method as oppossed to grabbing + # the data from `assay@layers` directly as that matrix won't contain the dimnames + SeuratObject::LayerData(assay, "counts") } #' Select clusters from the assay From fbdb3dcd9e481447be1ee7dd33ac7457ea05c89c Mon Sep 17 00:00:00 2001 From: Eric Siegel Date: Tue, 5 Dec 2023 09:29:51 -0800 Subject: [PATCH 3/3] remove strict dependency on seurat 5 --- DESCRIPTION | 4 ++-- NAMESPACE | 1 - R/util.R | 16 +++++++++------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index c46ce40..07c15b6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -15,9 +15,9 @@ RoxygenNote: 7.2.3 Suggests: testthat (>= 3.0.0), Matrix, + SeuratObject (>= 5.0.0) Config/testthat/edition: 3 Imports: methods, - Seurat (>= 5.0.0), - SeuratObject (>= 5.0.0), + Seurat, hdf5r diff --git a/NAMESPACE b/NAMESPACE index 5f4163d..f91a3b1 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -17,7 +17,6 @@ importFrom(Seurat,Assays) importFrom(Seurat,GetAssay) importFrom(Seurat,Idents) importFrom(Seurat,Reductions) -importFrom(SeuratObject,LayerData) importFrom(hdf5r,H5File) importFrom(hdf5r,H5T_STRING) importFrom(methods,is) diff --git a/R/util.R b/R/util.R index 2400464..26c223d 100644 --- a/R/util.R +++ b/R/util.R @@ -74,15 +74,17 @@ select_assay <- function(obj) { #' #' @return A sparse counts matrix #' -#' @importFrom SeuratObject LayerData -#' #' @export counts_matrix_from_assay <- function(assay) { - # Support both Assay and Assay5 classes - # The same as using the helper `assay$counts` but less indirection. - # With Assay5 it is important to use this method as oppossed to grabbing - # the data from `assay@layers` directly as that matrix won't contain the dimnames - SeuratObject::LayerData(assay, "counts") + if (packageVersion("Seurat") >= 5) { + return(assay$counts) + } else { + if (is(assay, 'Assay5')) { + stop("Cannot get count matrix: Please upgrade to Seurat > 5 to support dataset") + } + + return(assay@counts) + } } #' Select clusters from the assay