Interactive Data Visualization with plotly
Note
Interactive Plotting with Plotly
Learn to create beautiful, interactive visualizations in R
What Youโll Learn:
# ref: https://www.r-graph-gallery.com/138-green-world-data-art/
library(ggplot2)
library(RColorBrewer)
ngroup=20
names=paste("G_",seq(1,ngroup),sep="")
DAT=data.frame()
for(i in seq(1:50)){
data=data.frame( matrix(0, ngroup , 3))
data[,1]=i
data[,2]=sample(names, nrow(data))
data[,3]=prop.table(sample(
c(rep(0,100),
c(1:ngroup)),
nrow(data)))
DAT=rbind(DAT,data)
}
colnames(DAT)=c("Year","Group","Value")
DAT=DAT[order( DAT$Year, DAT$Group) , ]
ggplot(DAT, aes(x=Year, y=Value, fill=Group )) +
geom_area(alpha=1 , color="transparent" )+
theme_bw() +
scale_fill_brewer(palette="greens", breaks=rev(levels(DAT$Group)))+
theme(line = element_blank(),
text = element_blank(),
# line = element_blank(),
title = element_blank(),
legend.position="none",
panel.border = element_blank(),
panel.background = element_blank())Tip
Read more about it at Data to Art
Explore a variety of chart types and styles available for all kinds of data visualization applications.
Find code examples to edit at; R-Graph-Gallery
PlotlyPlotly is a powerful graphing library that creates interactive, publication-quality visualizations
Key Features:
Plotly vs ggplot2: ggplot2 excels at static graphics; Plotly adds interactivity for web dashboards and exploration.
Tip
Start with a clean workspace for reproducible R scripts
Note
List the packages your script needs, then install any that are missing.
Note
Simple Scatter Plot โ The easiest way to start with Plotly
Note
Static ggplot2 version of the plotly output; run the plotly code for the interactive version.
Note
The first example uses the same core arguments in plot_ly().
plot_ly(): Main plotting functiondata: Your data framex, y: Variables (use ~ notation)type: Chart type (โscatterโ, โbarโ, โboxโ, etc.)mode: For scatter plots (โmarkersโ, โlinesโ, โmarkers+linesโ)Tip
Every Plotly plot comes with built-in interactivity!
Explore the plot:
Exploring Relationships Between Variables
Tip
Adjust marker size, fill, and outline to make points easier to distinguish.
Customizing Markers:
Adding Color Dimension
Visualize a third variable with color
Color Options:
color = ~variable: map a variable to colorcolors = 'Set1': use an RColorBrewer palettecolors = c(...): provide custom colorsTip
Customize Tooltip Information
Note
Use hoverinfo to show only the details that help explain the plot.
Hover Options:
hoverinfo = 'x': Show only x valuehoverinfo = 'y': Show only y valuehoverinfo = 'x+y': Show both coordinateshoverinfo = 'text': Show custom texthoverinfo = 'none': Disable hoverAdding Statistical Models
library(plotly)
library(dplyr)
# Calculate linear model
model <- lm(Petal.Length ~ Sepal.Length, data = iris)
iris$predicted <- predict(model)
# Plot with trend line
fig <- plot_ly(data = iris, x = ~Sepal.Length) %>%
add_markers(y = ~Petal.Length, name = 'Actual',
marker = list(size = 8, opacity = 0.6)) %>%
add_lines(y = ~predicted, name = 'Trend',
line = list(color = 'red', width = 2)) %>%
layout(title = "Scatter Plot with Linear Regression",
xaxis = list(title = "Sepal Length"),
yaxis = list(title = "Petal Length"))
figNote
Visualizing Distributions โ Box plots show median, quartiles, and outliers
Note
The box summarizes the distribution; points beyond the whiskers are outliers.
Comparing Multiple Groups
Tip
Jitter spreads points horizontally so overlapping observations are easier to see.
Tip
Better for Long Category Names
# Horizontal orientation
fig <- plot_ly(data = iris,
x = ~Sepal.Length, # x for horizontal
y = ~Species, # y for categories
color = ~Species,
type = 'box',
orientation = 'h') # h for horizontal
fig <- fig %>% layout(
title = "Sepal Length by Species (Horizontal)",
xaxis = list(title = "Sepal Length (cm)"),
yaxis = list(title = "")
)
figNote
Comparing Different Measurements
# Create subplot with multiple box plots
fig <- plot_ly(data = iris, x = ~Species) %>%
add_trace(y = ~Sepal.Length, name = 'Sepal Length',
type = 'box', boxmean = 'sd') %>%
add_trace(y = ~Sepal.Width, name = 'Sepal Width',
type = 'box', boxmean = 'sd') %>%
add_trace(y = ~Petal.Length, name = 'Petal Length',
type = 'box', boxmean = 'sd') %>%
add_trace(y = ~Petal.Width, name = 'Petal Width',
type = 'box', boxmean = 'sd') %>%
layout(title = "All Iris Measurements by Species",
yaxis = list(title = "Measurement (cm)"))
figNote
Set boxmean = 'sd' to show the mean and standard deviation.
Distribution of a Single Variable
Note
Choose the number of bins or specify exact bin boundaries.
nbinsx: Number of bins (auto-calculated if not specified)xbins: Manual bin configurationWarning
Binwidth Matters! The choice of binwidth dramatically affects interpretation
Too Few Bins (Large Binwidth):
Advantages: โ
Clear overall pattern, less noise
Disadvantages: โ Loses fine-grained patterns, may hide bimodality
Too Many Bins (Small Binwidth):
Advantages: โ
Shows fine detail, reveals minor peaks
Disadvantages: โ Noisy, harder to see overall pattern, sparse bins
Tip
Rules of Thumb for Choosing Bins
Common Rules:
bins โ logโ(n) + 1bins โ โnbinwidth โ 3.5ฯ / โnbinwidth โ 2IQR / โnTip
Plotly chooses a default binning; compare it with other choices to see which best tells the dataโs story.
Note
Manual Control Over Bins
# Specify exact bin size
fig <- plot_ly(x = ~iris$Sepal.Length,
type = 'histogram',
xbins = list(
start = 4.0, # First bin starts at 4
end = 8.0, # Last bin ends at 8
size = 0.2 # Each bin is 0.2 cm wide
))
fig <- fig %>% layout(
title = "Sepal Length with 0.2 cm Bins",
xaxis = list(title = "Sepal Length (cm)"),
yaxis = list(title = "Frequency")
)
figComparing Distributions
# Create separate data for each species
setosa <- iris %>% filter(Species == "setosa")
versicolor <- iris %>% filter(Species == "versicolor")
virginica <- iris %>% filter(Species == "virginica")
# Overlaid histograms
fig <- plot_ly(alpha = 0.6) %>%
add_histogram(x = ~setosa$Sepal.Length, name = "Setosa") %>%
add_histogram(x = ~versicolor$Sepal.Length, name = "Versicolor") %>%
add_histogram(x = ~virginica$Sepal.Length, name = "Virginica") %>%
layout(barmode = "overlay", # Overlay instead of stack
title = "Sepal Length by Species",
xaxis = list(title = "Sepal Length (cm)"),
yaxis = list(title = "Count"))
figOther barmode options: 'stack', 'group'
Tip
Showing Composition
# Stacked histogram
fig <- plot_ly() %>%
add_histogram(x = ~setosa$Sepal.Length,
name = "Setosa",
marker = list(color = '#e74c3c')) %>%
add_histogram(x = ~versicolor$Sepal.Length,
name = "Versicolor",
marker = list(color = '#3498db')) %>%
add_histogram(x = ~virginica$Sepal.Length,
name = "Virginica",
marker = list(color = '#2ecc71')) %>%
layout(barmode = "stack",
title = "Species Distribution Across Sepal Lengths",
xaxis = list(title = "Sepal Length (cm)"),
yaxis = list(title = "Total Count"))
figNote
Categorical Data Visualization
# Count by species
species_count <- iris %>%
group_by(Species) %>%
summarise(Count = n())
fig <- plot_ly(data = species_count,
x = ~Species,
y = ~Count,
type = 'bar',
marker = list(color = c('#e74c3c', '#3498db', '#2ecc71')))
fig <- fig %>% layout(
title = "Sample Count by Species",
xaxis = list(title = "Species"),
yaxis = list(title = "Number of Samples")
)
figTime Series and Trends
iris_sorted <- iris %>% arrange(Sepal.Length)
fig <- plot_ly(iris_sorted, x = ~seq_along(Sepal.Length),
y = ~Sepal.Length, color = ~Species,
type = 'scatter', mode = 'lines+markers',
line = list(width = 2), marker = list(size = 6)) %>%
layout(title = "Sepal Length Sorted Values",
xaxis = list(title = "Sample Index"),
yaxis = list(title = "Sepal Length (cm)"))
figTip
Density + Box Plot Combined
# Violin plot shows distribution shape
fig <- plot_ly(data = iris,
x = ~Species,
y = ~Sepal.Length,
color = ~Species,
type = 'violin',
box = list(visible = TRUE), # Show box plot inside
meanline = list(visible = TRUE)) # Show mean line
fig <- fig %>% layout(
title = "Sepal Length Distribution (Violin Plot)",
xaxis = list(title = "Species"),
yaxis = list(title = "Sepal Length (cm)")
)
figViolin plots show the full probability density, making them superior to box plots for multimodal distributions!
Note
Correlation Matrix Visualization
iris_numeric <- iris %>% select(-Species)
cor_matrix <- cor(iris_numeric)
fig <- plot_ly(x = colnames(cor_matrix), y = rownames(cor_matrix),
z = cor_matrix, type = "heatmap",
colors = colorRamp(c("blue", "white", "red"))) %>%
layout(title = "Iris Feature Correlation Matrix",
xaxis = list(title = ""), yaxis = list(title = ""))
figThree-Dimensional Data
fig <- plot_ly(iris, x = ~Sepal.Length, y = ~Sepal.Width,
z = ~Petal.Length, color = ~Species,
type = 'scatter3d', mode = 'markers',
marker = list(size = 5)) %>%
layout(scene = list(
xaxis = list(title = 'Sepal Length'),
yaxis = list(title = 'Sepal Width'),
zaxis = list(title = 'Petal Length')),
title = "3D Iris Visualization")
figInteractivity is KEY! Rotate the plot by clicking and dragging!
Tip
Fine-Tuning Your Plots
fig <- plot_ly(iris, x = ~Sepal.Length, y = ~Petal.Length,
color = ~Species, type = 'scatter', mode = 'markers')
fig <- fig %>% layout(
title = list(text = "Beautiful Iris Plot",
font = list(size = 24, color = '#2c3e50')),
xaxis = list(title = "Sepal Length (cm)", gridcolor = '#E0E0E0',
showline = TRUE, linecolor = '#2c3e50', linewidth = 2),
yaxis = list(title = "Petal Length (cm)", gridcolor = '#E0E0E0'),
plot_bgcolor = '#F8F9FA', paper_bgcolor = '#FFFFFF')
figNote
Using Color Effectively
Note
Use a palette that helps readers distinguish values without distracting from the data.
Built-in Color Scales:
colors = 'Viridis', 'Blues', 'Reds', 'RdBu'colors = colorRamp(c("blue", "yellow", "red"))Add a text label and arrow to call attention to a data point.
Tip
Use a transparent rectangle to mark an area of the plot without hiding the data.
Tip
Multiple Plots in One Figure
library(plotly)
# Create individual plots
p1 <- plot_ly(iris, x = ~Sepal.Length, type = "histogram",
name = "Sepal Length")
p2 <- plot_ly(iris, x = ~Petal.Length, type = "histogram",
name = "Petal Length")
p3 <- plot_ly(iris, x = ~Sepal.Length, y = ~Petal.Length,
color = ~Species, type = "scatter", mode = "markers")
p4 <- plot_ly(iris, x = ~Species, y = ~Sepal.Length,
color = ~Species, type = "box")Tip
After defining p1 through p4, arrange them in a 2 ร 2 layout.
Build Your Own Plotly Visualization!
Interactive tool to generate Plotly code for different plot types
Click "Generate Code" to create your Plotly code!
Tip
Interactive Learning โ Experiment with the controls and inspect the generated code.
Try these options:
Try it: Generate code for a 3D scatter plot of iris data colored by Species!
Note
Choosing the Right Tool
Choose Plotly for:
โ
Interactive dashboards and web apps
โ
Exploratory data analysis
โ
Presentations where you can click and zoom
โ
Sharing HTML reports
โ
3D visualizations
Note
Choose a static plot when publication control matters most.
โ
Publication-quality static graphics
โ
Fine-grained control over every element
โ
Complex multi-layered plots
โ
PDF/PNG exports for papers
โ
Faceted plots with many panels
Need both? Convert a ggplot with ggplotly().
The Power of ggplotly()
Advantages:
Warning
Making Plotly Fast
For Large Datasets:
# 1. Use webgl for better performance
fig <- plot_ly(data = large_dataset,
x = ~x, y = ~y,
type = 'scattergl', # Note: scattergl instead of scatter
mode = 'markers')
# 2. Reduce marker count with sampling
sampled <- large_dataset %>% sample_n(1000)
fig <- plot_ly(data = sampled, ...)
# 3. Disable hover for thousands of points
fig <- plot_ly(..., hoverinfo = 'skip')Note
Choose a rendering strategy that matches the size of your data.
Tips:
scattergl for >1000 pointsTip
Export Options
Tip
Static PNG export requires a configured image engine such as Kaleido.
Note
In an R Markdown or Quarto document, print the plot object to include it.
Note
What We Learned
1. Installation: Use install.packages('plotly') and setup functions
2. Basic Syntax:
3. Plot Types: - Scatter, Box, Histogram, Bar, Line, Violin, Heatmap, 3D
4. Binwidths: - Too few bins โ lose detail - Too many bins โ too noisy - Use Plotlyโs smart defaults or calculate optimal bins
Note
Make plots clearer and shareable
5. Customization: - layout() for axes, titles, colors - add_trace() for multiple layers - Annotations and shapes for context
Tip
Try This on Your Own!
Challenge: Create an interactive Plotly visualization using the mtcars dataset
Requirements:
mpg vs wt (weight)cyl (cylinders)Tip
Try an extension after the required scatter plot is complete.
Bonus:
disp as z-axisTime: 5-10 minutes
Continue Learning
Documentation: Plotly R ยท Graph reference ยท Community forum
Tutorials: Getting started ยท Plotly book ยท R Graph Gallery
Cheat sheet: Plotly R PDF
Note
Keep Exploring!
You now know how to:
โ
Install and set up Plotly
โ
Create interactive scatter, box, and histogram plots
โ
Choose appropriate binwidths
โ
Customize plots with colors, layouts, and themes
โ
Use the code generator for quick starts
โ
Convert ggplot2 plots to interactive Plotly plots
Note
Keep exploring with your own data
Next Steps:
Happy Plotting! ๐โจ