library(ggplot2)
library(plotly)
# Create clean data for tooltips
mtcars_clean <- mtcars
mtcars_clean$Cylinders <- factor(mtcars$cyl)
# Create ggplot
p <- ggplot(mtcars_clean, aes(wt, mpg, color = Cylinders)) +
geom_point(size = 3) +
geom_smooth(method = "lm", se = FALSE) +
scale_color_brewer(palette = "Set1") +
theme_minimal() +
labs(title = "Fuel Efficiency by Weight",
x = "Weight (1000 lbs)",
y = "Miles per Gallon",
color = "Cylinders")10 Interactive Plots
10.1 Introduction
While static figures are required for publication, interactive plots are invaluable for data exploration, presentations, and HTML reports. This chapter shows you how to convert ggplot2 plots to interactive versions with minimal code using plotly.
Learning Objectives
By the end of this chapter, you will:
- Understand when to use interactive vs. static plots
- Learn to convert ggplot2 to plotly with
ggplotly() - Know how to customize tooltips for better hover information
- Be able to create linked plots with shared highlighting
- Understand file size considerations for HTML widgets
- Know how to save interactive plots as standalone HTML files
10.2 The Appeal of Interactivity
Why use interactive plots?
- ๐ฑ๏ธ Hover to see exact values
- ๐ Zoom and pan
- ๐๏ธ Toggle traces on/off
- ๐ Great for exploration
- ๐ฏ Excellent for presentations
10.3 Basic ggplotly Example
Try hovering over points!
- See exact values
- Toggle series on/off
- Zoom and pan
# Make interactive
ggplotly(p_example)`geom_smooth()` using formula = 'y ~ x'
10.4 Customizing Tooltips
# Control what appears on hover
mtcars_clean <- mtcars
mtcars_clean$Cylinders <- factor(mtcars$cyl)
p <- ggplot(mtcars_clean, aes(wt, mpg, color = Cylinders,
text = paste("Car:", rownames(mtcars),
"<br>HP:", hp))) +
geom_point(size = 3) +
theme_minimal()Now hover shows car name and horsepower!
Use the text aesthetic and tooltip parameter to customize what appears on hover.
ggplotly(p_tooltips, tooltip = c("text", "x", "y"))10.5 The Saving Problem
Interactive plots are HTML widgets, not static images!
Canโt just save as PDF or PNG traditionally.
10.6 Solution: Save as HTML (Keep Interactivity)
library(htmlwidgets)
# Create a plot and make it interactive
p_interactive <- ggplotly(p_save)
# Save as self-contained HTML
saveWidget(p_interactive_save,
"plots/10_interactive/interactive_plot.html",
selfcontained = TRUE)About selfcontained parameter:
selfcontained = TRUE: Bundles all JavaScript/CSS into one file- Perfect for emailing or sharing
- No external dependencies needed
- Larger file size
selfcontained = FALSE: Creates separate library files- Smaller main HTML file
- Requires folder structure to be maintained
Uses:
- Email the HTML file directly
- Upload to website
- Opens in any web browser!
10.7 Quarto/Markdown Integration
In Quarto, ggplotly works seamlessly:
```{r}
#| label: quarto-example
#| eval: false
library(plotly)
library(ggplot2)
# Create plot
p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
# Make it interactive
ggplotly(p)
```Perfect for modern scientific reports!
10.8 3D Plots
# 3D scatter plot
mtcars_3d <- mtcars
mtcars_3d$Cylinders <- factor(mtcars$cyl)
plot_ly(mtcars_3d,
x = ~wt, y = ~hp, z = ~mpg,
color = ~Cylinders,
type = "scatter3d",
mode = "markers")Rotate by clicking and dragging!
Great for exploring multivariate data in 3D space.
10.9 Linked Plots with Crosstalk
# Create shared data
mtcars$car_name <- rownames(mtcars)
shared_data <- SharedData$new(mtcars, ~car_name)
# Create linked plots
p1 <- plot_ly(shared_data, x = ~wt, y = ~mpg, type = 'scatter', mode = 'markers')
p2 <- plot_ly(shared_data, x = ~hp, y = ~mpg, type = 'scatter', mode = 'markers')
# Display with filter on top
bscols(widths = 12, filter_checkbox("cyl", "Cylinders:", shared_data, ~cyl, inline = TRUE))
subplot(p1, p2, nrows = 1, shareY = TRUE)10.10 Hybrid Approach: Both Versions
# Create output directory if needed
dir.create("plots/10_interactive", recursive = TRUE, showWarnings = FALSE)
# Create base plot
p_static <- ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
geom_point(size = 3) +
theme_classic(base_size = 12)
# Static version for publication
ggsave("plots/10_interactive/figure1.pdf", p_static, width = 7, height = 5)
# Interactive version for supplement/website
p_interactive <- ggplotly(p_static)
saveWidget(p_interactive, "plots/10_interactive/figure1_interactive.html")
# Best of both worlds!10.12 Limitations of ggplotly
Not all ggplot2 features convert:
- Some geoms donโt translate well
- Complex annotations may be lost
- Custom themes partially supported
- Facets work but can be slow
Test your conversion!
10.13 Alternative: ggiraph
library(ggiraph)
# Create plot with interactive elements
mtcars$car_name <- rownames(mtcars)
# Create rich tooltips with HTML formatting
mtcars$tooltip_text <- paste0(
"<b>", mtcars$car_name, "</b><br>",
"Weight: ", round(mtcars$wt, 2), " (1000 lbs)<br>",
"MPG: ", mtcars$mpg, "<br>",
"HP: ", mtcars$hp, "<br>",
"Cylinders: ", mtcars$cyl
)
p <- ggplot(mtcars, aes(wt, mpg,
tooltip = tooltip_text,
data_id = car_name)) +
geom_point_interactive(aes(color = factor(cyl)), size = 3) +
theme_minimal()girafe(ggobj = p_ggiraph)ggiraph offers better ggplot2 compatibility:
- Built specifically for ggplot2 (not a conversion layer)
- Preserves more complex themes and annotations
- Better control over tooltips and interactions
- Uses special
_interactivegeoms
Hover to see tooltips, click to select!
10.14 Key Takeaways
Core concepts:
- Interactive plots are HTML widgets, not images
- Use
ggplotly()to convert ggplot2 plots instantly - Use
saveWidget()withselfcontained = TRUEto save
When to use what:
- Interactive: exploration, presentations, HTML reports
- Static: publications, print, PDF reports
Tips:
- Create both versions when possible
- Sample large datasets to keep HTML file manageable
- Test thoroughly - not all ggplot2 features convert
- Consider ggiraph if ggplotly doesnโt preserve your styling
- Use selfcontained = TRUE for easy sharing
10.15 Summary
ggplotly()converts ggplot2 to interactive - easiest path to interactivityp <- ggplot(mtcars, aes(mpg, hp)) + geom_point() ggplotly(p)Use cases:
- โ Data exploration - zoom, pan, hover for exact values
- โ HTML presentations - engage your audience
- โ Interactive reports - let readers explore
- โ Publications - journals require static figures
- โ Print - obviously doesnโt work
Customize tooltips:
aes(text = paste("Name:", name, "\nValue:", value)) ggplotly(p, tooltip = "text")Linked plots with
crosstalk- highlight in one plot highlights in othersFile size management:
- Large datasets create huge HTML files
- Sample data or use
toWebGL()for performance
Save standalone HTML:
htmlwidgets::saveWidget(ggplotly(p), "plot.html", selfcontained = TRUE)Alternatives:
ggiraphfor better ggplot2 compatibility
10.16 Exercises
Convert a ggplot to interactive:
p <- ggplot(mtcars, aes(mpg, hp, color = factor(cyl))) + geom_point(size = 3) + theme_bw() ggplotly(p)Add custom tooltips showing car names:
mtcars_named <- mtcars %>% rownames_to_column("car") p <- ggplot(mtcars_named, aes(mpg, hp, text = car)) + geom_point() ggplotly(p, tooltip = "text")Try the zoom and pan tools - explore the data
Save as HTML and share with a colleague
Compare
ggplotly()vs.ggiraph::girafe()on the same plot
10.17 Further Reading
- plotly for R book - comprehensive guide by Carson Sievert
- ggplotly documentation - official reference
- ggiraph package - alternative with better ggplot2 compatibility
- crosstalk - linking multiple HTML widgets
- htmlwidgets - R interface to JavaScript libraries