::p_load(tmap, tidyverse, sf) pacman
In-Class Exercise 3: Analytical Mapping
1 Importing and loading packages
2 Importing Data
Importing NGA_wp.rds from In-Class Ex02
<- read_rds("data/rds/NGA_wp.rds") NGA_wp
3 Plotting Choropleth Map
Saving maps into object p1 and p2, then plotting the maps
<- tm_shape(NGA_wp) +
p1 tm_fill("wp_functional",
n = 10,
style = "equal",
palette = "Blues") +
tm_borders(lwd = 0.1,
alpha = 1) +
tm_layout(main.title = "Distribution of functional water point by LGAs",
legend.outside = FALSE)
<- tm_shape(NGA_wp) +
p2 tm_fill("total_wp",
n = 10,
style = "equal",
palette = "Blues") +
tm_borders(lwd = 0.1,
alpha = 1) +
tm_layout(main.title = "Distribution of total water point by LGAs",
legend.outside = FALSE)
tmap_arrange(p2, p1, nrow = 1)
4 Choropleth Map for Rates
It is important to map rates rather than counts because water points are not equally distributed in space. If we do not account for how many water points are somewhere, we end up mapping total point size rather than the poic of interest
4.1 Deriving Proportion of Funtional & Non-Functional WP
Mutate() derives the fields pct_functional and pct_nonfunctional
<- NGA_wp %>%
NGA_wp mutate(pct_functional = wp_functional/total_wp) %>%
mutate(pct_nonfunctional = wp_nonfunctional/total_wp)
4.2 Plotting Map of rate
tm_shape(NGA_wp) +
tm_fill("pct_functional",
n = 10,
style = "equal",
palette = "Blues",
legend.hist = TRUE) +
tm_borders(lwd = 0.1,
alpha = 1) +
tm_layout(main.title = "Rate map of functional water point by LGA",
legend.outside = TRUE)
5 Extreme Value Maps
Variations of choropleth maps in which classification is designed to highlight extreme values at lower and upper ends of the scale (goal is to identify outliers).
5.1 Percentile Map
Quantile map with 6 specific categories (0-1%, 1-10%, 10-50%, 50-0%, 90-99%, 99-100%). Corresponding breakpoints are derived by means of the base R quantile command, passing an explicit vector of cumulative probabilities. Begin & end point needs to be included
5.1.1 Data Preparation
Excluding records with NA
<- NGA_wp %>%
NGA_wp drop_na()
Creating customised classification and extracting values
<- c(0, .01, .1, .5, .9, .99, 1)
percent <- NGA_wp["pct_functional"] %>%
var st_set_geometry(NULL)
quantile(var[,1], percent)
0% 1% 10% 50% 90% 99% 100%
0.0000000 0.0000000 0.2169811 0.4791667 0.8611111 1.0000000 1.0000000
When variables are extracted from an sf dataframe, the geometry is extracted as well. For mapping and spatial manipulations this is expected behavior, but many R functions cannot deal with geometry. quantile() will give an error. Hence, st_set_geometry(NULL) is used to drop the geometry field.
5.1.2 Creating Functions
Creating get.var function
This function extracts a variable (e.g. wp_nonfunctional) as a vactor out of an sf dataframe.
arguments: vname: variable name df: (name of the sf dataframe)
returns: v: a vector with values
<- function(vname, df) {
get.var <- df[vname] %>%
v st_set_geometry(NULL)
<- unname(v[,1])
v return(v)
}
Percentile Mapping Function
<- function(vnam, df, legtitle=NA, mtitle ="Percentile Map"){
percentmap <- c(0, .01, .1, .5, .9, .99, 1)
percent <- get.var(vnam, df)
var <- quantile(var, percent)
bperc tm_shape(df) +
tm_polygons() +
tm_shape(df) +
tm_fill(vnam,
title=legtitle,
breaks=bperc,
palette="Blues",
labels=c("<1%", "1%-10%", "10%-50%", "50%-90%", "90%")) +
tm_borders() +
tm_layout(main.title = mtitle,
title.position = c("right", "bottom"))
}
Running the function
percentmap("total_wp", NGA_wp)
5.2 Box Map
An augmented quartile map with an additional lower and upper category. If there are lower outliers, starting point for the breaks is the minimum value, second break is the lower fence.
On the other hand, if there is no lower outliers, the starting point for the breaks is the lower fence, and the second break is the minimum value. There is no observations that fall in the interval between the lower fence and minimum value.
ggplot(data = NGA_wp,
aes(x = "",
y = wp_nonfunctional)) +
geom_boxplot()
To create a box map, custom breaks specifications will be used. However, the break points will vary depending on whether there are lower/upper outliers.
5.2.1 Creatings functions
boxbreaks function
Creating break points for the box map.
It takes in the arguments v (a vector with multiple observations) and mult (multiplier for IQR, 1.5 by default). It returns bb, a vector with 7 break points compute quartile and fences
<- function(v, mult=1.5) {
boxbreaks <- unname(quantile(v))
qv <- qv[4] - qv[2]
iqr <- qv[4] + mult * iqr
upfence <- qv[2] - mult * iqr
lofence
# initialise break points vector
<- vector(mode="numeric", length=7)
bb
# logic for lower and upper fence
if (lofence < qv[1]) { # no lower outliers
1] <- lofence
bb[2] <- floor(qv[1])
bb[else {
} 2] <- lofence
bb[1] <- qv[1]
bb[
}
if (upfence > qv[5]) { # no upper outliers
7] <- upfence
bb[6] <- ceiling(qv[5])
bb[else {
} 6] <- upfence
bb[7] <- qv[5]
bb[
}
3:5] <- qv[2:4]
bb[return(bb)
}
get.var function
<- function(vname,df) {
get.var <- df[vname] %>% st_set_geometry(NULL)
v <- unname(v[,1])
v return(v)
}
Testing the function
<- get.var("wp_nonfunctional", NGA_wp)
var boxbreaks(var)
[1] -56.5 0.0 14.0 34.0 61.0 131.5 278.0
Boxmap function
Function to create box map.
<- function(vnam, df,
boxmap legtitle=NA,
mtitle = "Box Map",
mult = 1.5) {
<- get.var(vnam, df)
var <- boxbreaks(var)
bb tm_shape(df) +
tm_polygons() +
tm_shape(df) +
tm_fill(vnam, title=legtitle,
breaks=bb,
palette="Blues",
labels = c("lower outlier",
"< 25%",
"25% - 50%",
"50% - 75%",
">75%",
"upper outlier")) +
tm_borders() +
tm_layout(main.title = mtitle,
title.position = c("left", "top"))
}
tmap_mode("plot")
boxmap("wp_nonfunctional", NGA_wp)
<- NGA_wp %>%
NGA_wp mutate(wp_functional = na_if(
< 0)) total_wp, total_wp