Server function
Now that you’ve had some practice with the UI, it’s time to move on to the server function.
Again, before we get into the details, let’s remind ourselves of the anatomy of a Shiny app. The basic task of the server function is to define the relationship between inputs and outputs.
Here again is the app that we are working with in this module
Earlier we saw how to build the UI of this app, and we also noted that each input was tagged with an inputId
that can be used to refer to them in the server.
This is the server function code for this app
Once again there is a lot going on here to parse at once, so in the following sections we take a closer look at the function.
At the outermost layer
We define our server function which takes two arguments: an input
and an output
. Both of these are named lists.
The server function accesses inputs selected by the user to perform computations and specifies how outputs laid out in the UI should be updated.
The server function can take on one more argument, session
, which is an environment that can be used to access information and functionality relating to the session. However this concept is beyond the scope of this tutorial, so for now we’ll stick to server functions that only have input and output arguments.
output
Our simple app had only one output – a plot. So our server function contains the logic necessary to build this plot.
The renderPlot()
function specifies how the plot output should be updated. Let’s take a look at what is happening in the renderPlot()
function first.
renderPlot()
This is good ol’ ggplot2 code! So even if you’re new to shiny, if you’ve previously used ggplot2 for plotting in R, this syntax should look familiar to you.
One aspect of the syntax that might be new, however, is how the x and y variables are defined. They come from the input list that is built in the UI.
Inputs
Here is the relevant UI and server code.
Input x and y come from the selectInput()
widgets, and map to the x
and y
arguments of the plot aesthetics.
Rules of server functions
There are three rules of building server functions:
Always save objects to display to the named output list, i.e. something of the form
output$xx
, wherexx
is the plot you want to display.Always build objects to display with one of the
render*()
functions, like we built our plot withrenderPlot()
.Use input values from the named input list, with
input$xx
.
Output types
Just like various inputs, Shiny also provides a wide selection of output types each of which works with a render function.
For example, in our app we used the renderPlot()
function to build our reactive plot (we’ll get to what I mean by reactive in a second) and laid out the plot with the plotOutput()
function.
Shiny knows to match these two together as they use the same outputID
, scatterplot.
In the following exercises you’ll get a chance to work with other render/output function pairs to add more elements to your app.
Practice: Matching inputs and outputs
Here is a simple Shiny app. Try entering some text and observe how the text is displayed back to you after a short pause.
Example Shiny App
The code for this app is given below, with a few pieces missing (indicated with ___
). Each of the blanks are numbered, e.g. ([1]
, [2]
, etc.)
library(shiny)
<- page_fluid(
ui
textInput(
inputId = "custom_text",
label = "_[1]_"
),
strong("Text is shown below:"),
2]_(outputId = "_[3]_")
_[
)
<- function(input, output, session){
server
$user_text <- renderText({ input$_[4]_ })
output
}
shinyApp(ui = ui, server = server)
Which of the following is false?
[1]
should be"Input some text here:"
[2]
should betextOutput
[3]
should be"custom_text"
[4]
should be"custom_text"
Reactivity
Let’s also briefly discuss reactivity.
It’s easy to build interactive applications with Shiny, but to get the most out of it, you’ll need to understand the reactive programming scheme used by Shiny.
In a nutshell Shiny automatically updates outputs, such as plots, when inputs that go into them change.
Putting all the pieces together
Before we wrap up this section, I should also mention the last component of each Shiny app, which is a call to the aptly named shinyApp()
function, which puts the UI and the server pieces together to create a Shiny app object.
Time to put this all into practice!
Practice: Rules of server functions
Which of the following is not true about server functions?
- Server functions should include a call to #
runApp()
- Objects to be displayed should be saved to #
output$
- Reactive objects should be built with
render*()
functions - Input values should be referred to with
input$
Practice: Fix it up
Below is the code for the Shiny app we built earlier, however currently the code is broken. Specifically there are errors in the definition of the server function as well as in the mainPanel
of the UI.
Your turn
- Review the app and identify errors in the code. (Hint: Refer back to the rules of server functions.)
- Do the render functions match the output functions? If not, make the appropriate change and try running the app. Are there any remaining errors?
- Are the inputs referred to using the correct syntax? If not, make the appropriate change and try running the app. Are there any remaining errors?
- Are the outputs referred to using the correct names? If not, make the appropriate change and try running the app. Are there any remaining errors?
Navigate to the project called 1-3 Fix it up after clicking the button below
- Download the data if you haven’t already
```{r}
# Get the data
file <- "https://github.com/rstudio-education/shiny-course/raw/main/movies.RData"
destfile <- "movies.RData"
download.file(file, destfile)
```
- Copy the code below into an R script
# Load packages ----------------------------------------------------------------
library(shiny)
library(bslib)
library(ggplot2)
# Load data --------------------------------------------------------------------
load("movies.RData")
# Define UI --------------------------------------------------------------------
<- page_sidebar(
ui sidebar = sidebar(
# Select variable for y-axis
selectInput(
inputId = "y",
label = "Y-axis:",
choices = c(
"IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics score" = "critics_score",
"Audience score" = "audience_score",
"Runtime" = "runtime"
),selected = "audience_score"
),
# Select variable for x-axis
selectInput(
inputId = "x",
label = "X-axis:",
choices = c(
"IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics score" = "critics_score",
"Audience score" = "audience_score",
"Runtime" = "runtime"
),selected = "critics_score"
),
# Select variable for color
selectInput(
inputId = "z",
label = "Color by:",
choices = c(
"Title type" = "title_type",
"Genre" = "genre",
"MPAA rating" = "mpaa_rating",
"Critics rating" = "critics_rating",
"Audience rating" = "audience_rating"
),selected = "mpaa_rating"
)
),
# Output: Show scatterplot
card(plotOutput(outputId = "scatterPlot"))
)
# Define server ----------------------------------------------------------------
<- function(input, output, session) {
server $scatterplot <- renderTable({
output
ggplot(data = movies, aes_string(x = x, y = y, color = z)) +
geom_point()
})
}
# Create a Shiny app object ----------------------------------------------------
shinyApp(ui = ui, server = server)
# Load packages ----------------------------------------------------------------
library(shiny)
library(bslib)
library(ggplot2)
# Load data --------------------------------------------------------------------
load("movies.RData")
# Define UI --------------------------------------------------------------------
<- page_sidebar(
ui sidebar = sidebar(
# Select variable for y-axis
selectInput(
inputId = "y",
label = "Y-axis:",
choices = c(
"IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics score" = "critics_score",
"Audience score" = "audience_score",
"Runtime" = "runtime"
),selected = "audience_score"
),
# Select variable for x-axis
selectInput(
inputId = "x",
label = "X-axis:",
choices = c(
"IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics score" = "critics_score",
"Audience score" = "audience_score",
"Runtime" = "runtime"
),selected = "critics_score"
),
# Select variable for color
selectInput(
inputId = "z",
label = "Color by:",
choices = c(
"Title type" = "title_type",
"Genre" = "genre",
"MPAA rating" = "mpaa_rating",
"Critics rating" = "critics_rating",
"Audience rating" = "audience_rating"
),selected = "mpaa_rating"
)
),
# Output: Show scatterplot
card(
plotOutput(outputId = "scatterplot")
)
)
# Define server ----------------------------------------------------------------
<- function(input, output, session) {
server $scatterplot <- renderPlot({
outputggplot(data = movies, aes_string(x = input$x, y = input$y, color = input$z)) +
geom_point()
})
}
# Create a Shiny app object ----------------------------------------------------
shinyApp(ui = ui, server = server)