Introduction to interactivity

Lecture 18

Dr. Benjamin Soltoff

Cornell University
INFO 3312/5312 - Spring 2024

March 28, 2024

Announcements

Announcements

  • Project 02 peer review

Visualization critique

The Big Mac Index

  • How is the information organized?
  • How does interactivity assist in understanding the data?

Making interactive graphics

Three general approaches

  1. Single plots with Plotly

    • Easy(-ish) to convert existing ggplot2 plots
    • More complicated to develop them directly in plotly
  2. Dashboards with Quarto

    • More complicated to develop
    • More powerful and flexible
  3. Interactive web applications with Shiny

    • Can become highly complicated
    • Complete control over the user interface and dynamic content

Single plots with Plotly

Single plots with Plotly

  • Open source software for creating graphs using JavaScript
  • Unlike D3.js, does not require extensive knowledge of JavaScript
  • ggplotly() in plotly converts ggplot2 plots to plotly plots

Plotly

library(gapminder)
library(plotly)

gapminder_2007 <- filter(
  gapminder,
  year == 2007
)

my_plot <- ggplot(
  data = gapminder_2007,
  mapping = aes(
    x = gdpPercap, y = lifeExp,
    color = continent
  )
) +
  geom_point() +
  scale_x_log10() +
  theme_minimal()

ggplotly(my_plot)

Plotly tooltips

my_plot <- ggplot(
  data = gapminder_2007,
  mapping = aes(
    x = gdpPercap, y = lifeExp,
    color = continent
  )
) +
  geom_point(aes(text = country)) +
  scale_x_log10() +
  theme_minimal()

ggplotly(
  my_plot,
  tooltip = "text"
)

Works with most geoms

car_hist <- ggplot(
  data = mpg,
  mapping = aes(x = hwy)
) +
  geom_histogram(
    binwidth = 2,
    boundary = 0,
    color = "white"
  )

ggplotly(car_hist)

Create a basic interactive chart with ggplot2 and plotly

Get and clean data

library(tidyverse)
library(WDI)
library(scales)
library(plotly)
library(colorspace)
library(ggbeeswarm)
# get World Bank indicators
indicators <- c(
  population = "SP.POP.TOTL",
  prop_women_parl = "SG.GEN.PARL.ZS",
  gdp_per_cap = "NY.GDP.PCAP.KD"
)

wdi_parl_raw <- WDI(
  country = "all", indicators, extra = TRUE,
  start = 2022, end = 2022
)

# keep actual "economies"
wdi_clean <- wdi_parl_raw |>
  filter(region != "Aggregates")
glimpse(wdi_clean)
Rows: 215
Columns: 15
$ country         <chr> "Afghanistan", "Albania", "Algeria…
$ iso2c           <chr> "AF", "AL", "DZ", "AS", "AD", "AO"…
$ iso3c           <chr> "AFG", "ALB", "DZA", "ASM", "AND",…
$ year            <int> 2022, 2022, 2022, 2022, 2022, 2022…
$ status          <chr> "", "", "", "", "", "", "", "", ""…
$ lastupdated     <chr> "2024-02-21", "2024-02-21", "2024-…
$ population      <dbl> 41128771, 2777689, 44903225, 44273…
$ prop_women_parl <dbl> NA, 35.714286, 8.108108, NA, 46.42…
$ gdp_per_cap     <dbl> NA, 5155.291, 3999.758, 14969.060,…
$ region          <chr> "South Asia", "Europe & Central As…
$ capital         <chr> "Kabul", "Tirane", "Algiers", "Pag…
$ longitude       <chr> "69.1761", "19.8172", "3.05097", "…
$ latitude        <chr> "34.5228", "41.3317", "36.7397", "…
$ income          <chr> "Low income", "Upper middle income…
$ lending         <chr> "IDA", "IBRD", "IBRD", "Not classi…

Creating a basic interactive chart

wdi_2022 <- wdi_clean |>
  filter(year == 2022) |>
  drop_na(prop_women_parl) |>
  # Scale this down from 0-100 to 0-1 so that scales::label_percent() can format
  # it as an actual percent
  mutate(prop_women_parl = prop_women_parl / 100)

