rlegendrichtexttmap

How do I get tmap legends to play nicely with subscripts, italics, etc.?


When I use expression() to add text formatting such as italics and subscripts to a tmap legend, I'm getting huge amounts of unnecessary white space, and I have no idea why.

Here's my reprex code;

library(tmap)
  library(sf)
  
  # dummy data
  nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)

  # default map
  map1 <- tm_shape(nc) +
    tm_polygons("AREA", 
                title = "Area[avg] (km^2)") +
    tm_layout(bg.color = "grey",
              legend.frame = TRUE,
              legend.bg.color = "white")
  
  # text-formatted map
  map2 <- tm_shape(nc) +
    tm_polygons("AREA", 
                title = expression(Area[avg]~(italic(km)^2))) +
    tm_layout(bg.color = "grey",
              legend.frame = TRUE,
              legend.bg.color = "white")

Which results in map1, showing the legend box fitting nicely around the un-formatted text, and map2, where we can see the needless white space tacked onto the right side of the legend.

I haven't been able to find many resources on this topic, but some things I've tried and their effects are:

Attempt Result
tm_layout(legend.width) doesn't allow me to override what it detects as the minimum width
tmap fontface arguments affect the whole legend title, rather than specific characters therein
tm_credit() is covered by legend, regardless of the order I place it in the code
blank title, grid.text label way too difficult to space correctly
avoid ~, use space inside quotes instead minimal effect
use as.expression(bquote()) extra white space remains
remove the frame and bg color while the legend frame isn't needed in this reprex example, it is in my actual use case

Solution

  • When running your code with tmap version 4.1, I got the following warning

    ── tmap v3 code detected ───────────────────────────────────────────────────────────────────────────────────────────────────
    [v3->v4] `tm_polygons()`: migrate the argument(s) related to the legend of the visual variable `fill` namely 'title' to
    'fill.legend = tm_legend(<HERE>)'
    

    so I followed this advice and it worked + your described problem did not appear. I used this vignette to recreate the legend position.

    # install.packages("tmap") # this works for tmap version 4.1
    library(tmap)
    library(sf)
    
    # dummy data
    nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
    
    # text-formatted map
    tm_shape(nc) +
      tm_polygons("AREA",
                  fill.legend = tm_legend(
                    title = expression(Area[avg] ~ (italic(km)^2)),
                    show = TRUE,
                    position = c("left", "bottom")
                  )) +
      tm_layout(
        bg.color = "grey",
        legend.frame = TRUE,
        legend.bg.color = "white"
      )
    

    giving out

    If you specifically need help with your tmap version, can you please provide it?

    Rolling back to version 3.3-4 I could recreate your issue and found that the legend width is tied to the legend.title.size (Source) so one could decrease it to legend.title.size = 0.6 and this will remove the white space, but also shrink the legend title.

    remotes::install_version("tmap", version = "3.3-4")
    
    library(tmap)
    library(sf)
    
    nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
    
    t <- tm_shape(nc) +
      tm_polygons("AREA", 
                  title = expression(Area[avg]~(italic(km)^2), parse = TRUE)) +
      tm_layout(bg.color = "grey",
                legend.frame = TRUE,
                legend.bg.color = "white",
                legend.title.size = 0.6)
    

    out