Welcome back everyone! Today we will have a look at
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.
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:
a user interface object - the (ui) object controls the layout and appearance of your app.
a server function - the server function contains the instructions that your computer needs to build your app.
a call to the shinyApp
function - the shinyApp function creates Shiny app objects from an explicit UI/server pair.
# illustrated workflow
<- fluidPage()
ui
<- function(input, output) {}
server
shinyApp(ui = ui, server = server)
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")
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.
<- fluidPage(
ui 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.
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:
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.
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")))
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.
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:
<- fluidPage(
ui titlePanel("Movie explorer"),
fluidRow(
column( ... ),
column(9,
plotlyOutput("plot1"),
wellPanel(
span("Number of movies selected:",
textOutput("n_movies")
) ))
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:
<- function(input, output, session) {
server
... ,
$n_movies <- renderText({ nrow(movies()) })
output
}
# 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.
You can create more complicated Shiny apps by loading R Scripts, packages, and data sets.
What you need to know is that:
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.
Now it is your turn, adapt the shiny app by:
Adding a widget that let’s you subset by the film’s genre:
Turn our scatter plot into a bubble plot, where the size of the bubbles is determined by the revenues generated at the Box-Office.
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?
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.
Only if you answered ticked the box after the majority of the questions above should you really opt for a dashboard-based approach.
Even then, there are a number of design guidelines that you should follow. Here is a non-exhaustive list:
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:
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:
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). 👀
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.
One mid-range way that we’d recommend (it requires some coding experience, but you have that!) is to use GitHub Pages because
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 is an R package based on Hugo, another static site generator. Again
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.
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