R Shiny server variable definition. modified value is not reflected - r

Might be a basic question. But could not find a solution in the net.
Issue is i want to define a variable in server.r as below
function(input, output, session) {
currentrunid <- ""
Then on a submit button click i want to assign a value to it.
observeEvent(input$submit, {
currentrunid <- 1234 #Its dynamic
Then on a status button click i want to retrieve the value of the variable. The variable is used to retrieve the files generated as part of the submit.
observeEvent(input$checkstatus,{
runid <- currentrunid
Getoutputfiles(runid)
But the problem is the value assigned on submit Button is not available on Status button click.
Tried session$currentrunid <- 1234 But got an error as below
cannot add bindings to a locked environment
I have used <<- But i was suggested, i should not use this, instead, i should use reactive variable. But could not successfully implement it yet.
Please let me know what is the best practice here. Or how to implement reactive

I don't understand what you want to do so I'm not sure this answer is appropriate. Maybe you need a reactive value, like this:
function(input, output, session) {
currentrunid <- reactiveVal()
observeEvent(input$submit, {
currentrunid(1234) # this assigns 1234
})
# to get the value, do currentrunid(), for example:
observe({
print(currentrunid())
})
......

Related

How to make changes reflect in many places when input is changed without ObserveEvent() in shiny

I have an input variable input$shop_id. Which is used to get data in server function using:
observeEvent(input$shop_id,{id<<-input$shop_id})
`Data=dbGetQuery(connection_name,paste0("SELECT * FROM tab_name WHERE id_shop=",id"))`
That Data is further used to create dynamic UI using selectInput()
output$dependant=renderUI({
selectInput("choice","Choose the Data you want to view",names(Data))
})
I can't come up with the logic of the arrangement of these functions. I cannot get it to work. I have created a sample data and similar sample code for someone to try on:
library(shiny)
library(ggplot2)
ui=fluidPage(
column(6,uiOutput("shop_select")),
column(6,uiOutput("cust_select")),
column(6,uiOutput("select3")),
column(12,offset=6,uiOutput("plot"))
)
server = function(input, output) {
#sample data
shopdata=data.frame(id=c(1,2,3,4,5,6,7,8,9,10),name=c("a","b","c","d","e","f","g","h","i","j"))
cdata=data.frame(id=c(123,465,6798,346,12341,45764,2358,67,457,5687,4562,23,12124,3453,12112),
name=c("sadf","porhg","wetgfjg","hwfhjh","yuigkug","syuif","rtyg","dygfjg","rturjh","kuser","zzsdfadf","jgjwer","jywe","jwehfhjh","kuwerg"),
shop=c(1,2,1,2,4,6,2,8,9,10,3,1,2,5,7),
bill_total=c(12341,123443,456433,234522,45645,23445,3456246,23522,22345,23345,23454,345734,23242,232456,345456),
crating=c(4,4.3,5,1.2,3.2,4,3.3,2.4,3.8,3,3.2,3.3,1.4,2.8,4.1))
output$shop_select=renderUI({
selectInput("shop_id","Shop ID",shopdata$id)
})
output$cust_select=renderUI({
selectInput("cust_id","Customer ID",cdata$id,multiple = T)
})
output$select3=renderUI({
a=input$shop_id
selectInput("choice","Choose the Data you want to view",names(cdata))
})
output$plot=renderUI({
renderPlot({
require(input$choice)
plotOutput(
ggplot(cdata,aes(x=cust_id,y=input$choice))
)})})
}
shinyApp(ui=ui,server=server)
I know I am not clear on the question. Fixing the code which I posted is more than enough to clear my doubt. Basically, I just need to know what is the logic when we have to use while using a renderUI() which is dependent on another renderUI()
If you want to set up a series of subsetting operations and then call renderUI()s on each subset, you will need to take advantage of Shiny's reactive({}) expressions.
Reactive expressions are code chunks that produce variables and their magic is that they "watch" for any changes to their input data. So in your case one you select a shop_id in the first UI element, the reactive expression detects that and updates itself, automatically!
Here is an example showing the updating, just select different shop_id's and watch the available cust_ids change on the fly.
library(shiny)
library(ggplot2)
library(tidyverse)
ui=fluidPage(
column(6,uiOutput("shop_select")),
column(6,uiOutput("cust_select")),
column(6,uiOutput("select3")),
column(12,offset=6,tableOutput("plot"))
)
server = function(input, output) {
#sample data
shopdata=data.frame(id=c(1,2,3,4,5,6,7,8,9,10),name=c("a","b","c","d","e","f","g","h","i","j"))
cdata=data.frame(id=c(123,465,6798,346,12341,45764,2358,67,457,5687,4562,23,12124,3453,12112),
name=c("sadf","porhg","wetgfjg","hwfhjh","yuigkug","syuif","rtyg","dygfjg","rturjh","kuser","zzsdfadf","jgjwer","jywe","jwehfhjh","kuwerg"),
shop=c(1,2,1,2,4,6,2,8,9,10,3,1,2,5,7),
bill_total=c(12341,123443,456433,234522,45645,23445,3456246,23522,22345,23345,23454,345734,23242,232456,345456),
crating=c(4,4.3,5,1.2,3.2,4,3.3,2.4,3.8,3,3.2,3.3,1.4,2.8,4.1))
output$shop_select=renderUI({
selectInput("shop_id","Shop ID",shopdata$id)
})
cdata_reactive <- reactive({
req(input$shop_id)
filter(cdata, shop == input$shop_id)
})
output$cust_select=renderUI({
selectInput("cust_id","Customer ID",cdata_reactive()$id, multiple = T)
})
output$select3=renderUI({
selectInput("choice","Choose the Data you want to view",names(cdata_reactive()))
})
output$plot <- renderTable({
filter(cdata_reactive(), id %in% input$cust_id) %>%
.[input$choice]
})
}
shinyApp(ui=ui,server=server)
A renderUI generates UI elements. Therefore it can only contain ui functions. You need to use it to generate the plotOutput and then use renderPlot separately to add content.
The names you assign in the aes call are the names of variables in the data frame you provided. Therefore x should be id not the values of input$cust_id (which must be called as input$cust_id, since it refers to an input object.
input$choice returns a string, not an object, so you can't use it normally in aes (recall that if this was a normal dataframe your aes would be aes(x=id, y=choice) not aes(x='id', y='choice'). Therefore, you need to use aes_ with the as.name function to convert those strings into proper variable names.
What I think you want to do with input$cust_id is filter cdata to only include rows with the chosen id values. dplyr::filter is the best way to do that.
Finally, you're missing a geom_* in your ggplot call which is needed to actually render your data.
If you replace your output$plot <- ... call with the below code it should work the way I think you want it to:
output$plot=renderUI({
plotOutput('plotout')
})
output$plotout <- renderPlot({
ggplot(dplyr::filter(cdata, id %in% input$cust_id),
aes_(x=as.name('id'),y=as.name(input$choice))) +
geom_point()
})
As for the question in your title, you only need to use observeEvent if you want to limit the code in the expression to only run when a specific trigger occurs. Any reactive expression (reactive, observe, render_ etc.) will become invalidated and update itself if any reactive value (either a reactiveValues object or an input$...) changes. If you have an input$ or a reactive value in a render_ block, it will update if they change -- no observeEvent needed.

R Shiny make two inputs equal

I want to somehow make two inputs equal to one another when I press an Actionbutton. I have several tabs in my Shiny Dashboard and in some of the tabs there are repeat data inputs. For example, in tab 1 we have an input for AGE, we have the same input in tab 2. I want to make it such that if I input a value for age and click "run" (an Actionbutton), then it automatically makes the age in the other tab equal to the one in the current tab.
I'm really really new to using Shiny, so I made a few attempts at using reactive commands, but I'm not sure why it isn't working:
reactive(
if(input$runbutton==0){
input$numeric1=input$numeric2
})
That code has no effect, it doesn't even return an error.
You should use updateNumericInput() to change the value of an input. Also it makes more sense to use observeEvent() to track button presses. Here a simple sample application
ui <- fluidPage(
numericInput("numeric1","in1",1),
numericInput("numeric2","in2",2),
actionButton("runbutton", "set equal")
)
server <- function(input, output, session) {
observeEvent( input$runbutton, {
updateNumericInput(session, "numeric1", value=input$numeric2)
})
}
shinyApp(ui=ui, server=server)

Shiny - Updating UI after API call inside observeEvent

My UI has an activeButton and whenever the user presses it, the following observeEvent method calls an API and returns a numeric value.
observeEvent(input$submit, {
url <- "http://my_ip/predict?"
value <- paste0('value=', input$value)
response <- POST(paste0(url,value))
predicted <- as.numeric(content(response))
})
The problem is that I want to show the result ("predicted" variable) in a infoBox in the UI, but only when predicted has a value. Therefore, that infoBox has to be hidden until the user presses the button the first time.
What kind of output should I put in the UI?.
How could "predicted" behave like input$value?.
Thank you very much in advance.
EDIT
The solution was using the function reactiveValues() when calling the API:
reactiveValues <- reactiveValues()
reactiveValues$predicted <- as.numeric(content(response))
And then, using the function renderInfoBox() based on the previous value.
To update this from the comments above:
Use reactiveValues to add the response to it.
reactiveValues$predicted <- as.numeric(content(response))
then bind it to the infoBox

Shiny: Make list of UIs relate dynamic

With shiny it is very easy to create n inputs by creating a list of UIs like so (I am using ... to save space):
output$test <- renderUI({
lapply(1:input$count, function(x) numericInput(paste0('numId',x),...))
})
Let's say I want to dynamically set each numericInput's minimum to be the value of the previous numericInput. This won't work:
output$test <- renderUI({
lapply(1:input$count, function(x)
if (x==1) numericInput(paste0('numId',x),...))
else numericInput(paste0('numId',x),min=eval(parse(text=paste0("input$numId",x-1))),...))
})
It seems that using eval/parse to use the previous input as a parameter fails.
My next idea was to try adding this to the original code:
observe({
if (input$count>1) {
for (i in 2:input$count) {
updateNumericInput(paste0("numId",i),min=eval(parse(text=paste0("input$numId",i-1))))
}}})
Problem here is that observe doesn't know to respond when the numId's are updated because none of the objects input$numIdx are actually in the observe statement, just strings that are turned into those objects when observe is run.
Any ideas on how to handle this? It would be very nice to be able to generate n inputs, and make them relate to each other dynamically.
Regards

Can I save the old value of a reactive object when it changes?

Note: After coming up with the answer I reworded the question to make if clearer.
Sometimes in a shiny app. I want to make use of a value selected by the user for a widget, as well as the previous value selected for that same widget. This could apply to reactive values derived from user input, where I want the old and the new value.
The problem is that if I try to save the value of a widget, then the variable containing that value has to be reactive or it will not update every time the widget changes. But, if I save the the value in a reactive context it will always give me the current value, not the previous one.
How can I save the previous value of a widget, but still have it update every time the user changes the widget?
Is there a way that does not require the use of an actionButton every time the user changes things? Avoiding an actionButton can be desirable with adding one is otherwise unnecessary and creates excess clicking for the user.
Seeing as the session flush event method seems to be broken for this purpose, here is an alternative way to do it using an observeEvent construct and a reactive variable.
library(shiny)
ui <- fluidPage(
h1("Memory"),
sidebarLayout(
sidebarPanel(
numericInput("val", "Next Value", 10)
),
mainPanel(
verbatimTextOutput("curval"),
verbatimTextOutput("lstval")
)
)
)
server <- function(input,output,session) {
rv <- reactiveValues(lstval=0,curval=0)
observeEvent(input$val, {rv$lstval <- rv$curval; rv$curval <- input$val})
curre <- reactive({req(input$val); input$val; rv$curval})
lstre <- reactive({req(input$val); input$val; rv$lstval})
output$curval <- renderPrint({sprintf("cur:%d",curre())})
output$lstval <- renderPrint({sprintf("lst:%d",lstre())})
}
options(shiny.reactlog = TRUE)
shinyApp(ui, server)
Yielding:
Update This answer was posted before the advent of the reactiveValues/observeEvent model in shiny. I think that #MikeWise 's answer is the better way to do this.
After some playing around this is what I came up with. The ui.r is nothing special
ui.r
library(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectizeInput(inputId="XX", label="Choose a letter",choices=letters[1:5])
),
mainPanel(
textOutput("Current"),
textOutput("old")
)
)
))
"Current" will display the current selection and "old" displays the previous selection.
In the server.r I made use of three key functions: reactiveValues, isolate and session$onFlush.
server.r
library(shiny)
server <- function(input, output,session) {
Values<-reactiveValues(old="Start")
session$onFlush(once=FALSE, function(){
isolate({ Values$old<-input$XX })
})
output$Current <- renderText({paste("Current:",input$XX)})
output$old <- renderText({ paste("Old:",Values$old) })
}
The server.r works like this.
First, Values$old is created using the reactiveValues function. I gave it the value "Start" to make it clear what was happening on load up.
Then I added a session$onFlush function. Note that I have session as an argument in my server function. This will run every time that shiny flushes the reactive system - such as when the selectizeInput is changed by the user. What is important is that it will run before input$XX gets a new value - so the value has changed at the selectizeInput but not at XX.
Inside the session$onFlush I then assign the outgoing value of XX to Values$old. This is done inside an isolate() as this will prevent any problems with input$XX gets updated with the new values. I can then use input$XX and Values$old in the renderText() functions.

Resources