I have built a Shiny app that allows users to upload a .txt file, filter for key terms and then download the returned dataset. When hosting locally it works. However, when I deployed it to shinyapps.io the download function no longer works. Everything else (e.g the data upload + wrangling step) do work. Nothing comes up as an error in the code log. The file it downloads is called 'downloadData.html' and simply says 'Please wait. Loading'. When I run and download locally it returns a .txt file (which is strange as the function is write.csv). My code is
library(tidyverse)
library(shiny)
library(rsconnect)
ui <- fluidPage(
titlePanel("Download data"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose .txt file",
multiple = F,
accept = c(".txt")),
textInput('energy_co', 'Name of energy company'),
textInput('asset', 'name of Asset Manager'),
downloadButton("downloadData", "Download")
),
mainPanel(
tableOutput("table")
)
)
)
options(shiny.maxRequestSize=30*1024^2)
server <- function(input, output, session) {
company_data <- reactive({
req(input$file1,input$asset,input$energy_co)
data <- read_lines(input$file1$datapath)
text_df <- as_data_frame(data)
company_data <- text_df %>%
filter(str_detect(value, input$asset)) %>%
filter(str_detect(value, input$energy_co)) %>%
distinct(.)
company_data
})
output$table <- renderTable({
company_data()
})
output$downloadData <- downloadHandler(
filename = function() {
paste(company_data(), ".csv", sep = "")
},
content = function(file) {
shiny::withProgress(
message = paste0("Downloading", company_data(), " Data"),
value = 0,
{
shiny::incProgress(1/10)
Sys.sleep(1)
shiny::incProgress(5/10)
write.csv(company_data(), file, row.names = FALSE)
}
)
}
)
}
shinyApp(ui, server)
Does anyone have any idea how to get this to work? The code is similar (and works locally) to other related questions on SO, but unable to work out what goes wrong when hosting remotely. Nothing comes up on the app's logs.
Related
I have an R shiny app that gets a .csv import from a user and searches the imported data across a built-in data frame, then gives the % match in the output. The UI is very simple, with a few different inputs (import .csv, a slider, and some radio buttons). What I want is to be able to take the reactive table output and print this to a .csv that the user can download to their machine. The server side of the app looks something like this:
server <- function(input, output){
rvals <- reactiveValues()
observeEvent(input$file_1,{
req(input$file_1)
rvals$csv <<- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
if(input$select == 1){
x <- function
}else if(input$select == 2){
x <- function
}else if(input$select == 3){x <- function}
#some more data processing and formatting here
return(x)
},digits = 4)
}
I would like to have the data table x be able to become a .csv that can be downloaded by clicking a download button. In the server, I added the following code, but when I try to download the data it just downloads a blank file and says "SERVER ERROR" in my downloads manager on my machine.
output$downloadData <- downloadHandler(
filename = "thename.csv",
content = function(file){
write.csv(x, file)
}
In the console I also get the error message:
Warning: Error in is.data.frame: object 'x' not found [No stack trace available]
The object you create inside the expression of renderTable is not available outside of it. Instead you could assign it to the reactive values you set up. Below is a working example (note that I have tried to replicate your code so the data will not be available until you click on "Upload CSV", which here just calls mtcars).
library(shiny)
ui = fluidPage(
sidebarPanel(
actionButton(inputId = "uploadCsv", label = "Upload CSV:", icon = icon("upload")),
selectInput(inputId = "preProc", label = "Pre-processing", choices = c("Mean"=1,"Sum"=2)),
downloadButton("downloadData", label = "Download table")
),
mainPanel(
h4("My table:"),
tableOutput("contents")
)
)
server <- function(input, output) {
rvals <- reactiveValues(
csv=NULL,
x=NULL
)
observeEvent(input$uploadCsv,{
rvals$csv <- mtcars # using example data since I don't have your .csv
# rvals$csv <- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
# Assuing the below are functions applied to your data
req(
input$preProc,
!is.null(rvals$csv)
)
if(input$preProc == 1){
rvals$x <- data.frame(t(colMeans(mtcars)))
}else {
rvals$x <- data.frame(t(colSums(mtcars)))
}
return(rvals$x)
},digits = 4)
output$downloadData <- downloadHandler(
filename = "myFile.csv",
content = function(file){
write.csv(rvals$x, file)
}
)
}
shinyApp(ui,server)
EventReactive already outputs a reactive value, you don't need to create an extra reactiveVal, see example below :
library(shiny)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Test"),
mainPanel(
actionButton("show", "Download"),
textOutput("result")
)
)
server <- function(input, output) {
csvfile <- eventReactive(req(input$show), ignoreNULL = T, {
"Content of file"
})
output$result <- reactive(
paste("result : ",csvfile()))
}
# Run the application
shinyApp(ui = ui, server = server)
I would also avoid to use <<-operator in a reactive expression.
I would like a user to be able to answer the form multiple times before downloading the file, with each subsequent form added into the excel file.
I've considered a loop with the user able to input how many times through the loop, but I would prefer the user to be able to calculate multiple times, but only need to download the file once. I am not sure where to begin with this. I've also considered shiny modules, but I am not sure that would be the most effective way to complete this. I've included a simplified version:
library(shiny)
library(lubridate)
library(openxlsx)
ui <- fluidPage(
textInput("name","Name"),
dateInput("date","Birthdate"),
textInput("title","Title"),
fileInput("excelfile","Excel File"),
actionButton("calculate","Calculate"),
downloadButton("download","Download")
)
server <- function(input, output) {
createcolumns<-observeEvent(input$calculate,{
age<-year(Sys.Date())-year(input$date)
df<-data.frame("Name"=input$name,"Age"=age,"Title"=input$title)
wb<-loadWorkbook(input$excelfile$datapath)
writeData(wb,"Sheet1",df)
saveWorkbook(wb,input$excelfile$datapath,overwrite = TRUE)
})
output$download<-downloadHandler(
file = function(){
filename<-strsplit(input$excelfile$name,"\\.")
filename<-filename[[1]][1]
filename<-paste0(filename,"_",Sys.Date())
paste(filename,"xlsx",sep=".")
},
content = function(file){
file.rename(input$excelfile$datapath,file)
},
contentType = "application/xlsx"
)
}
# Run the app ----
shinyApp(ui = ui, server = server)
Ideally, the user could input multiple people at once visit, then once everyone was entered, download the completed excel file.
I was able to do this by adding a few two variables in the server function (globaldf, x) and moving the bulk of the work into an if statement that checks if the calculate button has increased since the last time.
library(shiny)
library(lubridate)
library(openxlsx)
ui <- fluidPage(
fluidRow(
column(6,
textInput("name","Name",value = 1),
dateInput("date","Birthdate"),
textInput("title","Title"),
fileInput("excelfile","Excel File"),
actionButton("calculate","Calculate"),
downloadButton("download","Download")
),
column(6,
h1("Output"),
tableOutput("data")
)
)
)
server <- function(input, output) {
globaldf<-data.frame("Name"=NULL,"Age"=NULL,"Title"=NULL)
x<-0
createcolumns<-reactive({
req(input$name,input$date,input$title,input$excelfile,input$calculate)
y<-input$calculate
if(x<y){
age<-year(Sys.Date())-year(input$date)
df<-data.frame("Name"=input$name,"Age"=age,"Title"=input$title)
globaldf<<-rbind(globaldf,df)
wb<-loadWorkbook(input$excelfile$datapath)
writeData(wb,"Sheet1",globaldf)
saveWorkbook(wb,input$excelfile$datapath,overwrite = TRUE)
x<<-y
globaldf
} else {return()}
})
output$data<-renderTable({
outputtable<-data.frame(createcolumns())
outputtable
})
output$download<-downloadHandler(
file = function(){
filename<-strsplit(input$excelfile$name,"\\.")
filename<-filename[[1]][1]
filename<-paste0(filename,"_",Sys.Date())
paste(filename,"xlsx",sep=".")
},
content = function(file){
file.rename(input$excelfile$datapath,file)
},
contentType = "application/xlsx"
)
}
I am trying to setup a shiny app that can download html plots from the googleViz package. The code works on my machine, but when I move it to the server I get the following message when testing the download...
"The requested URL was rejected. Please consult with your administrator."
I am struggling to figure out what the IT staff, that set up the server, need to do to fix the problem - I know nothing about servers and they know nothing about R.
I built a small example app here to demonstrate the problem, based on the following ui.R
library(shiny)
library(googleVis)
# user interface
shinyUI(pageWithSidebar(
headerPanel("googleVis on Shiny"),
sidebarPanel(
selectInput("dataset", label = "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
downloadButton('download_gvis', label = 'Download')
),
mainPanel(
htmlOutput("view")
)
))
and server.R
library(googleVis)
library(webshot)
shinyServer(function(input, output) {
# data set from user
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})
# plot of data set from user
my_plot <- reactive({
gvisScatterChart(datasetInput(),
options=list(title=paste('Data:',input$dataset)))
})
# render plot of data set from user
output$view <- renderGvis({
my_plot()
})
# download plot of data set from user
output$download_gvis <- downloadHandler(
filename = "test.png",
content = function(file) {
g <- my_plot()
# print to html file
print(g, file = "gg.html")
# take a webshot of html file and save as png
webshot(
url = "gg.html",
file = "output.png",
delay = 2
)
# send output file to downloadHandler
file.copy("output.png", file)
# delete files
file.remove("gg.html")
file.remove("output.png")
}
)
})
I think the code breaks at print(g, file = "gg.html") in the server script. Thegg.html file never appears in the server directory (on my local machine I see it pop up in the directory view of RStudio).
So I want to have a Shiny page which:
A) Allows the user to upload a .xls file;
B) Offers that file back to the user for download as a .csv file;
C) Prints the head of the file in the Shiny app to ensure that it was properly read.
Here is the code I am using:
# Want to read xls files with readxl package
library(readxl)
library(shiny)
## Only run examples in interactive R sessions
if (interactive()) {
ui <- fluidPage(
fileInput("file1", "Choose File", accept = ".xls"),
tags$hr(),
uiOutput("downloader"),
htmlOutput("confirmText", container = tags$h3),
tableOutput("listContents")
)
server <- function(input, output) {
theOutput <- reactiveValues(temp = NULL, df = NULL, msg = NULL, fn = NULL)
observeEvent(input$file1, {
theOutput$fn <- paste('data-', Sys.Date(), '.csv', sep='')
theOutput$temp <- read_xls(input$file1$datapath)
theOutput$msg <- paste("File Contents:")
theOutput$df <- write.csv(theOutput$temp,
file = theOutput$fn,
row.names = FALSE)
})
output$confirmText <- renderText({
theOutput$msg
})
output$listContents <- renderTable({
head(theOutput$temp)
})
output$downloader <- renderUI({
if(!is.null(input$file1)) {
downloadButton("theDownload", label = "Download")
}
})
output$theDownload <- downloadHandler(
filename = theOutput$fn,
content = theOutput$df
)
}
shinyApp(ui, server)
}
The Shiny page renders correctly, it accepts the upload with no problems, it prints out the head of the .csv with no problems, and it creates a properly formatted "data-{today's date}.csv" file in the same directory as the app.R file.
Problem is, when I hit the download button I get the error message:
Warning: Error in download$func: attempt to apply non-function
[No stack trace available]
Can someone tell me what I am doing wrong?
Thanks to the comments above, this is the solution I found (with my comments added, to show where the code changed):
library(readxl)
library(shiny)
if (interactive()) {
ui <- fluidPage(
fileInput("file1", "Choose File", accept = ".xls"),
tags$hr(),
uiOutput("downloader"),
htmlOutput("confirmText", container = tags$h3),
tableOutput("listContents")
)
server <- function(input, output) {
theOutput <- reactiveValues(temp = NULL, msg = NULL)
observeEvent(input$file1, {
# Do not try to automate filename and the write.csv output here!
theOutput$temp <- read_xls(input$file1$datapath)
theOutput$msg <- paste("File Contents:")
})
output$confirmText <- renderText({
theOutput$msg
})
output$listContents <- renderTable({
head(theOutput$temp)
})
output$downloader <- renderUI({
if(!is.null(input$file1)) {
downloadButton("theDownload", label = "Download")
}
})
output$theDownload <- downloadHandler(
# Filename and content need to be defined as functions
# (even if, as with filename here, there are no inputs to those functions)
filename = function() {paste('data-', Sys.Date(), '.csv', sep='')},
content = function(theFile) {write.csv(theOutput$temp, theFile, row.names = FALSE)}
) }
shinyApp(ui, server) }
The fact that content takes an argument (named here "theFile"), which is not called anywhere else, is what was throwing me off.
I am very new to R shiny codes. I want to make an application which would allow users to save the selections and the project which could be availed for later usage. For example lets say I have uploaded a file and selected an input in ui. The users should be able to save the work somewhere so that they can open the project again tomorrow and continue working. this application would be desktop based in local machines not on server. I tried bookmark option wherein everything works fine, but the project as a whole cannot be saved in desktop app.
Is there a way in Rshiny where users can save the selections as a project in their directory and later on avail the project to continue working?
Any help would be much appreciated.
How do I save the below app as a project and then allow users to access .rds file in the environment?
library(shiny)
ui <- function(request){
fluidPage(
titlePanel("Put title of the application"),
sidebarLayout(
sidebarPanel(
radioButtons("sep", "File Separator: ",
choices = c(Comma = ",", Semicolon = ";", Tab = "\t"),selected = ","),
fileInput("file", "Select a file: ", multiple = FALSE,
accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
uiOutput("mytype")
,bookmarkButton()
),
mainPanel(
textOutput("mytext"),
textOutput("myrows")
)
)
)
}
server <- function(input, output, session) {
input_file <- reactive({
req(input$file)
read.csv(input$file$datapath,
header = TRUE,
sep = input$sep)
})
output$mytype <- renderUI({
selectInput("var1", "Select a type of drink: ", choices = levels(input_file()$Type))
})
onBookmark(function(state) {
state$values$var1 <- input$var1
})
onRestored(function(state){
updateSelectInput(session,"var1",selected=state$values$var1)
})
output$mytext <- renderText({paste("You have selected a Type of", tolower(input$var1))})
input_rows <- reactive({
data <- subset(input_file(), Type %in% input$var1)
nrow(data)
})
output$myrows <- renderText({paste("The selected type has", input_rows(), "rows")})
}
shinyApp(ui, server, enableBookmarking = "server")