downloadHandler not working with observeEvent - r

I am trying to download a file using downloadHandler with observeEvent shiny but I am not able to download the file,
library(shiny)
load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))
ui <- fluidPage(
sidebarLayout(
# Input
sidebarPanel(
# Numeric input for number of rows to show
numericInput(inputId = "n_rows",
label = "How many rows do you want to see?",
value = 10),
# Action button to show
actionButton(inputId = "button",
label = "Show")
),
# Output:
mainPanel(
tableOutput(outputId = "datatable")
)
)
)
server <- function(input, output, session) {
# creating a reactive expression
df <- eventReactive(input$button, {
movies %>% head(input$n_rows)
})
# download a csv everytime when user click on show button
observeEvent(input$button, {
output$button <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(df(), file)
}
)
cat("done downloading file \n")
})
# displays the data on the web in tabular format, data comes from reactive event
output$datatable <- renderTable({
df()
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)
I was able to execute above code without any errors, but csv file is not downloading, i want to display the data table and download the displayed data on same button click event , how can i achieve this, Am I missing something, any help would be appreciated

Try this:
library(shiny)
library(dplyr)
load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))
ui <- fluidPage(
sidebarLayout(
# Input
sidebarPanel(
# Numeric input for number of rows to show
numericInput(inputId = "n_rows",
label = "How many rows do you want to see?",
value = 10),
# Action button to show
downloadButton('downloadData', 'Download data')
),
# Output:
mainPanel(
tableOutput(outputId = "datatable")
)
)
)
server <- function(input, output, session) {
# Reactive value for selected dataset ----
df <- reactive({
movies %>% head(input$n_rows)
})
output$datatable <- renderTable({
df()
})
output$downloadData <- downloadHandler(
filename = function() {
paste("dataset-", ".csv", sep = "")
},
content = function(file) {
write.csv(df(), file, row.names = FALSE)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)

Related

How to read csv file and render UI?

I have a simple shiny app and when I press a button a .csv file is saved in the directory where the file app.R is.
I want to be able to read this csv file and render the information in a table on my shiny app.
This is a similiar example about what I would like to do
df <- data.frame(no =c(1:3),money=c(9999:10001),penalty=c(999:1001))
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),actionButton("sort","Do Sorting")
),
mainPanel(
tableOutput("contents"),tableOutput("sortedcontents")
)
)
)
server <- function(input, output) {
rawInputData = reactive({
rawData = input$file1
if(!is.null(rawData)) {
data = read.csv(rawData$datapath);
} else {
return(NULL);
}
});
output$contents <- renderTable({
newData = rawInputData()
if(is.null(newData))
return();
newData;
})
sorting = reactive({
if(input$sort){
newData = rawInputData()
newData$moneysort <- ifelse(newData$money >=10000, 1, 0)
newData$penaltysort <- ifelse(newData$penalty >=1000, 1, 0)
}
newData
})
output$sortedcontents <- renderTable({
newData = sorting()
if(is.null(newData))
return();
newData;
})
}
}
shinyApp(ui, server)
Instead to have the opportunity to choose the file with a fileInpunt() I would like to avoid this step and automatically check a specific directory to look for the csv called "myData.csv" and render this csv in a table.
Here is an example of just reading data from local directory and rendering in shiny.
library(shiny)
write.csv(iris, 'iris.csv')
df = read.csv('iris.csv')
shinyApp(
ui = fluidPage(
fluidRow(
column(12,
tableOutput('iris_table')
)
)
),
server = function(input, output) {
output$iris_table <- renderTable(df)
}
)
This example uses a slight modification from this shiny TableOutput reference.

How to download editable data table in shiny

