renderPlot loops continuously with req()


#1

I'm trying to do something very similar, renderPlot() only after input$RUN button has been executed.

Using req() results the same as using observeEvent() in my case, where once the button is executed a single time, the renderPlot will loop through the function continuously and not function like I want which is:
-> renderPlot() only once the button is clicked.


How to renderPlot only after the observeEvent produces reactiveValues, not before
#2

@kollaea, are you following @sowla's suggestion in her edit?

Using the original example, if your observeEvent stores the result of the calculation in a reactiveValue called main_reactive

main_reactive <- reactiveValues() 
observeEvent(input$run, {
 # calculation code that produces data frame called mydataframe
 main_reactive$forplot = mydataframe
})

then your renderPlot should look like this

output$my_plot <- renderPlot({ 
  req(main_reactives$forplot) 
  # plotting code
})

#3

Thanks for taking the time to respond @hinkelman.

I have tried that exactly yes as well as observedEvent() and the output from the renderPlot() function always outputs in the console but not in the fluidRow as desired.

Any ideas as to why this is the behavior I'm seeing or ideas to try are welcome.


#4

That's not enough information for me to understand the problem. You will get more helpful suggestions if you follow the guidelines in the Shiny debugging and reprex guide.


#5

Here is my code:

output$AutoML_plot <- renderPlot({ 

 #req(main_reactive) 
 #OE <- observeEvent(input$RUN, { 
 if(input$RUN == TRUE){ 

 OS <- .Platform 
 cat(paste("0.) OS:",OS$OS.type),sep="\n") 

 cat("1.) RUN model input initialized",sep="\n") 

 # Gather user options ### 
 cat("2.) data: ") 
 data <- getData() 
 cat("3.) targetNames: ") 
 targetNames <- getTargetNames() 
 cat("4.) type: ") 
 type <- getType() 
 cat("5.) preProcessing: ") 
 preProc <- getPreProc() 
 cat("6.) metric: ") 
 metric <- getMetric() 
 cat("7.) chosenModels: ") 
 chosenModels <- getChosenModels() 

 # Execute R Script ### 
 cat("8.) executing 'AutoML' script",sep="\n") 
 test <- return(AutoML(data,targetNames,type,preProc,metric,chosenModels)) 

 # Return generated plot ### 
 cat("9.) generating plot\n",sep="\n") 
 #AML <- AutoML(test) 
 #dashboard <- main_reactive$plot 

 return(test$Dashboard) 
 } 
 })

As you can see, I've tried a few approaches. The only way I can get the plot to render correctly is with an if(input$RUN == TRUE) statement which, once true, remains true, causing the rendering to occur if any input is updated.


#6

Your observeEvent code should not be inside your renderPlot code.


#7

Thanks @hinkelman for the quick response. I have tried the observe event outside of renderPlot as well as taking the getters and call to my main function and storing those into external functions, reactive variables, and observed events then storing the call to that function to another variable then returning the PNG that variable has stored in renderPlot as so

test <- observedEvent({
test <- AutoML()
return(test)
})

renderPlot({
 dashboard <- makePlot(test)
return(dashboard)
})

Is that what you have in mind?

main_reactive <- reactiveValues()

and both:

req(main_reactive)

main_reactive <- AutoML(data,targetNames,type,preProc,metric,chosenModels)

as well as,

test <- (AutoML(data,targetNames,type,preProc,metric,chosenModels))
main_reactive$plot = test$Dashboard

#8

You don't assign observeEvent to output. Instead, update the reactive value (main_reactive in this example) at the end of your observeEvent code. Maybe this discussion will help you understand how to use observeEvent.


#9

@hinkelman, I have tried both ways. Below is my code. Also, I would like this post unhidden from the community forum. I believe the issue is common and relevant to the post I originally replied to. Hiding posts is a form of censorship and not a part of an open & collaborative community.

If you understand the issue, please provide an example or of course show me my error with the correction. I have certainly researched the issue and cannot find a solution so I am asking an expert now for better clarification.

