I dont have a reproducible example as the question is more on how modules work. I am trying to understand how to pass some reactive function from one module to the next. I have received replies in the past about using ObserveEvent but they have not seem to work when I am using the reactive value in one module to perform some other operation in another module
module1 <- function(input, output, session){
data1<-reactive({
#some reacttive funcion that produces an output
})
data2<-reactive({
#some reacttive funcion that produces another output
})
return(list(data1,data2))
}
module2 <- function(input, output, session,data1){
observe( data1(), {
#perform some other functions here using data1().e.g reading or parsing data
})
}
So basically I have a module1 that returns two outputs from data1 and data2
I want to use the value of data1 in module 2 and perform some new operation using that value.
I have looked at other answers to similar questions here but I still dont understand them. If someone can help me explain this concept more clearly that would be of great help
thanks for your help
One possibility is passing the output from one module to the other at construction time. This allows hierachic relationships between modules. There is also the possibility to create memory that is shared between two modules which I will not cover in this answer.
reactiveValues
Here i created an inputModule and an outputModule. The inputModule recieves two textinputs by the user and the output module displays them via verbatimTextOutput. The inputModule passes the user submitted data to the output module as a reactiveValues object called ImProxy (input module proxy). The outputModule accesses the data just like a list (ImProxy$text1, ImProxy$text2).
library(shiny)
inputModuleUI <- function(id){
ns <- NS(id)
wellPanel(h3("Input Module"),
textInput(ns('text1'), "First text"),
textInput(ns('text2'), "Second text"))
}
inputModule <- function(input, output, session){
vals <- reactiveValues()
observe({vals$text1 <- input$text1})
observe({vals$text2 <- input$text2})
return(vals)
}
outputModuleUI <- function(id){
wellPanel(h3("Output Module"),
verbatimTextOutput(NS(id, "txt")))
}
outputModule <- function(input, output, session, ImProxy){
output$txt <- renderPrint({
paste(ImProxy$text1, "&", ImProxy$text2)
})
}
ui <- fluidPage(
inputModuleUI('IM'),
outputModuleUI('OM')
)
server <- function(input, output, session){
MyImProxy <- callModule(inputModule, 'IM')
callModule(outputModule, 'OM', MyImProxy)
}
shinyApp(ui, server)
This approach can be used with observe or observeEvent as well.
list(reactive)
If you want to use reactive rather than reactiveValues, the following adaptiation of the above code can be used. You can leave the ui functions as they are.
inputModule <- function(input, output, session){
list(
text1 = reactive({input$text1}),
text2 = reactive({input$text2})
)
}
outputModule <- function(input, output, session, ImProxy){
output$txt <- renderPrint({
paste(ImProxy$text1(), "&", ImProxy$text2())
})
}
shinyApp(ui, server)
reactive(list)
Again, this will give the same functionality for the app but the proxy pattern is slightly different.
inputModule <- function(input, output, session){
reactive(
list(
text1 = input$text1,
text2 = input$text2
)
)
}
outputModule <- function(input, output, session, ImProxy){
output$txt <- renderPrint({
paste(ImProxy()$text1, "&", ImProxy()$text2)
})
}
shinyApp(ui, server)
Related
In the below example code I reactively subset the mtcars dataframe inside the renderPlot() function. However, in my larger App with many render functions in the server section I am having to repeat the same rv$x[1:input$samples], etc., over and over in many places. How would I apply this subsetting instead "at the top", into the rv <- reactiveValues(...) function itself or equivalent "master function"? I tried subsetting inside the reactiveValues() and got the message "Warning: Error in : Can't access reactive value 'samples' outside of reactive consumer. Do you need to wrap inside reactive() or observer()?" I assumed incorrectly that the reactiveValues() function is a "reactive consumer".
If someone can answer this basic understanding question, please explain the logic for correctly subsetting "at the top" because I am getting very embarrassed by my repeated questions about Shiny reactivity.
library(shiny)
ui <- fluidPage(
sliderInput('samples','Nbr of samples:',min=2,max=32,value=16),
plotOutput("p")
)
server <- function(input, output, session) {
rv <- reactiveValues(
x = mtcars$mpg,
y = mtcars$wt
)
output$p <- renderPlot({plot(rv$x[1:input$samples],rv$y[1:input$samples])})
}
shinyApp(ui, server)
There are multiple ways you can handle this.
Here is one way to create new subset reactive values inside observe.
library(shiny)
ui <- fluidPage(
sliderInput('samples','Nbr of samples:',min=2,max=32,value=16),
plotOutput("p")
)
server <- function(input, output, session) {
rv <- reactiveValues(
x = mtcars$mpg,
y = mtcars$wt
)
observe({
rv$x_sub <- rv$x[1:input$samples]
rv$y_sub <- rv$y[1:input$samples]
})
output$p <- renderPlot({plot(rv$x_sub,rv$y_sub)})
}
shinyApp(ui, server)
I'd use reactiveValues only if you need them to be modified in different places.
reactive is shiny's basic solution for this:
library(shiny)
library(datasets)
ui <- fluidPage(
sliderInput(
'samples',
'Nbr of samples:',
min = 2,
max = 32,
value = 16
),
plotOutput("p")
)
server <- function(input, output, session) {
reactive_mtcars <- reactive({mtcars[1:input$samples,]})
output$p <- renderPlot({
plot(reactive_mtcars()$mpg, reactive_mtcars()$wt)
})
}
shinyApp(ui, server)
I am currently trying in vain to use the debounce function in Shiny to delay my input a bit. The goal is to have the renderText not fire every few milliseconds, but only after 2 second intervals.
I tried to implement the following solution. Thereby I absolutely need the reactiveValues and observeEvent functions. Other solutions here never take this combination into account and I am currently stuck. My example code is shortened. In reality the variable name1$data is still used by different functions and the RenderText accesses different variables.
if (interactive()) {
ui <- fluidPage(
textInput("IText1", "Input i want to slow down"),
textOutput("OName")
)
server <- function(input, output, session) {
Name1 <- reactiveValues()
observeEvent(input$IText1, {Name1$data <- input$IText1})
#Solutions on stackoverflow
#Just causes errors for me
#Name1$t <- debounce(Name1$data, 2000)
output$OName <- renderText({
Name1$data
})
}
shinyApp(ui, server)
}
Thank you very much for any hint!
Normally we debounce reactive conductors (reactive({......})):
ui <- fluidPage(
textInput("IText1", "Input i want to slow down"),
textOutput("OName")
)
server <- function(input, output, session) {
Name1 <- reactive({
input$IText1
})
Name1_d <- debounce(Name1, 2000)
output$OName <- renderText({
Name1_d()
})
}
shinyApp(ui, server)
EDIT
Or you need
server <- function(input, output, session) {
Name1 <- reactiveValues()
observe({
invalidateLater(2000, session)
Name1$data <- isolate(input$IText1)
})
output$OName <- renderText({
Name1$data
})
}
I have the following example:
library(shiny)
ui <- fluidPage(
textOutput("out"),
actionButton("plusX", "Increase X"),
actionButton("redraw", "redraw")
)
server <- function(input, output, session) {
x <- 0
observeEvent(input$plusX, {x <<- x+1})
output$out <- renderText({
input$redraw
x
})
}
shinyApp(ui, server)
Is this considered an anti-pattern in Shiny to modify a non-reactive variable in this way? Obviating the super assignment which can be problematic by itself.
I know this could be done, for example with a reactiveVal to store X, and isolate to obtain a similar result. This second way seems clearer and that would be my usual choice, but I was wondering if there any caveats in the first one, or it is possible way of doing that.
library(shiny)
ui <- fluidPage(
textOutput("out"),
actionButton("plusX", "Increase X"),
actionButton("redraw", "redraw")
)
server <- function(input, output, session) {
x <- reactiveVal(0)
observeEvent(input$plusX, {x(x()+1)})
output$out <- renderText({
input$redraw
isolate(x())
})
}
shinyApp(ui, server)
In this example there is no important difference between both codes as you are not using the benefit of ReactiveVal.
The benefit of ReactiveVal is that it has a reactive nature and thus can interact with other reactive elements.
Try for example to add a table to your code that depends on x:
output$tab <- renderTable({data.frame(y = x)})
(x() in the case of ReactiveVal)
The difference you will see that in the case of ReactiveVal the table automatically updates with plusX whereas in the case of the regular variable it does not update.
In my app, I have two modules (nested) for which I want to pass uiOuput. In the example below, the output named "screen1" (created in the outer module)has to be passed to the inner module where it will be displayed. But It doesn't work..
Passing such uiOutput work from the original shinyApp to one module but I can't make it works between two modules.
innerUI <- function(id){
ns <- NS(id)
tagList(
h4("Inner module"),
uiOutput(ns('displayScreens'))
)
}
inner <- function(input, output, session, params){
output$displayScreens <- renderUI({
params()
})
}
outerUI <- function(id){
ns <- NS(id)
innerUI(ns('test1'))
}
outer <- function(input, output, session){
rv <- reactiveValues(
test = uiOutput("screen1")
)
callModule(inner, 'test1', params= reactive({rv$test}))
output$screen1 <- renderUI({
h4("I am the screen 1 !")
})
}
ui <- fluidPage(
outerUI('test2')
)
server <- function(input, output, session){
callModule(outer, 'test2')
}
shinyApp(ui=ui, server=server)
Your problem seems to be one with namespaces. You are creating uiOutput("screen1") in outer and passing it to inner without a namespace. You could pass the uiOutput("screen1") in a reactive like this:
test <- reactive({
ns <- session$ns
uiOutput(ns("screen1"))
})
callModule(inner, 'test1', params=test)
This should work.
I am having trouble with nested selectizeInputs, i.e. a group of select inputs where the selection in the first determines the choices in the second, which control the choices in the third, and so on.
Let's say I have an select1 that lets you choose a dataset, and select2 which lets you pick a variable in the dataset. Obviously the choices in select2 depend on the selection in select1. I find that if a user selects a variable from select2, and then changes select1, it doesn't immediately wipe out the value from select2, but instead it goes through a reactive sequence with the new value in select1, and the old value from select2, which is suddenly referencing a variable in a different dataset, which is a problem.
Example:
library(shiny)
ui =fluidPage(
selectizeInput('d',choices=c('mtcars','iris'),
label="Datasets"),
uiOutput("vars"),
htmlOutput("out")
)
server = function(input, output, session) {
output$vars <- renderUI({
req(input$d)
selectizeInput("v",choices=names(get(input$d)), label="Variables",
options=list(onInitialize=I('function() {this.setValue("");}')))
})
output$out <- renderUI({
req(input$d,input$v)
HTML(paste0("The max is ",max(get(input$d)[[input$v]])))
})
}
runApp(list(ui = ui, server = server))
On launch, select mpg, and displays max value.
Now, after selecting mpg, if you switch to iris, you will get a barely noticeable error, then it corrects itself. This is a toy example, so the error is insignificant, but there could easily be cases where the error is much more dire (as is the case with the app I am currently developing).
Is there a way to handle nested selectizeInputs such that changes in an upstream selectizeInput won't evaluate with old values of down stream selectizeInputs when changed?
Thanks
edit: This issue turns out to have to do more with modules than anything else I believe:
library(shiny)
library(DT)
testModUI <- function(id) {
ns <- NS(id)
DT::dataTableOutput(ns("out"))
}
testMod <- function(input, output, session, data) {
output$out <- DT::renderDataTable({
data()
},caption="IN MODULE")
}
ui =fluidPage(
selectizeInput('d',choices=c('mtcars','iris'),
label="Datasets"),
uiOutput("vars"),
testModUI("test"),
DT::dataTableOutput("test2")
)
server = function(input, output, session) {
output$vars <- renderUI({
req(input$d)
selectizeInput("v",choices=names(get(input$d)), label="Variables",
options=list(onInitialize=I('function() {this.setValue("");}')))
})
observe({
req(input$d,input$v)#,get(input$d)[[input$v]])
validate(
need(input$v %in% names(get(input$d)), 'Wait.')
)
callModule(testMod,"test",reactive(data.frame(v1=max(get(input$d)[[input$v]]))))
})
output$test2 <- DT::renderDataTable({
req(input$d,input$v)#,get(input$d)[[input$v]])
validate(
need(input$v %in% names(get(input$d)), 'Wait.')
)
data.frame(v1=max(get(input$d)[[input$v]]))
},caption="OUTSIDE MODULE")
}
runApp(list(ui = ui, server = server))
Hello you can put condition to check if your code is going to run, here you just need that input$v to be a valid variable from input$d, so do :
output$out <- renderUI({
req(input$d,input$v)
if (input$v %in% names(get(input$d))) {
HTML(paste0("The max is ",max(get(input$d)[[input$v]])))
}
})
# or
output$out <- renderUI({
req(input$d,input$v)
validate(
need(input$v %in% names(get(input$d)), 'Wait.')
)
HTML(paste0("The max is ",max(get(input$d)[[input$v]])))
})
EDIT with module, you can define your module with an expression to validate like this :
testMod <- function(input, output, session, data, validExpr) {
output$out <- DT::renderDataTable({
validate(need(validExpr(), FALSE))
data()
},caption="IN MODULE")
}
And call the module in the server with the expression in a function :
observe({
req(input$d,input$v)
callModule(
module = testMod,
id = "test",
data = reactive({ data.frame(v1=max(get(input$d)[[input$v]])) }),
validExpr = function() input$v %in% names(get(input$d))
)
})