static_plot <- ggplot(
  data = wdi_2022,
  mapping = aes(y = fct_rev(region), x = prop_women_parl, color = region)
) +
  geom_quasirandom() +
  scale_x_continuous(labels = label_percent()) +
  scale_color_discrete_qualitative(guide = "none") +
  labs(x = "% women in parliament", y = NULL, caption = "Source: The World Bank") +
  theme_bw(base_size = 14)
static_plot

Make it interactive

ggplotly(static_plot)
  • Not everything translates to JavaScript
  • No caption
  • Legend has returned (must use theme(legend.position = "none"))

Modifying the tooltip

static_plot_tooltip <- ggplot(
  data = wdi_2022,
  mapping = aes(y = fct_rev(region), x = prop_women_parl, color = region)
) +
  geom_quasirandom(
    mapping = aes(text = country)
  ) +
  scale_x_continuous(labels = label_percent()) +
  scale_color_discrete_qualitative() +
  labs(x = "% women in parliament", y = NULL, caption = "Source: The World Bank") +
  theme_bw(base_size = 14) +
  theme(legend.position = "none")
Warning in geom_quasirandom(mapping = aes(text = country)): Ignoring unknown
aesthetics: text
static_plot_tooltip
Orientation inferred to be along y-axis; override with
`position_quasirandom(orientation = 'x')`

Modifying the tooltip

ggplotly(static_plot_tooltip,
  tooltip = "text"
)

Including more information in the tooltip

  • Creating custom tooltips with the format

    Name of country
    X% women in parliament
  • Generate a new column using mutate() with the required character string

    • str_glue() to combine character strings with data values
    • The <br> is HTML code for a line break
    • Use the label_percent() function to format numbers as percents

Create a custom tooltip

wdi_2022 <- wdi_clean |>
  filter(year == 2022) |>
  drop_na(prop_women_parl) |>
  mutate(
    prop_women_parl = prop_women_parl / 100,
    fancy_label = str_glue("{country}<br>{label_percent(accuracy = 0.1)(prop_women_parl)} women in parliament")
  )
wdi_2022 |>
  select(country, prop_women_parl, fancy_label) |>
  head()
              country prop_women_parl                                      fancy_label
1             Albania      0.35714286             Albania<br>35.7% women in parliament
2             Algeria      0.08108108              Algeria<br>8.1% women in parliament
3             Andorra      0.46428571             Andorra<br>46.4% women in parliament
4              Angola      0.33636364              Angola<br>33.6% women in parliament
5 Antigua and Barbuda      0.11111111 Antigua and Barbuda<br>11.1% women in parliament
6           Argentina      0.44747082           Argentina<br>44.7% women in parliament

Create a custom tooltip

static_plot_tooltip_fancy <- ggplot(
  data = wdi_2022,
  mapping = aes(y = fct_rev(region), x = prop_women_parl, color = region)
) +
  geom_quasirandom(
    mapping = aes(text = fancy_label)
  ) +
  scale_x_continuous(labels = label_percent()) +
  scale_color_discrete_qualitative() +
  labs(x = "% women in parliament", y = NULL, caption = "Source: The World Bank") +
  theme_bw(base_size = 14) +
  theme(legend.position = "none")

ggplotly(static_plot_tooltip_fancy,
  tooltip = "text"
)

Using Plotly

Scatterplot redux

plot_ly(
  data = gapminder_2007,
  x = ~gdpPercap,
  y = ~lifeExp,
  color = ~continent
) |>
  add_markers() |>
  layout(xaxis = list(type = "log"))

Using Plotly

Dashboards with Quarto

Dashboards with Quarto

  • Available as of Quarto 1.4
  • Publish related data visualizations as a dashboard
  • Flexible row and column-based layouts
  • Can include interactive/dynamic elements
  • Publish as a static web page or integrate with Shiny

Example dashboards

Why not use Tableau/PowerBi?

  • Closed-source proprietary software
  • Use point-and-click interface to construct dashboards (limited programming)
  • Limited customization and flexibility

Application exercise

ae-15

  • Go to the course GitHub org and find your ae-15 (repo name will be suffixed with your GitHub name).
  • Clone the repo in RStudio Workbench, open the Quarto document in the repo, and follow along and complete the exercises.

Wrap-up

Wrap-up

  • Interactivity provides additional dimensions and methods for communicating using data
  • Plotly is a powerful for creating interactive plots in R
  • Use ggplotly() to convert ggplot2 plots to an interactive form
  • Quarto dashboards provide a flexible way to create interactive data visualizations