Adding Subset Buttons to plotly Plots

Alice Tivarovsky 2022-09-18 15 minute read

Motivation

I recently found myself drafting some plotly figures for work, and I wanted to add a bit more interactivity without creating a shiny app. I plotted time-series data and I wanted the end user to be able to subset the plot to a year of their choosing, or to see the entire range of time in one figure.

After a bit of googling around, I found a few solutions, but this one suited my needs the best. These buttons are straight-forward for the user and pretty simple to code up. Below is a quick demo.

Data Preparation

library(tidyverse)
library(plotly)

We’ll be using Covid-19 case data in the United States, downloaded from Our World in Data.

raw_data <- 
  read.csv("./data/owid-covid-data.csv", header = TRUE) 

head(raw_data)
##   iso_code continent    location       date total_cases new_cases
## 1      AFG      Asia Afghanistan 2020-02-24           5         5
## 2      AFG      Asia Afghanistan 2020-02-25           5         0
## 3      AFG      Asia Afghanistan 2020-02-26           5         0
## 4      AFG      Asia Afghanistan 2020-02-27           5         0
## 5      AFG      Asia Afghanistan 2020-02-28           5         0
## 6      AFG      Asia Afghanistan 2020-02-29           5         0
##   new_cases_smoothed total_deaths new_deaths new_deaths_smoothed
## 1                 NA           NA         NA                  NA
## 2                 NA           NA         NA                  NA
## 3                 NA           NA         NA                  NA
## 4                 NA           NA         NA                  NA
## 5                 NA           NA         NA                  NA
## 6              0.714           NA         NA                  NA
##   total_cases_per_million new_cases_per_million new_cases_smoothed_per_million
## 1                   0.125                 0.125                             NA
## 2                   0.125                 0.000                             NA
## 3                   0.125                 0.000                             NA
## 4                   0.125                 0.000                             NA
## 5                   0.125                 0.000                             NA
## 6                   0.125                 0.000                          0.018
##   total_deaths_per_million new_deaths_per_million
## 1                       NA                     NA
## 2                       NA                     NA
## 3                       NA                     NA
## 4                       NA                     NA
## 5                       NA                     NA
## 6                       NA                     NA
##   new_deaths_smoothed_per_million reproduction_rate icu_patients
## 1                              NA                NA           NA
## 2                              NA                NA           NA
## 3                              NA                NA           NA
## 4                              NA                NA           NA
## 5                              NA                NA           NA
## 6                              NA                NA           NA
##   icu_patients_per_million hosp_patients hosp_patients_per_million
## 1                       NA            NA                        NA
## 2                       NA            NA                        NA
## 3                       NA            NA                        NA
## 4                       NA            NA                        NA
## 5                       NA            NA                        NA
## 6                       NA            NA                        NA
##   weekly_icu_admissions weekly_icu_admissions_per_million
## 1                    NA                                NA
## 2                    NA                                NA
## 3                    NA                                NA
## 4                    NA                                NA
## 5                    NA                                NA
## 6                    NA                                NA
##   weekly_hosp_admissions weekly_hosp_admissions_per_million total_tests
## 1                     NA                                 NA          NA
## 2                     NA                                 NA          NA
## 3                     NA                                 NA          NA
## 4                     NA                                 NA          NA
## 5                     NA                                 NA          NA
## 6                     NA                                 NA          NA
##   new_tests total_tests_per_thousand new_tests_per_thousand new_tests_smoothed
## 1        NA                       NA                     NA                 NA
## 2        NA                       NA                     NA                 NA
## 3        NA                       NA                     NA                 NA
## 4        NA                       NA                     NA                 NA
## 5        NA                       NA                     NA                 NA
## 6        NA                       NA                     NA                 NA
##   new_tests_smoothed_per_thousand positive_rate tests_per_case tests_units
## 1                              NA            NA             NA            
## 2                              NA            NA             NA            
## 3                              NA            NA             NA            
## 4                              NA            NA             NA            
## 5                              NA            NA             NA            
## 6                              NA            NA             NA            
##   total_vaccinations people_vaccinated people_fully_vaccinated total_boosters
## 1                 NA                NA                      NA             NA
## 2                 NA                NA                      NA             NA
## 3                 NA                NA                      NA             NA
## 4                 NA                NA                      NA             NA
## 5                 NA                NA                      NA             NA
## 6                 NA                NA                      NA             NA
##   new_vaccinations new_vaccinations_smoothed total_vaccinations_per_hundred
## 1               NA                        NA                             NA
## 2               NA                        NA                             NA
## 3               NA                        NA                             NA
## 4               NA                        NA                             NA
## 5               NA                        NA                             NA
## 6               NA                        NA                             NA
##   people_vaccinated_per_hundred people_fully_vaccinated_per_hundred
## 1                            NA                                  NA
## 2                            NA                                  NA
## 3                            NA                                  NA
## 4                            NA                                  NA
## 5                            NA                                  NA
## 6                            NA                                  NA
##   total_boosters_per_hundred new_vaccinations_smoothed_per_million
## 1                         NA                                    NA
## 2                         NA                                    NA
## 3                         NA                                    NA
## 4                         NA                                    NA
## 5                         NA                                    NA
## 6                         NA                                    NA
##   new_people_vaccinated_smoothed new_people_vaccinated_smoothed_per_hundred
## 1                             NA                                         NA
## 2                             NA                                         NA
## 3                             NA                                         NA
## 4                             NA                                         NA
## 5                             NA                                         NA
## 6                             NA                                         NA
##   stringency_index population population_density median_age aged_65_older
## 1             8.33   40099462             54.422       18.6         2.581
## 2             8.33   40099462             54.422       18.6         2.581
## 3             8.33   40099462             54.422       18.6         2.581
## 4             8.33   40099462             54.422       18.6         2.581
## 5             8.33   40099462             54.422       18.6         2.581
## 6             8.33   40099462             54.422       18.6         2.581
##   aged_70_older gdp_per_capita extreme_poverty cardiovasc_death_rate
## 1         1.337       1803.987              NA               597.029
## 2         1.337       1803.987              NA               597.029
## 3         1.337       1803.987              NA               597.029
## 4         1.337       1803.987              NA               597.029
## 5         1.337       1803.987              NA               597.029
## 6         1.337       1803.987              NA               597.029
##   diabetes_prevalence female_smokers male_smokers handwashing_facilities
## 1                9.59             NA           NA                 37.746
## 2                9.59             NA           NA                 37.746
## 3                9.59             NA           NA                 37.746
## 4                9.59             NA           NA                 37.746
## 5                9.59             NA           NA                 37.746
## 6                9.59             NA           NA                 37.746
##   hospital_beds_per_thousand life_expectancy human_development_index
## 1                        0.5           64.83                   0.511
## 2                        0.5           64.83                   0.511
## 3                        0.5           64.83                   0.511
## 4                        0.5           64.83                   0.511
## 5                        0.5           64.83                   0.511
## 6                        0.5           64.83                   0.511
##   excess_mortality_cumulative_absolute excess_mortality_cumulative
## 1                                   NA                          NA
## 2                                   NA                          NA
## 3                                   NA                          NA
## 4                                   NA                          NA
## 5                                   NA                          NA
## 6                                   NA                          NA
##   excess_mortality excess_mortality_cumulative_per_million
## 1               NA                                      NA
## 2               NA                                      NA
## 3               NA                                      NA
## 4               NA                                      NA
## 5               NA                                      NA
## 6               NA                                      NA

