In this tutorial, we will add interaction to data stories. Not all data stories need interaction, but sometimes interactivity can be a useful tool for narration, as we saw in examples we discussed earlier in class.
We take data from gapminder R package. Gapminder is a Sweden-based non-profit that works on data education about global development.
library(tidyverse)
library(patchwork)
library(gapminder)
library(janitor) #package for data cleaning
library(thematic) #helps us work with thematic visuals
Janitor is a packaged used to make data cleaning easier. It can be handy sometimes. janitor::clean_names() specifies that the clean_names function is from the package janitor.
dat <- gapminder::gapminder |>
janitor::clean_names() |>
mutate(
# Reformat continent as a character instead of as a factor
# (will be important later)
id = levels(continent)[as.numeric(continent)],
continent = forcats::fct_reorder(continent, life_exp)
)
color_palette <- thematic::okabe_ito(5)
names(color_palette) <- unique(dat$continent)
base_size <- 18
mean_life_exps <- dat |>
group_by(continent, year, id) |>
summarise(mean_life_exp = mean(life_exp)) |>
ungroup()
Before we make interactive plots, we will create a simple ggplot.
line_chart <- mean_life_exps |>
ggplot(aes(x = year, y = mean_life_exp, col = continent)) +
geom_line(linewidth = 2.5) +
geom_point(size = 4) +
theme_minimal(base_size = base_size) +
labs(
x = element_blank(),
y = 'Life expectancy (in years)',
title = 'Life expectancy over time'
) +
theme(
text = element_text(
color = 'grey20'
),
legend.position = 'none',
panel.grid.minor = element_blank(),
plot.title.position = 'plot'
) +
scale_color_manual(values = color_palette)
line_chart
We use ggiraph to create interactive charts.
Notice that we use geom_line_interactive() instead of geom_line(). This will help us add interactivity to the plot.
library(ggiraph)
line_chart <- mean_life_exps |>
ggplot(aes(x = year, y = mean_life_exp, col = continent, data_id = id)) +
geom_line_interactive(linewidth = 2.5) +
geom_point_interactive(size = 4) +
theme_minimal(base_size = base_size) +
labs(
x = element_blank(),
y = 'Life expectancy (in years)',
title = 'Life expectancy over time'
) +
theme(
text = element_text(
color = 'grey20'
),
legend.position = 'none',
panel.grid.minor = element_blank(),
plot.title.position = 'plot'
) +
scale_color_manual(values = color_palette)
No we make an interactive plot using the girafe function.
girafe(ggobj = line_chart)
While we get some interactive effect upon hovering over the lines, the interactivity serves no narrative purpose.
If we could highlight only the line that we are interested in, and other lines fade back, that could serve some purpose sometimes. We do that using options in girafe.
Take a look opts_hover and opts_hover_inv. How are they contributing to the interactivity?
girafe(
ggobj = line_chart,
options = list(
opts_hover(css = ''), ## CSS code of line we're hovering over
opts_hover_inv(css = "opacity:0.1;"), ## CSS code of all other lines
opts_sizing(rescale = FALSE) ## Fixes sizes to dimensions below
),
height_svg = 6,
width_svg = 9
)
We will create a boxplot based on the same data.
selected_year <- 2007
box_plot <- dat |>
filter(year == selected_year) |>
ggplot(aes(x = life_exp, y = continent, fill = continent, data_id = id)) +
geom_boxplot_interactive(
position = position_nudge(y = 0.25),
width = 0.5
) +
geom_point_interactive(
aes(col = continent),
position = position_nudge(y = -0.25),
size = 8,
shape = '|',
alpha = 0.75
) +
scale_fill_manual(values = color_palette) +
scale_color_manual(values = color_palette) +
labs(
x = 'Life expectancy (in years)',
y = element_blank(),
title = glue::glue('Distribution of Life Expectancy in {selected_year}')
) +
theme_minimal(base_size = base_size) +
theme(
text = element_text(
color = 'grey20'
),
legend.position = 'none',
panel.grid.minor = element_blank(),
plot.title.position = 'plot'
)
girafe(
ggobj = box_plot,
options = list(
opts_hover(css = ''),
opts_hover_inv(css = "opacity:0.1;"),
opts_sizing(rescale = FALSE)
),
height_svg = 6,
width_svg = 9
)
We can use patchwork library to “patch” plots. Here, we are placing the line chart and the box plot side-by-side.
library(patchwork)
girafe(
ggobj = box_plot + plot_spacer() + line_chart + plot_layout(widths = c(0.45, 0.1, 0.45)),
options = list(
opts_hover(css = ''),
opts_hover_inv(css = "opacity:0.1;"),
opts_sizing(rescale = FALSE)
),
height_svg = 8,
width_svg = 12
)
Notice how hovering over one element in the same chart, highlights the same element in the other chart?
This tutorial is based on Albert Rapp’s tutorial on creating interactive visualizations.