rtmap

Customize legend histogram axis labels


I have a histogram in my legend that displays the distribution of my data. I would like to edit the labels of the axis to improve readability. Ideally, this would be changed to reflect the categories, so the values of 500 and 1500 can be removed.

library(tmap)

custom_colors <- c("#ffd500",'orange', "#e60000")

tm_map <- tm_shape(merged) +
  tm_borders(lwd=NA) +
  tm_polygons("aantal_observaties", 
              id = "pc4", 
              breaks= c(1,1001, 2001, 3000),
              n=3,
              palette = custom_colors, 
              style = "fixed", 
              title = "Observations", 
              alpha = 1,
              na.color="purple",
              colorNA='#ebebeb',
              legend.hist=TRUE,
              legend.show=FALSE) +

tm_layout(legend.outside=TRUE,legend.outside.position = "right",
          frame=FALSE,
          title = 'Observations',
          title.size = 1) 
  
tm_map + tm_add_legend(labels=c("1 to 1000", "1001 to 2000", "2001 to 3000", "0"),
                col = c("#ffd500",'orange', "#e60000", "#ebebeb"),
                border.lwd = NA,
                                )

enter image description here


Solution

  • Did some toying around with this and it seems like legend.hist may not be supported in tmap v4. Installing tmap and loading the library gave me the message:

    > library(tmap)
    Breaking News: tmap 3.x is retiring. Please test v4, e.g. with
    remotes::install_github('r-tmap/tmap')
    

    Anyway, after installing that version, I was unable to get a legend.hist. On this other SO post on customizing the histogram axes in tmap Martijn Tennekes says

    Unfortunately, this is not possible (yet). tmap is currently in a big renovation (to v4): we will still have to decide how to proceed with histograms and other legend charts.

    That being the case, you can get something similar using ggplot2 and patchwork, though specifying the layout is a little clunky.

    Since you didn't post data, I created some that I think is similar enough:

    library(dplyr)
    library(sf)
    
    # outline
    outline <- system.file("gpkg/nc.gpkg", package = "sf") |>
        sf::st_read() |>
        sf::st_geometry() |>
        sf::st_union() |>
        sf::st_as_sf()
    
    # create polygons
    polys <- outline |>
        sf::st_sample(500) |>
        sf::st_buffer(units::as_units(2, "mi")) |>
        sf::st_as_sf()
    
    # generate data
    obs <- rnorm(10000, mean = 0, sd = 900) |>
        round() |>
        abs() |>
        sample(size = nrow(polys))
    
    # add observations for polys
    polys <- polys |>
        dplyr::mutate(obs = obs)
    
    # add factor for category
    polys <- polys |>
        dplyr::mutate(group = dplyr::case_when(
            dplyr::between(obs, 0, 1000) ~ "0 to 1000",
            dplyr::between(obs, 1001, 2000) ~ "1001 to 2000",
            obs > 2000 ~ "2001+"
        )) |>
        dplyr::mutate(group = as.factor(group))
    

    And for the plot:

    library(ggplot2)
    library(patchwork)
    
    map <- ggplot() +
        geom_sf(data = outline) +
        geom_sf(data = polys, aes(fill = group), show.legend = FALSE) +
        scale_fill_manual(values = c("#ffd500", "orange", "#e60000")) +
        theme_void()
    
    hist <- ggplot(data = polys, aes(x = obs, fill = group)) +
        geom_histogram(binwidth = 25) +
        scale_fill_manual(
            values = c("#ffd500", "orange", "#e60000")
        ) +
        theme_minimal() +
        theme(
            legend.position = "bottom",
            legend.title = element_blank(),
            plot.title = element_text(face = "bold"),        
            legend.direction = "vertical",
            axis.title.x = element_blank(),
            axis.title.y = element_blank()
        ) +
        ggtitle("Observations")
    
    design <- "AAAA#\nAAAAB\nAAAA#"
    
    wrap_plots(
        map, hist,
        design = design
    )
    

    output

    Since you create the histogram separately, you have full control over it. Know this isn't ideal since it's not in tmap but thought it might be close to what you're after.

    More on using patchwork (or gridExtra / cowplot) here