PPOL 6805 / DSAN 6750: GIS for Spatial Data Science
Fall 2024
Wednesday, September 11, 2024
From the sf
Cheatsheet
sf
and terra
.shp
et al.)A shape“file” is actually (at least) three separate files bundled together:
.shp
: Containing feature geometries.shx
: Positional indices.dbf
: Data attributes.prj
: Coordinate reference system.xml
: MetadataLet’s see what’s inside the shapefile we first saw in Week 1, containing data on DC’s Census Tracts: Census Tracts in 2020
DC Census Tracts (with the Georgetown campus tract highlighted!) from OpenData.DC.gov
From Rodrigue (2016)
.geojson
).csv
my_data.geojson
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[30, 20], [45, 40],
[10, 40], [30, 20]
]
]
},
"properties": {
"color": "green",
"area": 3565747
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[15, 5], [40, 10],
[10, 20], [5, 10],
[15, 5]
]
]
},
"properties": {
"color": "red",
"area": 3272386
}
}
]
}
.gpkg
).tif
or .tiff
)
.nc4
)
EPSG (European Petroleum Survey Group) Registry: Most common way to specify a CRS
PROJ: Rather than opaque numeric code like EPSG, uses plaintext “proj-strings” containing parameter info: datum, ellipsoid, projection, and units (e.g. meters). Example: PROJ4
code EPSG:4326
is represented as
+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
Using rnaturalearth
with mapview
Computing the union of all geometries in the sf
via sf::st_union()
library(leaflet.extras2)
africa_sf <- ne_countries(continent = "Africa", scale = 50)
africa_union_sf <- sf::st_union(africa_sf)
africa_map <- mapview(africa_sf, label="geounit", legend=FALSE)
africa_union_map <- mapview(africa_union_sf, label="st_union(africa)", legend=FALSE)
africa_map | africa_union_map
Use st_union()
first:
Computing the centroid of all geometries in the sf
via sf::st_centroid()
nc <- system.file("shape/nc.shp", package="sf") |>
read_sf() |>
st_transform('EPSG:2264')
gr <- st_sf(
label = apply(expand.grid(1:10, LETTERS[10:1])[,2:1], 1, paste0, collapse = ""),
geom = st_make_grid(nc))
gr$col <- sf.colors(10, categorical = TRUE, alpha = .3)
# cut, to verify that NA's work out:
gr <- gr[-(1:30),]
suppressWarnings(nc_j <- st_join(nc, gr, largest = TRUE))
par(mfrow = c(2,1), mar = rep(0,4))
plot(st_geometry(nc_j), border = 'grey')
plot(st_geometry(gr), add = TRUE, col = gr$col)
text(st_coordinates(st_centroid(st_geometry(gr))), labels = gr$label, cex = .85)
# the joined dataset:
plot(st_geometry(nc_j), border = 'grey', col = nc_j$col)
text(st_coordinates(st_centroid(st_geometry(nc_j))), labels = nc_j$label, cex = .7)
plot(st_geometry(gr), border = '#88ff88aa', add = TRUE)
st_intersects
lengths()
[1] 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0
[39] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2
geounit | num_points | geometry |
---|---|---|
Algeria | 2 | MULTIPOLYGON (((8.576563 36… |
Angola | 2 | MULTIPOLYGON (((13.07275 -4… |
Benin | 0 | MULTIPOLYGON (((1.622656 6…. |
Botswana | 0 | MULTIPOLYGON (((25.25879 -1… |
Burkina Faso | 0 | MULTIPOLYGON (((0.9004883 1… |
Burundi | 0 | MULTIPOLYGON (((30.55361 -2… |
mapview
ggplot2
Since we’re starting to get into data attributes rather than geometric features, switching to ggplot2
is recommended!
library(sf)
polygon <- po <- st_polygon(list(rbind(c(0,0), c(1,0), c(1,1), c(0,1), c(0,0))))
p0 <- st_polygon(list(rbind(c(-1,-1), c(2,-1), c(2,2), c(-1,2), c(-1,-1))))
line <- li <- st_linestring(rbind(c(.5, -.5), c(.5, 0.5)))
s <- st_sfc(po, li)
par(mfrow = c(3,3))
par(mar = c(1,1,1,1))
# "1020F1102"
# 1: 1
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("I(pol)",intersect(),"I(line) = 1")))
lines(rbind(c(.5,0), c(.5,.495)), col = 'red', lwd = 2)
points(0.5, 0.5, pch = 1)
# 2: 0
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("I(pol)",intersect(),"B(line) = 0")))
points(0.5, 0.5, col = 'red', pch = 16)
# 3: 2
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("I(pol)",intersect(),"E(line) = 2")))
plot(po, col = '#ff8888', add = TRUE)
plot(s, col = c(NA, 'darkgreen'), border = 'blue', add = TRUE)
# 4: 0
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("B(pol)",intersect(),"I(line) = 0")))
points(.5, 0, col = 'red', pch = 16)
# 5: F
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("B(pol)",intersect(),"B(line) = F")))
# 6: 1
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("B(pol)",intersect(),"E(line) = 1")))
plot(po, border = 'red', col = NA, add = TRUE, lwd = 2)
# 7: 1
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("E(pol)",intersect(),"I(line) = 1")))
lines(rbind(c(.5, -.5), c(.5, 0)), col = 'red', lwd = 2)
# 8: 0
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("E(pol)",intersect(),"B(line) = 0")))
points(.5, -.5, col = 'red', pch = 16)
# 9: 2
plot(s, col = c(NA, 'darkgreen'), border = 'blue', main = expression(paste("E(pol)",intersect(),"E(line) = 2")))
plot(p0 / po, col = '#ff8888', add = TRUE)
plot(s, col = c(NA, 'darkgreen'), border = 'blue', add = TRUE)
equals
corresponds to the DE-9IM string "T*F**FFF*"
. If any two geometries obey this relationship, they are (topologically) equal!PPOL 6805 Week 3: Unary Operations