Input updates

These functions are particularly useful when the options of an input are determined in some way by another input. For example, if a continent was one input and a country the other, the options of the latter would be restricted by the selection of the first.

In order to use input updates, the Shiny server needs to be initialized with an additional session argument. This means that the following should not be the starting line:

shinyServer(function(input, output){

Instead of the preceding code, this must be the starting line:

shinyServer(function(input, output,session){

Session is an optional parameter that can be included in the Shiny server function calls. This creates an object of the session class that keeps track of certain session information. For input updates, the session object is needed as it contains a function to communicate with the inputs (sendInputMessage) and consequently update it. However, there is no need to have a deep knowledge about session objects, as the high-level update functions can deal with them. For more information about this, visit Shiny's documentation at http://cran.r-project.org/web/packages/shiny/shiny.pdf.

The following scripts correspond to the example mentioned previously, where the countries' selections are determined by the continent and changed by updateSelectInput(). Then the selected countries are highlighted. The display is at the continent level.

Note that as the options for checkboxGroupInput() are directly determined, in this case, by updateCheckboxGroupInput() on the server.R side, its choices argument has just one empty value. This is required by the function, as the argument cannot be left empty. However, as the continent input variable always has a value assigned, the checkbox options are constantly updated (on the server side), and, for this reason, the widget always appears with its corresponding choices. To leave the choices argument with one empty value in UI.R is a decision that meets the need of this specific problem, but this does not mean that it is a rule whenever you use updateCheckboxGroupInput(). The following is a code for UI.R:

library(shiny)

# Starting line
shinyUI(fluidPage(
  
  # Application title
  titlePanel("Countries Update Example"),
  
  # Sidebar with a numeric input
  # Sidebar
  sidebarLayout(
    sidebarPanel(
      selectInput("continent", "Select the continent: ",
      c(Africa", "America", "Asia","Europe"),
      selected = "Africa"),
      checkboxGroupInput("country",
      "Select the countries:",choices = c(""))
    ),
    
    #The plot created in server.R is displayed
    mainPanel(
      htmlOutput("map"))
    )
))

It is in server.R where actually the different options are determined. Within observe(), the continent.countries object adopts the values corresponding to the continent input with a switch expression. You can learn more about switch expression in Chapter 2, First Steps towards Programming in R. It is important to consider that update functions will be called almost always inside an observe clause; creating an application with input updates coherent whenever one of the inputs is dependent on another. In this sense, as the update must evaluate a reactive input, it should be placed inside a reactive context, and as the update does not really generate an output (it just updates the arguments of an existing one), it must be included inside an observer.

The plotting is done with geoChart of googleVis. Inside the expression, firstly, an artificial dataset is generated in order to pass the data to geoChart in the exact way it is needed. For more information, see Chapter 6, Using R's Visualization Alternatives in Shiny. In this case, the dataset is directly generated inside the renderGvis() reactive expression instead of creating a reactive expression outside the plotting function. As there is no other process that uses this dataset, in this case, it is better to keep the expression inside the function. As it was already explained in Chapter 6, Using R's Visualization Alternatives in Shiny, gvisGeoChart() expects a code in its region argument, so the continent cannot be passed directly. For this reason, the continent code is determined by switch, stored in an object, and passed to the region argument:

library(shiny)
library(googleVis)

#initialization of server.R
shinyServer(function(input, output,session) {

  #Plot generation
  output$map <- renderGvis({
    
    validate(
      need(length(input$country) > 0, "Please select at least onecountry"))
    plot.dataset <- data.frame(countries = input$country, value=5)

    continent.code <- switch(input$continent,
      Africa = "002",
      America = "019",
      Asia = "142",
      Europe = "150")
    
    gvisGeoChart(plot.dataset, locationvar="countries",sizevar="value",
    options = list(region=continent.code,displayMode="regions"))
    
  })
  
  
  observe({
    
    continent.countries <- switch(input$continent,
    Africa = c("Tunisia","Egypt","South Africa","Lybia"),
    America = c("Argentina","Brazil","Mexico","USA"),
    Asia = c("China","Japan","India","Indonesia"),
    Europe = c("France","Germany","Italy","Spain"))
    
    updateCheckboxGroupInput(session,"country",choices = continent.countries)
  })
})

Note that when running the plot, if no country is selected, an error is thrown referring to the list in general (arguments imply differing number of rows: 0, 1). This is because the data frame created inside renderGvis() used by gvisGeoChart() cannot be generated, as the input$country argument is empty. Of course, it is not correct that the applications display these kinds of mistakes not correct, especially if they are going to be consumed by end users who do not have any technical experience in R as it gives them the impression that there is an error in the application.

In these cases, a validation can be used. As it has been explained previously, the error message in validation is custom and it can be used to provide the user with more information of what is still needed from them in order to display an output. In this case, for example, the message would be similar to Please select at least one country. This is how server.R would look like with this validation instance:

library(shiny)
library(googleVis)

#initialization of server.R
shinyServer(function(input, output,session) {

  #Plot generation
  output$map <- renderGvis({
    
    validate(
      need(length(input$country) > 0, "Please select at least one country"))
      
      plot.dataset <- data.frame(countries = input$country, value=5)

      continent.code <- switch(input$continent,
        Africa = "002",
        America = "019",
        Asia = "142",
        Europe = "150")
      
      gvisGeoChart(plot.dataset, locationvar="countries",sizevar="value",
      options = list(region=continent.code,displayMode="regions"))
    
  })
  
  
  observe({
    
    continent.countries <- switch(input$continent,
      Africa = c("Tunisia","Egypt","South Africa","Lybia"),
      America = c("Argentina","Brazil","Mexico","USA"),
      Asia = c("China","Japan","India","Indonesia"),
      Europe = c("France","Germany","Italy","Spain"))
      updateCheckboxGroupInput(session,"country",choices = continent.countries)
  })

})

However, not just the choices of an input can be updated. These input update functions can operate on any of the arguments of the functions that they are updating. In the following example for UI.R, consider the phrase of the second input is updated according to the species selected:

library(shiny)

# Starting line
shinyUI(fluidPage(

  # Application title
  titlePanel("Iris"),
  
  # Sidebar
  sidebarLayout(
    sidebarPanel(
      #Species selection
      selectInput("variable","Select a variable:",
        setdiff(names(iris),"Species")),
      
      # Value input
      numericInput("value","",value=0,min = 0)
    ),
    
    #The plot created in server.R is displayed
    mainPanel(
      tableOutput("table")
    )
  
  )
))

This is how server.R looks when the label argument is changed based on the selection:

library(shiny)

#initialization of server.R
shinyServer(function(input, output,session) {

  observe({

    input.label <- paste0("Select the minimum value for ",input$variable,":")

    updateNumericInput(session,"value",label = input.label)
  })
  
  #Table generation where the summary is displayed
  output$table <- renderTable({
    subset(iris, get(input$variable) > input$value )})

})

The example is very simple; it just displays a subset of iris based on the variable selected and the minimum value passed. In UI.R, instead of manually adding all the variables in selectInput(), setdiff() is used, a function that excludes the values in the second argument from the first one. In server.R, the input's text is updated via a very simple dynamic text object with paste0. Finally, the subset() expression inside renderTable() uses get(input$variable) because input$variable is a string and the subset expects an expression. In other words, get() is telling subset, in this case, that the string must be treated as a variable from iris.

To sum up, from the update functions, the following must be clear:

  • There is one corresponding update function for each input function.
  • Update functions do not create reactive outputs, they just update the existing ones. So, if they depend on a reactive value in any way (which they will most surely do), they have to be called within an observer.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset