Chapter 13 Interactive Graphs

Interactive graphs allow for greater exploration and reader engagement. With the exception of maps (Section 7) and 3-D scatterplots (Section 10.1), this book has focused on static graphs - images that can be placed in papers, posters, slides, and journal articles. Through connections with JavaScript libraries, such as htmlwidgets for R (https://www.htmlwidgets.org), R can generate interactive graphs that can be explored in RStudio’s viewer window or placed on external web pages.

This chapter will explore several approaches including plotly, ggiraph, rbokeh, rcharts, and highcharter. The focus is on simple, straight-forward approaches to adding interactivity to graphs. Be sure to run the code so that you can experience the interactivity.

The Shiny framework offers a comprehensive approach to interactivity in R (https://www.rstudio.com/products/shiny/). However, Shiny has a higher learning curve and requires access to a Shiny server, so it is not considered here. Interested readers are referred to this excellent text (Sievert 2020).

13.1 plotly

Plotly (https://plot.ly/) is both a commercial service and open source product for creating high end interactive visualizations. The plotly package allows you to create plotly interactive graphs from within R. In addition, any ggplot2 graph can be turned into a plotly graph.

Using the mpg data that comes with the ggplot2 package, we’ll create an interactive graph displaying highway mileage vs. engine displace by car class.

Mousing over a point displays information about that point. Clicking on a legend point, removes that class from the plot. Clicking on it again, returns it. Popup tools on the upper right of the plot allow you to zoom in and out of the image, pan, select, reset axes, and download the image as a png file.

# create plotly graph.
library(ggplot2)
library(plotly)

p <- ggplot(mpg, aes(x=displ, 
                     y=hwy, 
                     color=class)) +
  geom_point(size=3) +
  labs(x = "Engine displacement",
       y = "Highway Mileage",
       color = "Car Class") +
  theme_bw()

ggplotly(p)

Figure 13.1: Plotly graph

By default, the mouse over provides pop-up tooltip with values used to create the plot (dipl, hwy, and class here). However you can customize the tooltip. This involves adding a labeln = variablen* to the aes function and to the ggplotly function.

# create plotly graph.
library(ggplot2)
library(plotly)

p <- ggplot(mpg, aes(x=displ, 
                     y=hwy, 
                     color=class,
                     label1 = manufacturer,
                     label2 = model,
                     label3 = year)) +
  geom_point(size=3) +
  labs(x = "Engine displacement",
       y = "Highway Mileage",
       color = "Car Class") +
  theme_bw()

ggplotly(p, tooltip = c("label1", "label2", "label3"))

Figure 13.2: Plotly graph with custom tooltip

The tooltip now displays the car manufacturer, make, and year (see Figure 13.2).

You can fully customize the tooltip by creating your own label and including it as a variable in the data frame. Then place it in the aesthetic as text and in the ggplotly function as a label.

# create plotly graph.
library(ggplot2)
library(plotly)
library(dplyr)

mpg <- mpg %>%
  mutate(mylabel = paste("This is a", manufacturer, model, "\n",
                         "released in", year, "."))

p <- ggplot(mpg, aes(x=displ, 
                     y=hwy, 
                     color=class,
                     text = mylabel)) +
  geom_point(size=3) +
  labs(x = "Engine displacement",
       y = "Highway Mileage",
       color = "Car Class") +
  theme_bw()

ggplotly(p, tooltip = c("mylabel"))

Figure 13.3: Plotly graph with fully customized tooltip

There are several sources of good information on plotly. See the plotly R pages (https://plot.ly/r/) and the book Interactive web-based data visualization with R, Plotly, and Shiny (Sievert 2020). An online version of the book is available at https://plotly-book.cpsievert.me/.

13.2 ggiraph

It is easy to create interactive ggplot2 graphs using the ggiraph package. There are three steps:

  1. add _interactive to the geom names (for example, change geom_point to geom_point_interactive)
  2. add tooltip, data_id, or both to the aes function
  3. render the plot with the girafe function (note the spelling)

The next example uses the mpg dataset in ggplot2 package to create an interactive scatter plot between engine displacement and highway mileage.

library(ggplot2)
library(ggiraph)


p <- ggplot(mpg, aes(x=displ, 
                y=hwy, 
                color=class,
                tooltip = manufacturer)) +
  geom_point_interactive()

girafe(ggobj = p)

Figure 13.4: Basic interactive ggiraph graph

When you mouse over a point, the manufacturer’s name pops up. The ggiraph package only allows one tools tip, but you can customize it by creating a column in the data containing the desired information. By default the tooltip is white text on a black background. You can change this with the options argument to the girafe function.

library(ggplot2)
library(ggiraph)
library(patchwork)

library(dplyr)
mpg <- mpg %>%
  mutate(tooltip = paste(manufacturer, model, class))

p <- ggplot(mpg, aes(x=displ, 
                y=hwy, 
                color=class,
                tooltip = tooltip)) +
  geom_point_interactive()

girafe(ggobj = p, options = list(opts_tooltip(use_fill = TRUE)))

Figure 13.5: Interactive ggiraph graph with customized tooltip

Section 11.9 described how to combine two or more ggplot2 graphs into one over all plot using the patchwork package. One of the great strengths of the ggiraph package is that it allows you to link graphs. When graphs are linked, selecting observations on one graph, highlight the same observations on the other linked graphs.

The next example uses the fuel efficiency data from the mtcars dataset. Three plots are created (1) a scatterplot of weight vs mpg, (2) a scatterplot of rear axle ratio vs 1/4 mile time, and (3) a bar chart of number of cylinders.

Unlike previous graphs, the these three graphs are linked by a unique id (the car names in this case). This is accomplished by adding data_id = rownames(mtcars) to the aesthetic. The three plots are then arranged into one graph using patchwork and code=print is added to the girafe function.

In the Figure 13.6, clicking on location in any one of the three plots, highlights the car in the other plots. Run the code and try it out!

library(patchwork)
p1 <- ggplot(mtcars, aes(x=wt, 
                      y=mpg, 
                      tooltip = rownames(mtcars),
                      data_id = rownames(mtcars))) +
  geom_point_interactive(size=3, alpha =.6) 

p2 <- ggplot(mtcars, aes(x=drat, 
                         y=qsec, 
                         tooltip = rownames(mtcars),
                         data_id = rownames(mtcars))) +
  geom_point_interactive(size = 3, alpha = .6) 

p3 <- ggplot(mtcars, aes(x=cyl,
                         data_id = rownames(mtcars))) +
  geom_bar_interactive() 

p3 <- (p1 | p2)/p3
girafe(code = print (p3)) 

Figure 13.6: Linked interactive graphs

Here’s one more example. The gapminder dataset is used to create two bar charts for Asian countries: (1) life expectancy in 1982 and life expectancy in 2007. The plots are linked by data_id = country. As you mouse over a bar in one chart, the corresponding bar in the other is highlighted. If you move from the bottom to the top in the left hand chart, it become clear how life expectancy has changed. Note the jump when you hit Vietnam and Iraq.

data(gapminder, package="gapminder")

# subset Asian countries
asia <- gapminder %>%
  filter(continent == "Asia") %>%
  select(year, country, lifeExp)

p1 <- ggplot(asia[asia$year == 1982,], 
       aes(y = reorder(country, lifeExp), 
           x=lifeExp,
           tooltip = lifeExp,
           data_id = country)) +
  geom_bar_interactive(stat="identity", 
                       fill="steelblue") +
  labs(y="", x="1982") + 
  theme_minimal()

p2 <- ggplot(asia[asia$year == 2007,], 
             aes(y = reorder(country, lifeExp), 
                 x=lifeExp,
                 tooltip = lifeExp,
                 data_id = country)) +
  geom_bar_interactive(stat="identity", 
                       fill="steelblue") +
  labs(y="", x="2007") + 
  theme_minimal()

p3 <- (p1 | p2) +
  plot_annotation(title = "Life Expectancy in Asia")
girafe(code = print (p3)) 

Figure 13.7: Linked bar charts

Graphs created with ggiraph are highly customizable. The ggiraph-book website (https://www.ardata.fr/ggiraph-book/) is a great resource for getting started.

13.3 Other approaches

While Plotly is the most popular approach for turning static ggplot2 graphs into interactive plots, many other approaches exist. Describing each in detail is beyond the scope of this book. Examples of other approaches are included here in order to give you a taste of what each is like. You can then follow the references to learn more about the ones that interest you.

13.3.1 rbokeh

rbokeh is an interface to the Bokeh (https://bokeh.pydata.org/en/latest/) graphics library.

We’ll create another graph using the mtcars dataset, showing engine displace vs. miles per gallon by number of engine cylinders. Mouse over, and try the various control to the right of the image.

# create rbokeh graph

# prepare data
data(mtcars)
mtcars$name <- row.names(mtcars)
mtcars$cyl <- factor(mtcars$cyl)

# graph it
library(rbokeh)
figure() %>%
  ly_points(disp, mpg, data=mtcars,
            color = cyl, glyph = cyl,
            hover = list(name, mpg, wt))

Figure 13.8: Bokeh graph

You can create some remarkable graphs with Bokeh. See the homepage (http://hafen.github.io/rbokeh/) for examples.

13.3.2 rCharts

rCharts can create a wide range of interactive graphics. In the example below, a bar chart of hair vs. eye color is created. Try mousing over the bars. You can interactively choose between grouped vs. stacked plots and include or exclude cases by eye color by clicking on the legends at the top of the image.

# create interactive bar chart
library(rCharts)
hair_eye_male = subset(as.data.frame(HairEyeColor), 
                       Sex == "Male")
n1 <- nPlot(Freq ~ Hair, 
            group = 'Eye', 
            data = hair_eye_male, 
            type = 'multiBarChart'
)
n1$set(width = 600)
n1$show('iframesrc', cdn=TRUE)

To learn more, visit the project homepage (https://github.com/ramnathv/rCharts).

13.3.3 highcharter

The highcharter package provides access to the Highcharts (https://www.highcharts.com/) JavaScript graphics library. The library is free for non-commercial use.

Let’s use highcharter to create an interactive line chart displaying life expectancy over time for several Asian countries. The data come from the Gapminder dataset. Again, mouse over the lines and try clicking on the legend names.

# create interactive line chart
library(highcharter)

# prepare data
data(gapminder, package = "gapminder")
library(dplyr)
asia <- gapminder %>%
  filter(continent == "Asia") %>%
  select(year, country, lifeExp)

# convert to long to wide format
library(tidyr)
plotdata <- spread(asia, country, lifeExp)

# generate graph
h <- highchart() %>% 
  hc_xAxis(categories = plotdata$year) %>% 
  hc_add_series(name = "Afghanistan", 
                data = plotdata$Afghanistan) %>% 
  hc_add_series(name = "Bahrain", 
                data = plotdata$Bahrain) %>%
  hc_add_series(name = "Cambodia", 
                data = plotdata$Cambodia) %>%
  hc_add_series(name = "China", 
                data = plotdata$China) %>%
  hc_add_series(name = "India", 
                data = plotdata$India) %>%
  hc_add_series(name = "Iran", 
                data = plotdata$Iran)

h

Figure 13.9: HighCharts graph

In Figure 13.9 I’ve clicked on the Afghanistan point in 1962. The line is highlighted, the other lines are dimmed, and a pop-up box shows the values at that point.

Like all of the interactive graphs in this chapter, there are options that allow the graph to be customized.

# customize interactive line chart
h <- h %>%
  hc_title(text = "Life Expectancy by Country",
           margin = 20, 
           align = "left",
           style = list(color = "steelblue")) %>% 
  hc_subtitle(text = "1952 to 2007",
              align = "left",
              style = list(color = "#2b908f", 
                           fontWeight = "bold")) %>% 
  hc_credits(enabled = TRUE, # add credits
             text = "Gapminder Data",
             href = "http://gapminder.com") %>% 
  hc_legend(align = "left", 
            verticalAlign = "top",
            layout = "vertical", 
            x = 0, 
            y = 100) %>%
  hc_tooltip(crosshairs = TRUE, 
             backgroundColor = "#FCFFC5",
             shared = TRUE, 
             borderWidth = 4) %>% 
  hc_exporting(enabled = TRUE)

h

Figure 13.10: HighCharts graph with customization

In Figure 13.10 I’ve moused over 1982. All points in that year are highlighted and a pop-up menu shows the country values for that year.

There is a wealth of interactive plots available through the marriage of R and JavaScript. Choose the approach that works best for you.

References

Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Book. Boca Raton, Florida: CRC Press.