In this tutorial, I’m going to walk you through the basics of setting up a shiny app, starting with the example built into RStudio I’m not going to explain yet how shiny apps are structured, the goal is to just get something up and running, and give you some familiarity with the layout of a fairly simple app.
shiny
, ggplot2
Under the File
menu, choose New Project...
. You will see a popup window like the one below. Choose New Directory
.
Choose Shiny Web Application
as the project type.
I like to put all of my apps in the same directory`, but it doesn’t matter where you save it.
Your RStudio interface should look like this now. You don’t have to do anything else at this step.
If RStudio has changed their demo app and your source code doesn’t look like this, replace it with the code below:
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
Click on Run App
in the top right corner of the source pane. The app will open up in a new window. Play with the slider and watch the histogram change.
You can also open up the app in a web browser by clicking on Open in Browser
.
Now we’re going to make a series of changes to the demo app until it’s all your own.
You can close the app by closing the window or browser tab it’s running in, or leave it running while you edit the code. If you have multiple screens, it’s useful to have the app open on one screen and the code on another.
Find the application title. It is the first argument to the function titlePanel
. Change the title to "My First App"
. Make sure the title is inside quotes and the whole quoted string is inside the parentheses. Save the file (cmd-S
or File > Save
).
Click Run App
(or Reload App
if you haven’t closed the app window) in the source pane. If you haven’t saved your changes, it will prompt you to do so. Check that the app title has changed.
Find the function sliderInput
(line 21). The first argument is the name you can use in the code to find the value of this input, so don’t change it just yet. The second argument is the text that displays before the slider. Change this to something else and re-run the app.
sliderInput("bins",
"Number of bins:",
min = 0,
max = 50,
value = 30)
See if you can figure out what the next three arguments to sliderInput
do. Change them to different integers, then re-run the app to see what’s changed.
The arguments to the function sidebarPanel
are just a list of things you want to display in the sidebar. To add some explanatory text in a paragraph before the sliderInput
, just use the paragraph function p("My text")
sidebarPanel(
p("I am explaining this perfectly"),
sliderInput("bins",
"Choose the best bin number:",
min = 10,
max = 40,
value = 25)
)
The sidebar shows up on the left if your window is wide enough, but moves to the top of the screen if it’s too narrow.
I don’t like it there, so we can move this text out of the sidebar and to the top of the page, just under the title. Try this and re-run the app.
# Application title
titlePanel("My First App"),
p("I am explaining this perfectly"),
# Sidebar with a slider input for number of bins
sidebarLayout(...)
See where you can move the text in the layout of the page and where causes errors.
I’m also not keen on the grey plot. We can change it inside the hist
function.
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'steelblue3', border = 'grey30')
There are a lot of ways to represent colour in R. The easiest three are:
#0066CC
,rgb
or hsl
functions,I like steelblue3
, as it’s pretty close to the shiny interface default colour, but feel free to choose whatever you like.
I prefer ggplot
graphs, so let’s make the plot with geom_histogram
instead of hist
(which is a great function for really quick plots). Since we need several functions from the ggplot2
package, we’ll need to load that package at the top of the script, just under where the shiny
package is loaded:
library(shiny)
library(ggplot2)
You can replace all of the code in the renderPlot
function with the code below.
output$distPlot <- renderPlot({
# create plot
ggplot(faithful, aes(waiting)) +
geom_histogram(bins = input$bins,
fill = "steelblue3",
colour = "grey30") +
xlab("What are we even plotting here?") +
theme_minimal()
})
You can set the fill
and colour
to whatever colours you like, and change theme_minimal()
to one of the other built-in ggplot themes.
What are we even plotting here? Type ?faithful
into the console pane to see what the waiting
column represents (faithful
is a built-in demo dataset). Change the label on the x-axis to something more sensible.
The faithful
dataset includes two columns:eruptions
and waiting
. We’ve been plotting the waiting
variable, but what if you wanted to plot the eruptions
variable instead?
Try plotting the eruption time (eruptions
) instead of the waiting time. You just have to change one word in the ggplot
function and update the x-axis label.
We can add another input widget to let the user switch between plotting eruption time and wait time. The RStudio Shiny tutorial has a great overview of the different input options. We need to toggle between two options, so we can use either radio buttons or a select box. Radio buttons are probably best if you have only a few options and the user will want to see them all at the same time to decide.
Add the following code as the first argument to sidebarPanel()
, which just takes a list of different widgets. radioButtons
is the widget we’re using. The first argument is display_var
, which we will use later in the code to find the value of this widget. The second argument is the label to display to the user. The next argument is choices
, which is a list of choices in the format c("label1" = "value1", "label2 = "value2", ...)
. The label is what gets shown to the user and the value is what gets used by the code (these can be the same, but you often want the user label to be more descriptive). The last argument is selected
, which is the value of the default choice. Save this and re-run the app.
radioButtons("display_var",
"Which variable to display",
choices = c("Waiting time to next eruption" = "waiting",
"Eruption time" = "eruptions"),
selected = "waiting"
),
You should have a radio button interface now. You can click on the options to switch the button, but it won’t do anything to your plot yet. We need to edit the plot-generating code to make that happen.
First, we need to change the x-axis label depending on what we’re graphing. We use an if/else statement to set the variable xlabel
to one thing if input$display_var
is equivalent to "eruptions"
, and to something else if it’s equivalent to "waiting"
. Put this code at the very beginning of the code block for the renderPlot
function (after the line output$distPlot <- renderPlot({
).
# set x-axis label depending on the value of display_var
if (input$display_var == "eruptions") {
xlabel <- "Eruption Time (in minutes)"
} else if (input$display_var == "waiting") {
xlabel <- "Waiting Time to Next Eruption (in minutes)"
}
The double-equal-signs ==
means "equivalent to and is how you check if two things are the same; if you only use one equal sign, you set the variable on the left to the value on the right.
Then we have to edit the ggplot
function to use the new label and to plot the correct column. The variable input$display_var
gives you the user-input value of the widget called display_var
.
# create plot
ggplot(faithful, aes(.data[[input$display_var]])) +
geom_histogram(bins = input$bins,
fill = "steelblue3",
colour = "grey30") +
xlab(xlabel) +
theme_minimal()
Notice that the function aes(waiting)
from before has changed to aes(.data[[input$display_var]])
. Because input$display_var
is a string, we have to select it from the .data
placeholder (which refers to the faithful
data table) using double brackets.
Re-run your app and see if you can change the data and x-axis label with your new widget. If not, check that your code against the code below:
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
library(ggplot2)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("My First App"),
p("I am explaining this perfectly"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
radioButtons("display_var",
"Which variable to display",
choices = c("Waiting time to next eruption" = "waiting",
"Eruption time" = "eruptions"),
selected = "waiting"
),
sliderInput("bins",
"Number of bins:",
min = 10,
max = 40,
value = 25)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# set x-axis label depending on the value of display_var
if (input$display_var == "eruptions") {
xlabel <- "Waiting Time to Next Eruption (in minutes)"
} else if (input$display_var == "waiting") {
xlabel <- "Waiting Time to Next Eruption (in minutes)"
}
# create plot
ggplot(faithful, aes(.data[[input$display_var]])) +
geom_histogram(bins = input$bins,
fill = "steelblue3",
colour = "grey30") +
xlab(xlabel) +
theme_minimal()
})
}
# Run the application
shinyApp(ui = ui, server = server)
term | definition |
---|---|
argument | A variable that provides input to a function. |
integer | A data type representing whole numbers. |
package | A group of R functions. |
panes | RStudio is arranged with four window “panes”. |
rstudio | An integrated development environment (IDE) that helps you process R code. |
shiny | An R package that builds interactive web apps |
string | A piece of text inside of quotes. |
widget | A interactive web element, like a dropdown menu or a slider. |