Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a basemap to a tmap plot in R?

Tags:

r

tmap

I'm wondering whether it is possible to add a basemap to a map made in tmap when the tmap mode is set to plot and not interactive mode.

This is the code I have used to produce my map

library(sf)

library(spData)

library(tmap)

tm_shape(nz) +
  tm_polygons(
    "Median_income",
    palette = "Blues",
    n = 10,
  ) +
  tm_layout(basemaps = leaflet::providers$OpenStreetMap)

With this code I can view the basemap whilst it is in Plot as I would just like to visualize New Zealand and not the surrounding ocean.

This is the map my code produces enter image description here

like image 593
T.2001 Avatar asked Jul 05 '19 12:07

T.2001


3 Answers

There are at least two ways:

Using tmaptools:

Via the read_osm function in tmaptools which uses the OpenStreetMap package to get tiles. Example here ripped straight from the docs:

> library(tmaptools)
> library(tmap)
Warning message:
replacing previous import ‘gdalUtils::gdal_rasterize’ by ‘sf::gdal_rasterize’ when loading ‘mapview’ 
> data(NLD_muni)
> osm_NLD <- read_osm(NLD_muni, ext=1.1)
> tm_shape(osm_NLD) + tm_rgb()
> 

map image

Note you should modify your mapping chain if you want to do an interactive web-browser map by removing this rgb layer and adding a standard basemap layer.

Or alternatively:

Using rosm.

Call osm.raster to get a raster image given a spatial object. Will reproject the raster to the source coordinate system.

> bg = osm.raster(NLD_muni)
Zoom: 8
> bg
class      : RasterBrick 
dimensions : 1046, 1074, 1123404, 3  (nrow, ncol, ncell, nlayers)
resolution : 373, 372  (x, y)
extent     : -28610.91, 371991.1, 303384.1, 692496.1  (xmin, xmax, ymin, ymax)
crs        : +init=epsg:28992 +proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.4171,50.3319,465.5524,-0.398957388243134,0.343987817378283,-1.87740163998045,4.0725 +units=m +no_defs 
source     : memory
names      :   layer.1,   layer.2,   layer.3 
min values : -6.848990, 41.156879,  1.062173 
max values :  266.3927,  290.5641,  263.3747 

This will not quite work with tm_rgb() yet because the min-max values are outside 0-255 for some of the layers. I think this is because the projection function used internally is doing an interpolation that is extrapolating in places. Fix roughly with:

> bg[bg[]>255]=255
> bg[bg[]<0]=0

Then you can

> tm_shape(bg) + tm_rgb() + tm_shape(NLD_muni) + tm_borders()

note the projection results in a non-square raster so there's NA values around it.

enter image description here

like image 145
Spacedman Avatar answered Sep 20 '22 14:09

Spacedman


As per the {tmap} documentation the basemap feature is available only in view mode https://www.rdocumentation.org/packages/tmap/versions/2.2/topics/tm_basemap

This seems logical, as the basemap comes not from directly tmap, but from the leaflet js package.

If you absolutely positively require a basemap for a static r plot you should be able to get one via {ggplot} / {ggmap} workflow (eg. ggmap::get_stamenmap() + usual ggplot techniques).

like image 25
Jindra Lacko Avatar answered Sep 19 '22 14:09

Jindra Lacko


The ceramic package provides a great solution for this. You can produce basemaps via Mapbox, which requires you to register but they offer a generous free tier so you shouldn't need to pay anything.


library(sf)
library(spData)
library(tmap)
library(ceramic)

basemap <- cc_location(loc=nz, max_tiles = 4,
                       base_url = "https://api.mapbox.com/styles/v1/mdsumner/cjs6yn9hu0coo1fqhdqgw3o18/tiles/512/{zoom}/{x}/{y}")


tm_shape(basemap) +
  tm_rgb() +
  tm_shape(nz) +
  tm_polygons(
    "Median_income",
    palette = "Blues",
    n = 10,
    alpha = 0.3
  ) 

Created on 2020-05-04 by the reprex package (v0.3.0)

like image 23
Michael Harper Avatar answered Sep 19 '22 14:09

Michael Harper