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
.
Here is an example using geom_scatterpie
from the scatterpie
package to plot pie-charts onto a map using ggplot2
.
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
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:
To get rid of the border around the pie charts add border.lwd = 0
to tm_symbols()
.