Ternary Plots in R with Plotly

6 minute read

Introduction

Ternary Plots enable us to visualize 3 parameters simultaneously on a plane. The proportion of the 3 variables must sum up to a constant.

Data

In a previous post we created bubble plots based on the proportion of young and economically active in Singapore’s subzones. However we were unable to plot the proportion of the old in the same graph. This set of data is ideal for a ternary plot. We will use the Singapore population data available from Singstat. Population data in the various residential subzones, planning areas and planning regions are available from 2002 to 2017. Singstat breaks down the population by 5 year cohorts; 0-4 years old, 5-9 years old, and so forth. For our analysis we will group the population into young (0-24 years old), economically active (25-64 years old) and old (65 years and above). Here is the header of our table

Ternary Plot

Plotly is plots ternary diagrams when the argument type is set to "scatterternary". Instead of specifyign the x and y axes, we specify a, b and c, set to % Young, % Economically Active and %Old respectively. Like in the bubble plot, the size of the bubble represents the total population in the subzone while the subzones are colored by Planning Region.

library(ggplot2)
library(plotly)
# we filter out data with zero %
tern %>%filter(`% Young`!=0 & `% Old`!=0 & `% Economically Active`!=0 & !is.na(`Planning Region`))%>%
        filter(Year>=2010)
tern2017<-tern %>% filter(Year=='2017')

# we create the ternary plot using plotly
p1<- plot_ly(
  tern2017, a = ~`% Economically Active`, b = ~`% Young`, c = ~`% Old`,
  color = ~`Planning Region`, type = "scatterternary", colors=~colors,
  size = ~Total,
  text = ~paste('Young:',sep='', round(`% Young`,1),'%',
                '<br>Economically Active:',
                round(`% Economically Active`,1),'%', '<br>Old:',
                round(`% Old`,1),'%','<br>Subzone:', Subzone, hoverinfo="text",
                      '<br>Planning Area:', `Planning Area`),
  marker = list(symbol = 'circle', opacity=0.55, sizemode="diameter", sizeref=1.5,
                      line = list(width = 2, color = '#FFFFFF')))

p1

We get the following ternary plot:

We can improve the plot by adding a title and limiting the range of the axes with the min parameter within the layout function.

# we create the ternary plot using plotly
p2 <- plot_ly(
  tern2017, a = ~`% Economically Active`, b = ~`% Young`, c = ~`% Old`,
  color = ~`Planning Region`, type = "scatterternary", colors=~colors,
  size = ~Total,
  text = ~paste('Young:',sep='', round(`% Young`,1),'%',
                '<br>Economically Active:',
                round(`% Economically Active`,1),'%', '<br>Old:',
                round(`% Old`,1),'%','<br>Subzone:', Subzone, hoverinfo="text",
                      '<br>Planning Area:', `Planning Area`),
  marker = list(symbol = 'circle', opacity=0.4, sizemode="diameter", sizeref=2,
                      line = list(width = 2, color = '#FFFFFF'))) %>%
  layout(
    title="Singapore Population 2017",
    ternary=list(aaxis=list(title="Economically Active",min=0.3),
    baxis = list(title="Young",min=0.1),
    caxis = list(title="Old")),
    paper_bgcolor = 'rgb(243, 243, 243)',
    plot_bgcolor = 'rgb(243, 243, 243)'
    )
p2

Improved plot:

Animation

Likewise, we animate using the frame parameter and edit the slider using the animation_opts function. Note that the bubbles only occupy a smaller portion of the ternary plot. For better visualization we limit the axes using the min parameter within the aaxis,baxis and caxis of the layout function. The Year is filtered after 2010 to limit the size of the table as plotly limits the upload size for free accounts.

# we create the ternary plot using plotly
p3 <- plot_ly(
  tern, a = ~`% Economically Active`, b = ~`% Young`, c = ~`% Old`,
  frame=~Year,
  color = ~`Planning Region`, type = "scatterternary", colors=~colors,
  size = ~Total,
  text = ~paste('Young:',sep='', round(`% Young`,1),'%',
                '<br>Economically Active:',
                round(`% Economically Active`,1),'%', '<br>Old:',
                round(`% Old`,1),'%','<br>Subzone:', Subzone, hoverinfo="text",
                      '<br>Planning Area:', `Planning Area`),
  marker = list(symbol = 'circle', opacity=0.4, sizemode="diameter", sizeref=2,
                      line = list(width = 2, color = '#FFFFFF'))) %>%
  layout(
    title="Singapore Population 2002-2017",
    ternary=list(aaxis=list(title="Economically Active",min=0.5),
    baxis = list(title="Young",min=0.2),
    caxis = list(title="Old")),
    paper_bgcolor = 'rgb(243, 243, 243)',
    plot_bgcolor = 'rgb(243, 243, 243)'
    ) %>%
  animation_slider(
    currentvalue = list(prefix = "YEAR ", font = list(color="red"))
  ) %>%
    animation_opts(
    2000, redraw = FALSE
  )
p3

We get the following ternary chart:

This gives us an overall picture of Singapore’s aging population compared to the bubble plot.