rgdal
: interface between R and GDAL (Geospatial Data Abstraction Library) and PROJ4 libraries: raster / vector geospatial data formats and coordinate transformation.
sp
: classes and methods for spatial data in R.
rgeos
: interface between R and GEOS (Geometry Engine - Open Source) library: area, perimeter, distances, dissolve, buffer, overlap, union, contains…
These packages are still widely used.
sf
Website: Simple Features for R
First release: October 20, 2016
sp
, rgeos
and rgdal
functionnalities in one package.
Easier data handling, simpler objects.
Tidy data: compatibility with the pipe synthax and tidyverse
operators.
Main author and maintainer: Edzer Pebesma (also sp
author)
sf objects data structure:
sf
Reading layer `martinique' from data source `/home/tim/Documents/prz/flo/lecture/data/mtq/martinique.shp' using driver `ESRI Shapefile'
Simple feature collection with 34 features and 23 fields
geometry type: POLYGON
dimension: XY
bbox: xmin: 690574.4 ymin: 1592426 xmax: 736126.5 ymax: 1645660
epsg (SRID): 32620
proj4string: +proj=utm +zone=20 +datum=WGS84 +units=m +no_defs
Units: m
[,1] [,2] [,3] [,4] [,5]
[1,] 0.000 35297.56 3091.501 12131.617 17136.310
[2,] 35297.557 0.00 38332.602 25518.913 18605.249
[3,] 3091.501 38332.60 0.000 15094.702 20226.198
[4,] 12131.617 25518.91 15094.702 0.000 7177.011
[5,] 17136.310 18605.25 20226.198 7177.011 0.000
Simple union:
mtq_u <- st_union(mtq)
plot(st_geometry(mtq), col="lightblue")
plot(st_geometry(mtq_u), add=T, lwd=2, border = "red")
Aggregation according to a grouping variable:
google: “st_voronoi R sf” (https://github.com/r-spatial/sf/issues/474 & https://stackoverflow.com/questions/45719790/create-voronoi-polygon-with-simple-feature-in-r)
CRAN task views aim to provide some guidance which packages on CRAN are relevant for tasks related to a certain topic.
CRAN Task View: Analysis of Spatial Data:
Several solutions are available:
ggplot2
users can have a look to ggplot2
mapping features (geom_sf) that can mix nicely with ggspatial
.tmap
cartography
is based on base graphics and allow most of basic and advanced cartographic representations.cartography
.Here we will focus on cartography
and do small examples with ggplot2
.
cartography
library(sf)
# Import geo layers
## Communes of Seine Maritime
sm <- st_read(dsn = "data/dep76/seine_maritime.geojson", stringsAsFactors = F, quiet=TRUE)
## French departements
dep <- st_read(dsn = "data/dep76/dep.geojson", stringsAsFactors = F, quiet=TRUE)
# change projection (lambert93)
sm <- st_transform(sm, 2154)
dep <- st_transform(dep, 2154)
# Import dataset
csp <- read.csv("data/dep76/data_seine_maritime.csv")
# merge geolayer and dataset
sm <- merge(sm, csp, by="INSEE_COM", all.x=TRUE)
# (Very) simple map
library(cartography)
plot(st_geometry(sm))
propSymbolsLayer(sm, var = "act")
title("Active Population")
# Custom map of active population
par(mar=c(0.2,0.2,1.4,0.2))
bb <- st_bbox(sm)
# the bbox is used to center the map on the Seine Maritime depatement
plot(st_geometry(dep), col = "ivory", border="ivory3", bg="azure",
xlim = bb[c(1,3)], ylim = bb[c(2,4)])
plot(st_geometry(sm), col="cornsilk2", border = NA, lwd = 0.5, add=T)
propSymbolsLayer(sm, var = "act", col="darkblue", inches = 0.6,
border = "white", lwd=0.7, symbols = "square",
legend.style = "e", legend.pos="topleft",
legend.title.txt = "Labor Force\n(2014)",
legend.values.rnd = 0)
# Scale Bar
barscale(size = 10)
# North Arrow
north(pos = "topright", col = "darkblue")
# Full layout
layoutLayer(title = "Workforce in Seine-Maritime",
sources = "Insee, 2018", author = "Kim & Tim, 2018",
col = "darkblue", coltitle = "white", tabtitle = TRUE,
frame = TRUE, scale = NULL, north = FALSE)
# To display qualitative data
# modalities
mod <- c("agr", "art", "cad", "int", "emp", "ouv")
# labels in the legedn
modlab <- c("Agriculteurs", "Artisans","Cadres", "Prof. Inter.", "Employés", "Ouvriers")
# colors
cols <- c("#e3b4a2", "#a2d5d6", "#debbd4", "#b5dab6", "#afc2e3", "#e9e2c1")
par(mar=c(0.2,0.2,1.4,0.2))
plot(st_geometry(dep), col = "ivory", border="ivory3", bg="azure",
xlim = bb[c(1,3)], ylim = bb[c(2,4)])
typoLayer(sm, var = "cat",
border = "ivory", lwd = 0.5,
legend.values.order = mod,
col = cols,
add=TRUE, legend.pos = "n")
# functions are dedicated to legend display
legendTypo(title.txt = "Dominant Socio-Professional\nCategory",
col = cols,
categ = modlab,
nodata = F)
barscale(size = 10)
north(pos = "topright", col = "darkblue")
layoutLayer(title = "Workforce Distribution in Seine-Maritime",
sources = "Insee, 2018", author = "Kim & Tim, 2018",
col = "darkblue", coltitle = "white", tabtitle = TRUE,
frame = TRUE, scale = NULL, north = FALSE)
# Compute the share of "managers" in the active population
sm$pcad <- 100 * sm$cad / sm$act
# The getBreaks() function is used to classify the variable
bks <- getBreaks(v = sm$pcad, method = "quantile", nclass = 6)
# The carto.pal() function give access to various cartographic color palettes
cols <- carto.pal("green.pal", 3,"wine.pal",3)
# Create the map
par(mar=c(0.2,0.2,1.4,0.2))
plot(st_geometry(dep), col = "ivory", border="ivory3", bg="azure",
xlim = bb[c(1,3)], ylim = bb[c(2,4)])
choroLayer(sm, var = "pcad", breaks = bks,
col = cols, border = "grey80",
legend.values.rnd = 1,
lwd = 0.4, legend.pos = "topleft",
legend.title.txt = "Share of managers (%)", add=T)
# Add a layout
layoutLayer(title = "Managers",
sources = "Insee, 2018", author = "Kim & Tim, 2018",
theme = "green.pal",
col = "darkred", coltitle = "white",
tabtitle = TRUE,
frame = TRUE, scale = 10)
north(pos = "topright")
We could create the same map on a cartogram based on the active population stock.
library(cartogram)
sm_c1 <- cartogram_cont(sm, "act", 3)
par(mar=c(0.2,0.2,1.4,0.2))
plot(st_geometry(dep), col = "ivory", border="ivory3", bg="azure",
xlim = bb[c(1,3)], ylim = bb[c(2,4)])
choroLayer(sm_c1, var = "pcad", breaks = bks,
col = cols, border = "grey80",
legend.values.rnd = 1,
lwd = 0.4, legend.pos = "topleft",
legend.title.txt = "Share of managers (%)", add=T)
# Add a layout
layoutLayer(title = "Managers",
sources = "Insee, 2018", author = "Kim & Tim, 2018",
theme = "green.pal",
col = "darkred", coltitle = "white",
tabtitle = TRUE,
frame = TRUE, scale = 10)
north(pos = "topright", south = TRUE)
These maps may allow to hide or, at least, diminish the MAUP.
# Create a grid based on sm (cell area = 4 square km)
grid <- getGridLayer(x = sm, cellsize = 4000*4000,
type = "regular", var = c('cad', 'act'))
# Compute the share of managers
grid$pcad <- 100 * grid$cad / grid$act
# Display the map as choropleth layer
par(mar=c(0.2,0.2,1.4,0.2))
plot(st_geometry(dep), col = "ivory", border="ivory3", bg="azure",
xlim = bb[c(1,3)], ylim = bb[c(2,4)])
choroLayer(grid, var = "pcad", breaks=bks,
col = cols, border = "grey80",
lwd = 0.4, legend.pos = "topleft",
legend.title.txt = "Share of managers\n(en %)", add=T)
layoutLayer(title = "Managers",
sources = "Insee, 2018", author = "Kim & Tim, 2018",
theme = "green.pal",
col = "darkred", coltitle = "white",
tabtitle = TRUE,
frame = TRUE, scale = 10)
north(pos = "topright")
It is also possible to create hexagonal grids.
# Create a grid based on sm (cell area = 4 square km)
grid2 <- getGridLayer(x = sm, cellsize = 4000*4000,
type = "hexagonal", var = c('cad', 'act'))
# Compute the share of managers
grid2$pcad <- 100 * grid2$cad / grid2$act
# Display the map as choropleth layer
par(mar=c(0.2,0.2,1.4,0.2))
plot(st_geometry(dep), col = "ivory", border="ivory3", bg="azure",
xlim = bb[c(1,3)], ylim = bb[c(2,4)])
choroLayer(grid2, var = "pcad", breaks=bks,
col = cols, border = "grey80",
lwd = 0.4, legend.pos = "topleft",
legend.title.txt = "Share of managers\n(en %)", add=T)
layoutLayer(title = "Managers",
sources = "Insee, 2018", author = "Kim & Tim, 2018",
theme = "green.pal",
col = "darkred", coltitle = "white",
tabtitle = TRUE,
frame = TRUE, scale = 10)
north(pos = "topright")
smoothLayer()
uses functions from package SpatialPosition
to computes Stewart’s potentials of population.
The computation of potentials could be considered as a spatial interpolation method such as inverse distance weighted interpolation (IDW) or kernel density estimator. These models aim to estimate unknown values of non-observed points from known values given by measure points. Cartographically speaking, they are often used to get a continuous surface from a set of discrete points. However, Stewart model is mainly a spatial interaction modeling approach, with a possible secondary use for spatial interpolation.
grid$cad100 <- grid$cad * 100
par(mar=c(0.2,0.2,1.4,0.2), bg="azure")
plot(st_geometry(dep), col = "ivory", border="ivory3",
xlim = bb[c(1,3)], ylim = bb[c(2,4)])
smoothLayer(x = grid, var = "cad100", var2 = "act",
typefct = "exponential",
span = 4000, beta = 2, breaks = bks, col = cols,
legend.pos = "topleft", mask = st_buffer(sm, 0),
legend.values.rnd = 2,
legend.title.txt = "Share of managers* (%)",
border = "grey90", lwd = 0.2, add=T)
layoutLayer(title = "Managers",
sources = "Insee, 2018", author = "Kim & Tim, 2018",
theme = "green.pal",
col = "darkred", coltitle = "white",
postitle = "center",
frame = TRUE, scale = 10)
north(pos = "topright")
text(x = 488000, y = 6921000,adj = 0,
font = 3, cex = 0.8,
labels = "* Potential smoothing\n exponential function\n span = 4 km, beta = 2")
ggplot2
library(ggplot2)
ggplot() +
geom_sf(data = dep, colour = "ivory3",fill = "ivory") +
geom_sf(data = sm %>% st_centroid(),
aes(size= act), colour="#E84923CC", show.legend = 'point') +
scale_size(name = "Active population",
breaks = c(100,1000,10000),
range = c(0,20)) +
coord_sf(crs = 2154, datum = NA,
xlim = st_bbox(sm)[c(1,3)],
ylim = st_bbox(sm)[c(2,4)]
) +
theme_minimal() +
theme(panel.background = element_rect(fill = "azure",color=NA)) +
labs(title = "Active population",
caption = "Insee, 2018\nKim & Tim, 2018")
ggplot() +
geom_sf(data = dep, colour = "ivory3",fill = "ivory") +
geom_sf(data = sm, aes(fill = pcad), colour = "grey80") +
scale_fill_gradientn(name = "Share of managers (%)",
colours = carto.pal("green.pal", 3,"wine.pal",3),
values=bks/max(bks))+
coord_sf(crs = 2154, datum = NA,
xlim = st_bbox(sm)[c(1,3)],
ylim = st_bbox(sm)[c(2,4)]
) +
theme_minimal() +
theme(panel.background = element_rect(fill = "azure",color=NA)) +
labs(title = "Managers",
caption = "Insee, 2018\nKim & Tim, 2018")
See file “data/paris13/data_prep.R” for data extraction.
# spatial data management
library(sf)
# cartography
library(cartography)
# Load data
adm <- readRDS("data/paris13/iris_p13.rds")
feat_sir <- readRDS("data/paris13/sir_p13.rds")
feat_osm <- readRDS("data/paris13/osm_p13.rds")
# Define margins
par(mar = c(0,0,1.2,0), mfrow = c(1,2))
# Plot the maps
plot(st_geometry(adm), col = "ivory1", border = "ivory3",lwd =0.5,bg = "#FBEDDA")
plot(st_geometry(feat_sir), col = "red", pch = 20, add=T, cex = 0.5)
layoutLayer(title = "SIR", sources=paste0(nrow(feat_sir), " restaurants"),
author="Kim & Tim, 2018", scale = NULL, frame=FALSE, tabtitle = TRUE)
legend(x = "topright", legend = "= 1 restaurant", pch = 20, pt.cex = 0.5,
bty = "n",cex = 0.7, col = "red")
plot(st_geometry(adm), col = "ivory1", border = "ivory3",lwd =0.5,bg = "#FBEDDA")
plot(st_geometry(feat_osm), col = "red", pch = 20, add=T, cex = 0.5)
layoutLayer(title = "OSM", sources=paste0(nrow(feat_osm), " restaurants"),
author="Kim & Tim, 2018",scale = .5, north = T, frame=FALSE,
tabtitle = TRUE)