Reactive Function Parameters - r

My goal is to make a reactive shiny function in R. There are multiple outputs (e.g. tables) which can be bind to a similar function. However I need the function to react on some parameter, specific to one table. Here is some simple sample code, which isn't working but it makes my idea clear - I hope:
output$tableOne <- DT::renderDataTable({
getData(foo)
})
getData <- reactive(function(funParameter){
corrStartDate <- input$StartDate
corrEndDate <- input$EndDate
return(someData(corrStartDate, corrEndDate, funParameter))
})
In all tables (if there is more then one) I wan't to show data with different base parameter (getData(x, y, foo)). So the second table could use "getData(x, y, bar)". I don't want to write every time the same function for another table.
The solution above is not working, since reactive functions do not support parameters.
How would you solve this?

This should work instead:
getData <- eventReactive(input$funParameter, {
corrStartDate <- input$StartDate
corrEndDate <- input$EndDate
return(someData(corrStartDate, corrEndDate, input$funParameter))
})
eventReactive only updates if arguments stated up front change. Practically speaking, this reactive will not trigger if input$StartDate or input$EndDate changes.
If this is not what you want, normal reactive functions should work. I.e.:
getData <- reactive({
funParameter <- input$funParameter
corrStartDate <- input$StartDate
corrEndDate <- input$EndDate
return(someData(corrStartDate, corrEndDate, funParameter))
})
which will trigger if any of the inputs change

Related

R Shiny: reactivevalues from function

I stored several tables in .rds files which I would like to import using readRDS in a Shiny session. Therefore I defined the following global function:
get.station <- function(sname){
file.name <- paste(sname".rds", sep="")
return(readRDS(file.name))
}
within the server function I define the reactive value:
st.reactive <- reactiveValues(get.station(input$station.sel))
where input$station.sel comes from the ui using selectInput(...). This results in the following error message:
Operation not allowed without an active reactive context.
(You tried to do something that can only be done from inside
a reactive expression or observer.)
This error message even does not disappear if I define this function using reactive():
get.station <- reactive({
file.name <- paste(input$station.sel".rds", sep="")
return(readRDS(file.name))
})
and within the server:
st.reactive <- reactiveValues(data=get.station())
Do you have any help?
You've got the right idea, just put the function inside a reactive or observe_ function. While you can define reactiveValues in the initial call, its best, in my opinion, to create the reactive values object empty and then do all your assignments with the <- notation.
The confusion comes from the fact that, despite it's name, reactiveValues is not a reactive expression. It generates a reactiveValues object that reactive values can be stored in, but it only runs once and does not check whether its values are invalidated.
In your case, I'd do the following:
rv <- reactiveValues()
rv$st.reactive <- observe({get.station(input$station.sel)})

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.

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

using values from a reactive input to directly input into a custom function

The following function fails:
get_num <- function(input$num){ans <-input$num
return(ans)}
since R is confused by the $ symbol.
Although this is a toy example, I would like to write a function that directly takes reactive input values (in this case, a number) and does something meaningful with them, without having to preempt the situation with
num <- input$num
get_num <- function(num){ans <-num
return(ans)}
Is this even possible?
There are three points here:
when you are dealing with reactive values, you use reactive() instead of function() in your script.
Here is example:
num_square = reactive({input$num^2})
observe(print(num_square()))
The first line defines a new reactive values base on input$num and second lines print it as soon as it changes. Note that reactive values are same as function, and you should call them with () in front of them.
when you want to save a value to outside environment (other that internal use of function or reactive) you should use <<- instead of = or <- notation.
Here is an example:
reactive1 <- reactive({num_square <<- input$num^2
print(num_square) })
The above line changes the value of num_square as soon as you run reactive1() some place in your code. note that without running reactive1() the value of num_square wont change. This is the BIG DIFFERENCE between reactive() (lazy evaluation) and observe() (eager evaluation).
observe() is another method to use reactive values in a function. It seems to me that you are looking for this one.
Here is an example. The value of get_num will change as soon as you change input$num in your program.
observe({get_num <<- input$num
print(get_tmp)})
Note that above script should be in middle of shinyServer(function(input, output) { ... }).
Difference between reactive() and observe(): [refer to: http://shiny.rstudio.com/reference/shiny/latest/observe.html ]
An observer is like a reactive expression in that it can read reactive
values and call reactive expressions, and will automatically
re-execute when those dependencies change. But unlike reactive
expressions, it doesn't yield a result and can't be used as an input
to other reactive expressions. Thus, observers are only useful for
their side effects (for example, performing I/O).
Another contrast between reactive expressions and observers is their
execution strategy. Reactive expressions use lazy evaluation; that is,
when their dependencies change, they don't re-execute right away but
rather wait until they are called by someone else. Indeed, if they are
not called then they will never re-execute. In contrast, observers use
eager evaluation; as soon as their dependencies change, they schedule
themselves to re-execute.
Try:
get_num <- function(ans = input$num) {
out <- seq(ans:ans*2)
return(out)
}
get_num()
or:
get_num <- function(ans) {
out <- seq(ans:ans*2)
return(out)
}
get_num(input$num)
I think a more natural way to do this in shiny is to use reactive like so:
get_num<-reactive({ ans<-input$num)}
Obviously you could do more, like:
get_num<-reactive({ans<-input$num*20
ans<-ans/pi
})
or whatever. Then refer to your value as get_num() as it is now a function.

Resources