seapen
seapen

Reputation: 394

RShiny Reactive data frame manipulation in dplyr using selected input

I can't make my dplyr code work within Shiny.

I'm trying to manipulate a data frame dependent on "input" selected by the user. I would like to use a drop down menu in the ui, but then can't make it work in server (when using dplyr select()). I've made it work with "action buttons", but that makes for very repetitive code (each observeEvent() essentially has the same code).

I'm adapting code written in RMarkdown in which I change the definition of a TARGET variable at the beginning of the notebook that affects all subsequent models, plots, and tables when I re-knit. By commenting In/Out one line, I produce results for several different target variables (which share some, but not all data). I would like to implement this in Shiny for self-service by other users.

# I would like to do it "this" way, but it doesn't work

library(shiny)
library(ggplot2)
library(dplyr)
library(datasets)
library(lubridate)


df <- airquality %>% 
    mutate(date = make_datetime(day = Day, month = Month), 
           Ozone1 = Ozone + 1, Temp1 = Temp + 1,
           Ozone_predictor = Ozone / 2, Temp_predictor = Temp / 2) %>% 
    select(date, everything(), -Month, -Day)


ui <- fluidPage(

    # Title
    titlePanel("New York AirQuality Measurements"),

    # Input Selection used to build dataframe
    sidebarLayout(
        sidebarPanel(
            selectInput(inputId = "target", 
                        label = "Choose a prediction target for visualization", 
                        choices = list("Ozone", "Ozone1", "Temp")
            )
        ), 

        # Plot
        mainPanel(
            plotOutput("plot", height = "1200px")
        )
    )
)


server <- function(input, output) {

    df <- reactive({
        if(input$target == "Ozone"){
            df <- df %>%
                select(-Ozone1, -contains("Temp")) %>% 
                tidyr::gather(key = key, value = value, -date)
            if(input$target == "Ozone1"){
                df <- df %>%
                    select(-Ozone, -contains("Temp")) %>% 
                    tidyr::gather(key = key, value = value, -date)
            }else{
                df <- df %>%
                    select(-contains("Ozone")) %>% 
                    tidyr::gather(key = key, value = value, -date)
            }
        }
    })


    output$plot <- renderPlot({
        ggplot(df(), aes(date, value)) +
            geom_line() +
            facet_wrap(key ~ ., scales = "free", ncol = 1) +
            labs(y = "", x = "") +
            theme_classic()
    })
}

# Run the application 
shinyApp(ui = ui, server = server)



# This does work... but is repetitive and may be problematic 
# if I have more target variables.

library(shiny)
library(ggplot2)
library(dplyr)
library(datasets)
library(lubridate)


df <- airquality %>%
    mutate(date = make_datetime(day = Day, month = Month),
           Ozone1 = Ozone + 1, Temp1 = Temp + 1,
           Ozone_predictor = Ozone / 2, Temp_predictor = Temp / 2) %>%
    select(date, everything(), -Month, -Day)


ui <- fluidPage(

    # Title
    titlePanel("New York AirQuality Measurements"),

    # Action buttons to define dataframe selection
    sidebarLayout(
        sidebarPanel(
            actionButton(inputId = "Ozone", label = "Ozone"),
            actionButton(inputId = "Ozone1", label = "Ozone One"),
            actionButton(inputId = "Temp", label = "Temperature")),

        # Plot
        mainPanel(
            plotOutput("plot", height = "1200px")
        )
    )
)


server <- function(input, output) {
    rv <- reactiveValues(
        data = df %>%
            tidyr::gather(key = key, value = value, -date)
    )

    observeEvent(input$Ozone,
                 { rv$data <-
                     df %>%
                     select(-Ozone1, -contains("Temp")) %>%
                     tidyr::gather(key = key, value = value, -date)
                 })

    observeEvent(input$Ozone1,
                 { rv$data <-
                     df %>%
                     select(-Ozone, -contains("Temp")) %>%
                     tidyr::gather(key = key, value = value, -date)
                 })

    observeEvent(input$Temp,
                 { rv$data <-
                     df %>%
                     select(-contains("Ozone")) %>%
                     tidyr::gather(key = key, value = value, -date)
                 })


    output$plot <- renderPlot({
        ggplot(data = rv$data, aes(date, value)) +
            geom_line() +
            facet_wrap(key ~ ., scales = "free", ncol = 1) +
            labs(y = "", x = "") +
            theme_minimal()
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

Error: no applicable method for 'select_'applied to an object of class "c('reactiveExpr', 'reactive')"

Upvotes: 0

Views: 1349

Answers (1)

TimTeaFan
TimTeaFan

Reputation: 18561

The (main) problem was, that you define a reactive df which has the same name as the non-reactive data frame in your global environment df which is created at the start-up of your app. This seemed to got things mixed up. I changed the name of the reactive to data.

Within your reactive the if statements were not connected with each other, I did that using else if. Further you do not need to assign <- the data to a temporary variable (in your case df). And if you use assign, you need to call this temporary object at the end of the reactive (or at the end of each if/else statement).

library(shiny)
library(ggplot2)
library(dplyr)
library(datasets)
library(lubridate)


df <- airquality %>% 
  mutate(date = make_datetime(day = Day, month = Month), 
         Ozone1 = Ozone + 1, Temp1 = Temp + 1,
         Ozone_predictor = Ozone / 2, Temp_predictor = Temp / 2) %>% 
  select(date, everything(), -Month, -Day)


ui <- fluidPage(

  # Title
  titlePanel("New York AirQuality Measurements"),

  # Input Selection used to build dataframe
  sidebarLayout(
    sidebarPanel(
      selectInput(inputId = "target", 
                  label = "Choose a prediction target for visualization", 
                  choices = list("Ozone", "Ozone1", "Temp")
      )
    ), 

    # Plot
    mainPanel(
      plotOutput("plot", height = "1200px")
    )
  )
)


server <- function(input, output) {

  data <- reactive({

    if(input$target == "Ozone"){
      df %>%
        select(-Ozone1, -contains("Temp")) %>% 
        tidyr::gather(key = key, value = value, -date)
      } else if(input$target == "Ozone1"){
        df %>%
          select(-Ozone, -contains("Temp")) %>% 
          tidyr::gather(key = key, value = value, -date)
      }else if (input$target == "Temp") {
        df %>%
          select(-contains("Ozone")) %>% 
          tidyr::gather(key = key, value = value, -date)
      }


  })


  output$plot <- renderPlot({
    ggplot(data(), aes(date, value)) +
      geom_line() +
      facet_wrap(key ~ ., scales = "free", ncol = 1) +
      labs(y = "", x = "") +
      theme_classic()
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Upvotes: 1

Related Questions