I'm building a shinyapp. I try to save the functions user selected as char into to a data.frame()
, and then use paste()
to generate something like "n = n(), sum = sum(value), mean = mean(value)" or shorter, and finally pass to summarise()
I tried the enquote()
and eval(parse())
, all failed.
library(shiny)
library(shinyjs)
library(tidyverse)
ui <- fluidPage(
useShinyjs(),
fluidRow(
column(width = 3,
wellPanel(
selectInput("data_groupby", label = "group_by", choices = c(Choose = "", "group", "sameple", "var"), selected = c("group", "var"), multiple = TRUE),
actionButton("data_groupby_ok", "click here to group_by"),
selectInput("data_summarise_fun", "Function", choices = c(Choose = "", "n", "sum", "mean")),
actionButton("data_summarise_add", "Summarise"),
h4("paras to be passed to summarise():"),
verbatimTextOutput("summarise_paras")
)
),
column(width = 3,
h4("data:"),
verbatimTextOutput("data")
),
column(width = 3,
h4("data_summarised:"),
verbatimTextOutput("data_summarised")
),
column(width = 3,
h4("data_desired (if add 3 functions):"),
verbatimTextOutput("data_desired")
)
)
)
server <- function(input, output, session) {
aggr <- reactiveValues(
data = NULL,
summarise_paras = data.frame(column = character()),
data_grouped = NULL,
data_summarised = NULL,
data_desired = NULL
)
set.seed(50)
aggr$data <- data.frame(
group = rep(LETTERS[1:3], each = 6),
sample = rep(c(paste0("A_", 1:3), paste0("B_", 1:3), paste0("C_", 1:3)), each = 2),
var = rep(c("height", "weight"), times = 9),
value = runif(18, min = 0, max = 1)
)
aggr$data_desired <- data.frame(
group = rep(LETTERS[1:3], each = 6),
sample = rep(c(paste0("A_", 1:3), paste0("B_", 1:3), paste0("C_", 1:3)), each = 2),
var = rep(c("height", "weight"), times = 9),
value = runif(18, min = 0, max = 1)
) %>%
group_by(group, var) %>% summarise(n = n(), sum = sum(value), mean = mean(value))
observeEvent(input$data_groupby_ok, {
groupby <- input$data_groupby
aggr$data_grouped <- aggr$data %>% group_by(across(all_of(groupby)))
disable("data_groupby")
})
observe({
toggleState("data_summarise_add", nchar(input$data_summarise_fun) >0)
})
observeEvent(input$data_summarise_add, {
tryCatch({
fun <- input$data_summarise_fun
if (fun == "n") {
para <- "n = n()"
} else if (fun == "sum") {
para <- "sum = sum(value)"
} else if (fun == "mean") {
para <- "mean = mean(value)"
}
aggr$summarise_paras <- aggr$summarise_paras %>%
filter(column != para) %>%
bind_rows(data.frame(column = para))
paras <- paste(aggr$summarise_paras$column, collapse = ",")
aggr$data_summarised <- aggr$data_grouped %>% summarise(enquote(paras))
reset("data_summarise_fun")
}, error = function(e) {
showNotification(paste(e$message), type = "error", duration = 5)
})
})
output$data <- renderPrint({print(aggr$data)})
output$summarise_paras <- renderPrint({print(aggr$summarise_paras)})
output$data_summarised <- renderPrint({print(aggr$data_summarised)})
output$data_desired <- renderPrint({print(aggr$data_desired)})
}
shinyApp(ui = ui, server = server)
My desired output is aggr$data_desired
, which was printed in my shiny example
The issue is that (presumably) you want the values to be things like "n = 10, sum = -0.369, mean = -0.036987", but what you have written isn't that - it's bad because it's not valid R code (you can't just write
x = 1, y = 2
in R, you will get the errorError: unexpected ',' in "x = 1,"
, but also because equals is for assignment, and you don't seem to want to assignn()
to the variablen
.One option is using glue:
Output: