Welcome back everyone! Today we will have a look at

  1. How to create Shiny Apps in R
  2. What to look out for when creating Dashboards

Shiny Applications in R 💎

What is Shiny?

Shiny is an R package that makes it easy to build interactive web applications (apps) straight from R. You need to install the package shiny:

install.packages("shiny")
library(shiny)

For a quick illustration of what you can do with Shiny head over to the interactive visualisation tool for the Freedom of Press Index

Throughout the lab we will use a running example to illustrate the different aspects of creating a shiny app. You can find it in the folder “our_app”. It is interactive plot that displays all movies on Rotten Tomatoes and includes several filtering options.

Structure of a Shiny App

Shiny apps are contained in a single script called app.R. The script app.R lives in a directory (for example, newdir/) and the app can be run with runApp(“newdir”).

app.R has three components:

  1. a user interface object - the (ui) object controls the layout and appearance of your app.

  2. a server function - the server function contains the instructions that your computer needs to build your app.

  3. a call to the shinyApp function - the shinyApp function creates Shiny app objects from an explicit UI/server pair.

# illustrated workflow 

ui <- fluidPage()

server <- function(input, output) {}

shinyApp(ui = ui, server = server)

Running a Shiny App

To create a Shiny app you need to create a new directory and save an app.R file inside it. This app.R script needs to contain the three components outlined above. Further, it is recommended that each app should have its own unique directory.

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

runApp("my_shiny_app")

Layout / UI 🗾

Shiny uses the function fluidPage to create a display that automatically adjusts to the dimensions of your user’s browser window. You lay out the user interface of your app by placing elements in the fluidPage function. Alternatives to fluidPage exist (i.e. fixedPage, bootstrapPage), but these are only useful in specific situations.

For example, the ui function below creates a user interface that has a title panel and a sidebar layout, which includes a sidebar panel and a main panel. Note that these elements are placed within the fluidPage function.

ui <- fluidPage(
  titlePanel("title panel"),

  sidebarLayout(
    sidebarPanel("sidebar panel"),
    mainPanel("main panel")
  )
)

While titlePanel and sidebarLayout create a basic layout for your Shiny app, you can also create more advanced layouts. For example you can use navbarPage to give your app a multi-page user interface that includes a navigation bar. Or you can use fluidRow and column to build your layout up from a grid system. If you’d like to learn more about these advanced options, have a look at the Shiny Application Layout Guide.

Within the different layout functions you can also customise your app further by italisising or making your font bold and even including html elements:

To include images you need to use the img function.

img(src = "my_image.png", height = 72, width = 72)

# "src =" needs to be spelled out since the html expects it. 

To learn more about how you can customise your ui see here and here.


Widgets 🐭

A widget is a web element that your users can interact with. In other words to make your app interactive, you need widgets. These provide a way for your users to send messages to the Shiny app, meaning that when a user changes the input in a widget, the value that is shown will change as well.

Shiny comes with a family of pre-built widgets, each created with a transparently named R function. For example, Shiny provides a function named actionButton that creates an Action Button and a function named sliderInput that creates a slider bar.

Some standard Shiny widgets are (gallery):

To add a widget to your app, you need to include a widget function in sidebarPanel or mainPanel in your ui object.

Each widget function requires several arguments. The first two arguments for each widget are:

  1. a name for the widget: The user will not see this name, but you can use it to access the widget’s value. The name should be a character string.

  2. a label: This label will appear with the widget in your app. It should be a character string, but it can be an empty string "".

The remaining arguments vary from widget to widget, depending on what the widget needs to do its job. They include things like initial values, ranges, and increments. You can find the exact arguments needed by a widget on the widget function’s help page, (e.g., ?selectInput).

Relevant chunk from our running example:

fluidPage(
  titlePanel("Movie explorer"),
  fluidRow(
    column(3, ... ,
        sliderInput(name = "reviews", label = "Minimum number of reviews on Rotten Tomatoes",
          10, 300, 80, step = 10),
        ... ,
        textInput("director", "Director name contains (e.g., Miyazaki)"),
    ),
    ...,
    selectInput("xvar", "X-axis variable", axis_vars, selected = "Meter")))

