Web Application Development with R Using Shiny(Third Edition)
上QQ阅读APP看书,第一时间看更新

Reactive objects

The rest of this code is wrapped in function(input, output){}. This is the reactive part of your application. We will talk in more detail about reactive programming later in the book; for now, let's just say that reactive programming is a type of programming where when the inputs change, the outputs change. 

The next piece of code looks like this:

theData = reactive({

mapData %>%
filter(year >= input$year)
})

This code defines a reactive object. Up until now, the server.R file has just contained a list of output commands that produce the output, ready to fill the allocated spaces in ui.R. Here, we're working a little differently. Sometimes, you want to prepare a reactive dataset once and then pass it around the program as needed.

This might be because you have tabbed output windows that use the same dataset (as in this case), and you don't want to write and maintain code that prepares the data according to the values of reactive inputs within all three functions. There are other times when you want to control the processing of data because it is time intensive or it might make an online query (such as in the case of a live application that queries data live in response to reactive inputs). The way that you can take more control over data processing from reactive inputs, rather than distributing it through your output code, is to use reactive objects. A reactive object, like a reactive function, changes when its input changes. Unlike a reactive function, it doesn't do anything, but is just a data object (dataframe, number, list, and so on) that can be accessed by other functions. Crucially, when it runs, its output is cached. This means that as long as its inputs don't change, it will not rerun if it is called on again by a different part of your application. This prevents your application from running the same data processing tasks repeatedly.

In this case, the data processing is very small, so we're not really saving any time using reactive objects; however, it is still good practice to use them because, as we just mentioned, it means that you only have one data function to maintain rather than several scattered between the outputs.

Let's have a look at an example:

theData = reactive({ 
mapData %>%
filter(year >= input$year[1], year <= input$year[2])
})

This function, very simply, filters the data so that it contains only data that was logged between the years selected in sliderInput(). The first thing to note is that, unlike previous examples, we are not making a call, such as output$lineGraph <- renderPlot({...}) or output$summaryText <- renderText({...}). Instead, we are marking whatever is inside the call reactive by enclosing it in reactive({...}) and assigning it, very simply, to theData. This generates a reactive object named theData. This can be accessed by calling this function—that is, by running theData() (for the whole dataframe), or theData()$variableName (for a variable), or theData()[, 2:10] (for the second to the tenth variable). Note the brackets after theData. More information on reactive objects, when to use them, and lots of advice about managing and controlling reactivity and data processing in your application is given in Chapter 8, Code Patterns in Shiny Applications