Skip to Content
Course content

110: Working with sf Package for Spatial Data

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you have a physical paper map of your city spread out on a table. On top of that map, you place a few transparent sheets of acetate. On the first sheet, you've traced the boundaries of every neighborhood in ink. On the second sheet, you've put a red dot for every coffee shop. On the third, you've drawn the paths of the subway lines.

When you look down through all three sheets, you aren't just looking at lists of names or coordinates; you're seeing relationships. You can instantly see which coffee shops are inside which neighborhood, or which subway stations are within a five-minute walk of a cafe. The sf (Simple Features) package in R does exactly this. It treats spatial data as a data frame where one special column—the geometry column—acts as those transparent overlays, allowing you to perform "spatial" logic instead of just "tabular" logic.

Turning Rows into Shapes

In the past, R handled spatial data using complex objects like SpatialPolygonsDataFrame. It was clunky. The sf package changed the game by making spatial data behave like a standard tibble. If you know how to use dplyr, you already know 80% of sf.

Let's say you have a CSV of city landmarks with longitude and latitude. To make this "spatial," you use st_as_sf(). This tells R: "Stop treating these numbers as just columns of data, and start treating them as a single point on a sphere."

library(sf)

# Imagine 'landmarks_df' is a regular data frame with 'lon' and 'lat' columns
landmarks_sf <- st_as_sf(landmarks_df, coords = c("lon", "lat"), crs = 4326)

The crs = 4326 part is crucial. It's the "GPS standard" (WGS84). Without it, R knows where the points are relative to each other, but it doesn't know where they are on Earth.

The Headache of Coordinate Reference Systems

This is where most people get stuck, and I've spent more hours than I'd like to admit debugging this. The Earth is a sphere (roughly), but your screen is flat. To map a sphere onto a flat surface, we use projections. This is what a Coordinate Reference System (CRS) is.

If you try to calculate the distance between two points using degrees (latitude/longitude), your answer will be in decimal degrees, which is useless for measuring a walk to a coffee shop. To get meters or feet, you have to "transform" your data to a projected coordinate system using st_transform().

# Transform from global GPS (4326) to a specific local projection (e.g., UTM)
# This allows us to calculate distance in meters
landmarks_projected <- st_transform(landmarks_sf, crs = 32610) 

Always check that your layers have the same CRS before you try to combine them. If you try to join a layer in EPSG:4326 with one in EPSG:3857, sf will throw an error because it's like trying to overlay a map of the world on a map of a city without scaling them first.

Asking Spatial Questions

Once your data is in sf format and projected correctly, you can stop thinking about coordinates and start thinking about geometry. The st_ prefix is your best friend here.

Want to know which landmarks are inside a specific park boundary? You use st_intersects(). Want to find everything within 500 meters of a subway stop? You create a "buffer" (a circle around the point) using st_buffer() and then check for intersections.

# Create a 500m buffer around subway stations
station_buffers <- st_buffer(subway_sf, dist = 500)

# Find landmarks that fall within those buffers
accessible_landmarks <- st_intersects(landmarks_sf, station_buffers)

I love the way sf integrates with ggplot2. You don't need a separate mapping library for basic visuals; just use geom_sf(). It automatically reads that geometry column and draws the shapes for you.




📋 Practical Task

Analyzing Urban Green Space Access in Chicago

You have been provided with two datasets: chicago_parks.rds (polygons of city parks) and chicago_libraries.rds (points representing public libraries). Your goal is to identify which libraries are "underserved" by being located outside of a 1-kilometer buffer of any city park.

Your requirements:

  • Load both datasets using readRDS().
  • Ensure both objects are transformed to a projected CRS suitable for Chicago (use EPSG: 6420) so that distance calculations are in meters.
  • Create a 1,000-meter buffer around all park polygons.
  • Use a spatial predicate (like st_intersects or st_within) to determine which libraries fall outside of these park buffers.
  • Create a final data frame containing only the names of the libraries that are not within 1km of a park.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.