Interactive graphics
SISBID 2025
https://github.com/dicook/SISBID
Some interactive graphics packages
crosstalk
: that’s what shiny is based on - we will look into shiny laterplotly
: interactive javascript graphics (maintained Carson Sievert)leaflet
: (RStudio) allows to make interactive maps. Has been picking up users and has developed a stable user base.ggvis
: both static and interactive graphics, work on it has stalled … (Wickham)animint2
: interactive, linked graphics with ggplot2 syntax (Toby Hocking)rCharts
,rbokeh
,gridSVG
,epivizr
,cranvas
previous approaches to packages with interactive graphics- see also https://r-graph-gallery.com/interactive-charts.html for additional packages (more specific)
Interactive Graphics
plotly
The plotly
package in R has two interfaces:
- plot specification via plotly
- translating
ggplot2
plots and adding interactive elements
Plotly creates interactive plots with javascript.
plot_ly(data = penguins_std,
x = ~fl,
y = ~bl,
color = ~species,
size = 3,
width=420, height=300)
plotly
ggplot2 and plotly
<- ggplot(data=penguins_std, aes(x = fl,
gg y = bl,
colour = species)) +
geom_point(alpha=0.5) +
geom_smooth(method = "lm", se=F)
ggplotly(gg, width=600, height=490)
Scatterplot(ly) matrix
library(GGally)
<- ggpairs(penguins_std, columns=2:5,
p mapping = ggplot2::aes(color = species,
alpha = 0.8))
ggplotly(p, width=600, height=490)
Maps
data(canada.cities, package = "maps")
<- ggplot(canada.cities, aes(long, lat)) +
viz borders(regions = "canada") +
coord_equal() +
geom_point(aes(text = name, size = log2(pop)),
colour = "red", alpha = 1/4) +
theme_map()
ggplotly(viz)
Not all ggplot2
geoms are supported in plotly, but when they are, they just work out of the box
Modifying plotly
plotly
uses elements of crosstalk
to provide additional interactivity, such as linked highlighting
<- highlight_key(txhousing, ~year)
txh_shared
<- ggplot(txh_shared, aes(month, median)) +
p geom_line(aes(group = year)) +
geom_smooth(data = txhousing, method = "gam") +
scale_x_continuous("", breaks=seq(1, 12, 1),
labels=c("J", "F", "M", "A", "M", "J",
"J", "A", "S", "O", "N", "D")) +
scale_y_continuous("Median price ('00,000)",
breaks = seq(0,300000,100000),
labels = seq(0,3,1)) +
facet_wrap(~ city)
<- ggplotly(p, height = 750, width = 900) %>%
gg ::layout(title = "Click on a line to highlight a year") plotly
highlight(gg)
The power of crosstalk
# install.packages("tsibble")
# install.packages("tsibbletalk")
# install.packages("feasts")
library(tsibble)
library(tsibbletalk)
library(feasts)
tourism_shared <- tourism |>
as_shared_tsibble(spec = (State / Region) * Purpose)
tourism_feat <- tourism_shared |>
features(Trips, feat_stl)
p1 <- tourism_shared |>
ggplot(aes(x = Quarter, y = Trips)) +
geom_line(aes(group = Region), alpha = 0.5) +
facet_wrap(~ Purpose, scales = "free_y") +
theme(axis.title = element_text(family="Helvetica"),
axis.text = element_text(family="Helvetica"),
legend.title = element_text(family="Helvetica"),
legend.text = element_text(family="Helvetica"))
p2 <- tourism_feat |>
ggplot(aes(x = trend_strength, y = seasonal_strength_year)) +
geom_point(aes(group = Region)) +
xlab("trend") + ylab("season") +
theme(axis.title = element_text(family="Helvetica"),
axis.text = element_text(family="Helvetica"),
legend.title = element_text(family="Helvetica"),
legend.text = element_text(family="Helvetica"),
plot.title = element_text(family="Helvetica"))
The shared data objects from crosstalk
make linking between plots easier!
Code
subplot(
ggplotly(p1, tooltip = "Region", width = 1200, height = 600) |>
config(displayModeBar = FALSE),
ggplotly(p2, tooltip = "Region", width = 1000, height = 500) |>
config(displayModeBar = FALSE),
nrows = 1, widths=c(0.5, 0.5), heights=1) |>
highlight(dynamic = FALSE)
Your Turn
- get the code from the previous plot to run in your RStudio session
- the function
highlight
allows to make modifications in how highlighted values are presented in plotly. Read through the parameter details in?highlight
. - the parameter
dynamic
is set toFALSE
by default. Turn it toTRUE
. What is the effect?
Animations
gganimate
(Lin-Pederson) allows to make and save animations: gganimate cheat sheet- Animations are different from interactive graphics in that the viewer does not have any control
- useful for different important stages of a visualization (e.g. time) and to keep track of how different visualizations are related
- can also be used in talks
An example animation
Countries are colored manually by country_colors
(hue shows continent, saturation is individual country)
gganimate
- Start with a ggplot2 specification
- Add layers with graphical primitives (geoms)
- Add formatting specifications
- Add animation specifications
A simple example
- Start by passing the data to ggplot
Thanks to Mitch O’Hara Wild for the example
A simple example
- add the mapping
Thanks to Mitch O’Hara Wild for the example
A simple example
- Add a graphical primitive, let’s do a line
Thanks to Mitch O’Hara Wild for the example
A simple example
- Just one extra line turns this into an animation!
Thanks to Mitch O’Hara Wild for the example
A not-so-simple example
Using the the datasaurus dozen, again, we first pass in the dataset to ggplot
A not-so-simple example
For each dataset we have x and y values, in addition we can map dataset to color
A not-so-simple example
Trying a simple scatter plot first, but there is too much information
A not-so-simple example
We can use facets to split up by dataset, revealing the different distributions
A not-so-simple example
We can just as easily turn it into an animation, transitioning between dataset states!
Your Turn
The datasaurus_dozen
data set is part of the R package datasauRus
.
- Load the gganimate package and get the animation from the previous page to run in your R session (might take a moment)
- The function
transition_states
drives the animation. It has values 2 and 3. What do these values mean? Read up on their meaning and change them.
Controlling an animation
We control plot movement with (a grammar of animation):
- Transitions:
transition_*()
define how the data should be spread out and how it relates to itself across time. - Views:
view_*()
defines how the positional scales should change along the animation. - Shadows:
shadow_*()
defines how data from other points in time should be presented in the given point in time. - Entrances/Exits:
enter_*()
andexit_*()
define how new data should appear and how old data should disappear during the course of the animation. - Easing:
ease_aes()
defines how different aesthetics should be eased during transitions.
Your Turn
The gapminder example from the beginning has the static part shown below
Add animation parts! adding transition_time(year)
results in the visualisation from the start.
What other animation are helpful? What views do you want to set? Maybe a shadow looks interesting?
ggplot(gapminder, aes(gdpPercap, lifeExp, size = pop, colour = country)) +
geom_point(alpha = 0.7) +
scale_colour_manual(values = country_colors) +
scale_size("Population size", range = c(2, 12), breaks=c(1*10^8, 2*10^8, 5*10^8, 10^9, 2*20^9)) +
scale_x_log10() +
facet_wrap(~continent) +
theme(legend.position = "bottom") +
guides(colour = "none")
Resources
- Carson Sievert Interactive web-based data visualization with R, plotly, and shiny
- website for gganimate
- Mitch O’Hara-Wild’s tutorial on gganimate
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.