Interactive Data Visualisation

Author
Affiliation

Jon Yearsley

School of Biology and Environmental Science, UCD

Published

September, 2024

Introduction

Below are three examples of interactive plots using the plotly and ggplot2 packages. These plots can be a novel way to visualise data.

Interactive Scatterplot

Here is an interactive version of a scatterplot. The scatterplot shows data from the msleep data frame that is bundled with the ggplot2 package.

Interactive 3D Plots

Using web-based (html) visualisations can make 3D plots much more informative, by being more interactive. Below is an example of the same scatterplot as above, but we’ve added a z-axis with data for the brain weight of each species. Try spinning the graph around (by holding down and moving your mouse) to visualise the data from different perspectives.

Animated Plots

Web-based visualisations also offer the possibility of including animation. Below we animate the rainfall data presented earlier to demonstrate web-based animation

Code for the plots

Interactive scatterplot code

  library(ggplot2)
  library(plotly)
  
  # Create a new variable containing feeding type names
  msleep$Feeding_Type=msleep$vore
  msleep$Feeding_Type[msleep$vore=='carni'] <- 'Carnivore'
  msleep$Feeding_Type[msleep$vore=='herbi'] <- 'Herbivore'
  msleep$Feeding_Type[msleep$vore=='insecti'] <- 'Insectivore'
  msleep$Feeding_Type[msleep$vore=='omni'] <- 'Omnivore'
  msleep$Total_Sleep <- msleep$sleep_total
  msleep$REM_Sleep <- msleep$sleep_rem
  
  
  # Use ggplotly to produce an interactive graph
  p <- ggplot(data=msleep, aes(text=paste('Species: ',name,sep=''),
                               fill=Feeding_Type, 
                               x=sleep_total, 
                               y=sleep_rem)) +
    geom_point(size=4, 
               alpha=0.8) +
    scale_fill_brewer(name='Feeding Type',
                      type='qual', 
                      palette='Set1') +
    theme_bw() +
    theme(axis.title=element_text(size=14,face="bold"),
          axis.text = element_text(size=14),
          legend.position = "right") +
    xlab('Total Sleep (hr/day)') + 
    ylab('REM Sleep (hr/day)')
  
  # Display the plot using plotly
  ggplotly(p)

Interactive 3D Plot

# Produce a 3D plot using plotly
library(tidyverse)
library(plotly)

# Create the plot (the syntax is different to ggplot2)
p <- plot_ly(
  msleep, 
  x = ~Total_Sleep, 
  y = ~REM_Sleep, 
  z = ~brainwt, 
  marker = list(size=8, 
                line = list(color = 'black',
                            width = 2)),
  color = ~Feeding_Type,
  colors = "Set1") %>%
  add_markers() %>%
  layout(
    scene = list(xaxis = list(title = 'Total Sleep (h/day)'),
        yaxis = list(title = 'REM Sleep (h/day)'),
        zaxis = list(title = 'Brain Weight (kg)'))
        )
  

p   # Display the plot

Animated Plot

# Import rainfall data
rainfall = read.table('MALIN_HEAD.TXT', header=T, sep='\t')

# Create a list of months
monthList <- c('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')

# Put rainfall data in long format
rainfall_long <- pivot_longer(data=rainfall, 
                             names_to = 'Month', 
                             values_to = 'rain', 
                             cols = monthList)
rainfall_long$Month <- ordered(rainfall_long$Month, levels=monthList)

accumulate_by <- function(dat, var) {
  var <- lazyeval::f_eval(var, dat)
  lvls <- plotly:::getLevels(var)
  dats <- lapply(seq_along(lvls), function(x) {
    cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
  })
  dplyr::bind_rows(dats)
}

# Process the rainfall data
plot_data <- rainfall_long

# Create days since start of data variable
plot_data$date <- as.Date(paste('01',match(plot_data$Month,monthList),
                               plot_data$Year,sep='-'), format='%d-%m-%Y')
plot_data$julian <- julian(plot_data$date)
plot_data$julian <- plot_data$julian - min(plot_data$julian)
plot_data <- plot_data[order(plot_data$julian),]

# Run the accumulate function using variable julian as the time
plot_data <- plot_data %>%
  accumulate_by(~julian)

# Use ggplotly to produce the graph
p <- ggplot(data=plot_data, 
            aes(x=date, 
                y=rain, 
                frame=frame)) +
  geom_line() +
  geom_point() +
  theme_bw() +
  theme(axis.title = element_text(size=14,face="bold"),
        axis.text = element_text(size=14)) +
  labs(x='Date', 
       y='Rainfall (mm)', 
       title='Monthly rainfall at Malin Head')

# Display the animation
ggplotly(p) %>% 
  animation_opts(
    frame = 100, 
    transition = 0, 
    redraw = FALSE
  )