Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: SpatialData
Title: Representation of Python's SpatialData in R
Depends: R (>= 4.6)
Version: 0.99.36
Version: 0.99.37
Description: R interface to Python/scverse's 'spatialdata' framework for
unified spatial omics data handling. Adheres to OME-NGFF standards,
providing lazy, on-disk representations for multiscale images and
Expand Down
4 changes: 3 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ exportMethods(tables)
exportMethods(transform)
exportMethods(translation)
import(geoarrow)
importClassesFrom(S4Vectors,DFrame)
importFrom(BiocGenerics,as.data.frame)
importFrom(BiocGenerics,colnames)
importFrom(BiocGenerics,combine)
Expand All @@ -136,6 +135,7 @@ importFrom(S4Vectors,isSequence)
importFrom(S4Vectors,make_zero_col_DFrame)
importFrom(S4Vectors,metadata)
importFrom(S4Vectors,setValidity2)
importFrom(S4Vectors,transform)
importFrom(SingleCellExperiment,"int_colData<-")
importFrom(SingleCellExperiment,"int_metadata<-")
importFrom(SingleCellExperiment,SingleCellExperiment)
Expand Down Expand Up @@ -188,8 +188,10 @@ importFrom(methods,as)
importFrom(methods,callNextMethod)
importFrom(methods,is)
importFrom(methods,new)
importFrom(methods,setClass)
importFrom(methods,setClassUnion)
importFrom(methods,setMethod)
importFrom(methods,setOldClass)
importFrom(methods,setReplaceMethod)
importFrom(rlang,"!!")
importFrom(rlang,.data)
Expand Down
73 changes: 23 additions & 50 deletions R/AllClasses.R
Original file line number Diff line number Diff line change
@@ -1,53 +1,7 @@
.SpatialDataAttrs <- setClass(
Class="SpatialDataAttrs",
contains="list")
#' @importFrom methods setClass setClassUnion setOldClass

.SpatialDataImage <- setClass(
Class="SpatialDataImage",
contains=c("Annotated"),
slots=list(data="list", meta="SpatialDataAttrs"))

.SpatialDataLabel <- setClass(
Class="SpatialDataLabel",
contains=c("Annotated"),
slots=list(data="list", meta="SpatialDataAttrs"))

# these are 'R6ClassGenerator's;
# this somehow does the trick...
setClass("FileSystemDataset", "VIRTUAL")
setClass("arrow_dplyr_query", "VIRTUAL")
setClass("tbl_duckdb_connection", "VIRTUAL")
setClass("duckspatial_df", "VIRTUAL")
setClass("Table", "VIRTUAL")

# TODO: this isn't great... arrow::open_dataset gives a FileSystemDataset,
# read_parquet gives a Table, dplyr calls give a query, but also wanna
# be able to store a normal data.frame, maybe?
#' @importFrom methods setClassUnion
setClassUnion(
"arrow_OR_df",
c("tbl_duckdb_connection", "duckspatial_df", "FileSystemDataset", "Table", "arrow_dplyr_query", "data.frame"))

.SpatialDataPoint <- setClass(
Class="SpatialDataPoint",
contains=c("Annotated"),
slots=list(data="arrow_OR_df", meta="SpatialDataAttrs"))

#' @importClassesFrom S4Vectors DFrame
.SpatialDataShape <- setClass(
Class="SpatialDataShape",
contains=c("Annotated"),
slots=list(data="arrow_OR_df", meta="SpatialDataAttrs"))

setClassUnion("SpatialDataArray", c("SpatialDataImage", "SpatialDataLabel"))
setClassUnion("SpatialDataFrame", c("SpatialDataPoint", "SpatialDataShape"))

setClassUnion("SpatialDataElement", c(
"SpatialDataImage", "SpatialDataLabel",
"SpatialDataPoint", "SpatialDataShape"))

