3

I have a shiny app that uses a reactive expression to respond to a user selecting a value from a drop-down list.

The value chosen is then used as a filter condition on a data frame.

If I want to create two different plots of the same filtered data frame, do I have to call the reactive expression twice, once for each renderPlot function (as in the example code below), or is there a way to store the results of a filtered data frame for use by different renderPlot calls?

server.R

library(shiny)
library(dplyr)
library(ggplot2)

shinyServer(function(input, output) {

    ## create dummy data
    set.seed(1)
    location <- c("locA", "locB", "locC")
    location <- sample(location, 20, replace=TRUE)
    service <- c("serviceA", "serviceB")
    service <- sample(service, 20, replace=TRUE)
    person <- c("A", "B")
    person <- sample(person, 20, replace=TRUE)
    value <- runif(20, 0, 5)

    df <- data.frame(location, service, person, value)

    ## reactive to user input
    select <- reactive({
        input$select
    })

    ## plot 1
    output$plot1 <- renderPlot({
        ## filter data frame for use in first plot
        df <- df %>%
            filter(person==select())   ## select() - calls reactive expression

        ggplot(data=df, aes(x=location, y=value, fill=person)) +
            geom_bar(stat="identity")
    })    
    ## plot 2
    output$plot2 <- renderPlot({
        ## filter data frame for use in second plot 
        ## this is the same data as in plot1
        df <- df %>%
            filter(person==select())  ## select() - calls reactive expression

        ggplot(data=df, aes(x=location, y=value, fill=person)) +
        geom_bar(stat="identity") +
            facet_wrap(~service)
    })  
})

ui.R

library(shiny)

shinyUI(navbarPage("Test",
                   tabPanel("panel",
                            sidebarLayout(
                                sidebarPanel(
                                    selectInput("select", label="select", choices=c("A", "B"))
                                ),
                                mainPanel(
                                    plotOutput("plot1"),
                                    hr(),
                                    plotOutput("plot2")
                                    )
                                )
                            )
                   )
        )

This is just a basic example; my actual application will use the same calculated and filtered data frame in many different plots, so I'd like it not to have to re-run the filter condition for each plot.

So the flow of information would be:

Select_Input > filter_data > (plot1, plot2, plot3, ... plotn)
tospig
  • 7,762
  • 14
  • 40
  • 79

1 Answers1

3

You can wrap the filtering of the data frame in a reactive expression and the call filter_df() in each of the data argument of your plots:

  filter_df <- reactive({
    df %>%
      filter(person==select())
  })
NicE
  • 21,165
  • 3
  • 51
  • 68
  • Does that mean the data frame would be filtered each time the `filter_df()` is called? so if I had two plots, the data would be filtered twice, three plots thrice, etc.? – tospig May 04 '15 at 10:21
  • 2
    hum, I think it only recalculates the value if it changes. The reactive expressions paragraph of [this page](http://shiny.rstudio.com/tutorial/lesson6/) says "ractive expressions are a bit smarter than regular R functions. They cache their values and know when their values have become outdated. What does this mean? The first time that you run a reactive expression, the expression will save its result in your computer’s memory. The next time you call the reactive expression, it can return this saved result without doing any computation (which will make your app faster)." – NicE May 04 '15 at 10:33
  • You can add `print("filtered")` to the expression and look in your console how many times it is run when you change the `select` – NicE May 04 '15 at 10:37
  • Ah yes; it was my understanding of how reactive expressions cache their results that was lacking. Thanks. – tospig May 04 '15 at 22:23