Yabin Da
Yabin Da

Reputation: 595

How to arrange the position of this legend

As shown in the map below, how can I place the legend to the last cell in the grid?

The code I used is

psp1 <-   tm_shape(province) + 
  tm_borders(col = 'black') + 
  tm_shape(county) + 
  tm_polygons(col = 'estimate', title = 'Changes in %', style = 'fixed', palette = brewer.pal(n = 6, name = 'Spectral'), 
              breaks = c(-15, -10, -5, 0, 5, 10, 15), legend.hist = F) + 
  tm_facets('warming', ncol = 2) + 
  tm_shape(province) + 
  tm_borders(col = 'black') + 
  tm_compass(north = 0, type = 'arrow', show.labels =0, position = c('right','top')) + 
  tm_layout(legend.format = list(fun = function(x) formatC(x, digits = 1, format = "f")),
            fontface = 'bold',
            legend.text.size = 1.3,
            legend.width = 0.2,
            legend.title.size = 1.5,
            panel.label.size = 1.5,
            panel.label.fontface = 'bold')

The data can be found from here. Thanks.

enter image description here

Upvotes: 3

Views: 651

Answers (1)

lovalery
lovalery

Reputation: 4652

My answer comes perhaps a little late... (almost one year after your request!) Anyway, your question is very interesting and I hope this answer will be useful, either now or for future projects, for you or other SO users (by the way, thanks for having kept your input data accessible for a year ;-)).

As far as I know, it is not possible to solve your problem by using the tm_facets() function of the tmap library. So I suggest a slightly different "strategy" (still using the tmap library) to get what you are looking for.

It is articulated in two steps:

  1. Build the maps and the legend manually... fortunately, not quite manually since the solution I suggest uses one custom function (i.e. make_graph()) that is run through a Map() function.

  2. Edit the map mosaic with the legend using the R base grid library. Again, the implementation is made easier by the use of one custom function (i.e. Maps_setup()) run through a Map() function.

So, please find below a reprex that details the approach.

Reprex

  • STEP 1 - BUILDING THE MAPS AND THE LEGEND
library(sf)
library(tmap)
library(RColorBrewer)

# Import data
province <- st_read("province.shp")
county <- st_read("county.shp")


# Split the 'sf' object 'county' into a list of five 'sf' objects corresponding 
# to the five warming scenarios (i.e. the first five facets of the final figure)
county_warm_list <- split(county , f = county$warming)


# Build the function 'make_graph' to generate the maps
make_graph <- function(x,y){
  
  results <- tm_shape(x, 
                      is.master = TRUE) + 
    tm_polygons(col = 'estimate', 
                title = 'Changes in %', 
                style = 'fixed', 
                palette = brewer.pal(n = 6, name = 'Spectral'), 
                breaks = c(-15, -10, -5, 0, 5, 10, 15), 
                legend.hist = FALSE, 
                midpoint = 0) + 
    tm_shape(province) + 
    tm_borders(col = 'black') + 
    tm_compass(north = 0, 
               type = 'arrow', 
               show.labels = 0, 
               position = c(0.93, 0.87),
               size = 1.2) +
    tm_layout(legend.show = FALSE, 
              # NB: the use of the 'get_asp_ratio()' function enables
              # to optimize the size of each map inside its own facet:
              asp = tmaptools::get_asp_ratio(x), 
              panel.labels = y,
              panel.label.size = 0.8,
              panel.label.fontface = 'bold', 
              inner.margins = c(0.02, 0.02, 0.02, 0.02))
  
  return(results)
  
}


# Run the 'make_graph()' function through the list of the five 'sf' objects (i.e. 
# 'county_warm_list') to generate the maps with their respective title using 
# the 'Map()' function
map_titles <- names(county_warm_list)
Maps_list <- Map(make_graph, county_warm_list, map_titles)


# Build the legend using only the object "county"
Maps_legend <- tm_shape(county) + 
  tm_polygons(col = 'estimate', 
              title = 'Changes in %', 
              style = 'fixed', 
              palette = brewer.pal(n = 6, name = 'Spectral'), 
              breaks = c(-15, -10, -5, 0, 5, 10, 15), 
              legend.hist = FALSE, 
              midpoint = 0) + 
  tm_layout(legend.only = TRUE, 
            legend.position = c("center", "center"), 
            legend.format = list(fun = function(x) formatC(x, digits = 1, format = "f")),
            fontface = 'bold',
            legend.text.size = 1.3,
            legend.width = 0.2,
            legend.title.size = 1.5)



# Add the legend to 'Maps_list'
Maps_list$Legend <- Maps_legend

At the end of this first step, you get a list (i.e. Maps_list) containing 6 elements (i.e. five maps and one legend).

  • STEP 2 - LAYOUT OF THE MOSAIC OF MAPS WITH THE LEGEND
library(grid)

grid.newpage()

# Build the function 'Maps_setup' to set up the layout
Maps_setup <- function(x,y,z){
  
  pushViewport(viewport(layout = grid.layout(nrow = 3, ncol = 2, 
                                             widths = unit(7.32, "cm"), 
                                             heights = unit(5, "cm"))))
  
  setup <- print(x, vp = viewport(layout.pos.row = y, layout.pos.col = z))
  
  return(setup)
  
}


# Run the 'Maps_setup()' function through the six objects of 'Maps_list' (i.e. 
# 5 maps + 1 legend) to place the maps and the legend on the page using 
# the 'Map()' function

# The 'pos_row' and 'pos_col' vectors are used to indicate where to place the 
# maps as the 'Maps_setup()' function works through the list

pos_row <- rep(1:3, each = 2)
pos_col <- rep(1:2, times = 3)


Final_Results <- Map(Maps_setup, Maps_list, pos_row, pos_col)

enter image description here

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

Upvotes: 1

Related Questions