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
argumentJavaScript 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! 🔥