In Shiny, how can I update dependent inputs automatically? - r

I'm creating a Shiny app that allows a user to load existing input data from a list. However, what I find is that only the independent inputs are being updated while the inputs that are dependent on other inputs remain blank. Here is the code that updates the inputs upon an observeEvent action button:
observeEvent(input$load_project, { #observes the actionButton load_project
projects = Your_projects() #a reactive with list of input names and values
project_names = projects[[1]]
projects_data = projects[[3]]
project_inputs = projects_data[[input$your_projects]]
nInputs = length(project_inputs)
nameInputs = names(project_inputs)
for(k in 1:4){ #hoping if it loops several times the dependent inputs would
#appear but no luck
for(i in 1:nInputs){ #loop through all of the inputs
Type = typeof(project_inputs[[i]]) #get type of input
if(Type == "character"){
updateTextInput(session,nameInputs[i],NULL,value = project_inputs[[i]])
}
}}
})
The code works for updating independent inputs but not dependent inputs. If I create similar code for observing the event of a "refresh_inputs" button and press it then the dependents inputs are updated. But I'd like an automated way to do it.
Thanks for any help on this!

Related

Export user inputs in a Shiny app (with some being lists) to a file and load them later

I am trying to accomplish something very similar to what this poster asked.
However, some of the values that the user is able to input are lists.
For example, the input value input$file1 has sub-values input$file1$name,
input$file1$size,
input$file1$type, and
input$file1$datatype.
Furthermore, I have two inputs, input$remove and input$force, which can take in a list of strings from a selectInput field.
Lastly, the function that I am using to save the user inputs is saving the action buttons, and doing so in an odd format. These values are not loading properly when utilizing the load action button. Here is a sample of the code I am using to attempt this:
observeEvent(input$load,{
if(!file.exists('inputs.RDS')) {return(NULL)}
savedInputs <- readRDS('inputs.RDS')
inputIDs <- names(savedInputs)
inputvalues <- unlist(savedInputs)
for (i in 1:length(savedInputs)) {
session$sendInputMessage(inputIDs[i], list(value=inputvalues[[i]]) )
}
})
observeEvent(input$save,{
saveRDS( reactiveValuesToList(input) , file = 'inputs.RDS')
})
Thank you in advance for the help!

Clearing and re-reading variables in Shiny app

I made an app that takes user input of a googlesheet and boxplots it https://sjgknight.shinyapps.io/boxplotr/ and https://github.com/uts-cic/BoxPlotR.shiny/.
It's mostly working. The inputs aren't reactive, the user has to click a button to read them. But (a) If I have a default 'value' in the input that causes problems, and (b) if a user changes their input and then it gives an error.
E.g. with this data https://docs.google.com/spreadsheets/d/1ycTplwz5q21s1Z3QzpeoP5rMKlkJnQ12GBJJyIU2_q0/ I should be able to create a 'Region' boxplot, and then change the input to 'Income', click the 'click to load data' button again, and I get an error unless I refresh and clear the URL.
Using the guidance at http://shiny.rstudio.com/articles/action-buttons.html I know I can create a 'clear' button that I guess removes all the values, but I'm not clear how I'd go about just re-reading the inputs. I have an isolate block and just tried setting the variables in that to NULL, which doesn't work. Welcome ideas on how to do this. Looking at other questions I'm mostly seeing issues around updating the UI based on user inputs passed to the server.
So, I figure I need to use observeEvent, but this doesn't seem to work:
observeEvent(
input$gloadsheet, {
isolate({
gs_data <- gs_url(input$gsheetURL)
data <- data.frame(gs_read(gs_data, ws = input$gsheetws))
data$nID <- row.names(data)
data <- reshape(data[c("nID",input$ggrouping,input$gdataID)], idvar = "nID", timevar = input$ggrouping, direction = "wide")
data <- data[,-c(1:2)]
data <- data.frame(data)
data
})
}
)
Alternatively, I thought I could use eventReactive per this question Shiny Reactivity Explaination (using ObserveEvent). It may be that the issue is the block this code is based in (which is a reactive to get a variable based on multiple options users can click through).
data <- eventReactive(input$gloadsheet, {
isolate({
gs_data <- gs_url(input$gsheetURL)
data <- data.frame(gs_read(gs_data, ws = input$gsheetws))
data$nID <- row.names(data)
data <- reshape(data[c("nID",input$ggrouping,input$gdataID)], idvar = "nID", timevar = input$ggrouping, direction = "wide")
data <- data[,-c(1:2)]
data <- data.frame(data)
})
data
})
data
You can try this on your server-side:
update <- reactiveValues(please = 0)
observeEvent(input$clearValues, {
updateTextInput(...) # Clear everything #
update$please <- update$please + 1
})
inYourRenderingFunction <- render..({
update$please
.
.
})
You create a reactive value that change after clear your inputs. Your render functions has to react to this reactive value (update$please)
I'm using this already. Hope it helps to you.

