Reputation: 299
This is a follow-up question from This Question which was correctly answered by @K.Rohde. I am unable to call an input from UI as an argument in a user-defined function. Below is the complete reproducible shiny code:
library(shiny)
library(lubridate)
library(dplyr)
rm(list = ls())
Aging <- function(data, Transaction.Date, Report.Date = Sys.Date()){
if(missing(Transaction.Date)) stop("You forgot to specify Transaction Date")
Transaction.Date <- deparse(substitute(Transaction.Date))
Report.Date <- deparse(substitute(Report.Date))
data$year <- year(data[,Transaction.Date])
data$Age <- car::recode(year(data[,Transaction.Date]), paste0("year(", Report.Date, ") = year(", Report.Date, "); year(", Report.Date, ") - 1 = year(", Report.Date, ") - 1; else = paste(year(", Report.Date, ")-2, 'And Prior')"))
return(data)
}
ui <- fluidPage(
dateInput("Report.Date", "Enter Cut-off Date"),
actionButton("Submit", "Submit"),
dataTableOutput("Aged.Data")
)
server <- function(input, output) {
Debtors <- eventReactive(input$Submit, {
data.frame(Names = c("John", "Mary", "Charles", "Peter", "David", "Fabian", "Aggrey", "Elizabeth", "Anthony", "Catherine"), Amount = seq(from = 100000, by = 600, length.out = 10), Transaction.Date = seq.Date(from = as.Date("2016/1/1"), by = "quarter", length.out = 10))
})
Aged.Data <- eventReactive(input$Submit, {
Debtors() %>% Aging(., Transaction.Date, input$Report.Date)
})
output$Aged.Data <- renderDataTable(Aged.Data())
}
shinyApp(ui, server)
The error I get is as below:
in recode term: else = paste(year(input$Report.Date)-2, 'And Prior')
message: Error in year(input$Report.Date) : object 'input' not found
This seems to be from the part where I'm calling my Aging function and trying to reference the input$Report.Date as an argument, i.e,
Aged.Data <- eventReactive(input$Submit, {
Debtors() %>% Aging(., Transaction.Date, input$Report.Date)
I've tried looking online for a similar solution through questions like This one and This one and though the error is similar, the proposed methods of resolving them seem to be unique to those questions.
I will appreciate any assistance on this.
Joseph.
Upvotes: 1
Views: 2880
Reputation: 9676
This is due to the combination of deparse
and substitute
.
Lets revisit what you are doing in simpler terms:
a <- function(val) {
val <- deparse(substitute(val))
val
}
b <- function() {
c <- "someVariable"
a(c)
}
With this setup you will get:
> b()
[1] "c"
I hope you are aware of this and if not, make yourself. You basically are sending the variable name from the calling scope of b
into the function scope of a
. This is almost never what you want to happen in programming.
In your code sample, you are giving a variable name called input$Report.Date
into the globally defined function Aging
and you hope that it will be interpreted there in the right way. But of course, input
is not an object in this function.
But why would it? Why do you have to interpret the variable in Aging
. If you leave away the deparse(substitute(...))
, you are not getting the variable name but the variable value. And nothing else is it that you want here.
I bet the recode
function is to blame for you having to be aware of what is code to be interpreted and what are just values.
So the fix is to just leave away
Report.Date <- deparse(substitute(Report.Date))
Little Extra: If I were you, I would never use something like deparse
and substitute
unless there really is code involved that comes as plain text and must be interpreted.
Also recode
seems to be so much over the line, since it just cloaks very simple modifications that you can easily do without this overcomplicated tool.
If I were you, my Aging
function would look like this:
Aging <- function(data, dateColumnName, reportDate = Sys.Date()){
if(missing(dateColumnName)) stop("You forgot to specify Transaction Date")
maxDisplayYear <- year(reportDate) - 2
data$Age <- year(data[,dateColumnName])
data$Age[data$Age <= maxDisplayYear ] <- paste(maxDisplayYear, 'And Prior')
return(data)
}
and you would call it in your example with
Debtors() %>% Aging("Transaction.Date", input$Report.Date)
Upvotes: 1