I'm trying to build a shiny app and I've never done this before.
What I want to do is allow the user to upload data from a CSV file of the user's choice that looks something like this:
ID Date Name Amount
123 01/12/2018 John Doe 100
124 01/02/2018 Bob Smith 110
125 01/03/2018 Jane Jones 100
126 01/02/2018 John Doe 110
127 01/03/2018 Bob Smith 100
128 01/04/2018 Jane Jones 110
129 01/03/2018 John Doe 100
130 01/04/2018 Bob Smith 110
131 01/04/2018 Jane Jones 120
132 01/14/2018 Tom Thomas 100
Then I want to have the app USE this data to run code such as this:
as.Date(myDF$Date, format="%m/%d/%Y")
sortedByDate = myDF[order(myDF$Date)]
amountPerDate = aggregate(data=myDF, Amount ~ Date, sum)
amountPerDate
to produce output such as this:
Date Amount
01/02/2018 220
01/03/2018 300
01/04/2018 340
01/12/2018 100
01/14/2018 100
so the user can see the total amount per date, with the dates in correct order. I've been doing stuff like this in regular R script for months but have never before tried it in shiny.
So to upload the data into shiny I'm using this code:
shinyServer(function(input, output){
output$contents <- renderTable({
inFile <- input$file1
if(is.null(inFile))
return(NULL)
userData = read.csv(inFile$datapath, sep=",")
#here I run chunks of code to clean the data
#assign data frame to global environment
assign("userData", userData, envir = .GlobalEnv)
#display data table in app
userData
})
So now the user can look at the data but can't DO anything with it.
The data frame in the global environment has every variable as class Factor. I thought it would be easy to coerce the variables into their proper classes (Numeric for "ID" and "Amount", Character for "Name" and Date for "Date" but I can't do it. The very next thing I try to make the app do is display the date in the first row. I tried it with this code:
output$text <- renderText({
userData$Date = as.Date(as.character(userData$Date), format = "%m/%d/%Y")
userData[1,2]
})
But the output in the app is 17533, NOT 01/12/2018 like I expected.
For some weird reason the following code WILL produce an output of 01/12/2018:
output$text <- renderText({
userData$Date = as.character(userData$Date)
userData[1,2]
})
but I need the dates to be class DATE, not class character.
Without the ability to coerce the variables into their proper classes my entire app is useless. Please help.
Don't use assign in Shiny, that is bad practice and it also doesn't allow for any reactivity. Instead, use a reactive to store your input data.
Regarding the unexpected printing output, this probably has to do with the way dates are stored. If you output a Date object in renderText, it will apparently parse it to it's integer value and convert that to character. To prevent that, parse it to character yourself first.
Here is a working example:
library(shiny)
library(data.table)
server <- function(input, output, session) {
filedata <- reactive({
infile <- input$file1
if (is.null(infile)) {
return(NULL)
}
df <- fread(infile$datapath)
return(df)
})
output$my_table <- renderDataTable({
if(is.null(filedata()))
{
return(NULL)
}
else
{
myDF <- filedata() # read the uploaded data from reactive
myDF$Date <- as.Date(myDF$Date, format="%m/%d/%Y") # Change format!
sortedByDate = myDF[order(myDF$Date)]
amountPerDate = aggregate(data=myDF, Amount ~ Date, sum)
print('done')
return(amountPerDate)
}
})
output$my_text <- renderText({
if(is.null(filedata()))
{
return(NULL)
}
else
{
as.character(as.Date(filedata()$Date, format="%m/%d/%Y"))[1]
}
})
}
ui <- fluidPage(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
dataTableOutput('my_table'),
textOutput('my_text')
)
shinyApp(ui,server)
Hope this helps!