###########################################
observeEvent(input$RUN, {

OS <- .Platform
cat(paste("0.) OS:",OS$OS.type),sep="\n")

cat("1.) RUN model input initialized",sep="\n")

Gather user options

cat("2.) data: ")
data <- getData()
cat("3.) targetNames: ")
targetNames <- getTargetNames()
cat("4.) type: ")
type <- getType()
cat("5.) preProcessing: ")
preProc <- getPreProc()
cat("6.) metric: ")
metric <- getMetric()
cat("7.) chosenModels: ")
chosenModels <- getChosenModels()

Execute R Script

cat("8.) executing 'AutoML' script",sep="\n")
main_reactive$test <- AutoML(data,targetNames,type,preProc,metric,chosenModels)
})

output$AutoML_plot <- renderPlot({
AutoML_plot <- NULL
req(main_reactive$test, {
AutoML_plot <- main_reactive$test
cat("9.) generating plot\n",sep="\n")
})
return(AutoML_plot$Dashboard)
})

output$AutoML_table <- renderTable({
AutoML_table <- NULL
req(main_reactive$test, {
AutoML_table <- main_reactive$test
cat("10.) generating table\n",sep="\n")
})
return(AutoML_table$Results)
})

####################################

Thanks,

Ed


#10

Sorry, that was previously my code (I am reaching out to multiple sources).

This is the code I believe is correct:

########################################### 
observeEvent(input$RUN, { 

 OS <- .Platform 
 cat(paste("0.) OS:",OS$OS.type),sep="\n") 

 cat("1.) RUN model input initialized",sep="\n") 

 ### Gather user options ### 
 cat("2.) data: ") 
 data <- getData() 
 cat("3.) targetNames: ") 
 targetNames <- getTargetNames() 
 cat("4.) type: ") 
 type <- getType() 
 cat("5.) preProcessing: ") 
 preProc <- getPreProc() 
 cat("6.) metric: ") 
 metric <- getMetric() 
 cat("7.) chosenModels: ") 
 chosenModels <- getChosenModels() 

 ### Execute R Script ### 
 cat("8.) executing 'AutoML' script",sep="\n") 
 main_reactive$test <- AutoML(data,targetNames,type,preProc,metric,chosenModels) 
 })

output$AutoML_plot <- renderPlot({ 
 AutoML_plot <- NULL 
 req(main_reactive$test, { 
 AutoML_plot <- main_reactive$test 
 cat("9.) generating plot\n",sep="\n") 
 }) 
 return(AutoML_plot$Dashboard) 
 }) 

 output$AutoML_table <- renderTable({ 
 AutoML_table <- NULL 
 req(main_reactive$test, { 
 AutoML_table <- main_reactive$test 
 cat("10.) generating table\n",sep="\n") 
 }) 
 return(AutoML_table$Results) 
 }) 

####################################

Thanks,

Ed


#11

So I admittedly have not read this whole thread, but a few pointers based on your last code sample here:

  • It would probably be worth your time to read a bit about functional programming. The functional programming paradigm can feel time consuming, but it explicitly declares inputs and makes your functions much easier to reason about. It would also suggest that executing functions like getData() is probably not what you want, since I presume you are using some type of user set variable to decide which data you are getting.
  • When referencing a reactive, you usually have to reference it as a function. I.e.
obj <- reactive("blah")
output$something <- renderText({ obj() })

It does not look like you do so with main_reactive$test, and so will probably need main_reactive$test().

  • Correction - I did not realize you were using reactiveValues, so that functional notation may not be necessary. I would also recommend taking a look at reactiveVal instead of reactiveValues. reactiveValues obscures some of the functional behavior, but it tries to be "magical" and sometimes will not do what you want. reactiveVal gives you much more fine-grained control, which it seems like you may appreciate in this context.
obj <- reactiveVal("old value")
observeEvent(input$RUN, {
 obj("new value")
})
output$text <- renderText({ obj() })

Is your example above working as you expect? One additional approach would be to simplify your example to get reactivity working the way you expect without all of the package / function -specific behavior. This would also help us help you - by giving us a minimal reproducible example with which to debug in our environment and assist you.


#12

@cole,

I tried reactiveVal and was able to lock reactiveVals until I got the output I was trying to render successfully. Clearly you have a higher understanding of the concept and relevant experience with the topic.

Thank you,

Ed


#13

Glad you got to the bottom of the issue! Reactivity can be super tricky, and those circular loops can be nightmarish. isolate() is another trick worth keeping in your back pocket. It can force something to only evaluate once and then breaks the reactive dependency afterwards.