How to get the input that is invalidated in Shiny?

I'm trying to update a text box based on the click events in multiple graphs. I use the observeEvent function to trigger the update of the text box. A snippet of the code is shown below.
observeEvent({
input$plot1_click
input$plot2_click
input$plot3_click
...
}, {
# only need the invalidated input
invalid_input <- which.invalid(input$plot1_click,
input$plot2_click,
input$plot3_click,
...)
updateTextInput(session,
"textbox",
label = NULL,
value = invalid_input)
})
Currently the updateTextInput function will run whenever there's a click in any of the plots, which is desired, but I can't figure out how to capture which plot is clicked last and should be used to update the text input. Is there a function to check which input is invalidated from a list of inputs?
Hi I think the easiest way is to make a separate observer for each input. This way the input that was changed last will always processed last. You can put it in a lapply if you don't want to bloat you code with repetitive code. It could look something like this
lapply(1:3, function(idx){
observeEvent({input[[paste0("plot",idx,"_click")]]},
{updateTextInput(session,
"textbox",
label = NULL,
value = input[[paste0("plot",idx,"_click")]])})
})
Hope this helps!

How to send data (selected radiobutton) in R to googlesheets for every new user?

I wish to take feedback from the user asking "Did you like the song suggestion?" (Options will be "Yes" or "No"..) for every new user and send this data to googlesheets. On every new user, I want the googlesheet to get updated instead of creating new sheet for new user. How do I do it? Please help.
ui.r
This is in main panel
radioButtons("feedback","Did you like song suggestion?",list("Yes"="Yes","No"="No"),""),
actionButton("increment","Submit Feedback"), uiOutput("count"),
server.r logic
# A reactiveValues object holds the value of the counter
values <- reactiveValues(i = 0)
# Print the value of the counter stored in values$i
output$count <- renderUI({
h4(paste0(values$i,"are the no of users who have liked song suggestion"))})
# The observers re-run the code whenever the button is clicked
# Use isolate to avoid getting stuck in an infinite loop
observe({
chosen <- input$increment
isolate(values$i <- values$i + 1)
})

R Shiny: mirror R console outputs to Shiny

I made a function that is performing some complex calculations via a for loop. In order to show progress, the function will print out the current progress via something like message(...), and the final outcome of this function is a data frame.
But when I implement this in Shiny, the for loop counter is printed only in the R console rather than the Shiny document as intended. Is there a way to showing the outputs in the R console in real time during executions?
A very minimal example is here. Notice that in the Shiny interface, the counter is not present.
foo <- function() {
ComplexResult = NULL # vector initiation
for(i in 1:5){
ComplexResult[i] = letters[i]
# At each stage of the for loop, we store some complex calculations
message(paste0("For loop counter is on i = ", i))
# This shows progress of the for loop, also other relevant messages if necessary.
Sys.sleep(0.1) # Comment this out to remove pauses during execution.
}
return(as.data.frame(ComplexResult))
}
runApp(shinyApp(
ui = fluidPage(
dataTableOutput("VeryFinalOutcome")
),
server = function(input,output, session) {
fooOutcome = foo()
output$VeryFinalOutcome = renderDataTable(fooOutcome) # This will only display the function output (i.e. the letters) in Shiny.
}
))
My attempt: the capture.output(foo(),type="message") function did not help. Even though it captured the messages successfully, but it can only be displayed after all execution. And there is a extra issue of not being able to store the actual foo() outputs.
Thanks

Resources