There’s a fundamental difference between showing someone data and engaging them with it. Static charts are like museum exhibits—beautiful to look at, but protected behind glass. Interactive visualizations, on the other hand, are like science museum displays where you’re encouraged to push buttons, turn cranks, and see what happens. They transform your audience from passive observers into active explorers.
This is where plotly shines. It’s your toolkit for building data experiences that invite curiosity, answer follow-up questions on the fly, and make complex relationships intuitively understandable.
Why Interactivity Changes Everything
Before we dive into code, let’s consider what interactivity actually buys you:
- Instant Context: Hover over a data point and see its exact details without cluttering the visual.
- Personalized Exploration: Let users zoom into what interests them, not just what you decided to show.
- Layered Complexity: Reveal different levels of detail—from a high-level trend down to individual records.
- “What If” Analysis: With filters and controls, users can test their own hypotheses in real-time.
Think of it as the difference between giving someone a printed map versus handing them a smartphone with Google Maps. One is fixed; the other is a conversation.
Your First Interactive Plot: A Simple Conversation Starter
Let’s say we’re analyzing customer feedback for a new mobile app. We have data on user satisfaction scores versus the number of app crashes they experienced.
r
library(plotly)
library(dplyr)
# Sample app feedback data
feedback_data <- data.frame(
user_id = 1:50,
satisfaction = runif(50, 1, 10),
crashes = sample(0:10, 50, replace = TRUE),
user_type = sample(c(“Free”, “Premium”), 50, replace = TRUE)
)
# Create our first interactive plot
fig <- plot_ly(
data = feedback_data,
x = ~crashes, # Number of app crashes
y = ~satisfaction, # User satisfaction score
type = “scatter”,
mode = “markers”,
color = ~user_type, # Color points by Free vs Premium
colors = c(“steelblue”, “orange”),
text = ~paste(“User:”, user_id, “<br>Score:”, round(satisfaction, 1)), # Hover text
hoverinfo = “text”,
marker = list(size = 12, opacity = 0.7)
) %>%
layout(
title = “How App Crashes Impact User Satisfaction”,
xaxis = list(title = “Number of Crashes Experienced”),
yaxis = list(title = “Satisfaction Score (1-10)”),
showlegend = TRUE
)
fig
With just this code, we’ve created a plot where you can:
- Hover over any point to see the user ID and exact satisfaction score
- Click legend items to show/hide Free or Premium users
- Zoom into specific areas by dragging a box
- Pan around the plot once zoomed
- Download the plot as a PNG with one click
The ggplot2 Bridge: Making Your Existing Work Interactive
If you’ve already invested time in learning ggplot2, here’s the best part: you can make almost any ggplot interactive with one function.
r
library(ggplot2)
# Create a detailed static plot with ggplot2
static_plot <- ggplot(feedback_data, aes(x = crashes, y = satisfaction, color = user_type)) +
geom_point(size = 3, alpha = 0.7) +
geom_smooth(method = “lm”, se = FALSE) +
facet_wrap(~ user_type) +
labs(title = “Customer Satisfaction Analysis”,
subtitle = “Premium users seem more tolerant of technical issues”,
x = “App Crashes”, y = “Satisfaction Score”) +
scale_color_manual(values = c(“steelblue”, “orange”)) +
theme_minimal()
# Convert to interactive with one line
interactive_plot <- ggplotly(static_plot)
interactive_plot
The ggplotly() function automatically preserves your faceting, trend lines, and styling while adding all the interactive capabilities. It’s like giving your carefully crafted static charts a superpower.
Telling Stories with Animation: The Gapminder Effect
Some of the most powerful data stories show change over time. Static charts often struggle with this, requiring small multiples or crowded overlays. Animation lets you see the evolution directly.
r
# Using the built-in gapminder dataset
library(gapminder)
animated_fig <- gapminder %>%
plot_ly(
x = ~gdpPercap,
y = ~lifeExp,
size = ~pop,
color = ~continent,
frame = ~year, # This is the magic ingredient
text = ~paste(“Country:”, country, “<br>GDP:”, round(gdpPercap), “<br>Life:”, round(lifeExp)),
type = “scatter”,
mode = “markers”,
hoverinfo = “text”
) %>%
layout(
title = “The World’s Health and Wealth Transformation (1952-2007)”,
xaxis = list(title = “GDP per Capita”, type = “log”),
yaxis = list(title = “Life Expectancy (years)”)
) %>%
animation_opts(frame = 100, transition = 50) %>% # Control animation speed
animation_slider(currentvalue = list(prefix = “Year: “))
animated_fig
When you run this, you get a play button and a slider. Watching countries move across the chart—some leaping forward in wealth and health, others stagnating—tells a story no static chart could match.
Building Dashboards: Multiple Linked Views
True exploratory power comes when you connect multiple visualizations. When a selection in one chart filters all the others, you’ve created an analytical environment.
r
# For this example, we’ll use plotly’s subplot and linking capabilities
library(plotly)
# Chart 1: Satisfaction distribution by user type
plot1 <- plot_ly(feedback_data, y = ~satisfaction, color = ~user_type, type = “box”) %>%
layout(title = “Satisfaction Distribution”)
# Chart 2: Crashes over time (simulated date)
feedback_data$signup_date <- seq.Date(from = as.Date(“2024-01-01”), by = “day”, length.out = 50)
plot2 <- plot_ly(feedback_data, x = ~signup_date, y = ~crashes, color = ~user_type,
type = “scatter”, mode = “lines+markers”) %>%
layout(title = “Crashes Over Time”)
# Combine into a dashboard
subplot(plot1, plot2, nrows = 2, titleX = TRUE, shareX = FALSE) %>%
layout(title = “App Performance Dashboard”,
showlegend = TRUE)
While this creates a multi-view dashboard, for true cross-filtering (where selecting points in one chart highlights them in others), you’d typically use plotly within a Shiny app, which provides even more powerful interactivity.
Real-World Application: Exploring E-commerce Data
Let’s build something practical for business analysis. Imagine we have customer purchase data and want to understand spending patterns.
r
# Simulated e-commerce data
set.seed(123)
customer_data <- data.frame(
customer_id = 1:200,
total_spent = runif(200, 10, 1000),
order_count = sample(1:20, 200, replace = TRUE),
days_since_last_purchase = sample(1:365, 200, replace = TRUE),
customer_tier = sample(c(“Bronze”, “Silver”, “Gold”, “Platinum”), 200,
replace = TRUE, prob = c(0.5, 0.3, 0.15, 0.05))
)
# Create an interactive bubble chart
ecom_plot <- plot_ly(
customer_data,
x = ~order_count,
y = ~total_spent,
size = ~days_since_last_purchase, # Larger bubbles = inactive customers
color = ~customer_tier,
colors = c(“brown”, “gray”, “gold”, “purple”),
text = ~paste(“Customer:”, customer_id,
“<br>Orders:”, order_count,
“<br>Total: $”, round(total_spent),
“<br>Last Purchase:”, days_since_last_purchase, “days ago”),
type = “scatter”,
mode = “markers”,
marker = list(sizemode = “diameter”, opacity = 0.7, sizeref = 2)
) %>%
layout(
title = “Customer Value Analysis”,
xaxis = list(title = “Number of Orders”),
yaxis = list(title = “Total Amount Spent ($)”),
hoverlabel = list(bgcolor = “white”)
)
ecom_plot
This single visualization lets business users:
- Identify high-value customers (top-right quadrant)
- Spot at-risk customers (large bubbles = haven’t purchased recently)
- Compare performance across customer tiers
- Get detailed information about any customer instantly
Sharing Your Interactive Stories
Once you’ve created an engaging interactive visualization, you’ll want to share it. plotly makes this straightforward:
r
# Save as a standalone HTML file
htmlwidgets::saveWidget(ecom_plot, file = “customer_analysis_dashboard.html”)
# The file can be opened in any web browser, emailed to colleagues,
# or embedded in websites and blogs
For internal business use, embedding plotly visualizations in R Markdown reports or Shiny applications means your stakeholders always have access to the latest data with full exploratory capabilities.
Conclusion: From Presentation to Conversation
Learning plotly isn’t just about adding fancy features to your charts. It’s about fundamentally changing how you communicate with data. You’re moving from delivering monologues to facilitating dialogues.
The progression often looks like this:
- Static ggplot2: “Here’s what I found.”
- Basic plotly: “Here’s what I found—and you can explore the details.”
- Advanced plotly with animation and linking: “Let’s explore this story together.”
The most powerful outcome of interactive visualization isn’t technical—it’s psychological. When people can manipulate the data themselves, when they can satisfy their own curiosity with a hover or a click, they develop ownership of the insights. They don’t just understand your conclusion; they arrive at it with you.
In a world where data-informed decisions are increasingly crucial, the ability to create these engaging, exploratory experiences isn’t just a nice-to-have skill. It’s becoming essential for anyone who wants their analysis to be not just seen, but understood and acted upon.