Skip to content

Commit

Permalink
Make .df2sf_check optional to speed up the transformation using sfhea…
Browse files Browse the repository at this point in the history
…der. Closing #32
  • Loading branch information
lambdamoses committed Apr 12, 2024
1 parent 96cd7b5 commit d61adbf
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 31 deletions.
67 changes: 39 additions & 28 deletions R/df2sf.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
if (grepl("MULTI", geometryType) && !group_col %in% names(df)) {
stop("Column", group_col, " to identify MULTI geometries is abesent.")
}
df <- unique(df)
n_vertices <- table(df[[id_col]])
ids <- names(n_vertices)
min_vertices <- switch(geometryType,
Expand Down Expand Up @@ -63,16 +64,16 @@
}

.df2sf_point <- function(df, spatialCoordsNames, spotDiameter, multi,
group_col = "group") {
group_col = "group", check = TRUE) {
# Case 1: centroids, use POINT
if (!is.na(spotDiameter)) {
if (spotDiameter <= 0) {
stop("spotDiameter must be a positive number.")
}
}
if (multi) {
df <- .df2sf_check(df, spatialCoordsNames, "MULTIPOINT",
group_col = group_col)
if (check) df <- .df2sf_check(df, spatialCoordsNames, "MULTIPOINT",
group_col = group_col)
if (!is.data.table(df)) ..group_col <- group_col
df <- df[order(df[,..group_col]),]
out <- sf_multipoint(df, x = spatialCoordsNames[1],
Expand All @@ -93,10 +94,11 @@
}

.df2sf_polygon <- function(df, spatialCoordsNames, multi,
group_col = "group", id_col, subid_col) {
group_col = "group", id_col, subid_col,
check = TRUE) {
gt <- if (multi) "MULTIPOLYGON" else "POLYGON"
df <- .df2sf_check(df, spatialCoordsNames, gt,
group_col, id_col, subid_col)
if (check) df <- .df2sf_check(df, spatialCoordsNames, gt,
group_col, id_col, subid_col)
if (multi) {
out <- sf_multipolygon(df, x = spatialCoordsNames[1],
y = spatialCoordsNames[2],
Expand All @@ -119,10 +121,10 @@
}

.df2sf_linestring <- function(df, spatialCoordsNames, multi,
group_col = "group", id_col) {
group_col = "group", id_col, check = TRUE) {
gt <- if (multi) "MULTILINESTRING" else "LINESTRING"
df <- .df2sf_check(df, spatialCoordsNames, gt,
group_col, id_col)
if (check) df <- .df2sf_check(df, spatialCoordsNames, gt,
group_col, id_col)
if (multi) {
out <- sf_multilinestring(df, x = spatialCoordsNames[1],
y = spatialCoordsNames[2],
Expand Down Expand Up @@ -157,24 +159,28 @@
#' @inheritParams SpatialFeatureExperiment
#' @inheritParams BiocParallel::bplapply
#' @param df An ordinary data frame, i.e. not \code{sf}. Or a matrix that can be
#' converted to a data frame.
#' converted to a data frame.
#' @param spatialCoordsNames Column names in \code{df} that specify spatial
#' coordinates.
#' coordinates.
#' @param geometryType Type of geometry to convert the ordinary data frame to.
#' If the geometry in \code{df} is de facto points, then this argument will be
#' ignored and the returned \code{sf} will have geometry type POINT.
#' @param group_col Column to indicate which coordinates for which MULTI geometry,
#' such as to identify which MULTIPOLYGON or MULTIPOINT.
#' If the geometry in \code{df} is de facto points, then this argument will be
#' ignored and the returned \code{sf} will have geometry type POINT.
#' @param group_col Column to indicate which coordinates for which MULTI
#' geometry, such as to identify which MULTIPOLYGON or MULTIPOINT.
#' @param id_col Column to indicate coordinates for which geometry, within a
#' MULTI geometry if applicable, such as to identify which POLYGON or which
#' polygon within a MULTIPOLYGON.
#' MULTI geometry if applicable, such as to identify which POLYGON or which
#' polygon within a MULTIPOLYGON.
#' @param check Logical, whether to check the input data frame for issues
#' related to constructing the geometry of interese such as number of vertices
#' per geometry. If \code{FALSE}, it will save a bit of time, which is useful
#' when the input is already known to be good.
#' @param subid_col Column to indicate coordinates for holes in polygons.
#' @return An \code{sf} object.
#' @export
#' @concept Utilities
#' @importFrom BiocParallel bplapply SerialParam
#' @importFrom sfheaders sf_multipoint sf_polygon sf_multipolygon sf_linestring
#' sf_multilinestring
#' sf_multilinestring
#' @examples
#' # Points, use spotDiameter to convert to circle polygons
#' # This is done to Visium spots
Expand Down Expand Up @@ -216,7 +222,8 @@ df2sf <- function(df, spatialCoordsNames = c("x", "y"), spotDiameter = NA,
),
group_col = "group",
id_col = "ID",
subid_col = "subID", BPPARAM = deprecated()) {
subid_col = "subID", check = TRUE,
BPPARAM = deprecated()) {
if (is_present(BPPARAM)) {
deprecate_warn("1.6.0", "df2sf(BPPARAM = )",
details = "The sfheaders package is now used instead for much better performance")
Expand All @@ -235,24 +242,26 @@ df2sf <- function(df, spatialCoordsNames = c("x", "y"), spotDiameter = NA,
out <- switch(geometryType,
POINT = .df2sf_point(df, spatialCoordsNames, spotDiameter, multi = FALSE),
MULTIPOINT = .df2sf_point(df, spatialCoordsNames, spotDiameter, multi = TRUE,
group_col = group_col),
group_col = group_col, check = check),
LINESTRING = .df2sf_linestring(df, spatialCoordsNames, multi = FALSE,
id_col = id_col),
id_col = id_col, check = check),
MULTILINESTRING = .df2sf_linestring(df, spatialCoordsNames, multi = TRUE,
group_col = group_col, id_col = id_col),
group_col = group_col, id_col = id_col,
check = check),
POLYGON = .df2sf_polygon(df, spatialCoordsNames, multi = FALSE,
id_col = id_col, subid_col = subid_col),
id_col = id_col, subid_col = subid_col, check = check),
MULTIPOLYGON = .df2sf_polygon(df, spatialCoordsNames, multi = TRUE,
group_col = group_col, id_col = id_col,
subid_col = subid_col)
subid_col = subid_col, check = check)
)
out
}

# Call in SFE constructor and *Geometries replacement methods
.df2sf_in_list <- function(x, spatialCoordsNames = c("x", "y"),
spotDiameter = NA, geometryType = "POLYGON",
group_col = "group", id_col = "ID", subid_col = "subID") {
group_col = "group", id_col = "ID", subid_col = "subID",
check = TRUE) {
if (!is.null(x) && !is(x, "sf") && !is.data.frame(x) && !is.matrix(x)) {
stop(
"Each element of the list for *Geometry must be an ",
Expand All @@ -263,13 +272,14 @@ df2sf <- function(df, spatialCoordsNames = c("x", "y"), spotDiameter = NA,
return(x)
} else if (is.data.frame(x) || is.matrix(x)) {
return(df2sf(x, spatialCoordsNames, spotDiameter, geometryType,
group_col, id_col, subid_col))
group_col, id_col, subid_col, check = check))
}
}

.df2sf_list <- function(x, spatialCoordsNames = c("x", "y"),
spotDiameter = NA, geometryType = "POLYGON",
group_col = "group", id_col = "ID", subid_col = "subID") {
group_col = "group", id_col = "ID", subid_col = "subID",
check = TRUE) {
x_is_sf <- vapply(x, function(t) is(t, "sf"), FUN.VALUE = logical(1))
if (all(x_is_sf)) {
return(x)
Expand All @@ -287,7 +297,8 @@ df2sf <- function(df, spatialCoordsNames = c("x", "y"), spotDiameter = NA,
MoreArgs = list(
spatialCoordsNames = spatialCoordsNames,
spotDiameter = spotDiameter,
group_col = group_col, id_col = id_col, subid_col = subid_col
group_col = group_col, id_col = id_col, subid_col = subid_col,
check = check
),
SIMPLIFY = FALSE
)
Expand Down
3 changes: 2 additions & 1 deletion R/transformation.R
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@
subid_col <- paste0("L", nd - 1L)
g2 <- df2sf(as.data.frame(coords), coord_names,
geometryType = gt,
group_col = group_col, id_col = id_col, subid_col = subid_col)
group_col = group_col, id_col = id_col, subid_col = subid_col,
check = FALSE)
st_geometry(g) <- st_geometry(g2)
g
}
Expand Down
10 changes: 8 additions & 2 deletions man/df2sf.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d61adbf

Please sign in to comment.