In data table, we can use argument editable to make the table editable. I'm making a shiny app in which table is both editable and downloadable.
My question is how I can download a datatable after I edit it?
Here is my app code:
library(shiny)
library(DT)
server <- function(input, output) {
df = iris
output$data = DT::renderDataTable ({
DT::datatable(df, editable = list(
target = 'row',
disable = list(columns = c(1, 3, 4))
))
})
output$downloadData <- downloadHandler(
filename = function() {
#paste(input$dataset, ".csv", sep = "")
},
content = function(file) {
write.csv(df, file, row.names = FALSE)
}
)
}
ui <- fluidPage(
DT::dataTableOutput('data'),
downloadButton("downloadData", "Download")
)
shinyApp(ui = ui, server = server)
When you edit a cell of a datatable named "XXX", the info about the cell edit is in input$XXX_cell_edit. This info contains the indices of the edited cell and its new value. So you can do:
library(shiny)
library(DT)
dat <- iris[1:3, ]
ui <- fluidPage(
downloadButton("downloadData", "Download"),
DTOutput("table")
)
server <- function(input, output){
output[["table"]] <- renderDT({
datatable(dat, editable = "cell")
})
df <- reactiveVal(dat)
observeEvent(input[["table_cell_edit"]], {
cell <- input[["table_cell_edit"]]
newdf <- df()
newdf[cell$row, cell$col] <- cell$value
df(newdf)
})
output[["downloadData"]] <- downloadHandler(
filename = function() {
"mydata.csv"
},
content = function(file) {
write.csv(df(), file, row.names = FALSE)
}
)
}
shinyApp(ui, server)
Alternatively, as suggested by #MrGumble, you can use the embedded button of Datatables instead of a downloadHandler. This is more stylish.
library(shiny)
library(DT)
dat <- iris[1:3, ]
ui <- fluidPage(
DTOutput("table")
)
server <- function(input, output){
output[["table"]] <- renderDT({
datatable(dat, editable = "cell", extensions = "Buttons",
options = list(
dom = "Bfrtip",
buttons = list(
"csv"
)
))
})
observeEvent(input[["table_cell_edit"]], {
cellinfo <- input[["table_cell_edit"]]
dat <<- editData(dat, input[["table_cell_edit"]], "table")
})
}
shinyApp(ui, server)
You can add a download button directly to a DT datatable, which offers the user to download the current data in the table, see R Shiny: How to add download buttons in DT::renderDataTable
If you however want to use the edited data for server-side calculations, you are are on the right track, but need to save the edited table into the data.frame using replaceData. See e.g. https://yihui.shinyapps.io/DT-edit/

If Statement in Shiny based on values in reactive

I am building an authentication part in my app by comparing the code sent in email and the code users submit. I have tried adding if-statement by using either in reactive(),isolate(), renderTable(). I either get the value should be in the reactive part error, or the app does not respond at all.
Below is what I have in Server.R, the app does not respond at all with no error.
shinyServer(function(input, output, session) {
myData <- reactive({
req(input$Id)
#connect to the database, get the data, res
#send an email with random number, rnd
list(res,rnd)
})
output$tbTable <- renderTable({req(input$Auth)
if (input$AuthCode==myData()$rnd) {
myData()$res
}
else{
as.data.frame(c("Authentication Failed"))
}
})
output$downloadData <- downloadHandler(
filename = function() {
paste(input$Id, " filname.xlsx", sep = "")
},
content = function(file) {
write.csv(myData(), file, row.names = FALSE)
}
)#this part need to depend on the if-statement as well
}
)
UI.R
ui <- shinyUI(fluidPage(title = "aaa",
titlePanel("aaa"),
sidebarLayout(
sidebarPanel(
textInput("Id", "Enter Acct Name below"),
submitButton(text="Submit"),
tags$hr(),
numericInput("AuthCode",label="Authentication",value=""),
actionButton("Auth",label="Submit"),
tags$hr(),
tags$hr(),
downloadButton("downloadData", "Download Data")
),
mainPanel(
tabsetPanel(
tabPanel("Data", tableOutput("tbTable"))
))
),
)
)
I think I've got the fixed to do what you want. Please check. I've done the following changes
Replaced your submitButton to actionButton as Acc and using observeEvent to call that.
The authentication is also now triggered by an observeEvent when the second button is clicked
Excel extension wouldn't work in write.csv so changed the extension.
server.R
shinyServer(function(input, output, session) {
# the first button will trigger this
observeEvent(input$Acc,{
# myData <- reactive({
req(input$Id)
#connect to the database, get the data, res
#send an email with random number, rnd
#list(res,rnd)
myData <<- list(res = 123,rnd = 345) #passing test value and storing it as global variable for accessing in other functions
# })
cat("mydata done")
})
# the second button will trigger this
observeEvent(input$Auth,{
output$tbTable <- renderTable({
#req(input$Auth)
if (input$AuthCode==myData$rnd) {
myData$res
}
else{
#as.data.frame(c("Authentication Failed"))
shiny::showModal(modalDialog(
title = "Important message",
"Authentication Failed!"
))
}
})
})
output$downloadData <- downloadHandler(
filename = function() {
paste(input$Id, " filname.csv", sep = "") #renamed it to csv because write.csv writes to csv not excel
},
content = function(file) {
write.csv(myData, file, row.names = FALSE)
}
)#this part need to depend on the if-statement as well
}
)
ui.R
ui <- shinyUI(fluidPage(title = "aaa",
titlePanel("aaa"),
sidebarLayout(
sidebarPanel(
textInput("Id", "Enter Acct Name below"),
actionButton("Acc",label="Click to send code"),
tags$hr(),
numericInput("AuthCode",label="Authentication",value=000),
actionButton("Auth",label="Submit"),
tags$hr(),
tags$hr(),
downloadButton("downloadData", "Download Data")
),
mainPanel(
tabsetPanel(
tabPanel("Data", tableOutput("tbTable"))
))
)
)
)

