Introduction

What is Shiny?

The best way to have an idea of the possibilities offered by R/Shiny is to have a quick look at the following galleries (where you can find, and study, the associated R code!):

Explore now for a few minutes these galleries:

Note: Another way is to use the runExample() function. The Shiny package has eleven built-in examples that each demonstrate how Shiny works. Each example is a self-contained Shiny app. For example

library(shiny)
runExample("01_hello") # a histogram
runExample("02_text") # tables and data frames
runExample("03_reactivity") # a reactive expression
runExample("04_mpg") # global variables
runExample("05_sliders") # slider bars
runExample("06_tabsets") # tabbed panels
runExample("07_widgets") # help text and submit buttons
runExample("08_html") # Shiny app built from HTML
runExample("09_upload") # file upload wizard
runExample("10_download") # file download wizard
runExample("11_timer") # an automated timer

Due credits: in this course, we will explore material that can be found at these URL:

Prerequisites

You need a good knowledge about the R software: try this quiz to check your skills. If you want to improve your basic R skill, see for instance this book.

You also need a good knowledge about ggplot2. Download the Data Visualization Cheat Sheet.

Some basic knowledge about HTML, Javascript and CSS might help.

The Shiny (client) software can run on Windows/MacOS/Linux. Works best with Chrome.

If not already done, download and install the last version of RStudio, which appears to be 1.0.136 at the date this course is prepared (This information is found from RStudio via the menu Help/About RStudio.)

Also, from Rstudio:

install.packages("shiny")

Download the Shiny Cheat Sheet.

Your first Shiny app

Launch RStudio, then go to File/New File/Shiny Web App…

The following window pops up.

Change the entries as follows:

When you click on Create, this should open two new tabs in RStudio: ui.R and server.R. The corresponding files are stored in ~/My_First_Shiny_App. They already contain some R code that we will comment (and modify) in a while.

But, first let’s execute this code to see what happens. Select the ui.R (or the server.R) tab in RStudio. Then click on the Run App button. This should launch a web app in your favorite web browser. You can then interact with a slider to choose the number of bins to use in order to draw a histogram of the “Old Faithful Geyser Data”. Change the slider value and observe how the histogram is redrawn.

Geyser example

Geyser example

Note 1: You should also see in the console of RStudio a red message displayed. On my laptop, it is: “Listening on http://127.0.0.1:3452”. This means that in the background, RStudio launches locally a Shiny daemon web server on the port 3452. (This port number might be different on your computer.) This can be checked for example under Linux by typing the following command in a terminal and noting that the STATE is “open”:

[lafaye 15:16:51 ~] nmap localhost -p 3452

Starting Nmap 6.47 ( http://nmap.org ) at 2016-12-28 15:17 CET
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000027s latency).
Other addresses for localhost (not scanned): 127.0.0.1
PORT     STATE SERVICE
3452/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 0.05 seconds

Note 2: Your R session will be busy while the Hello Shiny app is active, so you will not be able to run any R commands. R is monitoring the app and executing the app’s reactions. To get your R session back, hit escape or click the stop sign icon (found in the upper right corner of the RStudio console panel).

Let’s comment the R code in the ui.R/server.R files

First, note that a full description of all Shiny functions (e.g., the ones used in the code of our current versions of ui.R and server.R) is given at the Shiny reference pages. Have a look at this webpage to see how it is organized.

Some vocabulary: “A typical web application consists of a number of user interface (UI) elements, say a button or a checkbox. Each of these elements can be interacted with, for example you can push the button. This button push then triggers an action, running a piece of code. This can then change the state of the web application, for example retrieve a piece of information from the server or draw a picture in the application. This style of programming is called event-driven programming. The piece of code that is executed based on an event is called an event handler.”

The structure of Shiny apps

“Shiny apps follow typical structure of web applications. However, as a user you only have to specify which UI elements you want to show, and the underlying R code that draws a plot, shows some text, or a table. These pieces of information are stored in two interacting codes (script) stored in the following files:

  • ui.R, for the user interface (ui) elements, and
  • server.R, for the content code."

The ui.R code creates the options a user can change, and controls what is displayed on the app.

  • This code also creates a list object (named input) to store all options
  • The UI operates using “output” pieces created by the server.

