rggplot2gisscatterpie

Plot piecharts onto map using tmap in R


I would like to plot pie-charts onto a map in R using tmap. I have found how to plot piecharts onto a map using ggplot2 but I would like to use tmap for basemap layers as I have already created all my other maps using the latter package and I find its aesthetics easier to manipulate and more suited to my mapping needs. There seems to be a way to use a grob object with tm_symbols but my understanding of ggplot2 is too limited as answered on this question: Creating piecharts with tm_bubbles() from tmap package in R

Here is an example using grob and tm_symbols for a stacked bar, which I think should be useful. It is based on the example provided in help documentation for tm_symbols.

enter image description here

Here is an example using geom_scatterpie from the scatterpie package to plot pie-charts onto a map using ggplot2.

enter image description here

I want to put the pie-charts onto the tmap mapping instead of the stacked bars. In my own map, the legend is much more complex and I have many other layers so I do not want to have to rewrite my entire code.

library(scatterpie)
library(ggplot2)
library(tmap)
library(dplyr)
library(data.table)
library(tidyr)
library(sf)
library(tmaptools)

data(NLD_prov)

origin_data <- NLD_prov %>% 
  st_set_geometry(NULL) %>% 
  select(name, origin_native, origin_west, origin_non_west) %>% 
  gather(key=origin, value=perc, origin_native, origin_west, origin_non_west, factor_key=TRUE)

plot_cols <- get_brewer_pal("Dark2", 3)

grobs <- lapply(split(origin_data, origin_data$name), function(x) {
  ggplotGrob(ggplot(x, aes(x="", y=-perc, fill=origin)) +
               geom_bar(width=1, stat="identity") +
               scale_y_continuous(expand=c(0,0)) +
               scale_fill_manual(values=plot_cols) +
               theme_ps(plot.axes = FALSE))
})

#stacked bars
tm_shape(NLD_prov) +
 tm_polygons(group = "Provinces") +
  tm_symbols(shape="name", 
             shapes=grobs, 
             legend.shape.show = FALSE, 
             legend.size.is.portrait = TRUE, 
              shapes.legend = 22)+
  tm_add_legend(type="fill", 
                col=plot_cols, 
                labels=c("Native", "Western", "Non-western"), 
                title="Origin")

#pie-chart
NLD_prov.pts<-NLD_prov%>%sf::st_centroid()%>%st_coordinates()
NLD_prov.pts<-data.table(long=NLD_prov.pts[,1], lat=NLD_prov.pts[,2], name=NLD_prov$name)
NLD_prov.dt<-left_join(origin_data, NLD_prov.pts)
NLD_prov.dt<-NLD_prov.dt%>%rename(value=perc)#quantitative variable must be stored as "value"

theme_set(theme_bw())
ggplot(NLD_prov)+
  geom_sf()+
 geom_scatterpie(aes(x=long, y=lat), data=NLD_prov.dt, cols="origin", long_format=TRUE)

Here are my failed attempts to write geom_scatterpie as a grob object:

grobs <- lapply(split(NLD_prov.dt, NLD_prov.dt$name), function(x) {
  ggplotGrob(ggplot(x, aes(x="", y=-value, fill=origin)) +
               geom_scatterpie(data=x, cols="origin", long_format=TRUE)+
               scale_y_continuous(expand=c(0,0)) +
               scale_fill_manual(values=plot_cols) +
               theme_ps(plot.axes = FALSE))
})
#Error in `[.data.frame`(data, , xvar) : undefined columns selected

grobs <- lapply(split(NLD_prov.dt, NLD_prov.dt$name), function(x) {
  ggplotGrob(ggplot() +
               geom_scatterpie(aes(x="", y=-value, fill=origin), 
                               data=x, cols="origin", long_format=TRUE))
})

Found someone who did what I want! https://twitter.com/evolution_v2/status/1169982127015890945


Solution

  • The quickest solution is to add + coord_polar("y", start=0) to the ggplots in the grob:

    This should work:

    grobs2 <- lapply(split(origin_data, origin_data$name), function(x) {
      ggplotGrob(ggplot(x, aes(x="", y=-perc, fill=origin)) +
                   geom_bar(width=1, stat="identity") +
                   coord_polar("y", start=0) +
                   scale_y_continuous(expand=c(0,0)) +
                   scale_fill_manual(values=plot_cols) +
                   theme_ps(plot.axes = FALSE))
    })
    
    
    #stacked bars
    tm_shape(NLD_prov) +
      tm_polygons(group = "Provinces") +
      tm_symbols(shape="name", 
                 shapes= grobs2, 
                 border.lwd = 0,
                 legend.shape.show = FALSE, 
                 legend.size.is.portrait = TRUE, 
                 shapes.legend = 22)+
      tm_add_legend(type="fill", 
                    col=plot_cols, 
                    labels=c("Native", "Western", "Non-western"), 
                    title="Origin")
    
    
    

    Here's link to more about pie charts: https://r-graph-gallery.com/piechart-ggplot2.html

    Here's what It looks like:

    tmap pie charts

    edit

    To get rid of the border around the pie charts add border.lwd = 0 to tm_symbols().