3

Is it possible to include more than one tm_compass() on a map created by tmap?

I know it's probably unlikely that you'd need to, but say you wanted to show off the different compass types. Using nz from the spData package I tried adding each new compass as an additional layer, but it seems only the first one is included on the map.

library(spData)
library(tmap)

tm_shape(nz)+
  tm_fill()+
  tm_compass(type = 'arrow', position = c(0.1, 0.9))+
  tm_compass(type = '4star', position = c(0.1, 0.8))+
  tm_compass(type = '8star', position = c(0.1, 0.7))+
  tm_compass(type = 'radar', position = c(0.1, 0.6))+
  tm_compass(type = 'rose', position = c(0.1, 0.5))

enter image description here

If arrow isn't included, then 4star takes it's place:

tm_shape(nz)+
  tm_fill()+
  # tm_compass(type = 'arrow', position = c(0.1, 0.9))+
  tm_compass(type = '4star', position = c(0.1, 0.8))+
  tm_compass(type = '8star', position = c(0.1, 0.7))+
  tm_compass(type = 'radar', position = c(0.1, 0.6))+
  tm_compass(type = 'rose', position = c(0.1, 0.5))

enter image description here

hugh-allan
  • 1,170
  • 5
  • 16
  • 2
    I don't think it is possible. For demonstration purposes, you can simply arrange different maps with different compasses with `tmap_arrange` – Elia Sep 27 '21 at 11:47
  • Thanks Elia, `tmap_arrange()` is looking like the best option – hugh-allan Sep 27 '21 at 20:44
  • Nice question, I have been exploring some work around methods and it does not seem to be a straightforward way. Recommendation by Elia is probably the best way. – Orlando Sabogal Oct 01 '21 at 20:38
  • Hi @hugh-allan, please find below one possible solution to your request... hoping that it will still be useful for you! Cheers. – lovalery Jan 31 '22 at 17:46

1 Answers1

2

Interesting question. As you point out, in normal use it is unlikely that one would need to display multiple compasses for the same map and that is probably why the default behavior of the tmap library does not handle this case.

That said, it is still possible to add all five tmap compasses to the same map using some workarounds! So, please find below the general "strategy":

  1. Building 5 maps, each with one of the tmap compasses. Then convert these maps into 'grob' objects using the tmap::tmap_grob() function to extract the compasses with the help of the getGrob() function from the base R library grid.

  2. Visualizing the compasses (without and with labels) using the cowplot library

  3. Building the final map with the five compasses using the cowplot library

NB: when running the reprex just below, don't worry about the rendering of the different plots that will be displayed in your plotting device (as the rendering depends on the aspect ratio of the device); what matters is the rendering of the maps saved in the .png files.

Reprex

STEP 1 - EXTRACT EACH COMPASS TYPE FROM FIVE 'DUMMY' MAPS AS 'GROB' OBJECTS

library(tmap)
library(spData)
library(grid)

# Get a list named 'maps' containing 5 maps, each one with a different compass
compass_type <- c("arrow", "4star", "8star", "radar", "rose")

maps <- lapply(compass_type,
               function(x)
                 tm_shape(nz) +
                 tm_fill() +
                 tm_compass(type = x, position = c(0.1, 0.7)))


# Get a list named 'compasses' containing the 5 compasses as 'grob' objects 
compasses <- lapply(maps, function(x) getGrob(tmap_grob(x), gPath("compass")))

STEP 2 - VISUALIZATION OF THE FIVE tmap COMPASSES

  • Without labels
library(cowplot)

compasses_only <- plot_grid(plotlist = compasses,
                            nrow = 3,
                            ncol = 2,
                            scale = 0.8, 
                            byrow = TRUE)

compasses_only

# Save the plot (need to install the 'rstudioapi' library)
# NB: adjust 'width' and 'height' params to get the best possible rendering 
rstudioapi::savePlotAsImage(
  "tmap_compasses.png", # add the path if different of the working directory   
  format = "png", # other possible formats: "jpeg", "bmp", "tiff", "emf", "svg", "eps"
  width = 780,
  height = 965
)

enter image description here

  • With labels
compasses_only_labeled <- plot_grid(plotlist = compasses,
                            nrow = 3,
                            ncol = 2,
                            scale = 0.8, 
                            labels = compass_type,
                            label_size = 10,
                            label_x = c(0.42, 0.43, 0.43, 0.42, 0.44),
                            label_y = 0.1,
                            byrow = TRUE)

compasses_only_labeled

# Save the plot (need to install the 'rstudioapi' library)
# NB: adjust 'width' and 'height' params to get the best possible rendering 
rstudioapi::savePlotAsImage(
  "tmap_compasses_labeled.png",  
  format = "png", 
  width = 780,
  height = 965
)

enter image description here

STEP 3 - BUILDING THE MAP WITH THE FIVE COMPASSES

# Get a 'nz' map (without any compass) as 'grob' object 
nz_map <- tmap_grob(tm_shape(nz) + tm_fill())

# Convert 'compasses_only" into 'grob' object
compasses_only <- cowplot::as_grob(compasses_only)

# Build the map with the 5 compasses
map_with_compasses_2 <- ggdraw() +
  draw_grob(nz_map) +
  draw_grob(compasses_only,
            width = 0.23, height = 0.65,
            x = 0.28, y = 0.35,
            hjust = 0,
            vjust = 0,
            halign = 0.5,
            valign = 0.5,
            scale = 0.8)

map_with_compasses_2

# Save the plot (need to install the 'rstudioapi' library)
# NB: adjust 'width' and 'height' params to get the best possible rendering 
rstudioapi::savePlotAsImage(
  "map_with_compasses_2.png",   
  format = "png", 
  width = 1500,
  height = 900
)

enter image description here

Created on 2022-01-31 by the reprex package (v2.0.1)

lovalery
  • 4,524
  • 3
  • 14
  • 28