Ther server.R code runs everything that responds to the changes made by the user in the app.

  • The server operates using the “input” list created by the UI, and creates an “output” list to store all rendered objects and values.
  • This code is reactive. This means that every time you change any option in the interface, shiny will scan through the server for any instance where that option is mentioned, and re run the corresponding code.

Note: As of version 0.10.2, Shiny supports single-file applications. You no longer need to build separate server.R and ui.R files for your app; you can just create a file called app.R that contains both the server and UI components. You can learn more about building a Shiny app in a single file here, however this tutorial will focus on the two file structure for building a Shiny app.

As you can see, the ui.R file starts (after some comments) with the instruction:

library(shiny)

that will load the shiny package. Next, a call to the shinyUI() function is made. This is not really necessary as can be read in the documentation of this function:

“Historically this function was used in ui.R files to register a user interface with Shiny. It is no longer required as of Shiny 0.10; simply ensure that the last expression to be returned from ui.R is a user interface. This function is kept for backwards compatibility with older applications. It returns the value that is passed to it.”

You can thus remove it. But leave the fluidPage stuff.

The fluidPage() function creates fluid page layouts. A fluid page layout consists of rows which in turn include columns. Rows exist for the purpose of making sure their elements appear on the same line (if the browser has adequate width). Columns exist for the purpose of defining how much horizontal space within a 12-unit wide grid its elements should occupy. Fluid pages scale their components in realtime to fill all available browser width.

Our current fluidPage contains two rows:

  • The first one builds a title thanks to the titlePanel() function. This row only displays “Old Faithful Geyser Data”.
  • The second one is created via the sidebarLayout() function. It contains a sidebar (on the left) and a main area. The sidebar is displayed with a distinct background color (light blue) and typically contains input controls (currently only a slider input). The main area occupies by default 2/3 of the horizontal width and typically contains outputs (currently our histogram).
Layout

Layout

The help page for this latter function is here. Have a look at it. From it, you can also access the sidebarPanel() and mainPanel() help pages.

In our case, the sidePanel contains only one UI element: a sliderInput. The mainPanel also contains one input element: a plotOutput. Look at the description of these functions here.

Note: You can run a Shiny app by giving the name of its directory to the function runApp. For example if your Shiny app is in a directory called my_app, run it with the following code:

library(shiny)
runApp("my_app")

If you would like your app to display in showcase mode, you can run runApp("my_app", display.mode = "showcase").

HTML Content

You can use one of Shiny’s HTML tag functions. These functions parallel common HTML5 tags. Let’s try out a few of them.

shiny function HTML5 equivalent creates
p() <p> A paragraph of text
h1() <h1> A first level header
h2() <h2> A second level header
h3() <h3> A third level header
h4() <h4> A fourth level header
h5() <h5> A fifth level header
h6() <h6> A sixth level header
a() <a> A hyper link
br() <br> A line break (e.g. a blank line)
div() <div> A division of text with a uniform style
span() <span> An in-line division of text with a uniform style
pre() <pre> Text ‘as is’ in a fixed width font
code() <code> A formatted block of code
img() <img> An image
strong() <strong> Bold text
em() <em> Italicized text
HTML() Directly passes a character string as HTML code

Integrating dynamic content

If only the ui.R file was present, no dynamic content would be available. This is the purpose of the server.R file to add interactivity.

At this point, we have to explain how the ui.R and server.R files communicate.

In the server.R file, we see a rendering function called renderPlot(), as well as two interesting pieces of code: output$distPlot and input$bins. Note that distPlot is the ID (outputId) used when we called the plotOutput() function, while bins is the ID (inputId) used when we called the sliderInput() function. Consult the help pages for these two functions.

It is through these ID that Shiny couples the UI elements defined in ui.R to the dynamic content in server.R.

The input variable of the shinyServer() functions contains all the UI elements, the output variable returns the dynamic content to the UI.

Exercise 1: Modify the ui.R and server.R files so as to add a textInput in the sidebarPanel (below the sliderInput) that will enable you to modify the title of the histogram. The histogram should now be created using the functions ggplot(), geom_histogram() and ggtitle() from the ggplot2 R package.

