SF is the R-Spatial package designed to work with tidy syntax like dyplr and pipes.
I would like to do a simple spatial filter on a simple features collection object. Given a simple features collection, I would like to return all features from the collection which meet some geometric condition. In particular, I would like to find the features that intersect with another object.
SF provides the function st_intersects(x,y,...)
to do this, but I cannot get it to work with dplyr.
I'm using R 3.5.2 and the latest sf installed from github.
library(tidyverse)
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
# many multipolygons:
nc <- st_read(system.file("shape/nc.shp", package="sf"))
#> Simple feature collection with 100 features and 14 fields
#> geometry type: MULTIPOLYGON
#> dimension: XY
#> bbox: xmin: -84.32385 ymin: 33.88199 xmax: -75.45698 ymax: 36.58965
#> epsg (SRID): 4267
#> proj4string: +proj=longlat +datum=NAD27 +no_defs
# A point in Ashe County:
ash_point <- nc %>%
filter(NAME == "Ashe") %>%
st_point_on_surface()
# how many counties intersect ash_point?
nc %>%
st_intersects(ash_point, sparse = FALSE) %>%
sum()
#> [1] 1
# return the features which intersect ash_point:
nc %>%
filter(st_intersects(ash_point, sparse = FALSE))
#> although coordinates are longitude/latitude, st_intersects assumes that they are planar
#> Simple feature collection with 100 features and 14 fields
#> geometry type: MULTIPOLYGON
#> dimension: XY
#> bbox: xmin: -84.32385 ymin: 33.88199 xmax: -75.45698 ymax: 36.58965
#> epsg (SRID): 4267
#> proj4string: +proj=longlat +datum=NAD27 +no_defs
#> First 10 features:
#> AREA PERIMETER CNTY_ CNTY_ID NAME FIPS FIPSNO CRESS_ID BIR74
#> 1 0.114 1.442 1825 1825 Ashe 37009 37009 5 1091
#> 2 0.061 1.231 1827 1827 Alleghany 37005 37005 3 487
#> 3 0.143 1.630 1828 1828 Surry 37171 37171 86 3188
#> 4 0.070 2.968 1831 1831 Currituck 37053 37053 27 508
#> 5 0.153 2.206 1832 1832 Northampton 37131 37131 66 1421
#> 6 0.097 1.670 1833 1833 Hertford 37091 37091 46 1452
#> 7 0.062 1.547 1834 1834 Camden 37029 37029 15 286
#> 8 0.091 1.284 1835 1835 Gates 37073 37073 37 420
#> 9 0.118 1.421 1836 1836 Warren 37185 37185 93 968
#> 10 0.124 1.428 1837 1837 Stokes 37169 37169 85 1612
#> SID74 NWBIR74 BIR79 SID79 NWBIR79 geometry
#> 1 1 10 1364 0 19 MULTIPOLYGON (((-81.47276 3...
#> 2 0 10 542 3 12 MULTIPOLYGON (((-81.23989 3...
#> 3 5 208 3616 6 260 MULTIPOLYGON (((-80.45634 3...
#> 4 1 123 830 2 145 MULTIPOLYGON (((-76.00897 3...
#> 5 9 1066 1606 3 1197 MULTIPOLYGON (((-77.21767 3...
#> 6 7 954 1838 5 1237 MULTIPOLYGON (((-76.74506 3...
#> 7 0 115 350 2 139 MULTIPOLYGON (((-76.00897 3...
#> 8 0 254 594 2 371 MULTIPOLYGON (((-76.56251 3...
#> 9 4 748 1190 2 844 MULTIPOLYGON (((-78.30876 3...
#> 10 1 160 2038 5 176 MULTIPOLYGON (((-80.02567 3...
Created on 2019-07-12 by the reprex package (v0.3.0.9000)
st_intersects() alone returns the correct logical matrix, but when used in a filter, all results are returned even the features for which the logical matrix has a "FALSE".
Note that st_intersection(, sparse = TRUE)
returns a logical matrix
, and filter
wants a vector. We can get the selection vector by subsetting the matrix:
nc %>%
filter(st_intersects(., ash_point, sparse = FALSE)[1,])
The .
is needed to have nc
also be the argument to st_intersects
, not only to filter
.
It would be nice if the filter.sf
method would directly be sensitive to the output of st_intersects
, without needing sparse=FALSE
and [1,]
. I'll put it on some TODO list.
Apparently for the dplyr verbs to work with sf functions, you need to specify the column name 'geometry'.
Corrected version:
nc %>%
filter(st_intersects(geometry, ash_point, sparse = FALSE))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With