Warning in summary(as.numeric(paste(input$to, "input$to"))) : NAs introduced by coercion in Shiny with R

I am very new to Shiny web app with R. I want to generate summary according to choice from checkboxGroupInput which i generated dynamically when browsing the CSV file. My problem is that when i want to convert from String to numeric that time it prints NA.
I am uploading my two files which are ui.r and server.r. I am trying since two days. If anyone help me then it will be very beneficial for me.
If i did anything wrong in my code then please suggest me right way.
ui.r
library(shiny)
library(shinythemes)
shinyUI(fluidPage(
theme = shinytheme("cyborg"),
themeSelector(),
# Application title
titlePanel("Data Analytics and Visualization Dashboard"),
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose CSV file',accept=c('text/csv', 'text/comma-
separated-values,text/plain')),
h5("Max file size to upload is 5 MB."),
radioButtons("sep", "Seperator", choices = c(Comma = ',', semicolon = ';',
tab = "\t", space = " " )),
#checkboxInput("header", "Header?")
br(),
h4("Select columns from CSV"),
uiOutput("toCol"),
br(),
h4("Summary"),
textOutput("sum")
# tableOutput("disp")
),
mainPanel(
numericInput("obs", "Enter the number of rows to display:", 5),
tableOutput("input_file"),
plotOutput("p")
)
)
))
server.r
library(shiny)
shinyServer(function(input, output,session) {
#This function is repsonsible for reading a csv file
output$input_file <- renderTable({
file_to_read = input$datafile
if(is.null(file_to_read))
{
return()
}
read.csv(file_to_read$datapath, sep = input$sep, nrows = input$obs))
})
#This function is repsonsible for loading in the selected file
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.csv(infile$datapath,nrows = input$obs)
})
#The following set of functions populate the column selectors
output$toCol <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
checkboxGroupInput("to", "Columns",items)
})
observe({
# db <- gsub(",","",input$to)
# print(db)
# paste( intToUtf8(160), input$to, intToUtf8(160))
# print(summary(as.numeric(as.character( paste( " ", input$to, "
#"))))) })
print(summary(as.numeric( input$to) ))})
# output$sum <- renderPrint({
# summary(input$data.frame[,as.numeric(input$var)])
# })
# output$disp <- renderTable({
# input$to
# })
# output$summary1 <- renderPrint({
# sum <- as.numeric(as.character(input$to))
# summary(sum)
#})
})
This could be a starting point, although I dont recommend using this for a productive app, as the login-process is not really safe nor encrypted. It is based solely on text-data.
But you will have to put the ui in the server and render the page depending on the login status. So there are 2 renderUI but just 1 server-function. I dont know if you can have 2 different server-functions and redirect them. I think it all has to be in 1 server-function.
library(shiny)
username = "joe"
password = "joe123"
ui <- fluidPage(
uiOutput("ui")
)
server <- function(input, output, session) {
LOGGED <- reactiveValues(user = FALSE)
observeEvent(input$action, {
if ((input$name == username ) & (input$pass == password)) {
LOGGED$user = TRUE
} else {
LOGGED$user = FALSE
}
})
observe({
if (LOGGED$user == FALSE) {
output$ui <- renderUI({
tagList(
p(HTML("User is joe <br> and password is joe123")),
textInput("name", "Enter your username"),
passwordInput("pass", "Enter your password"),
actionButton("action", label = "Action")
)
})
} else if (LOGGED$user == TRUE) {
output$ui <- renderUI({
tagList(
h1("You are logged in.")
)
})
}
})
}
shinyApp(ui, server)
Like #Codeer said, there is no line in your code like this one summary(as.numeric(paste(input$to, “input$to”))). I edited your code, so all the uncommented lines dont appear, as its not necessary to show them.
In your example, your loading the csv file twice, which you can definitly avoid.
I moved the csv-loading into the reactive only. Then you can access the loaded file everywhere in your shiny-app. And i think in your print(summary()) statement, you're missing the data, as your only printing out the summary of the input$tovariable, which is only text and if you convert it to numeric you create NA-values.
So i rearranged your code a bit, and I think its behaving the way you intend it to.
library(shiny)
library(shinythemes)
ui <- {shinyUI(fluidPage(
theme = shinytheme("cyborg"),
themeSelector(),
titlePanel("Data Analytics and Visualization Dashboard"),
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose CSV file',accept=c('text/csv', 'text/comma-
separated-values,text/plain')),
h5("Max file size to upload is 5 MB."),
radioButtons("sep", "Seperator", choices = c(Comma = ',', semicolon = ';',
tab = "\t", space = " " )),
br(),
h4("Select columns from CSV"),
uiOutput("toCol"),
br(),
h4("Summary"),
textOutput("sum")
),
mainPanel(
numericInput("obs", "Enter the number of rows to display:", 5),
tableOutput("input_file"),
verbatimTextOutput("summary"),
plotOutput("p")
)
)
))}
server <- shinyServer(function(input, output,session) {
#This function is repsonsible for loading and reading a csv file
filedata <- reactive({
req(input$datafile)
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.csv(infile$datapath,nrows = input$obs, sep = input$sep)
})
output$input_file <- renderTable({
filedata()
})
#The following set of functions populate the column selectors
output$toCol <- renderUI({
df <- filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
checkboxGroupInput("to", "Columns",items)
})
output$summary <- renderPrint({
req(input$to)
data <- filedata()
print(summary(data[,input$to]))
})
})
shinyApp(ui, server)
The csv file is loaded in the reactive (filedata). In the renderTable, you just enter the reactive variable - filedata(). And in the observe, you call again the reactive variable and only print out the summary of the data in the clicked column (input$to).

Download file from server to local directory using Shiny

I am not sure if I am understanding this correctly. Where should the data set that I want to download be in RStudio server? I do not want to deploy yet, so I am not using the Shiny server, but I want to use the download functionality and save the data set as a file in a local directory.
I have uploaded a file using Shiny fileInput and I have saved the file using copy.file(). I was told that the uploaded file is saved to the server. The file is called 0.tsv. Afterwards, I read that file and download it. The GUI works, but the file doe not get written to a file and saved to the local directory. My question is: is there any thing missing in my approach?
library(shiny)
ui <- fluidPage(
titlePanel('File download'),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("data")),
radioButtons("filetype", "File type:",
choices = c( "tsv")),
downloadButton('downloadData', 'Download')
),
mainPanel(
tableOutput('table')
)
)
)
function(input, output) {
datasetInput <- reactive({
# Fetch the appropriate data object, depending on the value
# of input$dataset.
data <- read.table("home/user/0.tsv")
switch(input$dataset,
"data" = data)
})
output$table <- renderTable({
datasetInput()
})
# downloadHandler() takes two arguments, both functions.
# The content function is passed a filename as an argument, and
# it should write out data to that filename.
output$downloadData <- downloadHandler(
# This function returns a string which tells the client
# browser what name to use when saving the file.
filename = function() {
paste(input$dataset, input$filetype, sep = ".")
},
# This function should write data to a file given to it by
# the argument 'file'.
content = function(file) {
sep <- switch(input$filetype, "tsv" = "\t")
# Write to a file specified by the 'file' argument
write.table(datasetInput(), file, sep = sep,
row.names = FALSE)
}
)
}
shinyApp(ui = ui, server = server)
ui <- fluidPage(
titlePanel('File download'),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("data")),
radioButtons("filetype", "File type:",
choices = c( "tsv")),
downloadButton('downloadData', 'Download')
),
mainPanel(
tableOutput('table')
)
)
)
function(input, output) {
datasetInput <- reactive({
# Fetch the appropriate data object, depending on the value
# of input$dataset.
data <- read.table("home/user/0.tsv")
switch(input$dataset,
"data" = data)
})
output$table <- renderTable({
datasetInput()
})
# downloadHandler() takes two arguments, both functions.
# The content function is passed a filename as an argument, and
# it should write out data to that filename.
output$downloadData <- downloadHandler(
# This function returns a string which tells the client
# browser what name to use when saving the file.
filename = function() {
paste(input$dataset, input$filetype, sep = ".")
},
# This function should write data to a file given to it by
# the argument 'file'.
content = function(file) {
sep <- switch(input$filetype, "tsv" = "\t")
# Write to a file specified by the 'file' argument
write.table(datasetInput(), file, sep = sep,
row.names = FALSE)
}
)
}
shinyApp(ui = ui, server = server)
Thanks very much for your response. Below is the correct way to do it. This works fine.
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(input$dataset,
"params" = params)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(input$dataset, ".csv", sep = "")
},
content = function(file) {
write.table(datasetInput(), file, row.names = FALSE)
}
)
}

Resources