Important note on code execution

The location of code in server.R determines how often it is run, and thus impacts the performance of the app. There are three zones where code is run more or less often:

# Zone 1
library(shiny)
library(ggplot2)

shinyServer(function(input, output) {
  # Zone 2
  output$distPlot <- renderPlot({
    # Zone 3 : run each time a user changes a widget that output$map relies on
  })
})
  • Zone 1, this code is only executed once when the app is started. Loading libraries is typically done here, as are reading large static datasets.
  • Zone 2, this code is ran each time a user requests/visits the app. This can for example be used to load data for the last \(x\) days, as this will be different for each user.
  • Zone 3, this code is ran each time a change is detected in the UI. This typically contains plotting code and such, or data that is requested based on changes in the UI (date range for example). If you put your code in the wrong zone, the app’s performance can be seriously impacted. For example, if reading a large static dataset is put into Zone 3, this large dataset will be read each time the plot needs to be redrawn.

Examples/exercises below will help to clarify these notions.

Reactive expressions

Normally, Shiny automatically reruns the code in the different zones as explained above. But consider the following fictitious example where two lines were added in Zone 3:

# Zone 1
library(shiny)
library(ggplot2)

shinyServer(function(input, output) {
  # Zone 2
  output$distPlot <- renderPlot({
    # Zone 3
    dat <- get_data(input$ui_element1, input$ui_element2)
    plot(dat, input$ui_element3)
  })
})

The (hypothetical, user-defined) get_data() function is called each time any of the three UI elements is updated (since it is in Zone 3). However, if only ui_element3 is updated the data should not be reloaded (to prevent time loss). This is where reactive expressions come in, as seen below:

# Zone 1
library(ggplot2)

shinyServer(function(input, output) {
  # Zone 2
  input_data <- reactive({
    dat <- get_data(input$ui_element1, input$ui_element2)
  })
  output$distPlot <- renderPlot({
    # Zone 3
    plot(input_data(), input$ui_element3)
  })
})

We wrap the data loading in a reactive block, and in the plotting refer to the new function input_data(). The advantage of this approach is that for a reactive expression Shiny first checks if the data actually needs to be updated or not. If only ui_element3 is updated, the reactive simply returns the previously stored data (i.e., caching), and the plot is redrawn without the costly step of re-reading the data.

At this point, you might want to have a better look at the Shiny cheatsheet that you downloaded previously.

Exercises

(Solutions can be accessed here)

Exercise 2. Open a new Shiny app in RStudio (File > New project > New directory > Shiny Web Application), which is essentially a new project in itself. Then edit the ui.R and server.R files to obtain the example given below (the actual plot is of mtcars$mpg as a function of mtcars$wt). Use the ggplot2 package to make the plot. For this exercise, no interactivity is required. In the next couple of excercises you will build a visualisation app for the mtcars dataset.

Exercise 3. Add another dropdown menu in the sidebar. The two dropdown menus should now select which variables from mtcars will be respectively plotted on the \(x\) and \(y\) axes. Tip: have a look at aes_string() from ggplot2. Also, the textInput in the sidebarPanel should now be connected interactively to the actual title of the plot. And the names of the two variables selected should now be displayed above the plot in an interactive manner (“You selected variables … and …”).

Exercise 4. Add a checkbox which enables the user to choose whether or not to include a stat_smooth() call (from ggplot2 package).

Exercise 5. Add a checkbox and a dropdown menu that allow the user to toggle the use of facetting and select which variable to facet with. Tip: see for instance this web page.

In the next couple of excercises we will build a stock price visualisation app (inspired by Shiny tutorial).

Exercise 6. We will download the stock price data using getSymbols() from the quantmod package. Ensure that the value of the argument auto.assign is set to FALSE, and you can use the from and to input arguments to select time. Extract stockprice data for AAPL (Apple), YHOO (Yahoo), and GS (Goldman Sachs). Create a chart of that data by calling the candleChart() function from quantmod on the resulting object from getSymbols(). Change the theme from black to white.

Exercise 7. Create a new Shiny app, and create a ui.R file that results in this user interface: