I would like to use the tmap package to create an extent indicator inset map to show a zoomed-out view of the area. However, I'm having trouble controlling the frame and size of the inset map. In the example below, I have tried changing a range of options that seem like they should impact the issue. However, I still cannot get the inset area to be tight to the inset map and change things like the size without margins/padding affecting placement, even though I can make those components invisible, they are still affecting the overall layout.
library(sf)
library(tmap)
library(tidyverse)
library(maptiles)
library(tmaptools)
nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
nc_sub <- nc %>%
filter(NAME %in% c("Clay"))
nc_sub_bound <- nc_sub %>%
st_bbox() %>%
st_as_sfc() %>% st_as_sf()
nc_basemap <- get_tiles(nc,
provider = "Esri.WorldTopoMap" ,
crop = T,
zoom = 8)
nc_sub_basemap <- get_tiles(nc_sub,
provider = "Esri.WorldTopoMap" ,
crop = T,
zoom = 12)
# no customisation --------------------------------------------------------
nc_sub_map_raw <- tm_shape(nc_sub_basemap) + tm_rgb(options = tmap:::opt_tm_rgb(interpolate = T)) +
tm_shape(nc_sub) + tm_polygons(fill_alpha = 0, lwd = 2)
nc_map_raw <- tm_shape(nc_basemap) +
tm_rgb(options = tmap:::opt_tm_rgb(interpolate = T)) +
tm_shape(nc) + tm_polygons(fill_alpha = 0) +
tm_shape(nc_sub_bound) +
tm_borders(col =
"red", lwd = 2)
#does not work need to convert to grob
nc_sub_map_raw+
tm_inset(nc_map_raw)
inset_grob_raw <- tmap_grob(nc_map_raw)
#draws maps but mismatch on frame and inset
nc_sub_map_raw+
tm_inset(inset_grob_raw, position = c("right", "top"))
# change options -----------------------------------------------------------
#remove all margins and set aspect ratio explicitly on the maps
nc_sub_map <- tm_shape(nc_sub_basemap) + tm_rgb(options = tmap:::opt_tm_rgb(interpolate = T)) +
tm_shape(nc_sub) + tm_polygons(fill_alpha = 0, lwd = 2)+
tm_layout(margins = c(0, 0, 0, 0),
outer.margins = c(0, 0, 0, 0),
inner.margins = c(0, 0, 0, 0),
asp=get_asp_ratio(nc_sub))
nc_map <- tm_shape(nc_basemap) +
tm_rgb(options = tmap:::opt_tm_rgb(interpolate = T)) +
tm_shape(nc) + tm_polygons(fill_alpha = 0) +
tm_shape(nc_sub_bound) +
tm_borders(col =
"red", lwd = 2) +
tm_layout(margins = c(0, 0, 0, 0),
outer.margins = c(0, 0, 0, 0),
inner.margins = c(0, 0, 0, 0),
asp=get_asp_ratio(nc))
inset_asp <- get_asp_ratio(nc_map)
inset_grob <- tmap_grob(nc_map)
#still has larger frame
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"))
#gets rid of frame but causes issues if resizing due to margins? only makes frame and backgroupd invisible but still impacting layout
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"), frame.lwd = NA, bg.alpha = 0)
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"), frame.lwd = NA, bg.alpha = 0, height=10, width = 10*inset_asp)
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"), frame.lwd = 1, bg.alpha = 0, height=10, width = 10*inset_asp)# same but turning frame back on to show being moved around
# trying different options ------------------------------------------------
#setting margins to zero does not affect in inset call
nc_sub_map+
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"), frame.lwd = 1, bg.alpha = 0, height=10, width = 10*inset_asp, margins = c(0, 0, 0, 0), between_margin = c(0, 0, 0, 0))
#layout options also not fixing
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"), frame.lwd = 1, bg.alpha = 0, height=10, width = 10*inset_asp, margins = c(0, 0, 0, 0), between_margin = c(0, 0, 0, 0))+
tm_layout(inset_grob.height = 10, inset_grob.width = 10*5, inset_map.height = 10, inset_map.width = 10*inset_asp,inset.margins=c(0,0,0,0), inset.in = 0)
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"), frame.lwd = 1, bg.alpha = 0, margins = c(0, 0, 0, 0), between_margin = c(0, 0, 0, 0))+
tm_layout(inset_grob.height = 10, inset_grob.width = 10*inset_asp)
nc_sub_map+
tm_inset(inset_grob, position = c("right", "top"), frame.lwd = 1, bg.alpha = 0, margins = c(0, 0, 0, 0), between_margin = c(0, 0, 0, 0))+
tm_layout(inset_grob.height = 10, inset_grob.width = 10*inset_asp, inset_map.margins = c(0, 0, 0, 0), inset_map.frame = F, inset.frame = F, inset.margins = c(0, 0, 0, 0), inset.between_margin = c(0, 0, 0, 0), inset_map.between_margin = c(0, 0, 0, 0))
# Save final map with inset
final_map <- nc_sub_map +
tm_inset(inset_grob, position = c("right", "top"),
frame.lwd = 1, bg.alpha = 0,
height = 10, width = 10 * inset_asp)
# Save to file
tmap_save(final_map, filename = "nc_map_with_inset.png", width = 10, height = 10, units = "in", dpi = 300)
You can use magick
package to remove empty margins from the final file and add a customized border. Also you can make use of viewport
and tmap_save
to save the map with the inset in a single file (and control inset position).
library(grid)
library(magick)
# Save map with inset
tmap_save(nc_sub_map_raw,
filename = "map1.png",
dpi = 300,
insets_tm = nc_map_raw,
insets_vp = viewport(x = 0.97,
y = 0.78,
width = 0.2,
height = 0.2,
just = c("right", "top")),
height = 15,
width = 20,
units = "cm")
# Trim empty spaces
map1 <- image_read("map1.png")
map1 <- image_trim(map1)
# Add 20 px border in white
map1 <- image_border(map1, "#FFFFFF", "20x20")
# Save final map
image_write(map1,
path = "map1.png",
format = "png")