So basically I am trying to make a small setup of sorts and once a certain analysis is done, I would want to export a certain dataset generated to a predefined location and a predefined name (based on the inputs selected earlier). For this purpose, I used the action button which when clicked does this,
observeEvent(input$export_button, {
write.csv(input_dummy_data4ads,paste0("Dummy Files/",unique(input_dummy_data4ads$Dependent_Variable),"_", unique(input_dummy_data4ads$Model_Type),"_", unique(input_dummy_data4ads$AGM),".csv"),row.names = F,na="")
})
The issue here is that if I click the action button once, it generates the desired csv file and at the desired location too. But after pressing it once, it takes the value of 1 (input$export_button) so when I select a new set of inputs using the radio buttons and generate a new plot based on that (by clicking another action button), the app saves a new csv file with a new name (based on the new inputs) at the desired location. What I am trying to do is to reset the value of the action button so that the new csv file is created only when I click it every time.
I tried to understand this but could not incorporate it https://github.com/rstudio/shiny/issues/167
There are specific functions in shiny for this, use downloadButton in your ui and downloadHandler in server.
server.R:
output$export_data <- downloadHandler(
filename = function() {
paste0("Dummy Files/", unique(input_dummy_data4ads$Dependent_Variable), "_", unique(input_dummy_data4ads$Model_Type), "_", unique(input_dummy_data4ads$AGM), ".csv")
},
content = function(con) {
write.csv(input_dummy_data4ads, con, row.names = F, na = "")
}
)
ui.R:
downloadButton("export_data", "Export")
Related
I am new to Shiny R. Based on a Table Editor, I would like to customise certain functions but I am having some issues. There is an Add button that contains several fields. I would not like to write every time some fields to fill the form, e.g., the Supplier or product names. I tried using SelectInput from the csv file created by the app, but when clicking the add row button, there is a drop list of the Suppliers but I can't write any other name that is not in that list. I read that another option would be textInput.typeahead but I can't figure out how to make it work.
Here is the piece of code I am using:
mydata1 = read.csv("Supplier_NCR1.csv", row.names = NULL, na.strings = "", stringsAsFactors = FALSE)
mylist1 <- as.list(unique(mydata1[[4]]))
observeEvent(input$Add_row_head, {
### This is the pop up board for input a new row
showModal(modalDialog(title = "Add a new row",
dateInput(paste0("Date_add", input$Add_row_head), "Date:", value = Sys.Date()),
numericInput(paste0("ReportNo_add", input$Add_row_head), "Report Number:",0),
selectInput(paste0("Supplier_add", input$Add_row_head), "Supplier Name:",choices=c("",mylist1)),
'''
Also, I do not know if it possible to read that field from the datatable itself instead of the csv file. Thank you in advance and hope to find a solution.
I have made an shiny app where I am giving a fileInput where user can input an excel sheet like this: 'enter image description here'. I have designed an app which looks like this: 'enter image description here'. My code is this:
library(shiny)
library(readxl)
library(tidyverse)
ui <- fluidPage(
fileInput("config","Load Configuration File",accept =c('.xls',',xlsx')),
actionButton("show_fields","Show Fields"),
actionButton("estimate","Estimate"),
uiOutput("ui"),
textOutput("prod")
)
server <- function(input,output) {
x <- reactive({read_excel(input$config$datapath)})
conf <- reactive({x() %>% column_to_rownames(., var = "Rows")})
design <- eventReactive(input$show_fields, {
fluidPage(
numericInput("size","Size",value = 0),
lapply(1:nrow(conf()),function(i) {
selectInput(row.names(conf())[i],label = row.names(conf())[i],choices = colnames(conf()))
})
)
})
output$ui <- renderUI({design()})
mul <- eventReactive(input$estimate, {
sapply(1:nrow(conf()), function(j) {
conf()[row.names(conf())[j],eval(parse(text = paste0("input$",row.names(conf())[j],sep = "")))]
})
})
output$prod <- renderText({paste("Product is: ",prod(mul(),na.rm = TRUE)*input$size)})
}
shinyApp(ui=ui,server = server)
when loading the xls sheet, 'Show Fields' button will show all the Rows as Drop-downs with columns as choices. So at last whatever I choose upon clicking 'Estimate' button Product will be shown of all corresponding values from excel sheet and the inputed size.
So now what I want:
1: All the boxes (numericInput & selectInputs) shall come in two or three columns. The page shall look filled.
2: The actual excel sheet I do have is not exactly I have shown above. It is actually like one you can see in the following image: 'enter image description here'.
Here A-E,U-Z,K-O are drop-downs choices, for corresponding rows(like A-Z for Ram, Shyam etc. , U-Z for Predeep, Sudeep and K-O for Aneeta). I want each such dropdowns and whatever user selects I need to provide the product of all corresponding values from excel sheet along with given Size.
I am trying this out for many days now, and now I am frustated. Somebody please do it.
I'm developing a shiny application where the user can upload a file and select X parameters, after that he press a button and it generates 5 plots (ggplot2 and barplot) and also a dynamic data table (DT). Also, I want to put my shiny app into a linux server.
I'm using tempfiles() for each file I'm using to create the plots and also the DT.
After that, my question is:
When the user closes the shiny app (close the window), do the tempfiles autodelete?
If not, what can I do to delete the tempfiles?
My tries:
session$onSessionEnded(function() {
if (!is.null(x1)) {
file.remove(x1)
}
if (!is.null(x2)) {
file.remove(x2)
}
if (!is.null(x3)) {
file.remove(x3)
}
if (!is.null(x4)) {
file.remove(x4)
}
if (!is.null(xx)) {
file.remove(xx)
}
})
Or:
session$onSessionEnded(function() {
files <- list.files(tempdir(), full.names = T, pattern = "^file")
file.remove(files)
})
With that code I delete the tempfiles when user presses the button once, and if the user presses the button more than 1 time then the window closes, and it will only delete the last generated files. The second part deletes all files at the temp dir but that affects to the other users?(I think yes so that's why I need another solution).
The .png tempfiles generated by ggplot and barplot doesn't autodelete.
My worry is that if the tempfiles won't autodelete and the linux server will collapse because of a lot of tempfiles.
Hope you can solve my doubts. Att Joan.
You can use the deleteFile=TRUE parameter if you want a render function to automatically delete your temporary files:
shinyServer(function(input, output, clientData) {
output$myImage <- renderImage({
# A temp file to save the output.
# This file will be removed later by renderImage
outfile <- tempfile(fileext='.png')
# Generate the PNG
png(outfile, width=400, height=300)
hist(rnorm(input$obs), main="Generated in renderImage()")
dev.off()
# Return a list containing the filename
list(src = outfile,
contentType = 'image/png',
width = 400,
height = 300,
alt = "This is alternate text")
}, deleteFile = TRUE)
})
A temp file is created to save the output, and that file is later automatically removed because of the deleteFile=TRUE argument.
The default Shiny (shiny.R) also has a built-in mechanism that clear file upload directories if that's your concern. The following code remove the upload directory when the session ends:
registerSessionEndCallbacks = function() {
# This is to be called from the initialization. It registers functions
# that are called when a session ends.
# Clear file upload directories, if present
self$onSessionEnded(private$fileUploadContext$rmUploadDirs)
}
Another point regarding manually deleting your temp files (as what you were attempting): the plot will have to render every time the user switched to another tab or resize his / her browser window, so if you're manually deleting the file, it may be inefficient since it needs to be re-rendered again. The onSessionEnded solution is nicer as it confirms that the session has ended.
session$onSessionEnded(function() {
if (!is.null(input$file1)) {
file.remove(input$file1$datapath)
}
})
I am following the simple file upload example from shiny gallery, but with a slight modification. I am required to modify the csv files locally, and see the changes reflected on the UI. However, I believe that this is not possible unless we poll for any changes in the source.
Therefore, I simplify the problem, by allowing re-uploading of the file. But, this is also not happening in Shiny. Once a file "file1.csv" is uploaded, i cannot upload the same file again. I have to upload a different file "file2.csv" and then once again the original file "file1.csv".
This is just time consuming, and I am wondering if anyone has come across such an issue, and possibly found a solution for it.
Adding a jquery to clear the value of the fileInput does the trick.
...
fileInput("csvInput", "Upload CSV file", multiple = TRUE,
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
tags$script('$( "#csvInput" ).on( "click", function() { this.value = null; });'),
...
Actually it is one of the shortcomings of Shiny's fileInput module: it stays still if the same file was selected again, and there is no force-upload option built-in.
To enforce re-uploading, the basic idea is:
After each time uploading, keep the uploaded data in a reactiveValues as storage.
Apply a new fileInput to replace original one
Show a successfully upload message under new fileInput for a better user experience.
In ui.R,using
uiOutput('fileImport')
In server.R:
# reactive storage
v <- reactiveValues()
# fileInput index
v$fileInputIndex <- 1
updateFileInput <- function (name = NULL){
# update output with a new fileInput module
output$fileImport <- renderUI({
index <- isolate(v$fileInputIndex)
result <- div()
result <- tagAppendChild(
result,
fileInput(paste0('file', index), 'Choose CSV File',accept=c('text/csv','text/comma-separated-values,text/plain','.csv'))
)
# show a message of successful uploading
if(!is.null(name)){
result <- tagAppendChild(
result,
div(name," upload complete")
)
}
result
})
}
dataInputRaw <- reactive({
# equals to `input$file1` when initialized
inFile <- input[[paste0('file', v$fileInputIndex)]]
# TICKY PART:
# 1. If initialized, `inFile` and `v$data` are both `NULL`
# 2. After each uploading, new `fileInput` is applied and
# we want to keep previous updated data.
# It also prevent recursive creation of new `fileInput`s.
if (is.null(inFile)){
return(v$data)
}
# load as data frame
v$data <- data.frame(read.csv(inFile$datapath))
# if file successfuly uploaded, increate the index
# then upload `fileInput` with successful message
if (!is.null(v$data)){
v$fileInputIndex <- v$fileInputIndex + 1
updateFileInput(name = inFile$name)
}
# return data
v$data
})
# init
updateFileInput()
I have tested this snippet and it works.
I'm working on a tcltk interface in R that creates a set of drop down combo boxes based on the fields in whichever dataset is loaded by the user. Right now I have a button ("getbox") to press after loading the data that reads the data then creates a combo box with an option for each field. I'd like to be able to re-create the combo box each time I press the button instead of adding a new combo box. Here is an example of what I have:
tt <- tktoplevel()
comboframe <- tkframe(tt)
getbox <- tkbutton(tt, text = "Create Combo Box", command = function() {
fields <- names(mtcars)
cbox <- tkwidget(comboframe, "ComboBox", editable = FALSE, values = fields)
tkgrid(cbox)
})
tkgrid(getbox)
tkgrid(comboframe)
I tried adding an if statement in the getbox command function, but couldn't get it to work.
if (exists(comboframe)) {
tkdestroy(comboframe)
} # then create combobox ...
Any thoughts on how to replace the combo box instead of adding a new one? Thanks!