Ever wanted to make your figures more interactive?
Today we are going to talk about making interactive plots using Plotly. Plotly in a variety of programming languages, but today we will be just talking about using it in R. All of the plotly documentation can be found here.
If you have not already installed plotly, please do so here.
install.packages("plotly")
Here are some useful links to find info about using ggplotly
.
ggplotly()
layout()
ggplotly()
tooltipsBefore we start, there are two basic ways to use plot in R using plotly:
ggplotly()
- this is what we will go over today because it has the same syntax as ggplot()
which we have already learnedplot_ly()
- there is slightly more functionality in this function, but the syntax is all new, so I’d suggest if you can do what you want with ggplotly()
, do that. The syntax is not particularly hard so don’t be scared to use it if interactive plots are something you’re very interested in.When you are googling about using plotly, you will find a combination of ggplotly()
and plot_ly()
approaches, and some parts of the code are interchangable. The easiesy way to see which parts are, is to try.
Also note, Google gets a bit confused when googling “ggplotly” and often returns information about just ggplot, so read extra carefully when problem solving.
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.3 ✓ purrr 0.3.4
## ✓ tibble 3.1.0 ✓ dplyr 1.0.5
## ✓ tidyr 1.1.3 ✓ stringr 1.4.0
## ✓ readr 1.4.0 ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(plotly) # for making interactive plots
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
library(htmlwidgets) # for saving html files
library(palmerpenguins) # for our penguins data
Let’s look at penguins_raw
this time, a df that has a bit more data than the penguins
df.
head(penguins_raw)
## # A tibble: 6 x 17
## studyName `Sample Number` Species Region Island Stage `Individual ID`
## <chr> <dbl> <chr> <chr> <chr> <chr> <chr>
## 1 PAL0708 1 Adelie Pengu… Anvers Torger… Adult,… N1A1
## 2 PAL0708 2 Adelie Pengu… Anvers Torger… Adult,… N1A2
## 3 PAL0708 3 Adelie Pengu… Anvers Torger… Adult,… N2A1
## 4 PAL0708 4 Adelie Pengu… Anvers Torger… Adult,… N2A2
## 5 PAL0708 5 Adelie Pengu… Anvers Torger… Adult,… N3A1
## 6 PAL0708 6 Adelie Pengu… Anvers Torger… Adult,… N3A2
## # … with 10 more variables: Clutch Completion <chr>, Date Egg <date>,
## # Culmen Length (mm) <dbl>, Culmen Depth (mm) <dbl>,
## # Flipper Length (mm) <dbl>, Body Mass (g) <dbl>, Sex <chr>,
## # Delta 15 N (o/oo) <dbl>, Delta 13 C (o/oo) <dbl>, Comments <chr>
head(penguins)
## # A tibble: 6 x 8
## species island bill_length_mm bill_depth_mm flipper_length_… body_mass_g sex
## <fct> <fct> <dbl> <dbl> <int> <int> <fct>
## 1 Adelie Torge… 39.1 18.7 181 3750 male
## 2 Adelie Torge… 39.5 17.4 186 3800 fema…
## 3 Adelie Torge… 40.3 18 195 3250 fema…
## 4 Adelie Torge… NA NA NA NA <NA>
## 5 Adelie Torge… 36.7 19.3 193 3450 fema…
## 6 Adelie Torge… 39.3 20.6 190 3650 male
## # … with 1 more variable: year <int>
bill_depth_length <- penguins_raw %>%
ggplot(aes(x = `Culmen Length (mm)`, y = `Culmen Depth (mm)`)) +
geom_point()
bill_depth_length
## Warning: Removed 2 rows containing missing values (geom_point).
Making plot interactive.
You can learn more about the ggplotly()
function, including its arguments here.
ggplotly(bill_depth_length)
Wow. That was easy!
Adding a title, and changing the theme.
bill_depth_length <- penguins_raw %>%
ggplot(aes(x = `Culmen Length (mm)`, y = `Culmen Depth (mm)`)) +
geom_point() +
theme_minimal() +
labs(title = "Understanding Penguin Bill Dimensions")
ggplotly(bill_depth_length)
What if we want to hover over each point and be able to tell which Island
the penguin was found on?
bill_depth_length <- penguins_raw %>%
ggplot(aes(x = `Culmen Length (mm)`, y = `Culmen Depth (mm)`,
text = Island)) +
geom_point() +
theme_minimal() +
labs(title = "Understanding Penguin Bill Dimensions")
ggplotly(bill_depth_length,
tooltip = "text")
To be able to hover with a variable, it has to be indicated someplace in your ggplot2 call.
bill_depth_length <- penguins_raw %>%
ggplot(aes(x = `Culmen Length (mm)`, y = `Culmen Depth (mm)`,
text = Island, group = `Individual ID`)) +
geom_point() +
theme_minimal() +
labs(title = "Understanding Penguin Bill Dimensions")
ggplotly(bill_depth_length,
tooltip = c("text", "Individual ID")) # hover test will be in this order
You can use paste
to add some information you’d like to see in each of the hover texts, here, we are indicating Island: Island
bill_depth_length <- penguins_raw %>%
ggplot(aes(x = `Culmen Length (mm)`, y = `Culmen Depth (mm)`,
text = paste("Island:", Island))) +
geom_point() +
theme_minimal() +
labs(title = "Understanding Penguin Bill Dimensions")
ggplotly(bill_depth_length,
tooltip = "text")
Changing hover label aesthetics and the fonts of your plot.
# setting fonts for the plot
font <- list(
family = "Roboto Condensed",
size = 15,
color = "white")
# setting hover label specs
label <- list(
bgcolor = "#FF0000",
bordercolor = "transparent",
font = font) # we can do this bc we already set font
# plotting like normal
bill_depth_length <- penguins_raw %>%
ggplot(aes(x = `Culmen Length (mm)`, y = `Culmen Depth (mm)`,
text = paste("Island:", Island))) +
geom_point() +
theme_minimal() +
labs(title = "A Deep Dive (ha) Into \nUnderstanding Penguin Bill Dimensions")
# use\n to bring your text to another line
# amending our ggplotly call to include new fonts and hover label specs
ggplotly(bill_depth_length, tooltip = "text") %>%
style(hoverlabel = label) %>%
layout(font = font)
Keep your axis labels so when you zoom, you can see where you are on your plot.
ggplotly(bill_depth_length,
tooltip = "text",
dynamicTicks = TRUE)
Don’t forget you can use things like faceting, that we have gone over previously in Session 10.
bill_depth_length <- penguins %>%
ggplot(aes(x = bill_length_mm, y = bill_depth_mm, color = species,
text = paste("Island:", island))) +
geom_point() +
theme_minimal() +
theme(legend.position = "none") +
labs(title = "Understanding Penguin Bill Dimensions",
x = "Culmen Bill Length (mm)",
y = "Culmen Bill Depth (mm)") +
facet_wrap(~species)
ggplotly(bill_depth_length,
tooltip = "text")
Add frame
in your aesthetics mapping to tell plotly what column to animate over.
# add frame
bill_depth_length <- penguins_raw %>%
ggplot(aes(x = `Culmen Length (mm)`, y = `Culmen Depth (mm)`,
frame = Island, text = `Individual ID`)) +
geom_point() +
theme_minimal() +
labs(title = "Understanding Penguin Bill Dimensions")
ggplotly(bill_depth_length,
tooltip = "text")
Assign the plot you want to save to an object, and use the function saveWidget()
to save it. You can find the documentation here.
# assign ggplotly plot to an object
ggplotly_to_save <- ggplotly(bill_depth_length,
tooltip = "text")
# save
saveWidget(widget = ggplotly_to_save,
file = "ggplotlying.html")
Back to birds. Let’s re-create the birds joined dataset from the end of Session 3 on joining.
# create directory for data to go
dir.create('data/birds/', recursive = TRUE)
## Warning in dir.create("data/birds/", recursive = TRUE): 'data/birds' already
## exists
# preparing to download
# denote bird file url
birds_url <-
'https://raw.githubusercontent.com/biodash/biodash.github.io/master/assets/data/birds/backyard-birds_Ohio.tsv'
# denote file name
birds_file <- 'data/birds/backyard-birds_Ohio.tsv'
# get file
download.file(url = birds_url,
destfile = birds_file)
# read in birds data
birds <- read_tsv(file = 'data/birds/backyard-birds_Ohio.tsv')
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## class = col_character(),
## order = col_character(),
## family = col_character(),
## genus = col_character(),
## species = col_character(),
## locality = col_character(),
## stateProvince = col_character(),
## decimalLatitude = col_double(),
## decimalLongitude = col_double(),
## eventDate = col_datetime(format = ""),
## species_en = col_character(),
## range = col_character()
## )
Look at your new df.
head(birds)
## # A tibble: 6 x 12
## class order family genus species locality stateProvince decimalLatitude
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
## 1 Aves Passer… Corvid… Cyano… Cyanocit… 44805 As… Ohio 40.9
## 2 Aves Passer… Corvid… Cyano… Cyanocit… 45244 Ci… Ohio 39.1
## 3 Aves Passer… Corvid… Cyano… Cyanocit… 44132 Eu… Ohio 41.6
## 4 Aves Passer… Corvid… Cyano… Cyanocit… 45242 Ci… Ohio 39.2
## 5 Aves Passer… Corvid… Cyano… Cyanocit… 45246 Ci… Ohio 39.3
## 6 Aves Passer… Corvid… Cyano… Cyanocit… 44484 Wa… Ohio 41.2
## # … with 4 more variables: decimalLongitude <dbl>, eventDate <dttm>,
## # species_en <chr>, range <chr>
dim(birds)
## [1] 311441 12
Filter your new birds
df to only inclue Blue Jays. Check to see how many bald eagle sightings there were in Ohio.
bald_eagle <- birds %>%
filter(species_en == "Bald Eagle")
# what do we have?
head(bald_eagle)
## # A tibble: 6 x 12
## class order family genus species locality stateProvince decimalLatitude
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
## 1 Aves Accipi… Accipi… Halia… Haliaeet… Mentor Ohio 41.7
## 2 Aves Accipi… Accipi… Halia… Haliaeet… 45742 Li… Ohio 39.3
## 3 Aves Accipi… Accipi… Halia… Haliaeet… Moreland… Ohio 41.4
## 4 Aves Accipi… Accipi… Halia… Haliaeet… Eastlake Ohio 41.7
## 5 Aves Accipi… Accipi… Halia… Haliaeet… 44060 Me… Ohio 41.7
## 6 Aves Accipi… Accipi… Halia… Haliaeet… 44839 Hu… Ohio 41.4
## # … with 4 more variables: decimalLongitude <dbl>, eventDate <dttm>,
## # species_en <chr>, range <chr>
# check our df dimensions
dim(bald_eagle)
## [1] 381 12
Create a map that plots all the bald eagles found around Ohio. Color the points blue. Make sure the aspect ratio of Ohio looks reasonable to you.
library(maps)
##
## Attaching package: 'maps'
## The following object is masked from 'package:purrr':
##
## map
# get map of the states
states <- map_data("state")
# filter states to only include ohio
ohio <- states %>%
filter(region == "ohio")
# plot
ggplot(data = ohio,
aes(x = long, y = lat, group = group)) +
geom_polygon(color = "black", fill = "white") +
geom_point(data = bald_eagle,
aes(x = decimalLongitude, y = decimalLatitude, group = NULL),
color = "blue", alpha = 0.2) +
coord_fixed(1.2) +
labs(title = 'Bald Eagles round Ohio')
Make your plot interactive so you can hover and and see the locality of each bald eagle observation.
bald_eagles_ohio <-
ggplot(data = ohio,
aes(x = long, y = lat, group = group)) +
geom_polygon(color = "black", fill = "white") +
geom_point(data = bald_eagle,
aes(x = decimalLongitude, y = decimalLatitude, group = NULL,
text = locality),
color = "blue", alpha = 0.2) +
coord_fixed(1.2) +
labs(title = 'Bald Eagles Around Ohio')
## Warning: Ignoring unknown aesthetics: text
ggplotly(bald_eagles_ohio,
tooltip = "text")
Change the hover text so that the background color is red, clean up your axis labels, and make all the fonts for the plot Arial.
# setting fonts for the plot
eagle_font <- list(
family = "Arial",
size = 15,
color = "white")
# setting hover label specs
eagle_label <- list(
bgcolor = "red",
bordercolor = "transparent",
font = eagle_font) # we can do this bc we already set font
bald_eagles_ohio <-
ggplot(data = ohio,
aes(x = long, y = lat, group = group)) +
geom_polygon(color = "black", fill = "white") +
geom_point(data = bald_eagle,
aes(x = decimalLongitude, y = decimalLatitude, group = NULL,
text = locality),
color = "blue", alpha = 0.2) +
coord_fixed(1.2) +
labs(title = 'Bald Eagles around the Ohio',
x = "Latitude",
y = "Longitude")
## Warning: Ignoring unknown aesthetics: text
# amending our ggplotly call to include new fonts and hover label specs
ggplotly(bald_eagles_ohio, tooltip = "text") %>%
style(hoverlabel = eagle_label) %>%
layout(font = eagle_font)
Let’s go back to the Gapminder data we looked at in the instructional part of Session 10 on faceting, animating, and multi-plotting.
# install.packages("gapminder") # if you weren't at Session 10
library(gapminder)
head(gapminder)
## # A tibble: 6 x 6
## country continent year lifeExp pop gdpPercap
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afghanistan Asia 1952 28.8 8425333 779.
## 2 Afghanistan Asia 1957 30.3 9240934 821.
## 3 Afghanistan Asia 1962 32.0 10267083 853.
## 4 Afghanistan Asia 1967 34.0 11537966 836.
## 5 Afghanistan Asia 1972 36.1 13079460 740.
## 6 Afghanistan Asia 1977 38.4 14880372 786.
Make a bubble-style plot that shows the life expectancy vs. GDP per capita over 1952 to 2007 for all countries. Color by continent, and indicate population by size. Use your knowledge of making plots to alter it such that you think it is descriptive and aesthetic.
gapminder_font <- list(
family = "Roboto Condensed")
gapminder_bubble <- gapminder %>%
ggplot(aes(x = gdpPercap, y = lifeExp,
fill = continent, size = pop,
text = paste(
"Country:", country,
"\nLife expectancy:", round(lifeExp,1),
"\nGDP per capita:", round(gdpPercap,0)))) +
geom_point(aes(frame = year), color = "black", shape = 21, stroke = 0.2) +
scale_x_log10() +
theme_minimal() +
theme(plot.title = element_text(size = 18)) +
labs(title = "Changing Life Expectancy and GDP Per Capita Worldwide \nFrom 1952 to 2007",
x = "GDP per capita (in International Dollars)",
y = "Life Expectancy (years)",
fill = "",
size = "")
## Warning: Ignoring unknown aesthetics: frame
ggplotly(gapminder_bubble,
tooltip = c("text")) %>%
layout(font = gapminder_font)