Chapter 2 Interactive graphs
Learning Objectives
- Be aware of R interactive graphing capabilities and options
- Know some graphing packages that are based on htmlwidgets
- Create a simple interactive plot
- Understand the basic structure of a
shiny
app
2.1 htmlwidgets
JavaScript is probably the most widely used scripting languages to create interactive webpages (html). The htmlwidgets
package provides a framework to bind R commands to various existing, interactive JavaScript libraries, including those that greate data graphs. The interactive components (“widgets”) created using the framework can be:
- used at the R console for data analysis just like conventional R plots (via RStudio Viewer).
- seamlessly embedded within R Markdown documents and Shiny web applications.
- saved as standalone web pages for ad-hoc sharing via email, Dropbox, etc.
While you can certainly develop yor own widget, there are a number of widgets already available, that you can install and that make creating interacive visualizations much easier. In fact, the packages used for the examples in section ?? are all based on htmlwidgets.
For a complete list check out the htmlwidgets gallery.
The htmlwidgets
framework ensures that the graphics are rendered locally. By default they either run in your web browser or in the R Studio viewer. If you use R Markdown, the html pages rendered contain the full JavaScript code, so you can also also deploy them to a standard webserver (like github pages).
2.2 plotly
We will start with a widget called plotly
. plotly
binds R commands to the JavaScript plotly.js graphing library. The R package allows you to easily translate ggplot2
graphics to an interactive web-based version.
First we install and load the package.
install.packages(plotly) # if you haven't installed the package
library(plotly)
Let us go back to our initial scatterplot.
ggplot(data = stops_county, aes(x = pct_black_stopped, y = pct_white_stopped)) +
geom_point()
To turn this into an interactive graph with plotly
, we create a ggplot object by assigning it to a variable:
p <- ggplot(data = stops_county, aes(x = pct_black_stopped, y = pct_white_stopped)) +
geom_point()
We can then pass that object to the ggplotly
function (the dev. version of ggplot2 has a ggplotly()
function, but this works):
ggplotly(p)
This is really all that is to it.
ALternatively, it is possible to forgo ggplot and using the plot_ly
function to create your graph from scratch. For our example that would be:
plot_ly(stops_county, x = ~pct_black_stopped, y = ~pct_white_stopped)
#> No trace type specified:
#> Based on info supplied, a 'scatter' trace seems appropriate.
#> Read more about this trace type -> https://plot.ly/r/reference/#scatter
#> No scatter mode specifed:
#> Setting the mode to markers
#> Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
Challenge
Go back to the box plot we created earlier using the Chickasaw_stops:
ggplot(Chickasaw_stops, aes(x = violation, y = driver_age)) +
geom_boxplot()
Create an interactive version of it, using both approaches,ggplotly
andplot_ly
.
The full documentation of all the arguments plot_ly
can take is here: https://plot.ly/r/reference/
2.3 shiny
htmlwidgets
are very powerful, but if you require more customization and flexibility, particularly with regard to user input, you may want to look into shiny
. Because it executes acutal R code, which web browsers cannot execute, shiny
requires its own server.
There are verious ways in which a shiny application can be run. We will use an example run it from the
R Commandline.
Rmarkdown: To call Shiny code from an R Markdown document, add runtime: shiny to the header shiny server: either run your own, or host it at ShinyApps.io
Building shiny apps deserves its own workshop, so here - to give you a teaser - I have provided only a very simple example. We will re-use our barchart from earlier where we plotted the proportional amount of traffic violations for each gender:
ggplot(stops, aes(violation)) +
geom_bar(aes(fill = driver_gender), position = "fill")
We want to create a plot where we can choose which county we’d like to display this bar chart for.
I have prepared the code for this, which you can run like this:
Install and load the
shiny
package (install.packages(shiny)
).In your
R-data-viz
folder create a new folder calledshinyapps
.Download
app.R
into that folder:
download.file("https://raw.githubusercontent.com/cengel/R-data-viz/master/shinyapp/app.R", "shinyapp/app.R")
- In your R console:
library(shiny)
runApp("./shinyapp/")
Let us now go over the code in the app.R
script.
We define two functions and call them ui
(for user interface, which we present to the user and receive input) and server
(where the input is used and the magic happens).
This is what happens in the ui
function:
Using some of the layout functions shiny comes with we define a panel with a sidebar, where the input is received the main panel, where the plot is going to be displahyed. We also assign the plot a name (violationsPlot
) that we will reuse later. Lastly we add some text to help users understand what this graph about.
A very important function is selectInput
, where we define the choices that the user has (the county names in the table) and also define the name of the variable that will hold the input from the user: county
.
The server
is where input and output are processed. In this example we really only render the plot. You see that the name for our plot (violationsPlot
) appears attached to the output
variable. You can also detect our ggplot code from earlier, with the only difference that we use the input county value input$county
to filter the data frame before we send them to ggplot to plot.
The very last line of the script binds the two together as a shiny app.
library(shiny)
library(ggplot2)
library(dplyr)
# uncomment this if you need to reload the stops table
# stops <- read.csv('https://github.com/cengel/R-data-viz/raw/master/data/MS_stops.csv')
## UI
# Use a fluid Bootstrap layout
ui <- fluidPage(
# Give the page a title
titlePanel("Missisippi Violations by County"),
# Generate a row with a sidebar
sidebarLayout(
# Define the sidebar with one input
sidebarPanel(
selectInput("county", "County:",
choices=unique(stops$county_name)),
hr(),
helpText("Data from Stanford Openpolicing Project.")
),
# Create a spot for the barplot
mainPanel(
plotOutput("violationsPlot")
)
)
)
## Server
# Define a server for the Shiny app
server <- function(input, output) {
# Fill in the spot we created for a plot
output$violationsPlot <- renderPlot({
stops %>%
filter(county_name == input$county) %>%
ggplot(aes(violation)) +
geom_bar(aes(fill = driver_gender), position = "fill")
})
}
shinyApp(ui, server)
There are numerous examples of shiny apps of different complexity, for example here: http://shiny.rstudio.com/gallery/