Reputation: 394
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
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