I'm making a shiny app that takes a numericInput(size,...) and displays a data frame of random numbers with input$size rows, and then saves it as a csv. I'm looking for some way to prevent the user of the app to change the inputed number once they have provided it. For example, if the user sees the data frame and thinks "Oh, I don't like these numbers", I want to make sure they cannot just keep entering numbers until they get a result they want (without closing and reopening the app). Is there someway to fix the first input as it is given? Thank you so much!
You can use a combination of reactiveValue and observeEvent with the parameter once = TRUE
This will allow the reactiveValue to only be set once. The user can then change the input but it will have no effect on the rest of the app
size <- reactiveVal()
observeEvent(input$size,{
size(input$size)
},
once = TRUE)
You might have to look into the parameters ignoreInit and ignoreNULL depending on how you initate your numericInput.
Related
I have the following issue with the behaviour of R shiny's numeric input behaviour. Consider the following snippet:
ui <- basicPage(
numericInput("example","Example",value=0),
verbatimTextOutput("changelog")
)
server <- function(input,output){
output$changelog <- renderPrint(input$example)
}
shinyApp(ui,server)
Suppose that I want to update the example input field to 12345. My issue is that the default event listener would react to every keystroke. Thus the input field would be set to 1, 12,123 and 1234 before I finally get the desired value of 12345. Each numeric input set would be followed by an expensive computation - so this is a very undesirable behaviour.
What I am after is modifying this behaviour so that the event listener only reacts to the numeric input when the user hits enter or leaves the input field. I have currently two approaches to this:
Use a reactiveValue with an update actionButton so that the input is updated only when the user clicks update. I find this an inelegant solution and only shirks the original problem without solving it.
Modify the local shiny.js file directly and remove the keyup.textInputBinding event. That creates another issue with running the shiny app on other computers and it would make this modified behaviour uniform for all numericInput.
I'm wondering if anyone has a solution/suggestion to this? Preferably something that does not involve changing the local shiny.js file. I'm guessing a solution would involve using shinyjs::runjs to manually unsubscribe the keyup.textInputBinding event - but I don't know enough JavaScript to execute it.
You can slow frequent invalidation down with debounce or throttle. In your case, my first guess would be debounce: Debouncing means that invalidation is held off for millis milliseconds.
The reactive expression will only be validated until that time window has passed without a subsequent invalidation which may have an effect like this: ooo-oo-oo---- => -----------o-
In your case:
library(shiny)
ui <- basicPage(
numericInput("example","Example",value=0),
verbatimTextOutput("changelogImmediate"),
verbatimTextOutput("changelog")
)
server <- function(input,output){
exampleInput <- reactive(input$example) %>% debounce(1000)
# debouncedExampleInput <- exampleInput
output$changelogImmediate <- renderPrint(input$example)
output$changelog <- renderPrint(exampleInput())
}
shinyApp(ui,server)
When you do restore a Shiny session using the native Bookmark functionality in a dashboard with multiple tabItems, you fall on the one which was active at the moment of the bookmarking (legit). However, outputs (tab, plots, ...) from other tabItems() are not refreshed/recalculated until you actually click on them and be displayed in the browser. Is there a way to also during the restoration process recalculate those undisplayed outputs?
One possible non-elegant work around would be to have at the end of the onRestored() a bunch of updateTabItems() for each existing tabItems we want to display properly.
For those that could be interested, a general answer to this general question and as #starja suggested, is to use suspendWhenHidden = TRUE.
The idea is quite simple: by default each output object of a Shiny application is not run until it is requested to be displayed within the browser (suspendWhenHidden = TRUE). To change that behavior, simply add the following line of code in your server (not sure there is a specific place):
outputOptions(output, "my_output_name", suspendWhenHidden = FALSE)
Therefore, after a session restauration (bookmarking), even if you land on tab "B", every output of tab "A" with suspendWhenHidden = FALSE will be executed, therefore leading your reactive expressions depending on those outputs to be "refreshed" and correctly ran/displayed within tab "B".
I am wanting to write a program in Shiny that will keep up with the response time taken to interact with various objects. The simplest analogue would be something like a timed matching game wherein the user must select a specific object/stimulus, and I want to be able to find out later (i.e., after the application is finished) how long each response took and whether it was correct.
I already know how to do most of this program; however, I cannot find anyway within Shiny to keep up with response time let alone as a function of interaction with a reactive element. Based on preliminary searches, it seems like Javascript may have a solution; however, I know zero Javascript experience and also don't have any experience integrating it with Shiny.
Does anyone know of a way of using existing R/Shiny language to perform a count-up timer that could be used to time responses to multiple objects? Alternatively, does anyone have a potentially better solution to timing responses that I may be missing?
EDIT: ABOVE ISSUE ADDRESSED, BUT NEW ONE HAS COME UP IN AN EXTENSION OF THE ANSWER
I initially left this as a comment, but it was too long to fit in the length requirements. I've come up with a new issue. This time, I want to keep a running tab of how long it has taken between any two clicks but without knowing how many clicks a user may submit. I've played around some with the code given, but I can't get it to work (relevant pieces below, nothing else was changed):
if(total_timestamps == 2){
duration <- rbind(duration, as.numeric(difftime(new_val[2],new_val[1],units = "secs")))
new_val[1] <- new_val[2]
new_val <- new_val[-2, ]
click_timestamps(new_val)
### other things to do
}
My thought was to switch the old and new values and then delete the oldest value to make room for a new one to continue the cycle, but it's not working as I had hoped. Thoughts or help?
You don't need JavaScript for this. You can create a reactive value, and append value to it each time an element is clicked. If you need to observe multiple different elements, then just write more observers.
library(shiny)
ui <- fluidPage(
actionButton("button","Click"),
tags$h2("Response Time"),
tags$div(id = "duration")
)
server <- function(input, output, session) {
click_timestamps <- reactiveVal(NULL)
observeEvent(input$button,{
new_val <- append(click_timestamps(),Sys.time())
# set click timestamp
click_timestamps(new_val)
total_timestamps <- length(new_val)
if(total_timestamps == 2){
duration <- as.numeric(difftime(new_val[2],new_val[1],units = "secs"))
insertUI(
selector = "#duration",
ui = tags$p(paste0("Seconds between clicks: ", duration))
)
# reset click timestamp
click_timestamps(NULL)
}
})
}
shinyApp(ui, server)
I'm working on an app in R where the users need to choose a file from their computer, with a RShiny fileInput button. I want to modify this, so that the associated variable can be assigned (i.e. a file can be loaded) automatically by the programm, without having the user click on the button and choose the file.
The problem I'm facing is that a fileInput has 4 fields, amongst which I only can know 3. For instance, when I load the file hello.csv in the variable inFile through the normal procedure, here is what I get :
inFile$name = hello.csv
inFile$size = 8320
inFile$type = text/csv
inFile$datapath = C:\\Users\\MyName\\AppData\\Local\\Temp\\Rtmpkh8Zcb/7d5f0ff0111d440c7a66b656/0
Though I could have guessed the second and the third one knowing the file, I have no idea how the datapath field is assigned...
I've tried to declare inFile as a NULL global variable, then to assign one by one the different fields, but I'm stuck with this last one. Is there an other way to do, like a function that mimics the behaviour of a user who clicks on the file input button and choose a specified file ?
Thank you very much.
If all you're looking to do is load a file initially, you don't have to rely on Shiny functions to do that. You can just rely on R functions. Set up your app like this:
ui <- shinyUI(
fileInput("inFile", label="Choose a file", multiple=F)
)
server <- shinyServer(function(input, output, session) {
values <- reactiveValues()
dat <- reactive({
if (is.null(inFile$datapath)) {
dat <- read.csv("path/to/your.csv")
values$file_name = "your.csv"
values$file_type = "csv"
values$file_size = file.size("path/to/your.csv")
values$file_path = "path/to/your.csv"
} else {
dat <- read.csv(inFile$datapath)
values$file_name = inFile$name
values$file_size = inFile$size
values$file_type = inFile$type
values$file_path = inFile$datapath
}
})
})
shinyApp(ui=ui, server=server)
In the above code, the Shiny app will start and see that inFile$datapath is NULL and will load a predefined file of your choosing. It won't run again until inFile changes, at which point it will load the file that the user pointed to.
Hope that helps.
Update
I changed the code above to use reactiveValues to store the pieces of information that need to be used throughout the app. If you just set those and then do a find/replace for input$inFile$datapath and replace it values$file_path, your code should work just fine.
Here is how I figured it out :
I edited the original code, so that all the read.csv(...) are replaced with calls to a data.frame global variable. I also added a small button that you need to click on before you continue. This button saves what you just loaded in the Database (if you chose a file with the fileInput) and assigns the right values to the global variables that will be needed for the following operations. If you chose no file at all, it will directly assign the variables from the data found in the Database.
So I did not find a proper solution to the problem, but this is a workaround that will do the job in my case.
#brittenb I couldn't get your reactive solution to work as I wanted to, that's why I ended up doing this another way. Thanks for having taken the time to think about it though.
I'm still open to suggestions on how to update the file in a fileInput without user interaction.
So this is somehow a follow up to my previous: Automatic GUI Generating in R Shiny wher I posted the solution to how to generate elements iteratively.
Now I am unable to recieve/check which actionbuttons have been pressed and perform some action upon press.
In general, there is a function that generates the buttons and sends it to the ui.R:
output$generateImages <- renderUI({
(...)
i <-1
for(dir in folders){
(...)
txt<-paste0("rep",i)
pp<-pathNameToImage
LL[[i]] <- list(actionButton(txt,icon=imageOutput(pp,width="100px",height="100px"),label=dir))
i<-i+1
}
return(LL)
}
in ui.R I have:
uiOutput('generateImages')
And it displays the buttons fine by accumulating them into the list called "LL".
I have tried looking for tutorials and examples but was not able to find how it is done with images, and how to later recieve input from buttons that were not created "by hand", but iteratively.
How do I access these buttons in "observe" so that I can perform a action? I have tried input$generateImages, input$LL and few others, but all of them had a value of NULL.
You'll need to access them by their unique ID. The first argument passed to actionButton is its ID. That's what you'll need to use to get it as input.
So:
LL[[i]] <- list(actionButton("SomeID"))
when you assign it, then
input[["SomeID"]]
when you want to reference it. Of course, you can use a variable instead of a hardcoded string for the ID.