This has been bugging me for ages.
I have a function where the first argument either needs to be of the form
function(data~ group_variable)
OR of the form function(data, group = data$group_variable)
.
I have this function running smoothly in the console, but it is integral to my shiny app and it has been bugging me for ages, because both the data and the group are user-selected reactive objects, so it needs to take the form:
function(datasetInput() ~ !!input$group_variable)
or some version thereof.
I haven't been able to find any combination of !!
s, enquo()
, substitute()
, as.function(substitute())
, etc that will make this work within the shiny app. as.Formula(substitute(data ~ group))
works in the console.
here is as minimal as I can make a reprex:
library(shiny)
library(shinyWidgets)
library(psych)
library(dplyr)
library(gt)
use <- function(name) {
# consider future support for .json?
if (grepl(".csv", name)) {
readr::read_csv(name)
} else if (grepl(".xlsx", name)) {
readxl::read_xlsx(name)
} else if (grepl(".dta", name)) {
haven::read_dta(name)
} else if (grepl(".sav", name)) {
haven::read_spss(name)
} else if (grepl(".rda", name)) {
load(name)
} else {
stop("unknown data type.")
}
}
ui <- fluidPage(
mainPanel(
fileInput("FileInput", "Input Your Data Set"),
helpText("Dataset must be one of: .csv, .sav, .dta, .xlsx, or .rda"),
materialSwitch(
inputId = "ext_desc",
label = "Extended Description",
value = FALSE,
status = "primary"
),
materialSwitch(
inputId = "desc_by_group_bool",
label = "Describe By A Group",
value = FALSE,
status = "primary"
),
varSelectInput(
inputId = "desc_group",
label = "Select A Group",
data = NULL,
width = "400px"
),
gt::gt_output("description")
)
)
server <- function(input,output, session){
datasetInput <- reactive({
infile <- input$FileInput
if (is.null(infile))
return(NULL)
dat<-use(infile$datapath)
names(dat) <- gsub(" ", "_", names(dat), fixed = TRUE)
return(dat)
})
observeEvent(datasetInput(), {
updateVarSelectInput(session, "desc_group", data = datasetInput())
})
desc <- reactive({
req(datasetInput())
if (input$desc_by_group_bool == FALSE) {
datasetInput() %>%
#select_if(is_numeric) %>%
psych::describe(., fast = !(input$ext_desc),
omit = TRUE) %>%
add_rownames(var = "Variable") %>%
dplyr::select(-c(vars)) %>%
dplyr::mutate(dplyr::across(is.numeric, round, 2)) %>%
gt::gt() %>%
gt::tab_options(
column_labels.font.size = "small",
table.font.size = "small",
row_group.font.size = "small",
data_row.padding = px(3)
) %>%
gt::tab_header(title = paste0("Data Description"))
} else {
# datasetInput() %>%
# select_if(is.numeric) %>%
psych::describeBy( datasetInput() ~ !!input$desc_group,
# here we get "invalid argument type" error
fast = !(input$ext_desc),
mat = TRUE) %>%
tibble::rownames_to_column() %>%
select(-c(item, vars)) %>%
dplyr::mutate(dplyr::across(is.numeric, round, 2)) %>%
arrange(group1) %>%
group_by(group1) %>%
gt() %>%
gt::tab_options(
column_labels.font.size = "small",
table.font.size = "small",
row_group.font.size = "small",
data_row.padding = px(3)
) %>%
tab_header(title = paste0("Data Description") ,
subtitle = paste0("Grouped by: ", input$desc_group)
)
}
})
output$description = gt::render_gt(desc())
}
shinyApp(ui = ui, server = server)
The line causing the error--and the source of my question, is, forgive me, line 85 above.
There are various ways we can solve this. One way would be to use
[[]]
to subset the specific column. So change thedescribeBy
line to :Also add
where
indplyr::across