Hands-on Exercise 5A

Published

February 5, 2024

Modified

February 26, 2024

13 Creating Ternary Plot

13.1 Overview and Learning Outcomes

This hands-on exercise is based on Chapter 13 of the R for Visual Analytics book.

Ternary plots are a way of displaying the distribution and variability of three-part compositional data. Its display is a triangle with sides scaled from 0 to 1. Each side represents one of the three components. A point is plotted so that a line drawn perpendicular from the point to each leg of the triangle intersects at the component values of the point.

In this hands-on exercise, a ternary plot is created to visualise and analyse the population structure of Singapore. The learning outcomes are:

  • Install and launch tidyverse and ggtern packages.

  • Derive three new measures using the mutate() function in the dplyr package.

  • Build a static ternary plot using the ggtern() function in the ggtern package.

  • Build an interactive ternary plot using the plot_ly() function in the Plotly R package.

13.2 Getting Started

13.2.1 Installing and Loading Required Libraries

In this hands-on exercise, the following R packages are used:

  • tidyverse (i.e. readr, tidyr, dplyr) for performing data science tasks such as importing, tidying, and wrangling data;

  • ggtern (ggplot extension) for plotting ternary diagrams; and

  • plotly for creating interactive web-based graphs via plotly’s JavaScript graphing library, plotly.js.

The code chunk below uses the p_load() function in the pacman package to check if the packages are installed. If yes, they are then loaded into the R environment. If no, they are installed, then loaded into the R environment.

pacman::p_load(tidyverse, plotly)
library(ggtern)
require(devtools)
install_version("ggtern", version = "3.4.1", repos = "http://cran.us.r-project.org")
library(ggtern)

13.2.2 Importing Data

The dataset for this hands-on exercise is imported into the R environment using the read_csv() function in the readr package and stored as the R object, pop_data. It contains data regarding Singapore Residents by Planning Area Subzone, Age Group, Sex and Type of Dwelling, June 2000-2018.

pop_data = read_csv("data/respopagsex2000to2018_tidy.csv") 

The tibble data frame, pop_data, has 5 columns and 108,126 rows.

13.2.3 Preparing Data

The mutate() function in the dplyr package is then used to derive three new measures - young, active, and old.

agpop_mutated = pop_data %>%
  mutate(`Year` = as.character(Year))%>%
  spread(AG, Population) %>%
  mutate(YOUNG = rowSums(.[4:8]))%>%
  mutate(ACTIVE = rowSums(.[9:16]))  %>%
  mutate(OLD = rowSums(.[17:21])) %>%
  mutate(TOTAL = rowSums(.[22:24])) %>%
  filter(Year == 2018)%>%
  filter(TOTAL > 0)

13.3 Plotting Ternary Diagram

13.3.1 Plotting Static Ternary Diagram

The ggtern() function in the ggtern package is used to create a simple ternary plot.

ggtern(data=agpop_mutated,
       aes(x=YOUNG,y=ACTIVE, z=OLD)) +
  geom_point()

The labels and a colour theme are then added to enhance the plot.

ggtern(data=agpop_mutated, 
       aes(x=YOUNG,y=ACTIVE, z=OLD)) +
  geom_point() +
  labs(title="Population Structure, 2018") +
  theme_rgbw()

13.3.2 Plotting Interactive Ternary Diagram

The plot_ly() function in the plotly package is then used to create an interactive ternary plot.

# reusable function for creating annotation object
label = function(txt) {
  list(
    text = txt, 
    x = 0.1, y = 1,
    ax = 0, ay = 0,
    xref = "paper", yref = "paper", 
    align = "center",
    font = list(family = "serif", size = 15, color = "white"),
    bgcolor = "#b3b3b3", bordercolor = "black", borderwidth = 2)}

# reusable function for axis formatting
axis = function(txt) {
  list(
    title = txt, tickformat = ".0%", tickfont = list(size = 10))}

ternaryAxes = list(
  aaxis = axis("Young"), 
  baxis = axis("Active"), 
  caxis = axis("Old"))

# Initiating a plotly visualisation 
plot_ly(
  agpop_mutated, 
  a = ~YOUNG, 
  b = ~ACTIVE, 
  c = ~OLD, 
  color = I("black"), 
  type = "scatterternary") %>%
  layout(annotations = label("Ternary Markers"), 
         ternary = ternaryAxes)

~~~ End of Hands-on Exercise 5A ~~~