Artwork by Allison Horst
In this lab, we’ll explore the basics of spatial and geometry operations on vector data in R using the sf
package. We’ll be working with data representing the heigh points of New Zealand.
Spatial data operations
Last week, we covered how the basics of the sf
package. We saw that the magic of working with spatial data in the tidyverse
means that we can leverage many of our favorite dplyr
functions to manipulate the data attributes. So far, we’ve only worked with the data.frame
component of sf
objects. In this section, we’ll see how we can perform analogous operations using the geometry
column.
1. Set Up
Let’s load all necessary packages:
library(sf)
library(tmap)
library(tidyverse)
library(spData)
2. Spatial subsetting (filtering)
When working with tabular data, we have frequently found it useful to subset the data.frame
we are working with based on some condition using dplyr::filter()
.
Artwork by Allison Horst
For example, last week we saw how we could filter to countries whose average life expectancy is greater than 80 years old using the following code:
%>%
world filter(lifeExp >= 80)
Similarly, we might want to filter data based on its spatial relationships. In this case, we use spatial subsetting which is the process of converting a spatial object into a new object containing only the spatial features that relate in space to another object. This is analogous the attribute subsetting that we covered last week (example above).
Topological relationships
When filtering based on attributes, we use conditions (for example, lifeExp >= 80
). In spatial subsetting, we use the relationships of objects to each other in space (topological relationships). These relationships are based on mathematical relationships, but can be more easily understood from visualizing them. The figure below shows how each relationship is satisfied.
st_intersects()
and st_disjoint()
Note that st_intersects()
is a “catch-all” that contains the following relationships:
st_touches()
st_overlaps()
st_contains()
and st_contains_properly()
st_covers()
andst_covered_by()
st_within()
st_disjoint()
is the opposite of st_intersects()
Examples
There are many ways to spatially subset in R, so we will explore a few.
As an example we’ll work with the following two datasets from the spData
package:
nz
: polygons representing the 16 regions of New Zealandnz_height
: top 101 heighest points in New Zealand
We’ll explore by trying to find all the high points in the region of Canterbury (shown in dark grey).
Code
tm_shape(nz) +
tm_polygons() +
tm_shape(canterbury) +
tm_fill(col = "darkgrey") +
tm_shape(nz_height) +
tm_dots(col = "red")
Bracket subsetting
Like attribute subsetting, the command x[y, ]
(equivalent to nz_height[canterbury, ]
) subsets features of a target x
using the contents of a source object y
. Instead of y
being a vector of class logical or integer, however, for spatial subsetting both x
and y
must be geographic objects. Specifically, objects used for spatial subsetting in this way must have the class sf
or sfc
: both nz
and nz_height
are geographic vector data frames and have the class s
f, and the result of the operation returns another sf
object representing the features in the target nz_height
object that intersect with (in this case high points that are located within) the Canterbury region.
# first filter to the region of Canterbury
<- nz %>%
canterbury filter(Name == "Canterbury")
# subset nz_heights to just the features that intersect Canterbury
<- nz_height[canterbury, ] c_height1
By default bracket subsetting will filter to features in x
that intersect features in y
. However, we can use other topological relationships by changing options.
= st_disjoint] nz_height[canterbury, , op
st_filter()
The sf
package also includes the function st_filter()
which is analogous to dplyr::filter()
. Using st_filter()
we can perform spatial subsetting in the same format as using dplyr
commands. The .predicate =
argument allows us to define which topological relationship we would like to filter by (e.g. st_intersects()
, st_disjoint()
).
The results from this method are the identical to the method above.
# subset to the features in Cantebury
<- nz_height %>%
c_height2 st_filter(y = canterbury, .predicate = st_intersects) # define the topological relationship
Topological operators (st_intersects()
)
The previous two methods either by default or explicitly use the argument st_intersects
. All topological relationships have their own topological operators which are functions that evaluate whether or not features meet the specified condition (e.g. st_intersects()
). These operators can be used for spatial subsetting, but are more complicated to use.
The output of st_intersects()
and other topological operators is a sparse geometry binary predicate list (yikes!) that’s a list that defines whether or not each feature in x
intersects y
.
This can be converted into logical vector of TRUE
and FALSE
values which can then be used for filtering.
# sparse binary predicate list
<- st_intersects(x = nz_height, y = canterbury)
nz_height_sgbp nz_height_sgbp
Sparse geometry binary predicate list of length 101, where the
predicate was `intersects'
first 10 elements:
1: (empty)
2: (empty)
3: (empty)
4: (empty)
5: 1
6: 1
7: 1
8: 1
9: 1
10: 1
# convert to logical vector
<- lengths(nz_height_sgbp) > 0
nz_height_logical
# filter based on logical vector
= nz_height[nz_height_logical, ] c_height3
Now let’s plot results from all three methods to confirm they gave the same results.
Code
<- tm_shape(nz) +
map1 tm_polygons() +
tm_shape(canterbury) +
tm_fill(col = "darkgrey") +
tm_shape(c_height1) +
tm_dots(col = "red") +
tm_layout(title = "Bracket subsetting")
<- tm_shape(nz) +
map2 tm_polygons() +
tm_shape(canterbury) +
tm_fill(col = "darkgrey") +
tm_shape(c_height1) +
tm_dots(col = "red") +
tm_layout(title = "st_filter()")
<- tm_shape(nz) +
map3 tm_polygons() +
tm_shape(canterbury) +
tm_fill(col = "darkgrey") +
tm_shape(c_height3) +
tm_dots(col = "red") +
tm_layout(title = "st_intersects()")
tmap_arrange(map1, map2, map3, nrow = 1)
Distance relationships
The topological relationships we have been discussing are all binary (features either intersect or don’t). In some cases, it might be helpful to subset based on a distance to a feature. In these cases we can use the st_is_within_distance()
to filter features. By default st_is_within_distance()
will return a sparse geometry binary predicate list as in st_intersects()
above. Instead, we can return a logical by setting sparse = FALSE
.
# find heights within 1000 km of Canterbury
<- st_is_within_distance(nz_height, canterbury,
nz_height_logical dist = units::set_units(1000, "km"), # set distance
sparse = FALSE) # return logical vector instead
<- nz_height[nz_height_logical, ] # filter based on logical c_height4
Now, we should see points appear that do not intersect Caterbury, but are within 1000 km.
Code
# additional high points should appear
tm_shape(nz) +
tm_polygons() +
tm_shape(canterbury) +
tm_fill(col = "darkgrey") +
tm_shape(c_height4) +
tm_dots(col = "red")
3. Spatial joins
Joins are a common way to link different data sources. Up until now, we have been performing joins using common attributes between data.frame
s. Last week, we saw that the same joins can be used on sf
objects. However, we can also perform joins by using the spatial relationship of datasets.
First, let’s remind ourselves of the different types of joins.
Toplogical relationships
With spatial data, we can join based on the geometry
columns using topological relationships using the st_join()
function. By default st_join()
will join based on geometries that intersect, but can accommodate other topological relationships by changing the join =
argument. By default st_join()
performs left joins, but can perform inner joins by setting left = FALSE
.
# specify join based on geometries x within y
st_join(x, y, join = st_within)
# specify inner join
st_join(x, y, left = FALSE)
Let’s consider the scenario where we would like to know which region each of the highest points is located in. We can left join the nz
dataset (polygons of NZ’s regions) onto the nz_height
dataset (points of highest points in the county).
<- st_join(nz_height, nz) %>%
nz_height_left_join select(id = t50_fid, elevation, region = Name)
head(nz_height_left_join)
Simple feature collection with 6 features and 3 fields
Geometry type: POINT
Dimension: XY
Bounding box: xmin: 1204143 ymin: 5048309 xmax: 1389460 ymax: 5168749
Projected CRS: NZGD2000 / New Zealand Transverse Mercator 2000
id elevation region geometry
1 2353944 2723 Southland POINT (1204143 5049971)
2 2354404 2820 Otago POINT (1234725 5048309)
3 2354405 2830 Otago POINT (1235915 5048745)
4 2369113 3033 West Coast POINT (1259702 5076570)
5 2362630 2749 Canterbury POINT (1378170 5158491)
6 2362814 2822 Canterbury POINT (1389460 5168749)
Now we could use this data to summarize the number of highest point in each region!
%>%
nz_height_left_join group_by(region) %>%
summarise(n_points = n()) %>%
st_drop_geometry()
# A tibble: 7 × 2
region n_points
* <chr> <int>
1 Canterbury 70
2 Manawatu-Wanganui 2
3 Marlborough 1
4 Otago 2
5 Southland 1
6 Waikato 3
7 West Coast 22
Distance-based joins
Similar to filtering, in some cases we may want to join datasets based on their proximity. Let’s see an example!
We’ll use the following two datasets from the spData
package:
cycle_hire
: points representing cycle hire points across London with information on number of bikes availablecycle_hire_osm
: dataset downloaded from OpenStreetMaps representing cycle hire points across London with information on the capacity of the hire point
In this example, we would like join the capacity
attribute from the cycle_hire_osm
dataset to the cycle_hire
dataset. Unfortunately it appears that the points from the two datasets do not perfectly align.
# check whether or not points overlap
if(any(st_intersects(cycle_hire, cycle_hire_osm, sparse = FALSE)) == TRUE){
print("points overlap")
else{
} warning("points don't overlap")
}
Warning: points don't overlap
Code
tmap_mode("view")
tm_shape(cycle_hire) +
tm_symbols(col = "red", alpha = 0.2) +
tm_shape(cycle_hire_osm) +
tm_symbols(col = "blue", alpha = 0.2)
We can join by again using st_join()
, but this time including a distance threshold using st_is_within_distance
.
<- st_join(cycle_hire, cycle_hire_osm,
cycle_hire_join
st_is_within_distance,dist = units::set_units(20, "m")) %>%
select(id, capacity)
head(cycle_hire_join)
Simple feature collection with 6 features and 2 fields
Geometry type: POINT
Dimension: XY
Bounding box: xmin: -0.1975742 ymin: 51.49313 xmax: -0.08460569 ymax: 51.53006
Geodetic CRS: WGS 84
id capacity geometry
1 1 9 POINT (-0.1099705 51.52916)
2 2 27 POINT (-0.1975742 51.49961)
3 3 NA POINT (-0.08460569 51.52128)
4 4 NA POINT (-0.1209737 51.53006)
5 5 NA POINT (-0.156876 51.49313)
6 6 8 POINT (-0.1442289 51.51812)
Let’s build some checks to diagnose the output.
if(nrow(cycle_hire) == nrow(cycle_hire_join)){
print("join matches original data dimensions")
else {
} warning("join does not match orginal data dimensions")
print(paste("cycle_hire has", nrow(cycle_hire), "rows"))
print(paste("cycle_hire_join has", nrow(cycle_hire_join), "rows"))
}
Warning: join does not match orginal data dimensions
[1] "cycle_hire has 742 rows"
[1] "cycle_hire_join has 762 rows"
Note that the joined result has more rows than the target data. This is because some of the cycle hire stations in cycle_hire
have multiple matches in cycle_hire_osm
. Depending on your project, you would need to think about how to resolve this. In this case, we can aggregate the values for the overlapping points by taking the mean.
# aggregate values for single points in cycle_hire
<- cycle_hire_join %>%
cycle_hire_join group_by(id) %>%
summarise(capacity = mean(capacity))
# check results
if(nrow(cycle_hire) == nrow(cycle_hire_join)){
print("join matches original data dimensions")
else {
} warning("join does not match orginal data dimensions")
print(paste("cycle_hire has", nrow(cycle_hire), "rows"))
print(paste("cycle_hire_join has", nrow(cycle_hire_join), "rows"))
}
[1] "join matches original data dimensions"
4. Spatial aggregation
As with aggregating attribute data, spatial data aggregation condenses data: outputs have few rows than inputs. Think about our friend group_by() %>% summarise()
! Spatial aggregation is the same.
Let’s consider the example where we would like to make a map of the mean elevation of high points within each region of NZ. There are several ways to do this, but the first thing we should be thinking is that we will need to retain the geometry
column of the NZ regions in order to make a map.
The first approach is by leveraging st_join()
again. But in this example, we want the nz
object to be the target to maintain the geometries we need.
tmap_mode("plot")
tmap mode set to plotting
<- st_join(x = nz, y = nz_height) %>%
nz_elevation group_by(Name) %>%
summarise(elevation = mean(elevation, na.rm = TRUE))
The second approah uses the aggregate()
function. Although it doesn’t follow the dplyr
piping convention we’re used to, aggregate()
will come in handy later, so it’s nice to see how it works.
The syntax looks slightly different, in this case the argument x
is the data we would like to aggregate (nz_height
) and the by
argument specifies the geometry that you would like to group by. The FUN
argument defines the function that you would like to use to aggregate, in this case mean
.
<- aggregate(x = nz_height, by = nz, FUN = mean) nz_elevation
Code
<- tm_shape(nz_elevation) +
map1 tm_polygons(col = "elevation",
title = "Mean elevation (meters)") +
tm_layout(title = "group_by()")
<- tm_shape(nz_elevation) +
map2 tm_polygons(col = "elevation",
title = "Mean elevation (meters)") +
tm_layout(title = "aggregate()")
tmap_arrange(map1, map2, nrow = 1)
An important consideration when aggregating spatial objects is that geometries are congruent, meaning aggregating zones align with the units being aggregating. This is often the case with administrative boundaries where units are sub-units of one another (e.g. countries > states > counties).
However, in some cases the aggregating zones do not share common borders with the target. This is an issue because it’s not clear how to aggregate underlying data. Areal interpolation overcomes this issue by transferring values to another using algorithms, including simple area weighted approaches.
<- spData::incongruent
incongruent <- spData::aggregating_zones
aggregating_zones
tm_shape(incongruent) +
tm_polygons(col = "lightblue",
border.col = "blue") +
tm_shape(aggregating_zones) +
tm_borders(col = "red")
The simplest useful method for this is area weighted spatial interpolation, which transfers values from the incongruent
object to a new column in aggregating_zones
in proportion with the area of overlap: the larger the spatial intersection between input and output features, the larger the corresponding value. This is implemented in st_interpolate_aw()
, as demonstrated in the code chunk below.
# select just the value to be aggregated
<- incongruent %>%
incongruent_2 select(value)
# use area-weighted interpolation to aggregrate the "value" attribute
<- st_interpolate_aw(incongruent_2, aggregating_zones, extensive = TRUE) aggregating_zones_area_weighted
Warning in st_interpolate_aw.sf(incongruent_2, aggregating_zones, extensive =
TRUE): st_interpolate_aw assumes attributes are constant or uniform over areas
of x
$value aggregating_zones_area_weighted
[1] 19.61613 25.66872
Geometry operations
In the previous section, we saw how we can use spatial relationship of datasets to perform operations. We did so by leveraging the geometry
columnn, but none of our operations changed the underlying geometries – mapping our output produces the same objects.
In this section, we will explore operations that change the geometries directly.
1. Aggregating
Geometry unions
We may come across situations where we would like to summarize data across several spatial units. For example, summarizing the population across states within regions of the US. Based on our experience with tabular data, we can summarize attributes by using group_by() %>% summarize()
. Alternatively we can use the aggregate()
function. So far this should look familiar, but if plot the outputs we notice that these functions have also aggregated the underlying geometries.
# load US states
<- spData::us_states
us_states
# summarize total population within each region
<- us_states %>%
regions1 group_by(REGION) %>%
summarise(population = sum(total_pop_15, na.rm = TRUE))
# alternative approach
<- aggregate(x = us_states[, "total_pop_15"], # data and attribute to be aggregated
regions2 by = list(us_states$REGION), # attribute to aggregate by
FUN = sum, na.rm = TRUE) # aggregating function
Code
<- tm_shape(us_states) +
map1 tm_polygons(col = "total_pop_15",
title = "Total population") +
tm_layout(title = "US States")
<- tm_shape(regions1) +
map2 tm_polygons(col = "population",
title = "Total population") +
tm_layout(title = "group_by()")
<- tm_shape(regions2) +
map3 tm_polygons(col = "total_pop_15",
title = "Total population") +
tm_layout(title = "aggregate()")
tmap_arrange(map1, map2, map3, nrow = 1)
What’s going on here? Behind the scenes, R is using st_union()
to combine geometries within each group. We can also use st_union()
to combine any pair of spatial objects.
# combine geometries of western states
<- us_states[us_states$REGION == "West", ]
us_west <- st_union(us_west)
us_west_union
# combine geometries of Texas and western states
<- us_states[us_states$NAME == "Texas", ]
texas <- st_union(us_west_union, texas) texas_union
Code
<- tm_shape(us_west) +
map1 tm_polygons() +
tm_layout(main.title = "western states")
<- tm_shape(us_west_union) +
map2 tm_polygons() +
tm_layout(main.title = "western states union")
<- tm_shape(texas) +
map3 tm_polygons() +
tm_layout(main.title = "TX")
<- tm_shape(texas_union) +
map4 tm_polygons() +
tm_layout(main.title = "TX + western states union")
tmap_arrange(map1, map2, map3, map4, nrow = 2)
2. Filtering
Buffers
In the previous section, we saw that we can filter spatial objects based on their proximity using st_is_within_distance()
. An alternative approach to finding items that are within a set distance would be to expand the geometry
and then intersect with objects of interest. We can change the size of geometries by creating a “buffer” using st_buffer()
In this example, let’s create 5 km and 50 km buffers around the Seine.
<- st_buffer(seine, dist = 5000)
seine_buffer_5km = st_buffer(seine, dist = 50000) seine_buffer_50km
Code
<- tm_shape(seine_buffer_5km) +
map1 tm_polygons() +
tm_shape(seine) +
tm_lines() +
tm_layout(title = "5km buffer")
<- tm_shape(seine_buffer_50km) +
map2 tm_polygons() +
tm_shape(seine) +
tm_lines() +
tm_layout(title = "50km buffer")
tmap_arrange(map1, map2, nrow = 1)
The Seine is actually comprised of multiple geometries. To make things simpler, and more look better on maps, we can combine geometries using our new friend st_union
!
<- st_union(seine_buffer_50km) seine_union
Code
tm_shape(seine_union) +
tm_polygons() +
tm_shape(seine) +
tm_lines() +
tm_layout(title = "50km buffer")
Now let’s see an example of using a buffer to find objects within a set distance. Here, we’ll repeat our previous example of finding points within 100 km of Canterbury. And check to see if the results match our previous approach!
# create buffer around high points
<- st_buffer(nz_height, dist = 1000000)
nz_height_buffer
# filter buffered points with those that intersect Canterbury
<- nz_height_buffer %>%
c_height5 st_filter(y = canterbury, .predicate = st_intersects)
# check to see if results match previous approach
if(nrow(c_height4) == nrow(c_height5)){
print("results from buffer approach match st_is_within_distance() approach")
else{
} warning("approaches giving different results")
}
[1] "results from buffer approach match st_is_within_distance() approach"
Clipping
Beyond filtering observations based on their spatial proximity, in some cases we might want to filter (or remove) portions of geometries. Spatial clipping is a form of spatial subsetting that involves changes to the geometry
columns of at least some of the affected features.
Clipping can only apply to features more complex than points: lines, polygons and their ‘multi’ equivalents.
There are several options for clipping geometries:
st_intersection(x, y)
- portion ofx
intersectingy
st_difference(x, y)
- portion ofx
not intersectingy
st_difference(y, x)
- portion ofy
not intersectingx
st_union(x, y)
- portion either inx
ory
st_sym_difference(x, y)
- portions ofx
andy
that do not intersect
To illustrate the concept, we will start with a simple example: two overlapping circles with a center point one unit away from each other and a radius of one.
<- st_sfc(st_point(c(0, 1))) %>%
x st_buffer(., dist = 1) %>%
st_as_sf()
<- st_sfc(st_point(c(1, 1))) %>%
y st_buffer(., dist = 1) %>%
st_as_sf()
<- st_intersection(x, y)
intersection <- st_difference(x, y)
difference_x_y <- st_difference(y, x)
difference_y_x <- st_union(x, y)
union <- st_sym_difference(x, y) sym_difference
Code
<- st_union(x, y)
bbox
<- tm_shape(x, bbox = bbox) +
map1 tm_borders(col = "red") +
tm_shape(y) +
tm_borders(col = "blue")
<- map1 +
map2 tm_shape(intersection, bbox = bbox) +
tm_fill(col = "purple") +
tm_layout(title = "st_intersection()")
<- map1 +
map3 tm_shape(difference_x_y, bbox = bbox) +
tm_fill(col = "purple") +
tm_layout(title = "st_difference(x,y)")
<- map1 +
map4 tm_shape(difference_y_x, bbox = bbox) +
tm_fill(col = "purple") +
tm_layout(title = "st_difference(y,x)")
<- map1 +
map5 tm_shape(union, bbox = bbox) +
tm_fill(col = "purple") +
tm_layout(title = "st_union()")
<- map1 +
map6 tm_shape(sym_difference, bbox = bbox) +
tm_fill(col = "purple") +
tm_layout(title = "st_sym_diffference()")
tmap_arrange(map1, map2, map3, map4, map5, map6, nrow = 2)
Now let’s see how we could use these updated geometries for filtering. Extending this simple example, we’ll create 100 random points. We want to find the points that intersect both x
and y
. We have a few different approaches that all produce the same results.
# create random points
<- st_bbox(st_union(x, y)) # create bounding box of x and y
bb <- st_as_sfc(bb)
box <- st_sample(x = box, size = 100) %>% # randomly sample the bounding box
p st_as_sf()
# find intersection of x and y
<- st_intersection(x, y)
x_and_y
# filter points
# first approach: bracket subsetting
= p[x_and_y, ]
p_xy1
# second approach: st_filter()
<- p %>%
p_xy2 st_filter(., x_and_y)
# third approach: st_intersection()
= st_intersection(p, x_and_y) p_xy3
Code
<- map1 +
map2 tm_shape(p) +
tm_dots(alpha = 0.5) +
tm_layout(main.title = "original")
<- map2 +
map3 tm_shape(p_xy1) +
tm_symbols(col = "purple", size = 0.2) +
tm_layout(main.title = "bracket subsetting")
<- map2 +
map4 tm_shape(p_xy2) +
tm_symbols(col = "purple", size = 0.2) +
tm_layout(main.title = "st_filter()")
<- map2 +
map5 tm_shape(p_xy3) +
tm_symbols(col = "purple", size = 0.2) +
tm_layout(main.title = "st_intersection()")
tmap_arrange(map2, map3, map4, map5, nrow = 2)
3. Making life easier!
Working with, and especially plotting, complex spatial objects can become quite cumbersome. This section we’ll see a few ways to create and manipulate geometries to make them easier to work with.
Centroids
Centroids are basically the center of spatial objects. They can be a handy way to display summary statistics (or we might actually use them for analysis – e.g. to find the distance between polygons).
There are many ways to that we might want to define the “center” of an object, but the most common is the geographic centroid which is the center of mass of a spatial object. The geographic centroid can be found using st_centroid()
.
Sometimes the geographic centroid may fall outside of the boundaries of the object (picture the centroid of a doughnut!). While correct, it might be confusing on a map, so we can use st_point_on_surface()
to ensure that the centroid is placed onto the object.
Let’s inspect a few examples!
<- st_centroid(nz)
nz_centroid <- st_centroid(seine)
seine_centroid
<- st_point_on_surface(nz)
nz_pos <- st_point_on_surface(seine) seine_pos
Code
<- tm_shape(nz) +
map1 tm_polygons() +
tm_shape(nz_centroid) +
tm_symbols(col = "red", alpha = 0.5) +
tm_shape(nz_pos) +
tm_symbols(col = "blue", alpha = 0.5)
<- tm_shape(seine) +
map2 tm_lines() +
tm_shape(seine_centroid) +
tm_symbols(col = "red", alpha = 0.5) +
tm_shape(seine_pos) +
tm_symbols(col = "blue", alpha = 0.5)
tmap_arrange(map1, map2, nrow = 1)
Simplification
We may also want to simplify a geometry
to make it easier to plot or take up less storage. There are several different algorithms for simplifying geometries, check out Geocomputation with R for more examples. The sf
packages uses the Douglas-Peucker algorithm within the st_simplify()
function.
Let’s see an example!
<- st_simplify(seine, dTolerance = 2000) # 2000 m seine_simple
Code
<- tm_shape(seine) +
map1 tm_lines() +
tm_layout("original")
<- tm_shape(seine_simple) +
map2 tm_lines() +
tm_layout("st_simplify()")
tmap_arrange(map1, map2, nrow = 1)
Summary of new functions
Function | Description |
---|---|
Spatial data operations | |
st_intersects(x,y) | tests whether objects intersects |
st_touches(x,y) | tests whether objects touch |
st_overlaps(x,y) | tests whether objects overlap |
st_contains(x,y) | tests whether object x contains object y (including boundary) |
st_contains_properly(x,y) | tests whether object x contains object y (not including boundary) |
st_covers(x,y) | identical to st_contains() when y is a polygon |
st_covered_by(x,y) | tests whether object y contains object x |
st_within(x,y) | tests whether object x is within object y |
st_disjoint(x,y) | tests whether objects have no intersection |
st_is_within_distance(x,y) | test whether objects intersect within a certain distance |
st_join(x,y) | performs spatial join |
st_interpolate_aw(x,y) | performs area-weighted interpolation of polygons |
Geometry operations | |
aggregate(x,y) | computes summary statistics for data subsets |
st_union(x,y) | combines geometries |
st_buffer(x) | creates polygon that represents all points within a distance threshold of original geometry |
st_intersection(x,y) | creates polygon of the area shared by x and y |
st_difference(x,y) | creates polygon of the area of x not in y |
st_sym_difference(x,y) | creates polygon of the area not shared by x and y |
st_centroid(x) | creates point(s) of the geographic centroid of a polygon(s) |
st_simplify(x) | creates a simplified representation of a geometry |