How to get the input that is invalidated in Shiny? - r

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!

Related

Problem with combination of hide(), show() and reset() in shiny

I have been having problems combining the hide(), show() and reset() functions from the shinyjs package.
I have two divs. One div collects data using multiple user inputs and ends with a submit button. Once the submit button is pressed, another div should appear that shows the collected data in a table. In this second div, there is another button that should reset the original giv and show it again so that more data can be collected.
I tried to produce a reproducible example using some code from the shinyjs help page:
library(shiny)
library(shinyjs)
shinyApp(
ui = fluidPage(
useShinyjs(),
div(
id = "form",
textInput("name", "Name", "Dean"),
radioButtons("gender", "Gender", c("Male", "Female")),
selectInput("letter", "Favourite letter", LETTERS)
),
div(
id = "formreset",
textInput("name", "Newform", "Dean"),
radioButtons("gender", "Newform", c("Male", "Female")),
selectInput("letter", "Newform letter", LETTERS)
),
actionButton("reset_originalDiv", "Reset to original div"),
actionButton("resetName", "Reset name"),
actionButton("resetGender", "Reset Gender"),
actionButton("change_div", "Change div")
),
server = function(input, output) {
observeEvent(input$resetName, {
reset("name")
})
observeEvent(input$resetGender, {
reset("gender")
})
observeEvent(input$change_div, {
hide("form")
show("formreset")
})
observeEvent(input$reset_originalDiv, {
reset("form")
hide("formreset")
show("form")
})
}
)
As you can see, when clicking the "Reset to original div", the original div is not shown again.
Where is my mistake?
Thank you very much in advance.
Up front: perhaps show(.) is not the show you think it is, use shinyjs::show.
Finding this: add a debugging step to one of the observeEvent blocks that calls show:
observeEvent(input$change_div, {
browser()
hide("form")
show("formreset")
})
Run the app, then click on the appropriate button.
If we look at hide, it is what we think it should be:
Browse[2]> hide
function (id = NULL, anim = FALSE, animType = "slide", time = 0.5,
selector = NULL, asis = FALSE)
{
...
}
<bytecode: 0x000000000a6a7538>
<environment: namespace:shinyjs>
However, perhaps show is not:
Browse[2]> show
standardGeneric for "show" defined from package "methods"
function (object)
standardGeneric("show")
<bytecode: 0x000000001b740f30>
<environment: 0x000000001a823fb0>
Methods may be defined for arguments: object
Use showMethods(show) for currently available ones.
(This generic function excludes non-simple inheritance; see ?setIs)
This is showing us methods::show, whose first argument is indeed a character, and its return value is not really important to us in general, since shinyjs::show's return value is NULL, operating solely in side-effect. Because of what it does, we will get no warning or error indicating something might be amiss.
If you change all of your references to shinyjs::show, perhaps it will work.
Note: the first time I ran this app, it behaved as I just documented with the incorrect show. Once I tested the fix, now I cannot reproduce the problem with regular show("formreset"), so it is possible that something else may be going on. Using shinyjs::show is never wrong or different (unless you really are expecting to use a different show).
I'm not positive on the why of the behavior, but if you remove the hide("formreset") and move reset("form") to the last call made in the observeEvent(input$reset_originalDiv... you get the behavior you're looking for.
observeEvent(input$reset_originalDiv, {
shinyjs::show("form")
reset("form")
# hide("formreset")
})
You might want to use toggle in an observe({}) block based on the style condition of the form div class, which when hidden is "display:none" to manage the formreset button.

How to add Update (Refresh) Button to the app.R

