The Shiny package includes several examples. The runExample()
command, with no arguments passed, displays the available examples as follows:
> runExample() Valid examples are "01_hello", "02_text", "03_reactivity", "04_mpg", "05_sliders", "06_tabsets", "07_widgets", "08_html", "09_upload", "10_download", "11_timer"
To see the examples running, the name of the example must be passed as shown here:
> runExample("01_hello")
The examples are displayed in a separate window that includes the application and both server.R
and UI.R
, which generate them. The scripts are very well described so that it is easy to understand what each piece of code does:
Some additional examples will be found in the following sections. The scripts for this application are available at Packt Publishing's website, where you can download all the examples in this book. To run it you have to either execute runApp("folder path")
, pointing at the application's directory or, in the newest versions of RStudio, the program enables a button in the Shiny-related scripts to easily run the application.
This first example consists of a very basic application where a number is passed, and a plot with the 1/x
series, where x
are the numbers between 1 and the passed number, is displayed. The following is the code for UI.R
:
library(shiny) # Starting line shinyUI(fluidPage( # Application title titlePanel("Example 1"), sidebarLayout( # Sidebar with a numeric input sidebarPanel( numericInput("number", "Insert a number:", value = 30, min = 1, max = 50) ), #The plot created in server.R is displayed mainPanel( plotOutput("plot") ) ) ))
The following is the code for the server.R
file:
library(shiny) #Starting line of server.R shinyServer(function(input, output) { #Plot generation output$plot <- renderPlot({ plot(1/1:input$number) }) })
Keeping in mind the preceding diagram (in the An introduction to server.R and UI.R section), the logic applied to this example would be as follows:
input$number
. All the functions that draw widgets to pass inputs in UI.R
have id
as their first argument. Basically, they generate a JavaScript form with the id
passed. They can be accessed afterwards by input$(id)
.server.R
.renderPlot()
in server.R
is re-executed whenever a change in an input occurs.renderPlot()
is saved within the output list with the output$(object_name)
form. This special object naming is necessary to be able to display the output in UI.R
. Of course, when using render functions, output elements must match the type of the object that is being created. For example, returning a text in renderPlot()
will not display any result in the application.plotOutput()
statement that calls the object generated in step 4, the Shiny framework passes that corresponding output to the browser.UI.R
, the object generated in step 4 is displayed. It is important to keep in mind that the displaying function (in this case, plotOutput()
) must be compatible with the object that has to be displayed, that is, if the output object is of the plot type, it can only be called successfully by plotOutput()
. If another function is selected, probably outputs that are not desired or no output will be displayed.Usually, reactive objects are enclosed by both parentheses and braces. The braces in R denote an expression. An expression is basically a piece of code where even objects can be created. In this case, the objects created are only accessible inside the function they are in (in this case, renderPlot()
). Back to the example, renderPlot()
could also be written as follows:
renderPlot({ numbers.to.plot <- 1/1:input$number plot(numbers.to.plot) })
The numbers.to.plot
object in this case is not accessible outside this call of renderPlot()
. Although in this example the use of an intermediate object is absolutely trivial, it can be very useful if more complex scripts are required.
As it was previously explained, R provides the possibility of creating intermediate reactive objects that can be used by other reactive functions, including those that effectively produce outputs. This is how UI.R
looks like for the second situation explained in the The concept of reactivity section:
library(shiny) # Starting line shinyUI(fluidPage( # Application title titlePanel("Example 2"), # Sidebar with a numeric input textInput("text", "Insert a text:", value = "The cat is brown"), #The plot created in server.R is displayed textOutput("text.words"), textOutput("text.longest") ) )
The following is the server.R
file:
library(shiny) #initialization of server.R shinyServer(function(input, output) { #Plot generation output$text.words <- renderText({ words <- unlist(strsplit(input$text, split = " ")) paste0("This phrase has ",length(words)," words in total") }) output$text.longest <- renderText({ words <- unlist(strsplit(input$text, split = " ")) word.chars <- nchar(words) max.len <- max(word.chars) longest.word <- words[which.max(word.chars)] paste0(longest.word, " is the longest word and has ",max.len," characters") }) })
As it can be seen, the unlist(strsplit(input$text, split = " "))
expression is repeated. In this case, as there is not much processing required, an execution time difference cannot be practically appreciated. However, when it comes to larger amounts of data, doing the same process twice can be a real waste of resources. In order to avoid this, a reactive object can be created, which will then be used by both the render()
functions. In this case, server.R
would be as follows:
library(shiny) #initialization of server.R shinyServer(function(input, output) { words <- reactive(unlist(strsplit(input$text, split = " "))) #Plot generation output$text.words <- renderText( paste0("This phrase has ",length(words())," words in total") ) output$text.longest <- renderText({ word.chars <- nchar(words()) max.len <- max(word.chars) longest.word <- words()[which.max(word.chars)] paste0(longest.word, " is the longest word and has ",max.len," characters") }) })
The repeated structure is called only once in a separate reactive expression and stored in the iris.sset
object. As it is actually a function, the call of this object shall be done with the inclusion of parentheses. In this case, the subsetting is done only once and then used in both the render functions.
This example is based on the iris dataset. It basically displays a summary of the variables based on the species selected. For this case, it is wise to call the dataset prior to launching the application, and this can be done by loading the data before the initialization of the Shiny server in the server
.R
script. UI.R
and would look as follows:
library(shiny) # Starting line shinyUI(fluidPage( # Application title titlePanel("Example 3"), sidebarLayout( # Sidebar sidebarPanel( #Species selection selectInput("species","Select a species:", c("setosa","versicolor", "virginica"))), mainPanel( #The summary table created in server.R is displayed tableOutput("table") ) ) ))
The following would be server.R
:
library(shiny) data(iris) #initialization of server.R shinyServer(function(input, output) { #Table generation where the summary is displayed output$table <- renderTable( summary(subset(iris, Species == input$species)[,-5]) ) })
This is a good example of the usefulness of pre-loading processing. To produce an equivalent result without this, either renderTable()
should include the call to the data or the data should be loaded in a reactive object. Both the options have a huge drawback that they imply inserting the same data load in a reactive process, that is, the same action will be repeated with no difference whenever an input changes.
The example with the data call in renderTable()
would be as follows:
output$table <- renderTable({ data(iris) summary(subset(iris, Species == input$species)[,-5]) })
Looking at the same previous example, instead of hard coding the options in the species input widget, they could be taken directly from the Species
variable of the dataset. To do this, the dataset must be loaded prior to the application load using global.R
. This is how the different files would look like:
global.R
will be a one-command file where only the dataset is loaded:
data(iris)
The following is the code for UI.R
. Notice that the input options of species are not hard coded any more but are defined as the levels of the Species
variable in the iris
dataset:
library(shiny) # Starting line shinyUI(pageWithSidebar( # Application title titlePanel("Example 4"), # Sidebar sidebarPanel( #Species selection selectInput("species","Select a species:", levels(iris$Species))), #The plot created in server.R is displayed mainPanel( #Table display tableOutput("table"), #Plot display plotOutput("plot") ) ) )
Finally, server.R
differs from the previous example only in the fact that there is no need to load the data prior to initializing shinyServer()
:
library(shiny) #initialization of server.R shinyServer(function(input, output) { iris.sset <- reactive({subset(iris, Species == input$species)[,-5]}) #Table generation where the summary is displayed output$table <- renderTable({ summary(iris.sset()) }) #Plot generation where the summary is displayed output$plot <- renderPlot({ plot(iris.sset()) }) })
The changes made in this example with respect to the previous one are only from the back end. From the end user's point of view, both applications will be identical.