I'm trying to build a shiny application that gets live data from a .csv file named "test.csv". Here is a example of the data :
name age timestamp
Paul 23 1654095025
Michael 23 1674095025
Jane 54 1654895025
Jack 31 1954095025
Luis 23 1954095025
Anna 85 1954095025
On this csv file, I would like to do some dplyr operations, like a mutate on a timestamp to convert it to datetime. To retrieve live data, I use the shiny reactiveFileReader function. Here is the code :
library(shiny)
library(shinydashboard)
library(dplyr)
ui <- fluidPage(
mainPanel(
tableOutput("data")
)
)
server <- function(input, output) {
fileData <- reactiveFileReader(10, NULL, 'test.csv', read.csv2)
output$data <- renderTable({
fileData() %>%
mutate(timestamp2 = as_datetime(timestamp))
})
}
shinyApp(ui = ui, server = server)
The problem is that the mutate is not taken into account and I can't do the operation on the timestamp field, here is a copy of the table displayed in the shiny app (result of the code above) :
name age timestamp timestamp2
Paul 23 1654095025 1654095025.00
Michael 23 1674095025 1674095025.00
Jane 54 1654895025 1654895025.00
Jack 31 1954095025 1954095025.00
Luis 23 1954095025 1954095025.00
Anna 85 1954095025 1954095025.00
Do you know how to solve this problem? Despite my research, I have not found anyone with a similar problem.
Note: this is actually a simplified example. I'm trying to do this in a more complex shiny application with a live connection to a mongoDB database. For that, I use reactivePoll() instead of reactiveFileReader(), but the problem is the same!
Thank you
CodePudding user response:
library(shiny)
library(dplyr)
f <- tempfile(fileext = ".csv")
writeLines(text =
'name age timestamp
Paul 23 1654095025
Michael 23 1674095025
Jane 54 1654895025
Jack 31 1954095025
Luis 23 1954095025
Anna 85 1954095025
', con = f)
ui <- fluidPage(
mainPanel(
tableOutput("data")
)
)
server <- function(input, output, session) {
fileData <- reactivePoll(1000, session,
checkFunc = function() {
info <- file.info(f)
return(paste(f, info$mtime, info$size))
},
valueFunc = function() {
read.table(f, header = TRUE)
})
output$data <- renderTable({
fileData() %>%
mutate(timestamp2 = as.character(lubridate::as_datetime(timestamp)))
})
}
shinyApp(ui = ui, server = server)
CodePudding user response:
Thank you for your feedback Aurèle. I think I have found the source of the problem, but I don't know how to solve it. The error I had seemed strange: I was told that a select or mutate operation was not possible on the data because the field did not exist but yet, the operation was done correctly!
In fact in my shiny, I use a pickerInput that allows the user to select the database he wants to work on (in your code above, it's as if we had two tables and could choose which one to retrieve from the reactivePoll using the pickerInput selection). This picker input must be reactive : if a database is added, the picker input must display the new database in the list (as a reminder, I work with mongoDB that I request with the mongolite package). To make the pickerInput reactive, I use updatePickerInput() with an observe().
I found that if I removed the updatePickerInput and put the databases names by hand in the choices argument of the pickerInput, the warnings disappeared! I'm not an expert, but I have the impression that when the application is opened, the "test" reactive value is executed before the pickerInput has time to retrieve the information. That's why shiny tells me that it can't find the data and displays the warning.
However, I have not yet managed to solve this problem.
I know it's quite heavy, but to help, here's an example of the code I use:
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(mongolite)
library(lubridate)
library(tidyverse)
#### UI
ui <- dashboardPage(
header = dashboardHeader(),
sidebar = dashboardSidebar(),
body = dashboardBody(
pickerInput(
inputId = "database_selection",
choices = NULL,
selected = NULL,
multiple = FALSE
),
hr(),
dataTableOutput("table1")
)
)
#### SERVER
server <- function(input, output, session) {
# GET LIVE DATABASES LIST ------------------------------------------------------
# get the databases list from server. Update every 10 ms to check
# if new database is added or deleted
databases_list <- reactivePoll(
intervalMillis = 10,
session = NULL,
valueFunc = function(){
admin <- mongo(db = "admin", url = YOUR_MONGDB_URL)
databasesinfos_list <- admin$run('{"listDatabases":1}')
databasesinfos_table <- databasesinfos_list[["databases"]] %>%
filter(startsWith(name, "LEXIM"))
databasesinfos_vector <- sort(c(databasesinfos_table$name))
return(databasesinfos_vector)},
checkFunc = function(){
admin <- mongo(db = "admin", url = YOUR_MONGDB_URL)
databasesinfos_list <- admin$run('{"listDatabases":1}')
databasesinfos_table <- databasesinfos_list[["databases"]] %>%
filter(startsWith(name, "LEXIM"))
return(nrow(databasesinfos_table))}
)
# Allows to propose to the user the live list of the existing databases in a
# picker input menu.
observe({
updatePickerInput(
session,
"database_selection",
choices = databases_list(),
selected = databases_list()[1]
)
})
# get the database chosen by the user in the picker input for the analysis.
database_selected <- reactive(
paste(input$database_selection)
)
# GET DATABASES DATA -----------------------------------------------------------------
# gets the data from the "my_collection" collection for the selected database
# Updates every 10 ms to check if new data is added
my_collection_poll <- reactivePoll(
intervalMillis = 500,
session = NULL,
# function that looks if the "my_collection" collection has changed
checkFunc = function(){
my_collection <- mongo(
collection = "my_collection",
db = database_selected(),
url = YOUR_MONGDB_URL)
return(nrow(my_collection$find('{}')))},
# function that fetches the data from the "my_collection" collection if it changes
valueFunc = function(){
my_collection <- mongo(
collection = "my_collection",
db = database_selected(),
url = YOUR_MONGDB_URL)
return(my_collection$find('{}'))
}
)
test <- reactive({
tmp <- my_collection_poll()
tmp <- tmp %>%
mutate(timestamp = as.character(as_datetime(timestamp)))
return(tmp)
})
# DISPLAY THE TABLE ------------------------------------------------------------
output$table1 <- renderDataTable({
test()
})
}
shinyApp(
ui,
server
)