Search code examples
rmapsscientific-computinggeographytmap

Smoothing map with elevation levels; R with tmap


I am creating a map for a scientific manuscript. The map should show a basic map of Mexico, with the sampling sites and display elevation level colours. For this, I am using R with the package tmap. This is my code:

library(sf)
library(raster)
library(dplyr)
library(spData)
library(spDataLarge)
library(tmap)    # for static and interactive maps

data(World)
data("metro")
data("land")

gpsdata <- read.csv('gps.csv')
gpsdata <- as.matrix(gpsdata)
gpspoints <- SpatialPoints(gpsdata)
plot(gpspoints)

gpsnames <- read.csv('gps_names.csv')

spdf = SpatialPointsDataFrame(gpsdata,gpsnames)

proj4string(gpspoints) <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")
proj4string(spdf) <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")

pdf('fig-sampling.pdf')
tm_shape(World[World$name=="Mexico", ]) + 
  tm_polygons() +
tm_shape(land) +
  tm_raster("elevation", breaks=c(-Inf, 250, 500, 1000, 1500, 2000, 2500, 3000, 4000, Inf),  
            palette = terrain.colors(9), title="Elevation") +
tm_shape(World) +
  tm_borders("black", lwd = 1) +
  tm_text("name") +
tm_layout(legend.position = c("right","center"),
          legend.bg.color = "lightblue", bg.color = 'lightblue') +
tm_shape(metro) +
  tm_bubbles("pop2020", title.size = "Population") +
  tm_text("name", size = "pop2010", legend.size.show = FALSE, root=8, size.lowerbound = 0.7, just = 'right', xmod = -0.5, ymod = 0)+
  tm_grid(projection="longlat", labels.size = .5) +
tm_shape(spdf) +
  tm_bubbles(col = 'blue', size = 0.3) +
  tm_text("Location", size = 0.8, just = 'left', xmod = 0.3)
dev.off()

Unfortunately, the elevation layer is drawn in very large pixels:

map with elevations; created with R/tmap.

Is there any way to smooth (I already tried style = 'cont' for the elevation raster layer)?


Solution

  • The easiest way to do something that looks smooth is to interpolate it using disaggregate from the raster package.

    This makes the raster bigger by a given factor, and interpolates the pixel values this affecting a smooth. But a bigger raster for the whole world might be too much for your computer (it is mine) so crop first down to Mexico.

    The World data is in a different coordinate system to the land so you will have to transform it to the land coordinates for the crop:

    > land = crop(land, st_transform(World[World$name=="Mexico",],crs(land)))
    > plot(land)
    

    That should show just Mexico, but still blocky.

    > land = disaggregate(land, 4, "bilinear")
    > plot(land)
    

    That should show Mexico, but smooth. Note the interpolated values can seem to have artefacts and shouldn't be used for analysis, they just look a bit prettier.

    If you want to do analysis, 30-metre resolution elevation data is available via the SRTM data set and other global DEM data sets.