This post explains how to use the
ggiraph package to create
interactive graph and how to use
JavaScript to add additional effects for your
ggplot interactive graphs, with reproducible code and
explanations.
For an introduction to
ggiraph
, check the
dedicated post
First we need to load the ggiraph and ggplot2 libraries.
The input dataset is about consumer confidence in 9 different countries at differente dates:
# library
library(ggplot2)
library(ggiraph)
library(tidyverse)
library(gapminder)
library(dplyr)
library(hrbrthemes)
library(viridis)
# The dataset is provided in the gapminder library
data <- gapminder %>%
filter(year == "2007") %>%
dplyr::select(-year) %>%
arrange(desc(pop)) %>%
mutate(country = factor(country, country))
Let’s start with a simple interactive version of this
bubble chart. It uses the
geom_point_interactive()
function to replace the
geom_point()
one and make it interactive.
plot <- data %>%
ggplot(mapping = aes(
x = gdpPercap,
y = lifeExp,
size = pop,
fill = continent,
tooltip = paste("Country:", country, "<br>Life Expectancy:", lifeExp, "<br>GDP per capita:", gdpPercap),
data_id = continent
)) +
geom_point_interactive(alpha = 0.5, shape = 21, color = "black") +
scale_size(range = c(.1, 24), name = "Population (M)") +
scale_fill_viridis(discrete = TRUE, guide = FALSE, option = "A") +
theme_ipsum() +
ylab("Life Expectancy") +
xlab("Gdp per Capita") +
theme(legend.position = "none")
interactive_plot <- girafe(ggobj = plot)
htmltools::save_html(interactive_plot, "HtmlWidget/geom-point-interactive-1.html")
onclick
argument
JavaScript is a powerful programming language
primarily used to create interactive and dynamic
content on web pages. When it comes to integrating
JavaScript with R, particularly in the context of
charts, one common use case involves the onclick
event handler.
The onclick
argument in
JavaScript allows you to specify functionality that
should occur when an element, like a part of a chart, is clicked.
Let’s see a basic example where a simple pop-up appears when clicking on one of the bubble.
Note: all quotes "
inside JS code must be preceded by
a \
for R to understand them correctly.
plot <- data %>%
ggplot(mapping = aes(
x = gdpPercap,
y = lifeExp,
size = pop,
fill = continent,
tooltip = paste("Country:", country, "<br>Life Expectancy:", lifeExp, "<br>GDP/capita:", gdpPercap),
data_id = continent
)) +
geom_point_interactive(
alpha = 0.5,
shape = 21,
color = "black",
onclick = "alert(\"Hello from R-Graph-Gallery.com\");"
) +
scale_size(range = c(.1, 24), name = "Population (M)") +
scale_fill_viridis(discrete = TRUE, guide = FALSE, option = "A") +
theme_ipsum() +
ylab("Life Expectancy") +
xlab("Gdp per Capita") +
labs(title = "Try to click on a bubble!") +
theme(legend.position = "none")
interactive_plot <- girafe(ggobj = plot)
htmltools::save_html(interactive_plot, "HtmlWidget/geom-point-interactive-2.html")
The following code uses D3.js to change the properties of the clicked point.
For example:
d3.select(this).style(\"fill\", \"red\");
tells to your
computer that this
(the point you just
clicked on) change its style
so that the
fill
parameter becomes red
.
plot <- data %>%
ggplot(mapping = aes(
x = gdpPercap,
y = lifeExp,
size = pop,
fill = continent,
tooltip = paste("Country:", country, "<br>Life Expectancy:", lifeExp, "<br>GDP/capita:", gdpPercap),
data_id = continent
)) +
geom_point_interactive(
alpha = 0.5,
shape = 21,
color = "black",
onclick = "
// Change point color
d3.select(this).style(\"fill\", \"red\");
// Increase point size
d3.select(this).attr(\"r\", function() {
return parseFloat(d3.select(this).attr(\"r\")) + 1.5;
});
"
) +
scale_size(range = c(.1, 24), name = "Population (M)") +
scale_fill_viridis(discrete = TRUE, guide = FALSE, option = "A") +
theme_ipsum() +
ylab("Life Expectancy") +
xlab("Gdp per Capita") +
labs(title = "Try to click on a bubble!") +
theme(legend.position = "none")
interactive_plot <- girafe(ggobj = plot)
htmltools::save_html(interactive_plot, "HtmlWidget/geom-point-interactive-3.html")
Since you can do anything you want with JavaScript, the only limitation is your imagination!
The following example shows how to add a
confetti effect when clicking + some other simple
features using the onclick
argument and a bit of
JavaScript
plot <- data %>%
ggplot(mapping = aes(
x = gdpPercap,
y = lifeExp,
size = pop,
fill = continent,
tooltip = paste("Country:", country, "<br>Life Expectancy:", lifeExp, "<br>GDP/capita:", gdpPercap),
data_id = continent
)) +
geom_point_interactive(
alpha = 0.5,
shape = 21,
color = "black",
onclick = paste0(
"this.style.fill = this.style.fill === \"red\" ? this.getAttribute(\"original-fill\") : \"red\";",
"this.classList.toggle(\"highlighted\");",
"var tooltip = document.getElementById(\"custom-tooltip\");",
"tooltip.innerHTML = \"A chart by: R-Graph-Gallery.com\";",
"tooltip.style.display = \"block\";",
"tooltip.style.left = (event.pageX + 10) + \"px\";",
"tooltip.style.top = (event.pageY + 10) + \"px\";",
"setTimeout(function() { tooltip.style.display = \"none\"; }, 1500);",
"confetti({
particleCount: 1000,
spread: 70,
origin: { y: 0.6 }
});"
)
) +
scale_size(range = c(.1, 24), name = "Population (M)") +
scale_fill_viridis(discrete = TRUE, guide = FALSE, option = "A") +
theme_ipsum() +
ylab("Life Expectancy") +
xlab("Gdp per Capita") +
labs(title = "Click on a bubble for amazing effects!") +
theme(legend.position = "none")
interactive_plot <- girafe(ggobj = plot)
html_content <- htmltools::tags$html(
htmltools::tags$head(
htmltools::tags$script(src = "https://cdn.jsdelivr.net/npm/canvas-confetti@1.5.1/dist/confetti.browser.min.js"),
htmltools::tags$style("
.highlighted {
stroke: black;
stroke-width: 10px;
}
#custom-tooltip {
position: absolute;
background: white;
border: 1px solid black;
padding: 5px;
display: none;
pointer-events: none;
}
")
),
htmltools::tags$body(
interactive_plot,
htmltools::tags$div(id = "custom-tooltip")
)
)
htmltools::save_html(html_content, "HtmlWidget/geom-point-interactive-4.html")
You might be interested in:
👋 After crafting hundreds of R charts over 12 years, I've distilled my top 10 tips and tricks. Receive them via email! One insight per day for the next 10 days! 🔥