Next, we’ll limit to United States data points, and select only the necessary columns. We’ll use new_cases_smoothed (smoothed over the week of data) to avoid the noise of daily fluctuation around the line. We’ll also fix the variable class of date.

us_df <- 
  raw_data %>% 
  select(location, date, new_cases_smoothed) %>% 
  filter(location == "United States") %>% 
  mutate(date = as.POSIXct(date))

us_df %>% 
  filter(!is.na(new_cases_smoothed)) %>% 
  head()
##        location       date new_cases_smoothed
## 1 United States 2020-01-28              0.571
## 2 United States 2020-01-29              0.714
## 3 United States 2020-01-30              0.714
## 4 United States 2020-01-31              0.857
## 5 United States 2020-02-01              0.857
## 6 United States 2020-02-02              0.429
# huge file, remove to save memory
rm(raw_data)

Analysis

We will start by plotting a regular plotly figure, as a “before” shot, if you will.

regular_plot <- 
  us_df %>% 
  plot_ly(x = ~date) %>% 
  add_lines(y = ~new_cases_smoothed) %>% 
  layout(title = "Covid-19 Incidence in the US", 
         yaxis = list(title = "New Cases (Smoothed)"))

regular_plot
Jul 2020Jan 2021Jul 2021Jan 2022Jul 20220100k200k300k400k500k600k700k800k
Covid-19 Incidence in the USdateNew Cases (Smoothed)


Now, we’ll apply the buttons. To do this, we will use an updatemenu relayout method, as detailed here. There are several methods, but relayout is the one most appropriate, since it will allow the user to modify a layout attribute, in this case the range of the x-axis.

button_plot <- 
  us_df %>% 
  plot_ly(x = ~date) %>% 
  add_lines(y = ~new_cases_smoothed) %>% 
  layout(
    title = "Covid-19 Incidence in the US", 
    yaxis = list(title = "New Cases (Smoothed)"),
    updatemenus = list(
      list(type = "buttons",
           buttons = list(list(label = "All", 
                              method = "relayout", 
                              args = list(list(xaxis = list(range = c("2020-01-01","2022-12-31"))))),
                           list(label = "2020", 
                                method = "relayout", 
                                args = list(list(xaxis = list(range = c("2020-01-01","2020-12-31"))))),
                          list(label = "2021", 
                                method = "relayout", 
                                args = list(list(xaxis = list(range = c("2021-01-01","2021-12-31"))))),
                          list(label = "2022", 
                                method = "relayout", 
                                args = list(list(xaxis = list(range = c("2022-01-01","2022-12-31")))))
                          ))))

button_plot
Jul 2020Jan 2021Jul 2021Jan 2022Jul 20220100k200k300k400k500k600k700k800k
Covid-19 Incidence in the USdateNew Cases (Smoothed)All202020212022


Conclusion

And that’s it! We took a plotly figure and made it even more functional with a few easy-to-code controls. Just when I thought I knew the ins and outs of plotly, it surprised me with a sweet feature I’ve never seen.