I have .txt file and .xlsx file which will be uploaded into shiny.
The .txt upload is fine, the builtin progress bar shows perfect progress.
But in the case of .xlsx file upload I have merging operation doing inside reactive element so it is not coinciding with the actual progress. (Progress bar always finishes ahead of the task)
I can use pbapply, but then again I have to monitor them through command line, this is not what I am looking for.
I am very much interested in making the built in progress bar in connection with the entire upload process inside the reactive element. How can I do that.
This is my program.
ui.R
shinyUI(fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose first file to upload',
accept = c(
'text/csv',
)
),))sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose second file to upload',
accept = c(
'.xlsx'
)
)
)))
server.R
shinyServer(function(input, output) {
a <- reactive({
fileinput1 <- input$file1
if (is.null(fileinput1))
return(NULL)
read.table(fileinput1$datapath, header = TRUE, col.names = c("Experiment","Mesocosm","Hour","Nphy","Cphy","CHLphy","Nhet","Chet","Ndet","Cdet","DON","DOC","DIN","DIC","AT","dCCHO","TEPC","Ncocco","Ccocco","CHLcocco","PICcocco","PAR","Temperature","Salinity","CO2atm","u10","DICflux","CO2ppm","CO2mol","pH"))
#a$Chla <- a$CHLphy + a$CHLcocco #Add new columns as per observation data
#a$PON <- a$Nphy + a$Nhet + a$Ndet + a$Ncocco
})
#Upload Observation Data
b <- reactive({
#xlfile <- list.files(pattern = "*.xlsx")
fileinput2 <- input$file2
if (is.null(fileinput2))
return(NULL)
xlfile <- fileinput2$datapath
wb <- loadWorkbook(xlfile)
sheet_ct <- wb$getNumberOfSheets()
for( i in 1:sheet_ct) { #read the sheets into 3 separate dataframes (mydf_1, mydf_2, mydf3)
print(i)
variable_name <- sprintf('mydf_%s',i)
assign(variable_name, read.xlsx(xlfile, sheetIndex=i))
}
colnames(mydf_1) <- names(mydf_3)
colnames(mydf_2) <- names(mydf_3)
full_data <- rbind(mydf_1[-1,],mydf_2[-1,],mydf_3[-1,]) #making one dataframe here
b <- lapply(full_data,function(x) as.numeric(x))
})
})
How can I achieve this ?
You have some problems in your code but in theory you can create progress bar to the top of the browser:
observe({
fileinput2 <- input$file2
if (is.null(fileinput2))
return(NULL)
withProgress(message = 'Downloading file', value = 0, {
#xlfile <- list.files(pattern = "*.xlsx")
xlfile <- fileinput2$datapath
wb <- loadWorkbook(xlfile)
sheet_ct <- wb$getNumberOfSheets() # this will be used in progressbar
for( i in 1:sheet_ct) { #read the sheets into 3 separate dataframes (mydf_1, mydf_2, mydf3)
print(i)
variable_name <- sprintf('mydf_%s',i)
assign(variable_name, read.xlsx(xlfile, sheetIndex=i))
incProgress(1/sheet_ct, detail = paste("Sheet:", sheet_ct,"Dowloaded"))
}
colnames(mydf_1) <- names(mydf_3)
colnames(mydf_2) <- names(mydf_3)
full_data <- rbind(mydf_1[-1,],mydf_2[-1,],mydf_3[-1,]) #making one dataframe here
b <- lapply(full_data,function(x) as.numeric(x))
})
})
})
More info: http://shiny.rstudio.com/articles/progress.html
Related
I just started to play around in shiny and made a simple app that reads a CSV file and replaces rows of one column with tokens. I would like the user to be able to download the tokenized data as a CSV file.
To do this I am using the downloadHandler() function. I have been looking in the documentation for this function, as well as similar questions in here but haven't been able to find a solution. I tried running the app externally as suggested in other similar questions.
app.R
# Only run examples in interactive R sessions
if (interactive()) {
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE),
textInput(inputId = 'variable', label = 'Name of variable to pseudonymize', placeholder = 'e.g., ID_PA'),
helpText("Case sensitive!"),
downloadButton('downloadData', 'Download')
),
mainPanel(
tableOutput("contents"),
br(), br(),
tableOutput('results')
)
)
)
server <- function(input, output) {
output$contents <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, it will be a data frame with 'name',
# 'size', 'type', and 'datapath' columns. The 'datapath'
# column will contain the local filenames where the data can
# be found.
inFile <- input$file1
if (is.null(inFile))
return(NULL)
head(read.csv(inFile$datapath, header = input$header))
})
output$results <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, it will be a data frame with 'name',
# 'size', 'type', and 'datapath' columns. The 'datapath'
# column will contain the local filenames where the data can
# be found.
inFile <- input$file1
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath)
# make sure to use utils::read_csv to read in data
# Function generates a lookup table that associates each unique identifier to an PSN. See lillemets
get_lookup_table <- function(data, id.var, key.length) {
if (any(duplicated(data[, id.var]))) warning('Duplicate id values in data. For longitudinal dataset, this is expected')
PSN <- c(1,1) # Allow the while loop to begin
while (any(duplicated(PSN))) { # Loop until all keys are unique
PSN <- replicate(length(unique(data[, id.var])),
paste(sample(c(LETTERS, 0:9), key.length, replace = T), collapse = ''))
}
lookup.table <- data.frame(id = unique(data[, id.var]), key = PSN)
return(lookup.table)
}
# Replace names with PSN
add_PSN <- function(data, id.var, lookup.table) {
data[, id.var] <- lookup.table[, 'key'][match(data[, id.var], lookup.table[, 'id'])]
return(data)
}
lookup_table <- get_lookup_table(df, input$variable, 10)
# Replace names with PSN
pseudo_df <- add_PSN(df, input$variable, lookup_table)
head(pseudo_df)
})
# Download file
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(pseudo_df, file)
}
)
}
shinyApp(ui, server)
}
When running the app and clicking download, I get the browser error 'File not found'.
In the R console I get the warning: Error in is.data.frame: object 'pseudo_df' not found
Comments on this issue would be much appreciated.
The download handler does not know that the pseudo_df data frame was created. You probably want to have one reactive that makes the data frame and then separate render and download handlers that call the reactive that creates the data frame. So for example
make_df <- reactive({}) # code that makes the data frame goes here
output$results <- renderTable({make_df()})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(make_df(), file) # notice the call to the reactive again
}
)
I am trying to write my first Shiny App that reads a PDF file, extracts tables and saves it into Excel document.
I am failing to produce suitable code. So far I have:
1) For UI
shinyUI(fluidPage(
titlePanel("CMM Report"),
sidebarPanel(
fileInput("file", "Upload Report")
),
downloadButton("dl", "Download")
))
2) For Server
library(shiny)
library (tabulizer)
library(writexl)
shinyServer(function(input, output) {
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
file1 <- ExtractTable (file1)
})
## Download
output$dl <- downloadHandler(
filename = function() { "ae.xlsx"},
content = function(file) {write_xlsx(data, path = file)}
)
})
I am not sure If I need to put the code for extracting table in a function and where to call the function, to make it work. Any help REALLY appreciated.
The data file of the example is from here
report <- "http://www.stat.ufl.edu/~athienit/Tables/Ztable.pdf"
Function to extract data
ExtractTable <- function (report){
lst <- extract_tables(report, encoding="UTF-8")
# Delete blank columns
lst[[1]] <- lst[[1]][, -3]
lst[[2]] <- lst[[2]][, -4]
# Bind the list elements
table <- do.call(rbind, lst)
table <- as.data.frame(table[c(2:37, 40:nrow(table)), ],
stringsAsFactors=FALSE) # ...w/o obsolete rows
# Take over colnames, cache rownames to vector
colnames(table) <- table[1, ]
rn <- table[2:71, 1]
table <- table[-1,-1] # and bounce them out of the table
# Coerce to numeric
table <- as.data.frame(apply(table[1:70,1:10], 2,
function(x) as.numeric(as.character(x))))
rownames(table) <- rn
return(table)
}
Could you try:
shinyServer(function(input, output) {
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
ExtractTable(file1$datapath) # $datapath was missing
})
## Download
output$dl <- downloadHandler(
filename = function() { "ae.xlsx"},
content = function(file) {write_xlsx(data(), path = file)} # parentheses () were missing
)
})
Using stackoverflow, I created a shiny app which uploads a csv file and then displays a datatable.
After selecting columns dynamically, where some columns have "_down" end.
I require help in shortening the dataframe (as in the code below) and also remove duplicates by ID column (if present).
# install.packages("shiny")
# install.packages("DT")
# install.packages("shinycssloaders")
library(DT)
library(shiny)
library(shinycssloaders)
UI code
##Creating the UI as a fluidPage,
##fluidPage allows scaling components of the browser in realtime to fill all available broswer width
##This is standard
ui <- fluidPage(
# Title of app
titlePanel("Upload file to table"),
# Main panel for displaying outputs
mainPanel(
#fileInput with acceptance of text/csv and more
fileInput('file', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'text/tab-separated-values',
'text/plain',
'.csv',
'.tsv',
'.html'
)),
# Output: datatable
DT::dataTableOutput("data_as_table")%>%withSpinner(),
#Download button
downloadButton("downloadData", "Download")
)
)
Server Code
Creating server
server <- function(input, output) {
#Data is a reactive element meaning it will update when the reactive input inside it change
#Data will update when input$file changes
#input$file is the uploaded file (se fileInput in ui)
data <-reactive({
#Store input$file as inFile
inFile <- input$file
#if its empty return nothing
if (is.null(inFile))
return(NULL)
#read in the file as a csv, with headers, comma seperated
dd = read.csv(inFile$datapath, header = T,
sep = ",")
dd = as.data.frame(dd)
#Shortening dataframe
#dd= dd[apply(dd[, endsWith(colnames(dd), "_down")], 1, function(x) any(x == "TRUE")), ]
#Remove duplicates by ID column, and show unique
#xxx
return(dd)
})
#Make the output data_as_table a datatable containing the reactive element data
output$data_as_table<-DT::renderDataTable({
data()
})
# Downloadable csv of reactive data() object
output$downloadData <- downloadHandler(
filename = function() {
paste("Download", Sys.date(), ".csv", sep = "")
},
content = function(file) {
write.csv(data(), file, row.names = FALSE)
}
)
}
#Launch shiny app
shinyApp(ui = ui, server = server)
You can remove duplicates using dplyr::distinct. It'll only keep the first instance of the ID and remove others. In your case add this before return(dd) in data reactive -
if("ID" %in% names(dd)) {
dd <- dplyr::distinct(dd, ID, .keep_all = T)
}
I have a function that generates "n" dataframes and saves it in a location as csv files and the function returns the file name of the saved CSVs.
I wish to take those csv files, read it using read.csv() and then display it on the UI using renderUI and renderDataTable()
While the code below has no syntax errors, but nothing is getting displayed on the screen.
Please suggest an appropriate method by which the tables generated in one part of the server.R can be used in output and display those data tables on the UI.
The code for the function is below :
Function
GenerateData <- function(){
#********************************************************************
# some sample data (originally, my data comes from an external souce)
#--------------------------------------------------------------------
a <- 1:10
b<- 21:30
c<-41:50
sampleDat1 <- data.frame(a,b,c)
sampleDat2<- data.frame(c,a,b,a)
NumOfDataFrames <- 2
#--------------------------------------------------------------------
FilePath <- "D:/FolDerName/"
FullPath<-WriteStatement <- NULL
for(i in 1:NumOfDataFrames){
FullPath[i]<-paste0(FilePath,"sampleDat",i,".csv")
WriteStatement[i]<-paste0("write.csv(sampleDat",i,",file = '",FullPath[i],"')")
eval(parse(text=WriteStatement[i]))
}
return(FullPath)
}
The UI.r
library(shiny)
shinyUI(
fluidPage(
# Application title
navbarPage("Sample Data Display",
tabPanel("Data",
sidebarLayout(
sidebarPanel(
titlePanel("Sample"),
numericInput("sample1",label = "Some Label",value = 20),
numericInput("sample2",label = "Some Other Label",value = 20)
),
mainPanel(
uiOutput("result")
)
)
)
)
)
)
The server.R
library(shiny)
GenerateData <- function(){
#********************************************************************
# already mentioned above, please copy the contents to server.R
#--------------------------------------------------------------------
}
shinyServer(function(input, output,session) {
dataSrc <- reactive({
paths <- GenerateData()
return(paths)
})
output$result <- renderUI({
dataTab1<-NULL
MyFilePath <- dataSrc()
for (i in 1:length(MyFilePath)){
dataTab1 <- read.csv(MyFilePath[i])
# print(dataTab1)
renderDataTable(dataTab1)
dataTab1<-NULL
}
})
}
)
You can try
1) use list of df
GenerateData <- function(){
#********************************************************************
# some sample data (originally, my data comes from an external souce)
#--------------------------------------------------------------------
a <- 1:10
b<- 21:30
c<-41:50
sampleDat1 <- data.frame(a,b,c)
sampleDat2<- data.frame(c,a,b,a)
NumOfDataFrames <- 2
ls_df=list(sampleDat1,sampleDat2)
names(ls_df)=c("sampleDat1","sampleDat2")
#--------------------------------------------------------------------
FilePath <- "C:\\12324\\files\\"
FullPath=character()
for(i in 1:length(ls_df)){
FullPath[i]<-paste0(FilePath,names(ls_df)[i],".csv")
write.csv(x=ls_df[[i]],file = FullPath[[i]])
}
return(FullPath)
}
2) Server.R( create dinamic ui and render DT in two step)
shinyServer(function(input, output,session) {
dataSrc <- reactive({
paths <- GenerateData()
return(paths)
})
output$result <- renderUI({
MyFilePath <- dataSrc()
lapply(1:length(MyFilePath),function(i)dataTableOutput(paste0('tbl',i)))
})
observe({
MyFilePath <- dataSrc()
lapply(1:length(MyFilePath),function(i) output[[paste0("tbl",i)]]<-renderDataTable(read.csv(MyFilePath[i])))
})
}
)
I have a function that generates "n" dataframes and saves it in a location as csv files and the function returns the file name of the saved CSVs.
I wish to take those csv files, read it using read.csv() and then display it on the UI using renderUI and renderDataTable()
While the code below has no syntax errors, but nothing is getting displayed on the screen.
Please suggest an appropriate method by which the tables generated in one part of the server.R can be used in output and display those data tables on the UI.
The code for the function is below :
Function
GenerateData <- function(){
#********************************************************************
# some sample data (originally, my data comes from an external souce)
#--------------------------------------------------------------------
a <- 1:10
b<- 21:30
c<-41:50
sampleDat1 <- data.frame(a,b,c)
sampleDat2<- data.frame(c,a,b,a)
NumOfDataFrames <- 2
#--------------------------------------------------------------------
FilePath <- "D:/FolDerName/"
FullPath<-WriteStatement <- NULL
for(i in 1:NumOfDataFrames){
FullPath[i]<-paste0(FilePath,"sampleDat",i,".csv")
WriteStatement[i]<-paste0("write.csv(sampleDat",i,",file = '",FullPath[i],"')")
eval(parse(text=WriteStatement[i]))
}
return(FullPath)
}
The UI.r
library(shiny)
shinyUI(
fluidPage(
# Application title
navbarPage("Sample Data Display",
tabPanel("Data",
sidebarLayout(
sidebarPanel(
titlePanel("Sample"),
numericInput("sample1",label = "Some Label",value = 20),
numericInput("sample2",label = "Some Other Label",value = 20)
),
mainPanel(
uiOutput("result")
)
)
)
)
)
)
The server.R
library(shiny)
GenerateData <- function(){
#********************************************************************
# already mentioned above, please copy the contents to server.R
#--------------------------------------------------------------------
}
shinyServer(function(input, output,session) {
dataSrc <- reactive({
paths <- GenerateData()
return(paths)
})
output$result <- renderUI({
dataTab1<-NULL
MyFilePath <- dataSrc()
for (i in 1:length(MyFilePath)){
dataTab1 <- read.csv(MyFilePath[i])
# print(dataTab1)
renderDataTable(dataTab1)
dataTab1<-NULL
}
})
}
)
You can try
1) use list of df
GenerateData <- function(){
#********************************************************************
# some sample data (originally, my data comes from an external souce)
#--------------------------------------------------------------------
a <- 1:10
b<- 21:30
c<-41:50
sampleDat1 <- data.frame(a,b,c)
sampleDat2<- data.frame(c,a,b,a)
NumOfDataFrames <- 2
ls_df=list(sampleDat1,sampleDat2)
names(ls_df)=c("sampleDat1","sampleDat2")
#--------------------------------------------------------------------
FilePath <- "C:\\12324\\files\\"
FullPath=character()
for(i in 1:length(ls_df)){
FullPath[i]<-paste0(FilePath,names(ls_df)[i],".csv")
write.csv(x=ls_df[[i]],file = FullPath[[i]])
}
return(FullPath)
}
2) Server.R( create dinamic ui and render DT in two step)
shinyServer(function(input, output,session) {
dataSrc <- reactive({
paths <- GenerateData()
return(paths)
})
output$result <- renderUI({
MyFilePath <- dataSrc()
lapply(1:length(MyFilePath),function(i)dataTableOutput(paste0('tbl',i)))
})
observe({
MyFilePath <- dataSrc()
lapply(1:length(MyFilePath),function(i) output[[paste0("tbl",i)]]<-renderDataTable(read.csv(MyFilePath[i])))
})
}
)