#' @rdname SpatialData
#' @export
#' @rdname SpatialData
.SpatialData <- setClass(
Class="SpatialData",
contains=c("list", "Annotated"),
Expand All @@ -58,5 +12,24 @@ setClassUnion("SpatialDataElement", c(
shapes="list", # 'SpatialDataShape's
tables="list")) # 'SingleCellExperiment's

. <- c("images", "labels", "points", "shapes", "tables")
names(.LAYERS) <- .LAYERS <- .
.LAYERS <- `names<-`(. <- c("images","labels","points","shapes","tables"), .)
.SpatialDataAttrs <- setClass("SpatialDataAttrs", contains="list")
setOldClass("duckspatial_df")

setClass("SpatialDataArray",
contains=c("Annotated", "VIRTUAL"),
slots=list(data="list", meta="SpatialDataAttrs"))

setClass("SpatialDataFrame",
contains=c("Annotated", "VIRTUAL"),
slots=list(data="duckspatial_df", meta="SpatialDataAttrs"))

.SpatialDataImage <- setClass("SpatialDataImage", contains="SpatialDataArray")
.SpatialDataLabel <- setClass("SpatialDataLabel", contains="SpatialDataArray")

.SpatialDataPoint <- setClass("SpatialDataPoint", contains="SpatialDataFrame")
.SpatialDataShape <- setClass("SpatialDataShape", contains="SpatialDataFrame")

setClassUnion("SpatialDataElement", c(
"SpatialDataImage", "SpatialDataLabel",
"SpatialDataPoint", "SpatialDataShape"))
5 changes: 1 addition & 4 deletions R/AllGenerics.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ setGeneric("image", \(x, ...) standardGeneric("image"))
setGeneric("label", \(x, ...) standardGeneric("label"))
setGeneric("shape", \(x, ...) standardGeneric("shape"))
setGeneric("point", \(x, ...) standardGeneric("point"))
#setGeneric("table", \(x, ...) standardGeneric("table"))
#' @importFrom BiocGenerics table

# get all ----

setGeneric("images", \(x, ...) standardGeneric("images"))
setGeneric("labels", \(x, ...) standardGeneric("labels"))
setGeneric("labels", \(object, ...) standardGeneric("labels"))
setGeneric("shapes", \(x, ...) standardGeneric("shapes"))
setGeneric("points", \(x, ...) standardGeneric("points"))
setGeneric("tables", \(x, ...) standardGeneric("tables"))
Expand Down Expand Up @@ -63,7 +61,6 @@ setGeneric("addCT", \(x, ...) standardGeneric("addCT"))
setGeneric("scale", \(x, t, ...) standardGeneric("scale"))
setGeneric("rotate", \(x, t, ...) standardGeneric("rotate"))
setGeneric("sequence", \(x, t, ...) standardGeneric("sequence"))
setGeneric("transform", \(x, i, ...) standardGeneric("transform"))
setGeneric("translation", \(x, t, ...) standardGeneric("translation"))

setGeneric("flip", \(x, ...) standardGeneric("flip"))
Expand Down
2 changes: 1 addition & 1 deletion R/SpatialData.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#' @param points list of \code{\link{SpatialDataPoint}}s
#' @param shapes list of \code{\link{SpatialDataShape}}s
#' @param tables list of \code{SingleCellExperiment}s
#' @param x \code{SpatialData}
#' @param x,object \code{SpatialData} object.
#' @param i,j character string, scalar or vector of indices
#' specifying the element to extract from a given layer.
#' @param drop ignored.
Expand Down
20 changes: 14 additions & 6 deletions R/mask.R
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ setMethod("mask", c("SpatialData", "ANY", "ANY"), \(x, i, j, k,
.i <- transform(.i, ct[k])
.j <- transform(.j, ct[k])
t <- tryCatch(error=\(.) NULL, getTable(x, i))
se <- .mask(.i, .j, how=how, table=t, ...)
se <- mask_i_by_j(.i, .j, how=how, table=t, ...)
ik <- if (is.null(t)) "instance" else instance_key(t)
md <- list(region=j, region_key="region", instance_key=ik)
int_metadata(se)$spatialdata_attrs <- md
Expand All @@ -81,14 +81,18 @@ setMethod("mask", c("SpatialData", "ANY", "ANY"), \(x, i, j, k,
`table<-`(x, nm, value=se)
})

setGeneric(".mask", \(i, j, ...) standardGeneric(".mask"))
# internal use only!
#' @noRd
setGeneric("mask_i_by_j", \(i, j, ...) standardGeneric("mask_i_by_j"))

#' @noRd
#' @importFrom methods as
#' @importFrom Matrix sparseVector
#' @importFrom SummarizedExperiment assayNames<-
#' @importFrom SingleCellExperiment SingleCellExperiment
setMethod(".mask", c("SpatialDataImage", "SpatialDataLabel"), \(i, j, how=NULL, ...) {
setMethod("mask_i_by_j",
c("SpatialDataImage", "SpatialDataLabel"),
\(i, j, how=NULL, ...) {
.wh <- \(.) {
ds <- dim(.); if (length(ds) == 3) ds <- ds[-1]
metadata(.)$wh %||% list(c(0, ds[2]), c(0, ds[1]))
Expand Down Expand Up @@ -129,7 +133,9 @@ setMethod(".mask", c("SpatialDataImage", "SpatialDataLabel"), \(i, j, how=NULL,
#' @importFrom SparseArray colSums
#' @importFrom SingleCellExperiment SingleCellExperiment
#' @importFrom dplyr mutate left_join coalesce join_by select count collect row_number
setMethod(".mask", c("SpatialDataPoint", "SpatialDataShape"), \(i, j, how=NULL, ...) {
setMethod("mask_i_by_j",
c("SpatialDataPoint", "SpatialDataShape"),
\(i, j, how=NULL, ...) {
if (!is.null(how)) message("Can only count when masking points; ignoring 'how'")
id_x <- id_y <- n <- NULL # R CMD check
ij <- .mask_map(i, j)
Expand Down Expand Up @@ -162,7 +168,9 @@ setMethod(".mask", c("SpatialDataPoint", "SpatialDataShape"), \(i, j, how=NULL,
#' @importFrom SummarizedExperiment assay
#' @importFrom duckspatial ddbs_intersects
#' @importFrom SingleCellExperiment SingleCellExperiment
setMethod(".mask", c("SpatialDataShape", "SpatialDataShape"), \(i, j, how=NULL, table=NULL, assay=1, ...) {
setMethod("mask_i_by_j",
c("SpatialDataShape", "SpatialDataShape"),
\(i, j, how=NULL, table=NULL, assay=1, ...) {
# validity
if (is.null(table)) stop("Missing 'table'; can't mask shapes without")
if (is.null(how)) { how <- "sum"; message("Missing 'how'; defaulting to 'sum'") }
Expand Down Expand Up @@ -201,5 +209,5 @@ setMethod(".mask", c("SpatialDataShape", "SpatialDataShape"), \(i, j, how=NULL,
})

#' @noRd
setMethod(".mask", c("ANY", "ANY"), \(i, j, ...)
setMethod("mask_i_by_j", c("ANY", "ANY"), \(i, j, ...)
stop("'mask'ing between these element types not supported"))
38 changes: 20 additions & 18 deletions R/methods.R
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@ setReplaceMethod("meta", c("SpatialDataElement", "list"),
names(j) <- rownames(x)[ne > 0]
for (. in names(j)) {
.j <- j[[.]]
n <- length(attr(x, .))
n <- length(x[[.]])
if (is.character(.j)) {
if (!all(.j %in% names(attr(x, .))))
if (!all(.j %in% names(x[[.]])))
stop("invalid 'j'")
} else if (length(.j) == 1 && is.infinite(.j)) {
.j <- n
} else if (any(.j > n)) {
stop("invalid 'j'")
}
attr(x, .) <- attr(x, .)[.j]
x[[.]] <- x[[.]][.j]
}
x
}
Expand Down Expand Up @@ -133,17 +133,20 @@ setMethod("colnames", "SpatialData", \(x) {

# layer ----

.invalid_i <- paste(
"invalid 'i'; should be a string or scalar integer",
"specifying the name or position of an element in 'x'")

#' @rdname SpatialData
#' @export
setMethod("layer", c("SpatialData", "character"), \(x, i) {
stopifnot(i %in% unlist(colnames(x)), length(i) == 1)
match.arg(i, unlist(colnames(x)))
names(Filter(\(.) i %in% ., colnames(x)))
})

#' @rdname SpatialData
#' @export
setMethod("layer", c("SpatialData", "ANY"), \(x, i)
stop("invalid 'i'; should be a string specifying an element in 'x'"))
setMethod("layer", c("SpatialData", "ANY"), \(x, i) stop(.invalid_i))

# element ----

Expand All @@ -163,8 +166,7 @@ setMethod("element", c("SpatialData", "missing"), \(x, i) element(x, 1))

#' @rdname SpatialData
#' @export
setMethod("element", c("SpatialData", "ANY"), \(x, i)
stop("invalid 'i'; should be a string specifying an element in 'x'"))
setMethod("element", c("SpatialData", "ANY"), \(x, i) stop(.invalid_i))

#' @rdname SpatialData
#' @export
Expand All @@ -180,7 +182,7 @@ setMethod("images", "SpatialData", \(x) x$images)

#' @export
#' @rdname SpatialData
setMethod("labels", "SpatialData", \(x) x$labels)
setMethod("labels", "SpatialData", \(object) object$labels)

#' @export
#' @rdname SpatialData
Expand All @@ -196,8 +198,7 @@ setMethod("tables", "SpatialData", \(x) x$tables)

# get nms ----

one <- c("image", "label", "point", "shape", "table")
all <- paste0(one, "s")
all <- paste0(one <- c("image", "label", "point", "shape", "table"), "s")

#' @name SpatialData
#' @exportMethod imageNames labelNames pointNames shapeNames tableNames
Expand Down Expand Up @@ -248,16 +249,17 @@ NULL
y[[i]]
}

#' @name SpatialData
#' @export
#' @name SpatialData
#' @importFrom BiocGenerics table
setMethod("table", "ANY", \(...) {
l <- list(...)
if (!is(l[[1]], "SpatialData"))
if (!is(l[[1]], "SpatialData"))
return(base::table(...))
n <- length(l)
i <- if (n == 1) 1 else l[[2]]
m <- length(i)
if (any(c(n, m) > 2))
if (n > 2 || m > 1)
stop("too many arguments")
y <- l[[1]]$tables
.get(y, i)
Expand Down Expand Up @@ -321,17 +323,17 @@ for (. in all) eval(f(.), parent.env(environment()))

# set one ----

#' @name SpatialData
#' @exportMethod image<- label<- point<- shape<- table<-
NULL

typ <- c(
image="SpatialDataImage",
label="SpatialDataLabel",
point="SpatialDataPoint",
shape="SpatialDataShape",
table="SingleCellExperiment")

#' @name SpatialData
#' @exportMethod image<- label<- point<- shape<- table<-
NULL

f <- \(.) setReplaceMethod(.,
c("SpatialData", "character", typ[[.]]),
\(x, i, value) {
Expand Down
13 changes: 0 additions & 13 deletions R/read.R
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,6 @@ readPoint <- function(x, ...) {
SpatialDataPoint(data=df, meta=SpatialDataAttrs(md))
}

# create DuckDB connection
# (to be used everywhere!)
#' @importFrom DBI dbIsValid
#' @importFrom duckspatial ddbs_create_conn
.conn <- \() {
nm <- ".SpatialData_DuckDB_conn"
if (!exists(nm, envir=.GlobalEnv) ||
!dbIsValid(.GlobalEnv[[nm]])) {
.GlobalEnv[[nm]] <- ddbs_create_conn()
}
.GlobalEnv[[nm]]
}

#' @rdname readSpatialData
#' @importFrom Rarr read_zarr_attributes
#' @importFrom duckspatial ddbs_open_dataset
Expand Down
Loading
Loading