Search code examples
rmappingshapefiler-sftmap

Zoom in rectangularly in map


I'm trying to have a rectangular "zoom in" into my chart. So far, I can create the chart itself and a smaller version, but I haven't figured out how to zoom in rectangularly.

(Builds on 1 and 2)

library(sf)
library(dplyr)
library(tmap)

Get shape files for Germany [55 MB]. In Germany zip codes are called Postleitzahlen (PLZ).

germany <- read_sf("data/OSM_PLZ.shp")

Create some arbitrary groups:

germany <- germany %>% 
  mutate(plz_groups = case_when(
    substr(plz, 1, 1) == "1" ~ "Group A",
    substr(plz, 2, 2) == "2" ~ "Group B",    
    substr(plz, 3, 3) == "2" ~ "Group C",    
    TRUE ~ "Group X" # rest
  ))

Make plot filling by PLZ:

map_de <- tm_shape(germany) +
  tm_fill(col = "plz_groups") 

map_de

enter image description here

germany_zoomin <- germany %>% 
  filter(substr(plz, 1, 1) == "4")
map_zoomin <-  tm_shape(germany_zoomin) +
  tm_fill(col = "plz_groups") 

So I can create a zoomed in chart, but this is NOT what I want:

map_zoomin

print(map_de, vp = grid::viewport(0.8, 0.185, width = 0.2, height = 0.45))
# tmap_save("test.png")

enter image description here

Instead, I would like to specify the location, e.g. the PLZ of Cologne (50667) and draw a rectangular box around it.


Solution

  • Do you mean something like the following? For Cologne I created some dummy values and added the postal codes as text to show where the reference postal code is located. Furthermore, I added a small rectangle that shows the zoom-in area in the Germany main map (only visible as small black polygon):

    library(tidyverse)
    library(sf)
    library(tmap)
    library(tmaptools)
    
    germany <- read_sf("data/OSM_PLZ.shp")
    
    germany <- germany %>% 
      mutate(plz_groups = case_when(
        substr(plz, 1, 1) == "1" ~ "Group A",
        substr(plz, 2, 2) == "2" ~ "Group B",    
        substr(plz, 3, 3) == "2" ~ "Group C",    
        TRUE ~ "Group X" # rest
      ))
    
    # take reference postal code in cologne
    cologne_plz_target <- germany %>% 
      filter(plz == "50667")
    
    # get content within bounding box defined around target postal code
    cologne_bbox = st_as_sfc(bb(st_bbox(cologne_plz_target), ext = 5))
    
    # convert bounding box to spatial object
    cologne_rect <- bb_poly(cologne_bbox)
    
    map_de <- tm_shape(germany) +
      tm_fill(col = "plz_groups") +
      tm_shape(cologne_rect) + # add zoom in area to main map
      tm_polygons(col = "black")
    
    # all cologne postal codes with dummy values
    cologne_plz_all <- germany %>% 
      filter(ort == "Köln") %>% 
      mutate(plz_groups = case_when(
        str_detect(plz, "^508") ~ "Group A",
        str_detect(plz, "^507") ~ "Group B",    
        str_detect(plz, "^509") ~ "Group C",    
        TRUE ~ "Group X" # rest
      ))
    
    map_cologne <- tm_shape(germany, bbox = cologne_bbox) +
      tm_polygons() +
      tm_shape(cologne_plz_all) +
      tm_fill(col = "plz_groups",
              legend.show = F) +
      tm_borders() +
      tm_text(text = "plz") # just to show where target plz is located
    
    map_cologne
    
    print(map_de, vp = grid::viewport(0.825, 0.25, width = 0.2, height = 0.45))
    

    enter image description here