Display Reactive Output

To give your Shiny App a feeling of live interactiveness you need to include a way to display reactive output. Reactive output automatically responds when your user selects an option in a widget.

There are two steps involved in making your widgets reactive: 1. Add the relevant output function to your ui function. 2. Provide R code to build the object in your server function.

Step 1:

Shiny provides a family of functions that turn R objects into output for your user interface. Each function creates a specific type of output.

Some examples are: plotOutput for reactive plots, tableOutput for reactive tables.

In our running example we used textOutput to give the number of movies displayed:

ui <- fluidPage(
  titlePanel("Movie explorer"),
  fluidRow(
    column( ... ),
    column(9,
           plotlyOutput("plot1"),
           wellPanel(
             span("Number of movies selected:",
                  textOutput("n_movies")
             )
           ))

Step 2:

Placing a function in ui tells Shiny where to display your object. Next, you need to tell Shiny how to build the object.

We do this by providing the R code that builds the object in the server function. You do this by defining a new element for output within the server function. The element name should match the name of the reactive element that you created in the ui.

If you created a textOutput("selected_var") in your ui, output$selected_var in the server function matches this.

To illustrate this let’s look at our example, where we used textOutput("n_movies"), in the server function we state:

server <- function(input, output, session) {
  ... ,
  
  output$n_movies <- renderText({ nrow(movies()) })
}

# Note that movies is a df that we create within our server function

Every output* function in ui, has a corresponding render* function in server to build the reactive widget.

Each render* function takes a single argument: an R expression surrounded by braces, {}. The expression can be one simple line of text, or it can involve many lines of code, as if it were a complicated function call.


More complicated examples ⚙️

You can create more complicated Shiny apps by loading R Scripts, packages, and data sets.

What you need to know is that:

  • The directory that app.R appears in will become the working directory of the Shiny app
  • Shiny will run code placed at the start of app.R, before the server function, only once during the life of the app.
  • Shiny will run code placed inside server function multiple times, which can slow down the app.

In our example, this is used to first create and join the necessary tables for the entirety of the app. This only needs to be done once. Within the server function we then filter and select based on certain inputs, obviously this needs to be repeated every time the input changes. This is why we placed that code within the server function.


Share your Apps 🧺

You can now build a useful Shiny app, but can you share it with others? This lesson will show you several ways to share your Shiny apps.

When it comes to sharing Shiny apps, you have two basic options:

  1. Share your Shiny app as R scripts. This is the simplest way to share an app, but it works only if your users have R on their own computer (and know how to use it). Users can use these scripts to launch the app from their own R session, just like you’ve been launching the apps so far in this tutorial. All they need to do this a copy of your app directory including the app.R script.

  2. Share your Shiny app as a web page. This is definitely the most user friendly way to share a Shiny app. Your users can navigate to your app through the internet with a web browser. They will find your app fully rendered, up to date, and ready to go.

If you prefer the second option, I propose that you have a look at Shinyapps.io. It is RStudio’s hosting service for Shiny apps. shinyapps.io lets you upload your app straight from your R session to a server hosted by RStudio. You have complete control over your app including server administration tools. You can find out more about shinyapps.io by visiting shinyapps.io.

The setup and installation for doing this is relatively straightforward, but requires all the standard boring steps, such as setting up an account, password and getting familiar with the website UI. Therefore we won’t do this here. However, if you have questions you can find a detailed guide here.


Exercises

Now it is your turn, adapt the shiny app by:

  1. Adding a widget that let’s you subset by the film’s genre:

    • Think about where you specify this?
    • Make sure to specify what the default option should be.
    • Genre Categories in the data include: Action, Adventure, Animation, Biography, Comedy, Crime, Documentary, Drama, Family, Fantasy, History, Horror, Music, Musical, Mystery, Romance, Sci-Fi, Short, Sport, Thriller, War, Western.
  2. Turn our scatter plot into a bubble plot, where the size of the bubbles is determined by the revenues generated at the Box-Office.

  3. In line 97 we use reactive({}) to change the filtering based on user input, how could we do this with an alternative (but slower) function?


Guidelines for Dashboards 🎨

Now that you have the tools to create interactive dashboards, you might be eager to use these skills liberally. And so you should. But, dashboards are not always the best way to visualise data. Prior to developing a dashboard you should make sure to ask yourself a few questions.


Checklist before you start ✅

  1. Are you tackling a monitoring task that needs your data/metrics to be updated frequently?
  2. Who will use the dashboard and to what end? What questions will they use it to answer? What actions will they take in response to these answers?
  3. What specific information should be displayed, and is it meaningful without much context?
  4. What could lead to the metrics being wrong/misleading?

Only if you answered ticked the box after the majority of the questions above should you really opt for a dashboard-based approach.


Design advice

Even then, there are a number of design guidelines that you should follow. Here is a non-exhaustive list:

  • Minimize distractions.
  • Focus on meaningful quantities of interest, not the ones that look cool.
  • Don’t overload with information.
  • Apply all rules of good data visualisation.
  • Use interactive figures with care (e.g., to make optional content conditionally visible)
  • Try not to exceed the boundaries of a single screen.
  • Ensure desktop/mobile screen responsiveness (fluidPage(), will achieve this).

Display all your new skills? 😁

Thinking a bit ahead (e.g. data science / academic job market), one way to go would be to create a personalized website as a central source to everything you would like to show. What to include, of course, highly depends on your profile, your discipline and the job market you are interested in.

For an academic webpage that could for example be:

  • about statement
  • CV
  • list of publications / working papers
  • list of course materials for courses that you’ve taught
  • example of data science project / app / package you’re proud of
  • contact + links to Github, Google Scholar, Twitter, etc.

Here is a recommendation by Elsevier on how to create effective academic personal website.

For a non-academic webpage (e.g. focus on industry jobs) that could be:

  • about statement
  • CV(?)
  • EXAMPLES of data science projects
  • contact + links to Github, LinkedIn, etc.

Usually, a good first step is to look at webpages of other people with similar profiles you find inspiring (e.g. people that already have the job you’d like to have). 👀

Tools to build personal webpages

There is a plethora of possibilities to build your personal webpage, from very basic to very very complicated.

Very simple point-and-click ways to create websites are Google Sites, WordPress, Wix, etc. However, the free versions often come with ads and other downsides.

GitHub Pages 🐙

One mid-range way that we’d recommend (it requires some coding experience, but you have that!) is to use GitHub Pages because

  • it is free and free of adds
  • the page would be directly hosted from your GitHub repository and
  • you can choose from a huge variety of Jekyll themes and
  • it compiles html from Markdown - something you’ve been doing all the time in this course
  • and there are even more advantages

For example Rob Williams created a great tutorial on how to build an academic websites with Github; and the academicpages template is a ready-to-fork GitHub Pages template that I used to build my webpage lfoswald.github.io. If you like, you can also configure custom URLs.

Here is a, possibly even more accessible, all purpose and less complicated Quick Start tutorial on GitHub Pages.

Blogdown

Blogdown is an R package based on Hugo, another static site generator. Again

  • it is free
  • you have great online support because you work with R and GitHub
  • and you can choose from a wide range of Hugo themes

Here is a tutorial by Andrew Hetherington on how to build a data-science personal website in R using blogdown. His personal webpage is also created with blogdown. You can deploy and host your website, for example, on Netlify.


Sources

The shiny tutorial leans heavily on RStudio’s series of written shiny tutorials. The running example was adapted from: Movies-Explorer Interactive App.

 

A work by Lisa Oswald & Tom Arend

Prepared for Intro to Data Science, taught by Simon Munzert

Hertie School, Berlin