"Shiny App" Uploads file -> Does Something -> Outputs file - r

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
)
})

Related

Export xlsx after filtering data table in shiny

I try to export a data table that i have filtered in a dataTableOutput.
but i can't get the modifyed data table.
in server.R
function(input, output) {
output$lesdoublons <- DT::renderDataTable(
DT::datatable({
MyLittleDataTable <- MYDATATABLE
MyLittleDataTable <- MyLittleDataTable[MyLittleDataTable$Mandant %in% input$mand,]
MyLittleDataTable} , filter = 'top',
)
)
output$downloadData <- downloadHandler(
filename = "myFile.xlsx",
content = function(file) {
wb <- createWorkbook()
sheet_1 <- createSheet(wb, "Liste_doublons")
addDataFrame(
MyLittleDataTable, # Here i can put MYDATATABLE but i want MyLittleDataTable :-(
row.names = FALSE
)
saveWorkbook(wb, file)
}
) # thank you for your help
}
Sure, we can store our filtered dataframe as a reactive dataframe. This means we only have to filter it once, and then we can use it in multiple places.
The below minimal example shows us creating a small, filtered dataframe from a larger one. And then that small dataframe being used in a table and as a download.
library(shiny)
ui <- fluidPage(
#Dropdown
selectInput("mydropdown", "mydropdown", choices = unique(PlantGrowth$group)),
#Download
downloadButton("mydownloadbutton", "mydownloadbutton"),
#Table
tableOutput("mytable")
)
server <- function(input, output, session) {
#My big dataframe (using the inbuilt plantgrowth dataframe)
mydatabig <- PlantGrowth
#My small, filtered dataframe, stored as a reactive dataframe
mydatasmall <- reactive({
mydatabig[mydatabig$group == input$mydropdown, ]
})
#Download (using small, filtered dataframe)
output$mydownloadbutton <- downloadHandler(
filename = function() {'mydatasmall.csv'}, content = function(file) {write.csv(mydatasmall(), file, row.names = FALSE)}
)
#Table (using small, filtered dataframe)
output$mytable <- renderTable({
mydatasmall()
})
}
shinyApp(ui, server)

How to fix 'File not found' when using the downloadHandler?

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
}
)

R shiny - update UI layout using output$"variable" [duplicate]

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])))
})
}
)

How to generate dataTableOutput dynamically by reading the .csv files in a loop in R shiny?

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])))
})
}
)

How to wrap the reactive elements inside a progress bar(Graphic)

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

Resources