I added the button but the values will automatically change before I hit "Update Order", I don't know how to fix it. Should be like this:enter image description hereBelow is my code:
library(shiny)
ui <- fluidPage(
titlePanel("My Simple App"),
sidebarLayout(
sidebarPanel(
helpText("Controls for my app"),
selectInput("fruitchoice",
label = "Choose a fruit",
choices = list("Apples",
"Oranges",
"Mangos",
"Pomegranate"),
selected = "Percent White"),
sliderInput("amt",
label = "Order Amount:",
min=0, max = 100, value=20),
actionButton ("Update","Update Order")
),
mainPanel(
helpText("Fruit Chosen:"),
verbatimTextOutput("fruit"),
helpText("Order Amount"),
verbatimTextOutput("amt")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
SelectInput <- eventReactive (input$Update , {
runif(input$fruitchoice,amt)
})
output$fruit = renderText(input$fruitchoice)
output$amt = renderText(input$amt)
}
# Run the application
shinyApp(ui = ui, server = server)
I will show you, how to rewrite your code to get this update behavior, however I would like to also get you know that this part of code:
SelectInput <- eventReactive (input$Update , {
runif(input$fruitchoice,amt)
})
Is wrong for three reasons: (1) object amt do not exists, you probably want input$amt; (2) even if you change amt to input$amt code won't work and you will get error; (3) now you are not using SelectInput in any place in your application, so there is no reason for this part to exists, however as I don't know what is your aim and how will look the final app, I'm not saying this is generally wrong.
Ok, so now about this update button. We will focus on this code:
output$fruit = renderText(input$fruitchoice)
output$amt = renderText(input$amt)
Here you instruct program to (re)render text when input$fruitchoice or (in second line) when input$amt change, but you want to (re)render text only when user clicks the button, so you need two things - first, be sure that user clicked the button and do not (re)render text when one of input$ changes. This will work:
output$fruit = renderText({
req(input$Update)
isolate(input$fruitchoice)
})
output$amt = renderText({
req(input$Update)
isolate(input$amt)
})
If I understand Shiny correctly, isolate() makes sure that text is not (re)rendering when input$ changes (however it has internally the new values) and req() makes sure that the input$Update was clicked; and when is clicked again, Shiny recomputes [(re)renders] text. It recomputes, because we didn't use isolate() on input$Update I think.
There's a few things wrong in your code. I will give a bit of explanation for each one:
You are initializing with reactive inputs. By using renderText(input$...) you create a text output that updates automatically when your input updates. Automatically is the problem here, you don't want that. We are going to write an alternative method that stores the inputs in a separate variable that we only allow to be updated when the button is pressed. We initialize that variable like so:
rv <- reactiveValues(fruit = "Apples",
amt = 20)
EventReactive creates a reactive variable that can later be used in the code. Generally speaking what you want to use in these kind of scenarios is observeEvent. You can do so like this:
observeEvent (input$Update , {
rv$fruit <- input$fruitchoice
rv$amt <- input$amt
})
We now have a list of variables under the name "rv" and an observeEvent that updates this variable every time the button gets pressed. All that is left to do is create the renderText which you can do like so:
output$fruit <- renderText(rv$fruit)
output$amt <- renderText(rv$amt)

RenderPlot doesn't display twice

I am trying to display some plots using renderplot(), and when i update y plots, it stays how it was before...
Let's have a look on my code:
UI.R
...
uiOutput("firstGraph")
uiOutput("seconfGraph")
uiOutput("thirdGraph")
...
server.R
observeEvent({input$CalcBtn,
output$firstGraph <- renderUI ({
if (dataTab$tabOne != 0) {
plotOutput(plotsValue$graphOne)}
}))
observeEvent({input$CalcBtn,
output$secondGraph <- renderUI ({
if (dataTab$tabTwo != 0) {
plotOutput(plotsValue$graphTwo)}
}))
observeEvent({input$CalcBtn,
output$thirdGraph <- renderUI ({
if (dataTab$tabThree != 0) {
plotOutput(plotsValue$graphThree)}
}))
output$graphPlot121 <- renderPlot({...})
Here, input$CalcBtn is a button that makes a calculation and "refresh" the page. dataTab$tabOne (dataTab$tabTwo and dataTab$Three are approximately the same as dataTab$tabOne) is determinated by a function that reads an argument and transform it into a number. 0 if it must not print the plot and a number like 121 if it must print the plot 121. in plotsValue, the graphOne, graphTwo and graphThree are character strings made before using the value of dataTab, so it looks like "graphPlot121". So when I click the button, the programm makes everything great, expect displaying a second time the plot when I modify the inputs used inside the renderPlot.
The programm works well when I change from one plot to the other, but the problem comes when I try to display twice the same.
Please, help me if you know how to refresh the plot when I update it.

In Shiny, how can I update dependent inputs automatically?

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!

selectize - shiny, action for multiple choices

still learning how to use Shiny/R, sorry if the answer is obvious
trying to cast on the map various layers based on selectize choices (multiple)
So i got:
selectizeInput('bays', 'Select rough bay outlines',
choices = list("Residents" = "residents", `Pay to park` = "ptp",
"Shared use" = "shared"), multiple = TRUE)
Every equivalent is a geojson file that should be used for the map (here "residents", but of course it populates with a selected option from the selectize input):
topoData <- readLines("residents.geojson", warn = FALSE)
%>% paste(collapse = "\n")
leafletProxy("mymap") %>%
addPolylines(topodata)
how can i construct the observeEvent(input$bays,...) so every choice triggers the action above (with the right geojson file of course)? I can do it for a single choice but a multiple choice might call for another way. And would it be more effective to use a submit button or react to actions? Please note that it can be either adding or removing value from the selectize list? And finally there is a cool gadget in selectize - plugin "remove_button" - adding the entries with a little marker to remove the item - i have seen it for javascript but not for shiny - is it possible somehow?
$('#input-tags3').selectize({
plugins: ['remove_button'],
delimiter: ',',
persist: false,
create: function(input) {
return {
value: input,
text: input
}
}
});
You do not want an observeEvent but a reactive. Something like this should work:
# server
topoData <- reactive(
paste(
lapply(
paste0(input$bays,".geojson"), function(geojson) {
readLines(geojson)
}
),collapse="\n")
)
leafletProxy %>% addPolyLines(topoData())
input$bays is a vector of the selected geojson files, and it is reactive so as people change the selectize input the value updates in the server inside of reactive statements (and observe statements).
topoData is a reactive the returns the geojson files that are selected. If I understand correctly you just went to paste the different files on top of each into a single character. The leafletProxy may have to go inside an observe, I'm not sure.

Resources