1
votes

I'm trying to crop a heat map (or "geom_tile") within a geographical boundary.

I define a random data frame for a heat-map along longitude and latitude coordinates.

set.seed(20)
lon = seq(from = 3.4, to = 6.3, by = 0.1)
lat = seq(from = 13.3, to = 10.1, by = -0.1)

lati <- c()
long <- c()
for (i in 1:length(lat)) {
  for (j in 1:length(lon)) {
    lati <- c(lati,lat[i])
    long <- c(long,lon[j])
  }
}

vals = rnorm(length(lati))

df <- data.frame(
longitude=long,
latitude=lati,
value=vals)

Then I make geographical boundary, specifically for Kebbi state in Nigeria.

library(raster)
library(sf)
nga <- getData('GADM', country='NGA', level=1)
keb <- subset(nga,NAME_1 %in% "Kebbi")
keb2 <- st_as_sf(keb)

Then I combine the heat map and geographical boundaries:

library(ggplot2)
tilekeb <- ggplot() + geom_tile(data=df,aes(x=longitude,y=latitude,fill=vals),alpha=1/2,color="black",size=0) +
  geom_sf(data = keb2, inherit.aes = FALSE, fill = NA)

This yields: enter image description here

My aim is cut-out (crop) the part that is outside the boundary, leaving the heatmap only within the confined geographical boundary. Does anybody have ideas on how to do that in R/ggplot?

Thank you

1
loosely related- just the other way round. stackoverflow.com/a/59958366/7941188 - tjebo
Of another note - check burns-stat.com/pages/Tutor/R_inferno.pdf - circle 2. Avoid growing objects by predefining your vector in the right length (or much longer), in this case e.g. with lati <- numeric(length(lon) *length(lat)) - tjebo

1 Answers

2
votes

I actually used raster to do the job

# create spatial points data frame from your df
spg <- df
coordinates(spg) <- ~ longitude + latitude
# coerce to SpatialPixelsDataFrame
gridded(spg) <- TRUE
# coerce to raster
rasterDF <- raster(spg)
# then I crop
plot(rasterDF)
rasterDF_crop <- crop(rasterDF, extent(keb2))
plot(rasterDF_crop)
rasterDF_masked <- mask(rasterDF_crop, keb2)
plot(rasterDF_masked)

then I convert it back to a dataframe :

df_masked <- raster::as.data.frame(rasterDF_masked,xy=TRUE)
colnames(df_masked) <- colnames(df)

and use your code to plot it again

library(ggplot2)
tilekeb <- ggplot() + geom_tile(data=df_masked,aes(x=longitude,y=latitude,fill=value),alpha=1/2,color="black",size=0) +
  geom_sf(data = keb2, inherit.aes = FALSE, fill = NA)

tilekeb