I am using Shiny and want to output some of the data.
This is the code I am using to load data and select variables
data.feature <- reactive({
# filename <- paste0("dataall_'", input$date, "'new.RData")
filename <- paste0("dataall_new.RData")
load(filename)
feature.test[input$variable,]
})
Then use the following code to download the data
output$downloadDatar <- downloadHandler(
filename = paste('data_summary.RData'),
content = function(file) {
save( data.feature, file= file)})
}})
But when I open the saved file, and enter data.feature I got this:
reactive({
filename <- paste0("dataall_new.RData")
load(filename)
feature.test[input$variable]
})
Is there any way to view the data inside?
BTW, I tried data.feature() in save function and got object ‘data.feature()’ not found error
Problem solved: just use isolate function
Problem solved: just use isolate function
Related
I am new to Shiny, apologies if this is obvious and has been asked numerous times, but I've been stuck on this for days.
I've been modifying a dashboard to process analytical chemistry data i.e. it reads in multiple csv files, processes the data (smooths etc.) with various sliders and functions in Shiny, but does not save/download the processed data/output, which I've been trying to do. I don't seem to be able to access the "output" or processed data e.g. as a list of matrices, which I then write out as new .csv files. (I get "object of type 'closure' is not subsettable")
I am competent in R, and have script which works well, but making this change to Shiny is proving problematic. How do I access the output data of detectedPeaks or baselineCorrectedSpectra to write to csv (or zip up the mutilple csv files)?
Thank you.
#Just part of the relevant code - a long script
#server
baselineCorrectedSpectra <- reactive({
if (is.null(input$bc)) {
method <- "SNIP"
hws <- 100
} else {
method <- input$bc
hws <- input$bcHws
}
return(lapply(smoothedSpectra(), function(y) {
bl <- estimateBaseline(y, method=method, hws)
intensity(y) <- intensity(y)-bl[, 2]
return(y)
}))
})
detectedPeaks <- reactive({
return(detectPeaks(baselineCorrectedSpectra(), method=input$pdNoise,
halfWindowSize=input$pdHws, SNR=input$pdSNR))
})
datasetInput <- reactive({
switch(input$dtset,
"peaks" = detectedPeaks(),
"centroided" = baselineCorrectedSpectra())
})
output$DownloadZip <- downloadHandler(
filename = function(){
paste0("Results",".zip")
},
content = function(con){
files <- c()
tmpdir <- tempdir()
setwd(tempdir())
for (i in 1:length(s)){
x<-as.matrix(datasetInput[[i]]) #This doesn't work,how do I access this data?
y<-metaData(s[[i]])
f<-(paste("processed", y, sep="_" ))
if(input$downloadType == ".csv")
write.csv(x,f)
else write.table(x,f)
files<-c(x,files)
}
zip(zipfile=con, files=files)
},
contentType = "application/zip"
)
I added () to datasetInput
Can you give this a try:
x<-as.matrix(datasetInput([[i]]))
The way to do it is below:
x<-as.matrix(datasetInput()[[i]])
I want to use Shiny within RMarkdown for users to upload data (xlsx file).
Then I want to pass all the worksheets as R data frames (w/o reactivity) to run rest of the RMarkdown file.
I mainly want to convert them into data frames so I can use reticulate to run Python code as well.
I've tried this, and it doesn't seem to quite work:
library(dplyr)
library(miniUI)
library(shiny)
library(XLConnect)
launch_shiny <- function() {
ui <- miniPage(
gadgetTitleBar("Input Data"),
miniContentPanel(
fileInput(inputId = "my.file", label = NULL, multiple = FALSE)
)
)
server <- function(input, output, session) {
wb <- reactive({
new.file <- input$my.file
loadWorkbook(
filename = new.file$datapath,
create = FALSE,
password = NULL
)
})
observeEvent(input$done, {
stopApp(c(wb()))
})
}
runGadget(ui, server)
}
test <- launch_shiny()
df1 <- readWorksheet(object = test, sheet = "sheet1")
df2 <- readWorksheet(object = test, sheet = "sheet2")
It throws this error:
Error in (function (classes, fdef, mtable) :
unable to find an inherited method for function ‘readWorksheet’ for signature ‘"list", "character"’
I can return one sheet at a time using stopApp(readWorksheet(object = wb(), sheet = "sheet1")), but I can't seem to return an entire workbook or multiple data frames at the same time.
I don't really want to read in xlsx, save each sheet as csv in working directory, then read those files in again.
Would anyone have a good suggestion on how to get around this?
The documentation of fileInput() states in the details:
datapath
The path to a temp file that contains the data that was
uploaded. This file may be deleted if the user performs another upload
operation.
Meaning that the datapath given in the input variable is a temporary file that is no longer accessible after you close the App, which is what the function readWorksheet will try to do.
So you'll have to read the sheets in the server and return the dataframes somehow.
I did that by defining a second reactive value which is basically a list of dataframes returned by applying lapply on all the sheets in wb, in this case test will be this list of data frames.
There might be other ways (more efficient, or suits your purpose better) to do this, but here it is:
library(dplyr)
library(miniUI)
library(shiny)
library(XLConnect)
launch_shiny <- function() {
ui <- miniPage(
gadgetTitleBar("Input Data"),
miniContentPanel(
fileInput(inputId = "my.file", label = NULL,
multiple = FALSE)
)
)
server <- function(input, output, session) {
wb <- reactive({
new.file <- input$my.file
loadWorkbook(
filename = new.file$datapath,
create = FALSE,
password = NULL
)
})
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
df_lst <- reactive({
# read all sheets into a list
lapply(getSheets(wb()),
function(sheet){
readWorksheet(object = wb(),
sheet = sheet)
})
})
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
observeEvent(input$done, {
# get the list of dfs from the app
stopApp(c(df_lst()))
})
}
runGadget(ui, server)
}
test <- launch_shiny()
I have a shiny app to generate a .txt file to download.
In addition, I would like to keep a copy of the file that users generate in my shiny server.
the server function looks like :
server <- function(input, output, session){
data_gen <- reactive({
d1= data.frame(...)
d2= data.frame(...)
result <- list(d1=d1, d2=d2)
return(result)
})
create_file <- reactive({
sink("/srv/shiny-server/S3/file.txt",append = TRUE)
print(data_gen()$d1)
print(data_gen()$d2)
sink()
})
output$downloadData <- downloadHandler(
filename = function() {"input.txt"},
content = function(file) {
sink(file,append = TRUE)
print(data_gen()$d1)
print(data_gen()$d2)
sink()
}
)
}
I'm able to download the data but the app does not react to the create_file function and it does not write a copy into shiny server.
Any Idea how could I fix this ?
Your create_file function is a reactive. Reactive functions only evaluate when 1) their output is required, and 2) their inputs have changed. Neither appears to apply here.
What you could do is move the contents of create_file inside your downloadhandler. content must receive a function that returns a file, but the function can do other things first. So try the following:
server <- function(input, output, session){
data_gen <- reactive({
d1= data.frame(...)
d2= data.frame(...)
result <- list(d1=d1, d2=d2)
return(result)
})
output$downloadData <- downloadHandler(
filename = function() {"input.txt"},
content = function(file) {
# save non-user copy
sink("/srv/shiny-server/S3/file.txt",append = TRUE)
print(data_gen()$d1)
print(data_gen()$d2)
sink()
# copy to be returned for user
sink(file,append = TRUE)
print(data_gen()$d1)
print(data_gen()$d2)
sink()
})
}
I'm trying to build a Shiny App that pulls dynamically updated data from an S3 bucket. I can currently pull data, but it doesn't update itself. I've been through the documentation for reactiveFileReader and examples, but can't figure it out? Help extremely appreciated!!!
Code below:
getFile<-function(){
my_bucket <- 'globalrss'
file <- paste0(as.character(getwd()),"/tmp")
r <- aws.s3::save_object("bodytype.csv", my_bucket, file=file)
}
shinyServer(function(input, output, session) {
fileReaderData <- reactiveFileReader(500, session, getFile(), readLines)
output$fileReaderText <- renderText({
text <- fileReaderData()
length(text) <- 14
text[is.na(text)] <- ""
paste(text, collapse = '\n')
})
})`
I think you may need to put the file reading part of your code in an observer. Maybe something like this:
shiny::shinyServer(function(input, output, session){
getFile<-function(){
my_bucket <- 'globalrss'
file <- paste0(as.character(getwd()),"/tmp")
r <- aws.s3::save_object("bodytype.csv", my_bucket, file=file)
}
theFile<- getFile() # do this once, just so you have the data right away
# Now setup an observer that surrounds invalidate later and the file read code
observe({
shiny::invalidateLater(millis=30000, session=session) # run every 30 seconds
theFile<<- getFile() # get the contents of the s3 bucket, replace data
cat(file=stderr(), "updating data", "\n") # have this report actions to the console, can be removed later
})
output$fileReaderText <- renderText({
text <- theFile
length(text) <- 14
text[is.na(text)] <- ""
paste(text, collapse = '\n')
})
})
Hopefully this gets you closer to what you want. Good luck. Cheers, nate
I have a file which i generate in shiny
The user clicks a button and the file should download. However nothing happens
The function export_report generates the excel file and saves it to a location. The function then passes back the file location to the download handler so it will download the file. The problem seems to be that it isnt being returned correctly. I have tested the function (export_report) outside of shiny and it returns everything perfectly so I'm clearly doing something wrong from the shiny perspective.
The file itself is created where it is supposed to be on the server because i can download it within RStudio and see it in the file explorer. Can anyone help
# UI Section
downloadButton("downloadRpt", "Download Report")
# Server Section
output$downloadRpt <- downloadHandler(
filename = function() {
mydf <- report()
dateRange <- input$dates_report
selection <- input$selection
myfile <- export_report (mydf, selection, dateRange)
},
content = function(file) {
file.copy(myfile, file)
}
)
I have seen other examples R Shiny: Download existing file which is what my code is based on
EDIT 1: Adding the export_report function with some fake data to run it
export_report <- function(mydf,selection,dateRange) {
# Template for where the template excel file is stored
myoutputTemplate <- '/home/shiny_tutorials/Save to Database/templates/output_template.xlsx'
start_date <- dateRange[1]
end_date <- dateRange[2]
date_range <- paste(start_date ,end_date, sep = " - " )
# Load workbook the template workbook
wb <- loadWorkbook(myoutputTemplate)
# write to the workbook the data frame
writeWorksheet(wb, mydf, sheet="Details",
startRow=8, startCol=2,
header=FALSE)
# add the the customer the user selected
writeWorksheet(wb, selection, sheet="Details",
startRow=3, startCol=3,
header=FALSE)
# date
writeWorksheet(wb, date_range, sheet="Details",
startRow=5, startCol=3,
header=FALSE)
# Create The file Name
filename <- paste(selection, Sys.Date(), sep = " - ") %>%
paste(.,"xlsx", sep = ".")
# removes the % sign and extra qoutes
filename <- gsub (pattern = '\'|%','', x = filename)
# output directory
myoutput <- paste('/home/shiny_tutorials/Save to Database/output/',
filename, sep = '')
# Save workbook
saveWorkbook(wb, myoutput)
# Return File Path
myoutput
}
To call the function you can use the data below
dateRange <- c("2011-09-23","2016-09-23")
selection = "COMPANY_A"
mydf <- iris
myfile <- export_report(mydf,selection,dateRange)
EDIT 2 I have now managed to get an error out of it. When i cat(myfile) in the filename = function() { section of the code i get the error after the correct file path has been returned
Warning in rep(yes, length.out = length(ans)) :
'x' is NULL so the result will be NULL
Warning: Error in ifelse: replacement has length zero
Stack trace (innermost first):
1: runApp
Error : replacement has length zero
This error is basically because my file path does not get passed to the segment myfile so
if someone can tell me how to get the filepath generated by my function to the server section of the code below, that should fix my problem
content = function(file) {
file.copy(myfile, file)
}
Thank you to everyone who commented and clarified my thinking a bit on how the download handler works.
In the end, i created a new function which split up the export function above
The new function i used is called generate_file() which simply returns the file name
generate_file_name <- function(selection) {
# Create The file Name
filename <- paste(selection, Sys.Date(), sep = " - ") %>%
paste(.,"xlsx", sep = ".")
# removes the % sign and extra qoutes
filename <- gsub (pattern = '\'|%','', x = filename)
# output directory
myoutput <- paste('/home/shiny_tutorials/Save to Database/output/',
filename, sep = '')
# Return File Path
myoutput
}
Then in the server side
output$downloadRpt <- downloadHandler(
filename = function() {
selection <- input$company
generate_file_name(selection)
},
content = function(file) {
mydf <- report()
dateRange <- input$dates_report
selection <- input$company
export_report(mydf,selection,dateRange)
myfile <- generate_file_name(selection)
file.copy(myfile, file)
}
)
This then finds the newly created file and exports it for the user
I just checked your problem with this example code and it worked:
output$downloadData <- downloadHandler(
filename = function() {
data <- mtcars
myfile <- "data.csv"
write.csv(data, myfile)
myfile
},
content = function(file) {
print(file) //prints: [...]\\Local\\Temp\\RtmpEBYDXT\\fileab8c003878.csv
file.copy(file, file)
}
)
myfile is the filename of the downloaded file. You cannot use it in file.copy as input, this variable is out of scope. It seems that R creates a temp file name (see the print()).
Try to use the filename function to define your path or a custom file name, and the write.csv in the content part. Example code:
output$downloadData <- downloadHandler(
filename = function() {
paste(<user_name or date for eg>, ".csv", sep="")
},
content = function(file) {
write.csv(data, file)
}
)
I noticed in your comment above, you have asked how the application would generate the correct file when used by multiple users. For this part, you need to use the session.
So if your business logic functions were to come from an R file called foo.R, the server code should look something like:
shinyServer(func = function(input, output, session) {
source("./foo.R", local=TRUE)
......
And this would separate out the session for each user, thereby generating files specific to each, when downloading. Hope this gives you some pointers.