Jacek Kotowski
Jacek Kotowski

Reputation: 704

tmap: how to apply formatting to numeric labels on small multiples choropleths

I am plotting small multiples, one for each competitor, with tmap. I am getting multiple choropleth maps of Poland divided into counties, colored by sales values, like ggplot facet_wrap).

First I appended data to a shp file and had each competitor values (for each small map of a country) as separate column. Each row is a province.

county_marketshare<-df_monthly_val %>% 
   filter(win_name %in% best6) %>% 
   select(win_name,value,inv_province) %>% 
   group_by(win_name,inv_province)%>% 
   summarise(value=round(sum(value)),0)%>%
   spread(key="win_name", value=value)

It all works well. Then I plot my shapes. My "best6" is a list of the names of columns, names of competitors and for each name a map is printed, six maps in total.

tm_shape(pl_geo) +
  tm_polygons(best6,
              id = "province",
              palette = colfunc(20),
              style="quantile",     #("pretty", "fixed" (describe breaks))
              legend.show = FALSE,
              free.scales.fill=FALSE
              )+
  tm_text(text =c(best6), legend.size.show = FALSE,ymod = -0.7, size = .8 )

The plots are OK but I am not satisfied with numeric labels and would like to format them in a more readable way.

The tm_text prints value on each province's shape. Note that as argument text it takes the vector names of columns with values per province for each competitor.

How do I add formatting to numeric labels in tmap? For instance, how I can add the following line to my tm_text command?

format(x, scientific = FALSE, big.mark=" ", big.interval=3)})

Edit: I tried the solution by Jindra Lacko and legend labels are formatted as specified but still not labels in the map.

tm_shape(pl_geo) +
  tm_polygons(best6,
              id = "province",
              palette = colfunc(20),
              style="quantile",     #("pretty", "fixed" (describe breaks))
              legend.show = TRUE,
              free.scales.fill=FALSE)+
  tm_text(c(best6) , legend.size.show = FALSE,ymod = -0.7, size = 1, 
          legend.format = list(fun = function(x) formatC(x, digits = 0, big.mark = " ", format = "f"))) 

EDIT2: I would like to clarify the issue further, because it was not very clear.

For choropleth plotting small ultiples, like facet_wrap in ggplot2, in tmap one needs to append data columns in "wide form" to shp data. (at least so I understood from various tutorials)

Each small plot gets a data from the column.

it means that unlike for one plot, tm_texts gets names of columns so that tmap can print small multiples. It means I cannot simply reformat, change values to text because I have no values there but names of columns in shp data.

Edit final: Following the answer by Jindra Lacko I created 6 columns, as many as source data and formatted them so that I could pass them separately to tm_text:

county_marketshare<-df_monthly_val %>% 
   filter(win_name %in% best6) %>% 
   select(win_name,value,inv_province) %>% 
   group_by(win_name,inv_province)%>% 
   summarise(value=round(sum(value),0))%>% 
   spread(key="win_name", value=value, fill=0) %>%  # teraz muszę stworzyc kolumny sformatowane "finansowo"
   mutate(!!as.symbol(paste0(best6[1],"_lbl")):= formatC(!!as.symbol(best6[1]),digits = 0, big.mark = " ", format = "f",zero.print = ""),
          !!as.symbol(paste0(best6[2],"_lbl")):= formatC(!!as.symbol(best6[2]),digits = 0, big.mark = " ", format = "f",zero.print = ""),
          !!as.symbol(paste0(best6[3],"_lbl")):= formatC(!!as.symbol(best6[3]),digits = 0, big.mark = " ", format = "f",zero.print = ""),
          !!as.symbol(paste0(best6[4],"_lbl")):= formatC(!!as.symbol(best6[4]),digits = 0, big.mark = " ", format = "f",zero.print = ""),
          !!as.symbol(paste0(best6[5],"_lbl")):= formatC(!!as.symbol(best6[5]),digits = 0, big.mark = " ", format = "f",zero.print = ""),
          !!as.symbol(paste0(best6[6],"_lbl")):= formatC(!!as.symbol(best6[6]),digits = 0, big.mark = " ", format = "f",zero.print = "")
          )

county_marketshare$inv_province <- iconv(county_marketshare$inv_province,from = "utf-8", to = "ascii//TRANSLIT")
pl_geo <-
  append_data(
    shp = pl_geo,
    data = county_marketshare,
    key.shp = "jpt_nazwa_",
    key.data = "inv_province",
    ignore.na = T
  )

Then I could pass separately numeric series columns' names for coloring the shapes and separately text formated series columns' names for tm_text.

colfunc <- colorRampPalette(c("white","green"))
mytext <- paste0(pl_geo$jpt_nazwa_)


best6lab<-paste0(best6,"_lbl")

pl_best6suppl_prov<-
  tm_shape(pl_geo) +
  tm_polygons(best6,
              id = "province",
              palette = colfunc(40),
              style="kmeans",     #("pretty", "fixed" (describe breaks))
              legend.show = FALSE)+
  tm_facets(free.scales.fill = FALSE)+
  tm_text("jpt_nazwa_", size = .7, legend.size.show = FALSE,col="darkgreen")+
  tm_shape(pl_geo) +                                
  tm_text(c(best6lab) , legend.size.show = FALSE,ymod = -0.7, size = 1) +
  tm_layout(panel.labels = best6)

Upvotes: 0

Views: 2471

Answers (2)

Jindra Lacko
Jindra Lacko

Reputation: 8719

To change the formatting you need to pass a function defining the format to the legend.format part of your tm_* call.

I believe legend.format = list(fun = function(x) formatC(x, digits = 0, big.mark = " ", format = "f")) should do the trick. Big interval = 3 is by default, you should be OK omitting it.

A while back I wrote a blog post on tmap legend formatting, among other things on using the C style format and adding currency / percentage symbols to the numbers.
Feel free to check https://www.jla-data.net/eng/tmap-legend/

Edit: Now I get it! Not the legend, but the labels on the map! My bad...

You need to convert the labels to text just before plotting them. I could not reproduce your code, so I am including an example on the Europe dataset, included with tmap.

library(tmap)
library(tidyverse)

data(Europe)

Europe$pop_est_adj <- as.character(formatC(Europe$pop_est, 
                                           big.mark = " ", 
                                           format = "f", 
                                           digits = 0))

tm_shape(Europe) + tm_borders() +
  tm_shape(Europe) + tm_text(text = "pop_est_adj", size = .7)

enter image description here

Upvotes: 2

Javier Acosta
Javier Acosta

Reputation: 41

m1 <- tm_shape(World) +
      tm_polygons("pop_est", palette="RdYlGn", n=8,
          title="Población estimada", id="name",
          legend.show = FALSE) 
m2 <- tm_shape(World) +
      tm_polygons("pop_est", palette="RdYlGn", n=8,
          title="Población estimada", id="name") + 
      tm_layout(legend.only = TRUE,
                legend.format = list(text.separator = 'a',
                                     fun = function(x) formatC(x, digits = 0, big.mark = ".", format = "f")))
tmap_arrange(m1, m2)

Upvotes: 1

Related Questions