Do you know a bit of R and have some data you need to visualize quickly? In this blog post we take a look at Rstudio’s Shiny package and the first steps toward creating a working interactive to explore your data with it.
What is Shiny?
Shiny is a framework to develop web-based frontends for applications created in the R programming language. If you have a data analysis written in R and want to create an exploration tool or dashboard using that R code, Shiny is a great option!
Shiny allows you to write both the frontend UI and backend server in R. It provides functionality to easily connect these two pieces so that when a user interacts with the UI (like a button or a drop down menu), the pieces on the server side that depend on that changed UI, like variables and charts, are automatically updated and reflected back in the UI.
Reactive Programming in Shiny
Shiny uses Reactivity to achieve this connection between the server and the UI. Conceptually, you chunk up your server code into little pieces and indicate the input dependencies for each of these chunks.
A quick example will help to explain. Say we want a drop-down input in our UI to specify a year. We can create this using the Shiny selectInput function.
selectInput("year",
"Year:",
c("2015", "2016", "2017"),
selected = "2015")
The important piece of this code is that first input parameter "year"
. This specifies the inputId
of the UI component.
In our server portion of the application we will use this inputId
to indicate that a particular block of server code depends on this input. For example, if we had some data that we wanted to filter by input year, we could do this using the reactive function to create a reactive function:
shinyServer(function(input, output) {
filtered_data <- reactive({
raw_data %>% filter(year == input$year)
})
})
The input
parameter of the shinyServer
callback function is where all our UI inputs are stored. reactive
takes a block of code. In our example, it’s only one line but it could be longer. The binding between UI and server occurs because of the use of input$year
.
So when our input with an inputId
of year
is updated, this reactive block of code will be re-run with the new value, and thus filtered_data
will be updated. Pretty cool!
Rendering Output
The example above provides for modifying a variable of the server code based on a UI input, but how do we send something back to the UI based on this change? That’s where Shiny’s suite of render
functions come into play.
Continuing the above example, say we wanted to use the now filtered_data
to generate a ggplot plot of the count by month (we can assume for the sake of simplicity that these counts are already part of the data). We can use renderPlot to create a new Shiny plot and assign it as an attribute of the output
list of our shinyServer
function.
It looks something like this:
output$monthPlot <- renderPlot({
filtered_data() %>%
ggplot(aes(x = month, y = count)) +
geom_bar(stat = "identity") +
labs(title = "Counts Per Month")
})
Here monthPlot
becomes the outputId
of this piece of output. Because it uses filtered_data
, a “reactive” variable, Shiny will re-run the chunk of code passed into renderPlot
every time filtered_data
is updated.
An important gotcha here is that due to the details of implementing reactive variables, filtered_data
is actually a function that we call in order to get the updated data, hence the ()
at the end.
The last piece of the puzzle is to go back to the UI portion of the app and indicate where this plot should be displayed. For that we use plotOutput.
So, together with our original selectInput
, a basic UI for this app would be:
shinyUI(fluidPage(
selectInput("year",
"Year:",
c("2015", "2016", "2017"),
selected = "2015"),
plotOutput("monthPlot")
))
Here the fluidPage function generates the HTML for a page with fluid layout. R functions like this one and selectInput
that generate HTML for creating fully featured UIs are a big part of the Shiny library. Check out the API Reference for the various layout and input functions, as well as the tags functions for building up custom HTML.
Note how we are using the plots outputId
: monthPlot
to reference which plot is to be plotted. You can imagine repeating this paradigm any number of times to create a variety of plots (and other outputs like tables) for your users to consume and interact with.
Expanding Shiny Functionality
Speaking of interactivity, the base Shiny functions provide a lot of boiler-plate capabilities for generating these R-backed UIs, but you soon start to wonder how to create more interactive components for your displays. Well, you are in luck! There is an additional, growing collection of these HTML and JS generating R functions in the htmlwidgets package.
For example, you could use the Leaflet htmlwidget to add a slippy map to your Shiny app that can be panned and interacted with, just as if you coded it up in raw JavaScript. As an additional benefit, most of these widgets have Shiny integration instructions to get you up and going quickly.
A Simple Starting Point
To pull together some of these lessons, I’ve built a simple Shiny App that looks at Boston police incidents.
The data comes from Boston’s open data portal. While the display is a bit spartan, the demo shows how quickly you can build visualization tools with Shiny. The CSV is around 30MB, so it would be too large to visualize in a browser without some sort of aggregation, but Shiny has no problems with it (after an initial startup delay).
The Future is Shiny
All in all, Shiny offers a compelling framework and toolkit for building powerful R-powered applications that can be accessed via the web. For folks interested in building quick, sharable analyses that allow for user manipulation, it’s hard to beat Shiny. Shiny could also be a great solution for when a dashboard needs to be built and iterated upon quickly, or for when you need to view datasets that are too large to fit into the browser.
So Shine on, and let us know what data you light up with this great tool!