Plots for the web

There has been increasing need and desirability to produce interactive graphics online. News outlets, like the The Economist, New York Times, Vox, 538, Pew, and Quartz, routinely use interactive displays.

There are two packages (among several) that allow us to create interactive graphics. The first is ggivis, which is based on ggplot2 and the other is googlevis.

ggvis follows the similar underlying theory of the grammar of graphics as ggplot2 but is expressed a little bit differently. It incorporates aspects from shiny as well as dplyr.

ggvis()

NOTE: For some reason my ggvis figures are not rendering and I am not 100% sure why. If you follow along with the below R code in RStudio these will generate. Hopefully, I can figure out what the issues are and I will update the post.

#install.packages("ggvis")

library(tidyverse)
## Loading tidyverse: tibble
## Loading tidyverse: tidyr
## Loading tidyverse: readr
## Loading tidyverse: purrr
## Loading tidyverse: dplyr
## Conflicts with tidy packages ----------------------------------------------
## filter(): dplyr, stats
## lag():    dplyr, stats
library(ggvis)
## 
## Attaching package: 'ggvis'
## The following object is masked from 'package:ggplot2':
## 
##     resolution

Like ggplot(), every call to ggvis starts with the ggvis() statement.

point_plot<-mtcars %>%
            ggvis(x = ~wt, y = ~mpg) %>%
            layer_points()

view_static(point_plot)

Like ggplot, you can mapping other visual properties like fill, stroke, size and shape.

mtcars %>% ggvis(~mpg, ~disp, stroke = ~vs) %>% layer_points()
mtcars %>% ggvis(~mpg, ~disp, fill = ~vs) %>% layer_points()
mtcars %>% ggvis(~mpg, ~disp, size = ~vs) %>% layer_points()
mtcars %>% ggvis(~mpg, ~disp, shape = ~factor(cyl)) %>% layer_points()

Unlike ggplot, you specify points a fixed colour or size, you need to use := instead of =. The := operator means to use a raw, unscaled value.

mtcars %>% ggvis(~wt, ~mpg, fill := "black", stroke := "firebrick") %>% layer_points()
mtcars %>% ggvis(~wt, ~mpg, size := 400, opacity := 0.25) %>% layer_points()
mtcars %>% ggvis(~wt, ~mpg, size := 100, shape := "square") %>% layer_points()

Layers

  • Points, layer_points(), with properties x, y, shape, stroke, fill, strokeOpacity, fillOpacity, and opacity.
mtcars %>% ggvis(~wt, ~mpg) %>% layer_points()
  • Paths and polygons, layer_paths()
set.seed(12345)

df <- data.frame(x = 1:20, y = runif(20))
df %>% ggvis(~x, ~y) %>% layer_paths()

If you add fill, you will get a polygon.

vals<-rbind(data.frame(x = 1:10, y = 1),
      data.frame(x = 1:10, y = 3),
      data.frame(x = 1, y = 1:3),
      data.frame(x = 10, y = 1:3))

vals %>% ggvis(~x, ~y) %>% layer_paths(fill := "pink")
  • Filled areas, layer_ribbons(). Use properties y and y2 to control the extent of the area.
df %>% ggvis(~x, ~y) %>% layer_ribbons(fill:="green", opacity:=0.3)
df %>% ggvis(~x, ~y + 0.25, y2 = ~y - 0.25) %>% layer_ribbons(fill:="green", opacity:=0.3)
  • Rectangles, layer_rects(). The location and size of the rectangle is controlled by the x, x2, y and y2 properties.
set.seed(12345)
df <- data.frame(x1 = runif(2), x2 = runif(2), y1 = runif(2), y2 = runif(2))

df %>% ggvis(~x1, ~y1, x2 = ~x2, y2 = ~y2, fillOpacity := 0.55, fill:= "blue") %>% layer_rects()
  • Text, layer_text(). Many options to control the apperance of the text: text (the label), dx and dy (margin in pixels between text and anchor point), angle (rotate the text), font (font name), fontSize (size in pixels), fontWeight (bold or normal), and fontStyle (e.g. italic or normal)
df2 <- data.frame(x = 4:1, y = c(1, 3, 2,4), label = c("a", "b", "c", "d"))

df2 %>% ggvis(~x, ~y, text := ~label) %>% layer_text()
df2 %>% ggvis(~x, ~y, text := ~label) %>% layer_text(fontSize := 50, fontWeight:= "bold", angle:= 45)

Compound layers

  • layer_lines() automatically orders by the x variable:
t <- seq(0, 2 * pi, length = 20)

df3 <- data.frame(x = sin(t), y = cos(t))

df3 %>% ggvis(~x, ~y) %>% layer_paths()
df3 %>% ggvis(~x, ~y) %>% layer_lines()
  • layer_histograms() and layer_freqpolys() first bin the data with compute_bin() and then display the results with either rects or lines.
