In this lab, we will learn how to compute various geometric properties of spatial objects.
library(tidyverse)
library(macleish)
library(sf)
Goal: by the end of this lab, you will be able to use sf
to perform computations on spatial objects.
dplyr
operationsMost dplyr
operations will just work on sf
objects, since they are data.frame
s.
rename()
to change the variable called Sheet1__Ve
in the forests layer to forest_type
.# SAMPLE SOLUTION
<- macleish_layers[["forests"]] %>%
forests rename(forest_type = Sheet1__Ve)
mutate()
and st_area()
to compute the area of each forest.# SAMPLE SOLUTION
<- forests %>%
forests mutate(area = st_area(geometry))
We can perform geometric operations on spatial objects. For example, the st_intersection()
function returns the geometry covered by both spatial objects. For example, in order to find the parts of the streams that are entirely inside the MacLeish boundary, we intersect those layers.
<- macleish_layers %>%
boundary pluck("boundary")
<- macleish_layers %>%
streams pluck("streams")
<- boundary %>%
streams_inside st_intersection(streams)
library(leaflet)
<- leaflet() %>%
macleish_map addTiles() %>%
addPolygons(data = boundary, weight = 1)
%>%
macleish_map addPolylines(data = streams_inside)
To find the corresponding part of the streams that lay outside of the MacLeish boundary, we use st_difference()
.
<- streams %>%
streams_outside st_difference(boundary)
%>%
macleish_map addPolylines(data = streams_outside)
# SAMPLE SOLUTION
<- macleish_layers %>%
trails pluck("trails")
<- trails %>%
trails_outside st_difference(boundary)
%>%
macleish_map addPolylines(data = trails_outside)
Since all sf
objects are also data.frame
s, you can add additional attributes to a spatial object using by joining that data.frame
to your sf
object in the usual way.
A distinct idea is to join two spatial layers together. This can be done with the st_join()
function.
Just like regular joins, spatial joins can be inner joins or left joins (the default). However, spatial joins require an additional predicate that determines the type of spatial join. Common values include st_intersects()
, st_contains()
, st_touches()
, etc. Please see help(st_intersects)
for the full list.
For example, a way to find the complete streams that are entirely inside the MacLeish boundary is to join those two layers together. In this case we use the st_within
predicate and set left
to FALSE
.
<- streams %>%
streams_inside st_join(boundary, join = st_within, left = FALSE)
%>%
macleish_map addPolylines(data = streams_inside)
# SAMPLE SOLUTION
<- streams %>%
streams_xing st_join(boundary, join = st_crosses, left = FALSE)
%>%
macleish_map addPolylines(data = streams_xing)
The dplyr
operations group_by()
and summarize()
can also be used to aggregate spatial features. This may change the geometric nature of the features. The default method of aggregation is st_union()
. Thus, for example, a collection of POINT
features will become MULTIPOINT
.
Suppose that we wanted to walk directly from the lowest point at MacLeish to the highest point. Both points are contained in the landmarks
layer.
<- macleish_layers %>%
run_points pluck("landmarks") %>%
filter(str_detect(Label, "Point")) %>%
summarize(N = n())
Note that since summarize()
always condenses things down to one row, run_points
has just one feature, and it is of type MULTIPOINT
.
Unfortunately, leaflet
canโt plot MULTIPOINT
geometries. We want to to show a line that connects the high point and the low point. So we need to convert our MULTIPOINT
feature to a LINESTRING
feature. We do this using the st_cast()
function.
<- run_points %>%
run_linestring st_cast("LINESTRING")
%>%
macleish_map addPolylines(data = run_linestring)
%>%
run_linestring st_length()
group_by()
and summarize()
to compute the total area of each type of forest.# SAMPLE SOLUTION
<- forests %>%
forests_total group_by(forest_type) %>%
summarize(N = n(), total_area = sum(area))
# SAMPLE SOLUTION
%>%
forests_total arrange(desc(total_area))
Red Oak-Hemlock Forest
on a leaflet
map. This should be one MULTIPOLYGON
feature.<- forests_total %>%
red_oak filter(forest_type == "Red Oak-Hemlock Forest")
# SAMPLE SOLUTION
%>%
macleish_map addPolygons(
data = red_oak,
weight = 1,
popup = ~forest_type
)
sf
contains a function called st_interpolate_aw()
that will compute area-weighted interpolations of various quantities. Please explore and use at your own risk.
Please respond to the following prompt on Slack in the #mod-spatial
channel.
Prompt: What questions do you still have about working with spatial data in R? What features would you like to know more about?