Reputation: 3486
Suppose t
is:
t <- structure(list(structure(list(structure(c(-89.990791, -89.990772,
-89.990901, -89.99092, -89.990791, 30.727025, 30.727083, 30.727114,
30.727057, 30.727025), .Dim = c(5L, 2L))), class = c("XY", "POLYGON",
"sfg")), structure(list(structure(c(-89.991691, -89.991755, -89.991755,
-89.991691, -89.991691, 30.716004, 30.716004, 30.715916, 30.715916,
30.716004), .Dim = c(5L, 2L))), class = c("XY", "POLYGON", "sfg"
))), class = c("sfc_POLYGON", "sfc"), precision = 0, bbox = structure(c(xmin = -89.991755,
ymin = 30.715916, xmax = -89.990772, ymax = 30.727114), class = "bbox"), crs = structure(list(
epsg = 4326L, proj4string = "+proj=longlat +datum=WGS84 +no_defs"), class = "crs"), n_empty = 0L)
> t
Geometry set for 2 features
geometry type: POLYGON
dimension: XY
bbox: xmin: -89.99176 ymin: 30.71592 xmax: -89.99077 ymax: 30.72711
epsg (SRID): 4326
proj4string: +proj=longlat +datum=WGS84 +no_defs
POLYGON ((-89.99079 30.72703, -89.99077 30.7270...
POLYGON ((-89.99169 30.716, -89.99175 30.716, -...
How can I filter polygons by long/lat boundaries? Suppose I want to filter out any polygon that hax lat>30.72 (so to keep only the second polygon). Is there any specific function I can use to filter polygons?
Upvotes: 4
Views: 2028
Reputation: 5209
You can do this a lot easier using a simple function:
filter_sf <- function(.data, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL) {
bb <- sf::st_bbox(.data)
if (!is.null(xmin)) bb["xmin"] <- xmin
if (!is.null(xmax)) bb["xmax"] <- xmax
if (!is.null(ymin)) bb["ymin"] <- ymin
if (!is.null(ymax)) bb["ymax"] <- ymax
sf::st_filter(.data, sf::st_as_sfc(bb), .predicate = sf::st_within)
}
So now you can do:
t %>%
filter_sf(ymin = 30.72)
This method works for both POLYGON
and MULTIPOLYGON
geometries.
Upvotes: 3
Reputation: 5932
I do not know if there is a ready-made function, but a rectangular “spatial filter” is easy to build. Just define the “corners”, create a bbox from them, convert to polygon and find which of your original polygons are contained / overlap the "filter area".
Here is a quick-and-dirty example:
library(sf)
polys_sf<-st_read(system.file("shape/nc.shp", package="sf") ) %>%
st_transform(crs="+init=epsg:4326")
plot(st_geometry(polys_sf))
Define a “spatial filter”
xmin <- -80
xmax <- -76
ymin <- 34
ymax <- 36
create a polygon based on the filter. (You can use "NA" for some values, so if you want for example to filter only "on the left", you can set xmax to NA)
filt_bbox <- sf::st_bbox(c(xmin = ifelse(is.na(xmin), -180, xmin),
ymin = ifelse(is.na(ymin), -90, ymin),
xmax = ifelse(is.na(xmax), +180, xmax),
ymax = ifelse(is.na(ymax), +90, ymax)),
crs = st_crs(4326)) %>%
sf::st_as_sfc(.)
Now "filter" the original dataset based on the bbox polygon: Use st_within
if you want to keep only the polys completely contained in the defined area
find_data <- sf::st_within(polys_sf, filt_bbox)
#> although coordinates are longitude/latitude, st_within assumes that they are planar
filt_data <- polys_sf[which(lengths(find_data) != 0), ]
plot(filt_bbox)
plot(st_geometry(filt_data), add = TRUE, reset = FALSE)
Use st_intersects
if you want to keep all polys that intersect the defined area
find_data <- sf::st_intersects(polys_sf, filt_bbox)
#> although coordinates are longitude/latitude, st_intersects assumes that they are planar
filt_data <- polys_sf[which(lengths(find_data) != 0), ]
plot(st_geometry(filt_data))
plot(filt_bbox, add = TRUE)
(Clearly, this works if both your polys and the “filtering extent” are lat/long, otherwise you have to take care of reprojecting, etcetera.) Created on 2018-11-15 by the reprex package (v0.2.1)
Upvotes: 6