mtcars %>% ggvis(~mpg) %>% layer_histograms(fill:= "red")
## Guessing width = 1 # range / 24
mtcars %>% ggvis(~mpg) %>% layer_freqpolys(fill:= "red")
## Guessing width = 1 # range / 24
  • layer_smooths() fits a smooth model to the data, and displays predictions with a line
mtcars %>% ggvis(~wt, ~mpg) %>% layer_smooths()

Multiple layers

Like ggplot2 we can combine multiple layers together.

mtcars %>% ggvis(~wt, ~mpg) %>% layer_points %>% layer_smooths()
mtcars %>% ggvis(~wt, ~mpg) %>%
  layer_points %>% 
  layer_smooths(span = 1) %>%
  layer_smooths(span = 0.5, stroke := "red")

Scales

Scales, to control the mapping between data and visual properties. These are described in the properties and scales vignette

Legends

Legends and axes to control the appearance of the guides produced by the scales. See the axes and legends vignette for more details.

Basic interactivity

`input_slider()

mtcars %>% 
  ggvis(x = ~wt, y = ~mpg) %>% 
  layer_smooths(span = input_slider(0.5, 1, 1, label = "span")) %>% 
  layer_points(size := input_slider(100, 1000, label = "size"))
## Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
## Generating a static (non-dynamic, non-interactive) version of the plot.

input_checkbox

mtcars %>% ggvis(~wt, ~mpg) %>%
  layer_smooths(se = input_checkbox(label = "Confidence interval", value = TRUE))
## Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
## Generating a static (non-dynamic, non-interactive) version of the plot.

input_radiobuttons

  mtcars %>% ggvis(x = ~wt, y = ~mpg) %>%
  layer_points(
    fill := input_radiobuttons(
      choices = c("Red" = "red", "Green" = "green", "Blue" = "blue"),
      label = "Colors",
      selected = "red")
  )
## Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
## Generating a static (non-dynamic, non-interactive) version of the plot.

input_checkboxgroup

  mtcars %>% ggvis(x = ~wt, y = ~mpg) %>%
  layer_points(
    fill := input_checkboxgroup(
      choices = c("Red" = "r", "Green" = "g", "Blue" = "b"),
      label = "Point color components",
      map = function(val) {
        rgb(0.8 * "r" %in% val, 0.8 * "g" %in% val, 0.8 * "b" %in% val)
      }
    )
  )
## Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
## Generating a static (non-dynamic, non-interactive) version of the plot.

input_text()

fill_text <- input_text(label = "Point color", value = "dodgerblue")
mtcars %>% ggvis(~wt, ~mpg, fill := fill_text) %>% layer_points()
## Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
## Generating a static (non-dynamic, non-interactive) version of the plot.

input_numeric()

size_num <- input_numeric(label = "Point size", value = 25)
mtcars %>% ggvis(~wt, ~mpg, size := size_num) %>% layer_points()
## Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
## Generating a static (non-dynamic, non-interactive) version of the plot.

input_select()

iris %>% 
  ggvis(x = input_select(c('Petal.Width', 'Sepal.Length'), map = as.name)) %>% 
  layer_points(y = ~Petal.Length, fill = ~Species)
## Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
## Generating a static (non-dynamic, non-interactive) version of the plot.

Outputting your ggvis plot

This is still in active development and is not especially user friendly. For more information, visit here

outfile <- iris %>% 
  ggvis(x = input_select(c('Petal.Width', 'Sepal.Length'), map = as.name)) %>% 
  layer_points(y = ~Petal.Length, fill = ~Species) %>%
  view_dynamic() %>% htmltools::html_print(viewer = NULL)

Some last notes on ggvis

ggvis is still actively being developed and there is a lot more detail than I have provided. In addition, there is still a lot that ggvis can not do. I encourage you to check out the ggvis website for more information and updates.

googleVis

The googleVis package provides an interface between R and the Google Charts API. Google Charts offer interactive charts which can be embedded into web pages.

There are many options for figures and given our time constraint, we will only cover a portion of what is available. I encourage you to look here and here for additional ideas and details.

# install.packages("googleVis")
library(googleVis)
## Creating a generic function for 'toJSON' from package 'jsonlite' in package 'googleVis'
## 
## Welcome to googleVis version 0.6.1
## 
## Please read the Google API Terms of Use
## before you start using the package:
## https://developers.google.com/terms/
## 
## Note, the plot method of googleVis will by default use
## the standard browser to display its output.
## 
## See the googleVis package vignettes for more details,
## or visit http://github.com/mages/googleVis.
## 
## To suppress this message use:
## suppressPackageStartupMessages(library(googleVis))
op <- options(gvis.plot.tag='chart')

To get these to work in RMarkdown you will need to specify results='asis' in the chunk options.

Line plots

df <- data.frame(time=c(1:70), 
              val1=c(1:70)*3 +rnorm(70, sd = 6), 
              val2=c(1:70)*5 +rnorm(70, sd = 10))
Line_plot <- gvisLineChart(df, xvar = "time", yvar = c("val1", "val2"))
plot(Line_plot)
Line_plot2 <- gvisLineChart(df, xvar = "time", yvar = c("val1", "val2"), options = list(series = "[{targetAxisIndex: 0}, {targetAxisIndex:1}]", 
    vAxes = "[{title:'val1'}, {title:'val2'}]"))
plot(Line_plot2)

Bar plots

mpg<-mtcars %>% 
    mutate(gear = paste("gear",gear,sep="_")) %>% 
    group_by(cyl, gear) %>% 
    summarise(M_mpg = mean(mpg)) %>% 
    spread(gear, M_mpg) %>% 
    as.data.frame()

mpg$gear_4[is.na(mpg$gear_4)] <-0
mpg_side <- gvisBarChart(data = mpg, xvar = c("cyl"), yvar = c("gear_3", "gear_4", 
    "gear_5"))

plot(mpg_side)
mpg_vert <- gvisColumnChart(data = mpg, xvar = c("cyl"), yvar = c("gear_3", 
    "gear_4", "gear_5"), options = list(title = "The mean mpg per cylinder", 
    colors = "['#cbb69d', '#603913', '#c69c6e']", vAxes = "[{title:'miles per gallon'}]", 
    hAxes = "[{title:'Number of cylinders'}]"))
plot(mpg_vert)
mpg_cars<-mtcars %>% 
    mutate(gear = paste("gear",gear,sep="_")) %>% 
    group_by(cyl, gear) %>% 
    summarise(N = n()) %>% 
    spread(gear, N) %>% 
    as.data.frame()

mpg$gear_4[is.na(mpg$gear_4)] <-0
mpg_stack <- gvisColumnChart(data = mpg, xvar = c("cyl"), yvar = c("gear_3", 
    "gear_4", "gear_5"), options = list(isStacked = TRUE, title = "The mean mpg per cylinder", 
    colors = "['#cbb69d', '#603913', '#c69c6e']", vAxes = "[{title:'Number of cars'}]", 
    hAxes = "[{title:'Number of cylinders'}]"))
plot(mpg_stack)

Area plots

df4 <- data.frame(Year = c(2013:2016), Sales = c(1000, 1170, 660, 1030), Expenses = c(400, 460, 1120, 540))

df4
##   Year Sales Expenses
## 1 2013  1000      400
## 2 2014  1170      460
## 3 2015   660     1120
## 4 2016  1030      540
Area <- gvisAreaChart(df4, xvar = "Year", yvar = c("Sales", "Expenses"))

plot(Area)
Area_stack <- gvisAreaChart(df4, xvar = "Year", yvar = c("Sales", "Expenses"), 
    options = list(isStacked = TRUE))

plot(Area_stack)

Combo plots

head(CityPopularity)
     City Popularity 1    New York        200 2      Boston        300 3       Miami        400 4     Chicago        500 5 Los Angeles        600 6     Houston        700
CityPopularity$Mean = mean(CityPopularity$Popularity)
CC <- gvisComboChart(CityPopularity, xvar = "City", yvar = c("Mean", "Popularity"), 
    options = list(seriesType = "bars", width = 450, height = 300, title = "City Popularity", 
        series = "{0: {type:\"line\"}}"))
plot(CC)

GeoChart plots

library(datasets)
states <- data.frame(state.name, state.x77)

head(states)
##            state.name Population Income Illiteracy Life.Exp Murder HS.Grad
## Alabama       Alabama       3615   3624        2.1    69.05   15.1    41.3
## Alaska         Alaska        365   6315        1.5    69.31   11.3    66.7
## Arizona       Arizona       2212   4530        1.8    70.55    7.8    58.1
## Arkansas     Arkansas       2110   3378        1.9    70.66   10.1    39.9
## California California      21198   5114        1.1    71.71   10.3    62.6
## Colorado     Colorado       2541   4884        0.7    72.06    6.8    63.9
##            Frost   Area
## Alabama       20  50708
## Alaska       152 566432
## Arizona       15 113417
## Arkansas      65  51945
## California    20 156361
## Colorado     166 103766
GeoStates <- gvisGeoChart(states, "state.name", "Murder", options = list(region = "US", 
    displayMode = "regions", resolution = "provinces", width = 600, height = 400, 
    colors = "['skyblue','red']"))
plot(GeoStates)

Interactive plots

Like using ggvis, you do have the option to make fully interactive plots. You won’t be able to get it to work in the console or in Rstudio because googleVis creates javascript that is embedded into an HTML document . The only way to know for sure if it’s working is to knit it to HTML, and then publish it to Rpubs (or anywhere else online). Once it is online it will work. Depending on your browser settings, you might be able to get it to work by opening the HTML locally, but the browser often blocks the embedded plot when opened locally

M <- gvisMotionChart(Fruits, "Fruit", "Year")
plot(M, 'chart')

Outputting googlevis plots

# write the HTML body to a temporary file without header and footer
cat(M$html$chart, file="/Users/cchizinski2/Documents/DataDepot/temp.html")