gWidgets: How to save user's work in the application? - r

I have been building application in R with gWidgets.
Application includes several editable tables, working sheets etc - basically works something like MS Excell, but for special purpose.
When the user will save the work done and exit application, he/she should be able to continue working from where he/she ended - something like clicking on the icon or importing "working document" into the application - so that all sheets and data will be opened (again something like MS Excell etc.) and the same as they were when application was closed.
However, I have no idea how to do that. Can anyone help?

Some pattern like this should work:
library(gWidgets2)
# Global variables
widgets <- list()
values <- NULL # or a list()
state <- NULL
## Layout GUI
w <- gwindow("Test")
g <- ggroup(cont=w)
g1 <- ggroup(horizontal=FALSE, cont=g)
save_btn <- gbutton("Save state", cont=g1)
restore_btn <- gbutton("restore state", cont=g1)
widgets$w1 = gedit("some text", cont=g)
nb = gnotebook(cont=g)
widgets$w2 = gradio(c("a","b","c"), label="radio", cont=nb)
widgets$w3 = gtable(mtcars[1:3,1:3], label="table", cont=nb)
# Save and restore actions
addHandlerClicked(save_btn, handler=function(...) {
values <<- lapply(widgets, svalue, index=TRUE)
state <<- lapply(widgets, "[")
})
addHandlerClicked(restore_btn, handler=function(...) {
if (!is.null(values)) {
for (nm in names(widgets)){
## screen for widgets without values
if (length(state[[nm]]))
widgets[[nm]] <- state[[nm]]
print(list(widgets[[nm]], values[[nm]]))
svalue(widgets[[nm]], index=TRUE) <- values[[nm]]
}
}
})

Related

multiple inputs in a same form gwidgets2

I am trying to put several ginputs into a form in gWidgets2, or to get the text entered in a gedit widget as a list or something to use in the rest of the code,
library(gWidgets2)
options(guiToolkit = "tcltk")
prj_name = ginput("Project name")
user = ginput("User name")
transfer = ginput("Transfer amount")
I tried with gformlayout but they ginput apparently can't be contained in one; and I haven't found how to pass the inputs on the widget to an object (a list in this case) in R
ginput is a dialog. The widget you want is gedit. This example is from the help page of gformlayout
w <- gwindow("gformlayout", visible=FALSE)
g <- gvbox(container=w)
flyt <- gformlayout(container=g)
gedit("", label="Name:", container=flyt)
gedit("", label="Rank:", container=flyt)
gedit("", label="Serial No.:", container=flyt)
b <- gbutton("Show me", container=g, handler=function(h,...) {
print(svalue(flyt))
})
addSpring(g)
visible(w) <- TRUE

How do I access outputs in Shiny renderUI, and write these to multiple .csv / .zip

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

Trying to use reactiveFileReader with AWS S3 files to update Shiny app

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

R shiny output table before program finishes execution

I created a dashboard with 15 data tables in Shiny. Each table draws data from an API and this process takes some time. So I want to output each table to ui at a time such that users can read the first table while the other ones load. But it seems Shiny always holds all output until server function finishes execution. Is there a way to change this?
I had a similar problem with an app once. What I did was to do the calculations that take much time in another R session. Maybe now there are packages that make it easier, but here is how I solved it:
You can make an observeEvent which is triggered by an actionButton. In this observer you start another R session (with a system call to Rscript for example).
Then the app is still responsive while an R session in the background is doing all the calculations.
To retrieve information from the background process you can use shiny's reactivePoll function.
In your case the background R session would do the process each table and write the result into a file once it is done with a table. The reactivePoll would watch out for these files. Once such a file appear the reactivePoll function can read it and present it as a reactive. The value of this reactive can then be rendered somehow for the user to see.
This way each table is processed 1 by 1, while the app is still responsive and able to show results while the background process is still running.
Here is a app that shows the principle.
server
library(shiny)
# batch process communicates via file
write("", "tmp.info")
# cheap function to check for results
cheap <- function() scan("tmp.info", what = "")
shinyServer(function(input, output, session) {
# start process
observeEvent(input$go, {
system2("Rscript", args = c("batch.r", input$num1, input$num2),
stdout = "", stderr = "", wait = FALSE)
})
# watch file
watch <- reactivePoll(500, NULL, cheap, cheap)
# retrieve result from batch process
result1 <- reactive(if(length(watch()) > 0) watch()[1] else NULL)
result2 <- reactive(if(length(watch()) > 1) watch()[2] else NULL)
# show results
output$add <- renderPrint(result1())
output$multiply <- renderPrint(result2())
})
ui
library(shiny)
shinyUI(fluidPage(sidebarLayout(
sidebarPanel(
h2("Add and multiply"),
numericInput("num1", "Number 1", value = 1),
numericInput("num2", "Number 2", value = 1),
helpText("Both numbers are added, and multiplied. Each calculation takes 4 sec."),
br(),
actionButton('go', 'Start')
),
mainPanel(
h4("Result of Addition"),
verbatimTextOutput("add"),
h4("Result of Multiplication"),
verbatimTextOutput("multiply")
)
)))
batch.r
# read info
args <- commandArgs(TRUE)
args <- as.numeric(args)
# add
res <- args[1] + args[2]
Sys.sleep(4)
write(res, "tmp.info")
# mult
res <- args[1] * args[2]
Sys.sleep(4)
write(res, "tmp.info", append = TRUE)
quit(save = "no")
server.r ui.r and batch.r must be in the same directory. A file "tmp.info" is created which is used for communication. The results are directly read from this file and batch.r is started with the input as parameters. You can also use files for all that.

Create general purpose "go back" button in shiny

I want the user to input a value in a text box in shiny and then be able to click on a button to review the value s/he typed before. I got this to work with the code below, but it is far from ideal. For one thing it requires me to click the "go back" button twice to work (no idea why). Any suggestions are appreciated. (Also, note that I included the table of iterations in the output just for reference).
library(shiny)
q <- new.env() # create new environment
assign("iteration",1,envir = q)
log <- data.frame(iteration=NULL,id=NULL)
assign("log",log,envir = q)
ui <- fluidPage(
actionButton("back", "go back"),
textInput("id","enter id",value=1),
tableOutput("x")
)
server <- function(input, output,clientData, session) {
observeEvent(input$id,{
id <- input$id
iteration <- get("iteration", envir = q) # get iteration
log <- get("log",envir = q) #'gets df'
temp <- data.frame(iteration=iteration,id=id,stringsAsFactors = F)
if (!nrow(log)) log <- rbind(log,temp) # for first iteration only
else log[iteration,] <- temp
assign("log",log,envir = q)
iteration <- iteration+1
assign("iteration",iteration,envir = q)
})
# back button
observeEvent(input$back,{
iteration <- get("iteration", envir = q) # get iteration
iteration <- iteration-1
assign("iteration",iteration,envir = q)
log <- get("log",envir = q) #'gets df'
#get data
id <- log$id[iteration]
updateTextInput(session,"id", value=id)
})
# for visualising table
x <- eventReactive(input$id,{
get("log",envir = q)
})
output$x <- renderTable({x()})
}
shinyApp(ui = ui, server = server)
I want a "go back" button than one clicked shows the value typed previously in the text box.
(A similar question exist, but I do believe mine is different enough).

Resources