0

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)
Jacek Kotowski
  • 620
  • 16
  • 49

2 Answers2

2

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

Jindra Lacko
  • 7,814
  • 3
  • 22
  • 44
  • Dear Jindra thanks for assistance. I applied the line and the legend labels are formatted accordingly. But the labels in the plot are not formatted well and they stay as they were. – Jacek Kotowski Feb 22 '18 at 12:59
  • 1
    @JacekKotowski Now I get your idea! Yes, I read your question wrong and was describing **legend** formatting. My bad. I have edited my answer to format the **labels**. The map is ugly, with numbers and borders overlapping, but the format is there... – Jindra Lacko Feb 22 '18 at 16:44
  • Thanks Jindra, It is great and it works in the case of one plot... however I discover that in the case of small multiples I do not have there data anymore so that I can turn it to text and format at will. What tmap requires is the names of columns in shp data for each series from which it will build small plots. Also I cannot turn values to text earlier, before plotting, because I will not be able to color the shapes (choropleth). – Jacek Kotowski Feb 23 '18 at 08:29
  • 1
    But you surely can create a **new** column with the text for labels and use the original one for coloring? – Jindra Lacko Feb 23 '18 at 08:39
  • Yes, you gave me a good proposal to try... I can try adding 4 extra columns to shp files with formatted txt's and then give the tm_text the names of these new columns. I presume they must be in the same order as the preciding ones with numbers. Theoretically it is some idea. I am not that fluent with R to try it quick but I will try it. – Jacek Kotowski Feb 23 '18 at 09:18
  • Jindra Lacko, I created new colums, as many as there were series or as many as there would be plots. It worked. See my edit in the question. – Jacek Kotowski Feb 23 '18 at 14:16
1
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)