diff --git a/api/r/CellCensus/DESCRIPTION b/api/r/CellCensus/DESCRIPTION index 2591593cb..4473e0604 100644 --- a/api/r/CellCensus/DESCRIPTION +++ b/api/r/CellCensus/DESCRIPTION @@ -23,7 +23,8 @@ Imports: stats, tiledbsoma, tiledb -Suggests: +Suggests: + bit64, knitr, rmarkdown, testthat (>= 3.0.0), diff --git a/api/r/CellCensus/NAMESPACE b/api/r/CellCensus/NAMESPACE index c266b2d32..803d4ee44 100644 --- a/api/r/CellCensus/NAMESPACE +++ b/api/r/CellCensus/NAMESPACE @@ -4,6 +4,7 @@ export(download_source_h5ad) export(get_census_version_description) export(get_census_version_directory) export(get_presence_matrix) +export(get_seurat) export(get_source_h5ad_uri) export(open_soma) importFrom(aws.s3,save_object) @@ -13,4 +14,5 @@ importFrom(jsonlite,fromJSON) importFrom(methods,is) importFrom(stats,setNames) importFrom(tiledbsoma,SOMACollection) +importFrom(tiledbsoma,SOMAExperimentAxisQuery) importFrom(tiledbsoma,SOMATileDBContext) diff --git a/api/r/CellCensus/R/get_helpers.R b/api/r/CellCensus/R/get_helpers.R index b0e86b738..225fda2ff 100644 --- a/api/r/CellCensus/R/get_helpers.R +++ b/api/r/CellCensus/R/get_helpers.R @@ -1,6 +1,6 @@ #' Read the feature dataset presence matrix. #' -#' @param census The census SOMACollection from which to read the presence matrix. +#' @param census The census object, usually returned by `CellCensus::open_soma()`. #' @param organism The organism to query, usually one of `Homo sapiens` or `Mus musculus` #' @param measurement_name The measurement object to query. Defaults to `RNA`. #' @@ -15,6 +15,46 @@ get_presence_matrix <- function(census, organism, measurement_name = "RNA") { return(presence$read_sparse_matrix()) } +#' Convenience wrapper around `SOMAExperimentAxisQuery`, to build and execute a +#' query, and return it as a `Seurat` object. +#' +#' @param census The census object, usually returned by `CellCensus::open_soma()`. +#' @param organism The organism to query, usually one of `Homo sapiens` or `Mus musculus` +#' @param measurement_name The measurement object to query. Defaults to `RNA`. +#' @param X_name The `X` layer to query. Defaults to `raw`. +#' @param obs_query A `SOMAAxisQuery` for the `obs` axis. +#' @param obs_column_names Columns to fetch for the `obs` data frame. +#' @param var_query A `SOMAAxisQuery` for the `var` axis. +#' @param var_column_names Columns to fetch for the `var` data frame. +#' +#' @return A `Seurat` object containing the sensus slice. +#' @importFrom tiledbsoma SOMAExperimentAxisQuery +#' @export +#' +#' @examples +get_seurat <- function( + census, + organism, + measurement_name = "RNA", + X_name = "raw", + obs_query = NULL, + obs_column_names = NULL, + var_query = NULL, + var_column_names = NULL) { + expt_query <- tiledbsoma::SOMAExperimentAxisQuery$new( + get_experiment(census, organism), + measurement_name, + obs_query = obs_query, + var_query = var_query + ) + return(expt_query$to_seurat( + # TODO: should we allow selection of the seurat 'counts' or 'data' slot? + c(counts = X_name), + obs_column_names = obs_column_names, + var_column_names = var_column_names + )) +} + #' Get the SOMAExperiment for a named organism #' #' @param census The census SOMACollection. diff --git a/api/r/CellCensus/man/get_presence_matrix.Rd b/api/r/CellCensus/man/get_presence_matrix.Rd index d9bfef229..c7cae581d 100644 --- a/api/r/CellCensus/man/get_presence_matrix.Rd +++ b/api/r/CellCensus/man/get_presence_matrix.Rd @@ -7,7 +7,7 @@ get_presence_matrix(census, organism, measurement_name = "RNA") } \arguments{ -\item{census}{The census SOMACollection from which to read the presence matrix.} +\item{census}{The census object, usually returned by \code{CellCensus::open_soma()}.} \item{organism}{The organism to query, usually one of \verb{Homo sapiens} or \verb{Mus musculus}} diff --git a/api/r/CellCensus/man/get_seurat.Rd b/api/r/CellCensus/man/get_seurat.Rd new file mode 100644 index 000000000..a1d851aac --- /dev/null +++ b/api/r/CellCensus/man/get_seurat.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/get_helpers.R +\name{get_seurat} +\alias{get_seurat} +\title{Convenience wrapper around \code{SOMAExperimentAxisQuery}, to build and execute a +query, and return it as a \code{Seurat} object.} +\usage{ +get_seurat( + census, + organism, + measurement_name = "RNA", + X_name = "raw", + obs_query = NULL, + obs_column_names = NULL, + var_query = NULL, + var_column_names = NULL +) +} +\arguments{ +\item{census}{The census object, usually returned by \code{CellCensus::open_soma()}.} + +\item{organism}{The organism to query, usually one of \verb{Homo sapiens} or \verb{Mus musculus}} + +\item{measurement_name}{The measurement object to query. Defaults to \code{RNA}.} + +\item{X_name}{The \code{X} layer to query. Defaults to \code{raw}.} + +\item{obs_query}{A \code{SOMAAxisQuery} for the \code{obs} axis.} + +\item{obs_column_names}{Columns to fetch for the \code{obs} data frame.} + +\item{var_query}{A \code{SOMAAxisQuery} for the \code{var} axis.} + +\item{var_column_names}{Columns to fetch for the \code{var} data frame.} +} +\value{ +A \code{Seurat} object containing the sensus slice. +} +\description{ +Convenience wrapper around \code{SOMAExperimentAxisQuery}, to build and execute a +query, and return it as a \code{Seurat} object. +} diff --git a/api/r/CellCensus/tests/testthat/test-get_helpers.R b/api/r/CellCensus/tests/testthat/test-get_helpers.R index 0d9fe3d13..99ab20f2d 100644 --- a/api/r/CellCensus/tests/testthat/test-get_helpers.R +++ b/api/r/CellCensus/tests/testthat/test-get_helpers.R @@ -31,3 +31,72 @@ test_that("get_presence_matrix", { expect_equal(max(pm), 1) } }) + +test_that("get_seurat", { + seurat <- get_seurat( + open_soma(), + "Mus musculus", + obs_query = tiledbsoma::SOMAAxisQuery$new(value_filter = "tissue_general == 'vasculature'"), + obs_column_names = c("soma_joinid", "cell_type", "tissue", "tissue_general", "assay"), + var_query = tiledbsoma::SOMAAxisQuery$new(value_filter = "feature_name %in% c('Gm53058', '0610010K14Rik')"), + var_column_names = c("soma_joinid", "feature_id", "feature_name", "feature_length") + ) + + expect_s4_class(seurat, "Seurat") + seurat_assay <- seurat[["RNA"]] + expect_s4_class(seurat_assay, "Assay") + expect_equal(nrow(seurat_assay), 2) + expect_gt(ncol(seurat_assay), 0) + expect_setequal(seurat_assay[[]][, "feature_name"], c("0610010K14Rik", "Gm53058")) + expect_equal(sum(seurat[[]][, "tissue_general"] == "vasculature"), ncol(seurat_assay)) +}) + +test_that("get_seurat coords", { + seurat <- get_seurat( + open_soma(), + "Mus musculus", + obs_query = tiledbsoma::SOMAAxisQuery$new( + coords = list(soma_joinid = bit64::as.integer64(0:1000)) + ), + var_query = tiledbsoma::SOMAAxisQuery$new( + coords = list(soma_joinid = bit64::as.integer64(0:2000)) + ) + ) + expect_equal(nrow(seurat[[]]), 1001) # obs dataframe + seurat_assay <- seurat[["RNA"]] + expect_equal(nrow(seurat_assay[[]]), 2001) # var dataframe + # NOTE: seurat assay matrix is var x obs, not obs x var + expect_equal(nrow(seurat_assay), 2001) + expect_equal(ncol(seurat_assay), 1001) +}) + +test_that("get_seurat allows missing obs or var filter", { + census <- open_soma() + + obs_query <- tiledbsoma::SOMAAxisQuery$new( + value_filter = "tissue == 'aorta'" + ) + seurat <- get_seurat(census, "Mus musculus", + obs_query = obs_query, + obs_column_names = c("soma_joinid"), + var_column_names = c("soma_joinid") + ) + control_query <- tiledbsoma::SOMAExperimentAxisQuery$new( + get_experiment(census, "Mus musculus"), + "RNA", + obs_query = obs_query + ) + expect_equal(ncol(seurat[["RNA"]]), control_query$n_obs) + expect_equal(nrow(seurat[["RNA"]]), control_query$n_vars) + + seurat <- get_seurat(census, "Mus musculus", + obs_query = tiledbsoma::SOMAAxisQuery$new( + coords = list(soma_joinid = bit64::as.integer64(0:10000)) + ), + var_query = tiledbsoma::SOMAAxisQuery$new( + value_filter = "feature_id == 'ENSMUSG00000069581'" + ) + ) + expect_equal(ncol(seurat[["RNA"]]), 10001) + expect_equal(nrow(seurat[["RNA"]]), 1) +})