R-Geofacet Will Change How We Visualize Spatial Data.

In April 2019, Indonesia had the presidential election and most of the online/offline media did some visualization regarding this. One of them is the graph where they split the result by province (see the picture below). In this post, I would like to use the election data and create a similar graph using a package from R called geofacet. I want to combine the map and the percentages into a single graph. That’s where geofacet will play around.

https://akurat.co/infografis/id-597877-read-peta-hasil-qc-pilpres-34-provinsi

What will be the chart looks like?

I code each province to the specific grid, where each square represents each province in Indonesia. The square might not be exact to the center of the area, but it will give you some understanding of which region is it. The information about the presidential election will be inside each square.

Each square represents each province in Indonesia. I use Adobe Illustrator for mapping

Transfer all the information above into code that can be read by R. I changed a little bit from above.

#install.packages("geofacet")
library(geofacet)
name <- c('Aceh','North Sumatra','West Sumatra','Riau','Jambi','Bengkulu','South Sumatra','Lampung','Riau Islands','Bangka Belitung','Banten','Jakarta','West Java','Central Java','East Java','Yogyakarta','West Kalimantan','Central Kalimantan','South Kalimantan','East Kalimantan','North Kalimantan','Bali','West Nusa Tenggara','East Nusa Tenggara','Southeast Sulawesi','South Sulawesi','West Sulawesi','Central Sulawesi','Gorontalo','North Sulawesi','North Maluku','Maluku','West Papua','Papua')
code <- c('AC','SU','SB','RI','JA','BE','SS','LA','KR','BB','BT','JK','JB','JT','JI','YO','KB','KT','KS','KI','KU','BA','NB','NT','SG','SN','SR','ST','GO','SA','MU','MA','PB','PA')

name_indo <- c('Aceh','Sumatera Utara','Sumatera Barat','Riau','Jambi','Bengkulu','Sumatera Selatan','Lampung','Kepulauan Riau','Bangka Belitung','Banten','DKI Jakarta','Jawa Barat','Jawa Tengah','Jawa Timur','DI Yogyakarta','Kalimantan Barat','Kalimantan Tengah','Kalimantan Selatan','Kalimantan Timur','Kalimantan Utara','Bali','Nusa Tenggara Barat','Nusa Tenggara Timur','Sulawesi Tenggara','Sulawesi Selatan','Sulawesi Barat','Sulawesi Tengah','Gorontalo','Sulawesi Utara','Maluku Utara','Maluku','Papua Barat','Papua')

x <- c(1,1,1,2,2,2,3,3,4,5,4,5,5,6,7,6,7,7,8,8,8,9,11,12,13,12,11,12,12,13,15,15,17,18)
y <- c(1,2,3,3,4,5,5,6,3,5,8,7,8,8,8,9,4,5,5,4,3,8,8,8,5,5,5,4,3,3,3,5,5,6)
indo_grid <- data.frame(col=x, row=y,code=code,name=name,name_indo = name_indo)
grid_preview(indo_grid)

If you copy and paste it into the R it will give you this graph. I am quite satisfied with this.

The result from code above

Get the data about Presidential Election

I googled it and got these two Presidential Election for 2014 and 2019.

From these two, I combine it using R. You can download the data with rds format in here. After downloading the data, we can start by calling the data into R, and then change format data from wide to long.

library(tidyverse)
library(ggrepel)
pilpres <- read_rds("pilpres.rds")
pilpres_long <- pilpres %>%
  gather(candidate,votes,-c(province,year)) %>% 
  group_by(province,year) %>% 
  mutate(pct_votes = votes/sum(votes),
         candidate = tools::toTitleCase(candidate)) %>% 
  arrange(province,candidate) %>% 
  rename(name = province) 

In case people who doesn’t familiar with facet in R.

If you are not familiar don’t worry here is some glimpse about facet in R.

Facet will divide the plot based on the specific column we select.

In the left is a normal function in ggplot while the right is when we add facet function. Basically, from a single panel, we divided by province using facet function in ggplot called facet_wrap. Some advantage of using this is, easier to see and compare. And for this tutorial instead of facet_wrap, we will replace it with facet_geoa function from geofacet.

First plot: Result From Presidential Election 2019

I will create a bar chart, where each bar represents each candidate. For this, I use a function called geom_col in ggplot2 and later we will also add facet_geo.

pilpres_long %>% filter(year==2019) %>% rename(name_indo = name) %>% 
ggplot( aes(candidate, pct_votes, fill = candidate)) +
  geom_col() +
  geom_text(aes(label=round(pct_votes*100,1)),angle=270,
            #position =  position_dodge(1),
    vjust = -0.2,
    size=1.4
 )+
  scale_fill_manual(values = c("#4e79a7", "#e15759")) +
  ylim(0,1.2)+
  facet_geo(~ name_indo, grid = indo_grid) + # this is where we use geofacet package
  theme_bw()+
  # some adjustments to make it more pleasant in the eye
  theme(axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    strip.text.x = element_text(size = 4),
    legend.position = "top"
    )+
  labs(fill = "Candidate")+
  coord_flip()

So above is a bar chart % voters based on candidate where each panel represents Province in Indonesia with help from geofacet’s library. Since 2014 and 2019 have the same candidate we can create another chart.

Second Chart: Movement from Voters 2014 vs 2019

We will create % voters movement from 2014 to 2019 using a graph called slope chart. We needgeom_pointand geom_line to create that chart.

geom_text_repel from ggrepel package also will be used for a label.

library(ggrepel)
pilpres_movement <- pilpres_long %>% rename(name_indo = name)
ggplot(data=pilpres_movement,aes(x=as.factor(year),y=pct_votes,group=candidate))+
  geom_line(aes(color = candidate))+
  geom_point(aes(color = candidate))+
  geom_text_repel(data = pilpres_movement %>% 
filter(year == 2014), 
            aes(label = paste0(round(pct_votes*100,1), "%")) , 
            #hjust = -1, 
            fontface = "bold",
            size=1.4)+
  geom_text_repel(data = pilpres_movement %>% # function from ggrepel
                  filter(year == 2019), 
            aes(label = paste0(round(pct_votes*100,1), "%")) , 
            #hjust = -1, 
            fontface = "bold",
            size=1.4)+
  facet_geo(~ name_indo, grid = indo_grid)+
  # some adjustments to make it more pleasant in the eye
  theme_bw()+
  ylim(0,1.2)+
  scale_color_manual(values = c("#4e79a7", "#e15759")) +
  theme(axis.title.x = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    strip.text.x = element_text(size = 3),
    axis.text.x = element_text(angle = 90),
    legend.position = "top"
    )

Above is the second chart, it’s called slope chart. Usually, this chart can be used to see the movement.

Conclusion

On this tutorial, we learn about how to create a map for geofacet manually and also learn how to use it in some use cases. You can use the map for data from the Central Bureau of Statistics in Indonesia and hopefully gain some insight from that.

All this stuff also documented in Github.

Leave a Reply