Reactivity / Chain Reaction Question

954 views
Skip to first unread message

John Lueders

unread,
Oct 5, 2013, 9:52:26 PM10/5/13
to shiny-...@googlegroups.com
Hello All,

This is a Reactivity / Chain Reaction Question...
------------------------------------------------------------------------
Working on a Shiny app which uses many reactive functions.
Below I have a screenshot that shows three reactive functions.

The first two reactive functions (which set 'k' and 'timing') are both dependent on input$timingType.
The third reactive function (which sets GSD) is dependent on the first two ('k' and 'timing').

I understand that when input$timingType changes, it causes the reactive functions 'k' and 'timing' to fire.
My question is...Does that mean that GSD function will fire twice...the first time for the 'k' value change and the second time for the 'timing' value?

It is hopeful (for performance issues) that the GSD function only gets called once after both 'k' and 'timing' are set.
Please write with your thoughts/tricks/best practices.

John

ZJ

unread,
Oct 6, 2013, 1:59:20 AM10/6/13
to shiny-...@googlegroups.com
TL;DR: It won't in most cases.

I am going to explain this from my understanding. Pro-Shiny-Users please correct me if I am wrong.

As far as reactives go, input changes don't cause them to recalculate, in reactive/Shiny lingo they do not react to flush events (see http://rstudio.github.io/shiny/tutorial/#execution-scheduling)
I will explain what this means, or you can read the tutorial to get the official version.

In this specific instance I believe there would be some outputs (or an observe()) that depend on GSD(). For simplicity suppose there is only one output$something that depends on GSD. 

In Shiny A will invalidate B if A was called in the previous run of the code B (you need not understand this in this particular instance but it may help you debug more complex cases later on)

So when your input$timingType changes, it invalidates both k() and timing(), both of these in turn invalidate GSD(). Finally GSD() will invalidate output$something..

One thing to highlight is that invalidation does not cause recalculation, so at this stage no re-calculation has occurred.

Now suppose all things that can be invalidated by the changes to input$timingType has occurred, now a flush event occurs. Once this occurs output$something will re-calculate as it is an endpoint. Since it depends on GSD so somewhere in its code it will call GSD() and this is when GSD() will recalcualte. Now GSD() depends on t() and timing() so inside GSD() both t() and timing() gets called. Now once t() and timing() were both called and their values updated, GDS() will use their values to update itself and now output$something can finish its computation based on GDS().

To summarise when output$something runs, it calls on GSS() which calls on k() and timing(). So each of k(), timing() and GSD() was run only once.

ZJ

unread,
Oct 6, 2013, 5:56:21 AM10/6/13
to shiny-...@googlegroups.com
The above explanation I find a bit convoluted.

When input$timingType changes, it doesn't "fire" timing() and k() in that it causes them rerun, it only invalidates them, the invalidation of timing() and k() will also invalidate GSD(), and GSD() will invalidate output$something. Once everything has been invalidated, a flush event happens. The flush event will attempt to recalculate output$something, which will call GSD() which calls k() and timing().

Things just happen in "reverse" compared to traditional event driven programming, where A fires B fires C. In Shiny/reactive programming it's like A invalidates B invalidates C, flush, fire C, C fires B, B fires A. 

David Reiner

unread,
Oct 7, 2013, 11:07:40 AM10/7/13
to shiny-...@googlegroups.com
I've found the reactive log visualizer to be very helpful for questions like this.
?showReactLog , the tutorial, and a very simple example, run from a fresh R session demonstrates what ZJ explains very clearly (second post ;-)).
Something like:

==> reactive/server.R <==
shinyServer(function(input, output) {

  A <- reactive({
    input$n ^ 2
  })

  B <- reactive({
    -input$n
  })

  output$Value <- renderText({
    A() + B()
  })
})


==> reactive/ui.R <==

shinyUI(pageWithSidebar(

  headerPanel("Reactive"),

  sidebarPanel(
    numericInput("n", "N:", 10)
  ),

  mainPanel(
    textOutput("Value")
  )
))


Then in a fresh R session,
> require(shiny)
Loading required package: shiny
> options(shiny.reactlog=TRUE)
> runApp("reactive/", port=8101L)

and after you change the input value, type ctrl-F3 and step through the reactive events.

HTH,
David Reiner

tcash21

unread,
Oct 7, 2013, 4:56:15 PM10/7/13
to shiny-...@googlegroups.com
Just wanted to say I tested out the showReactLog() function and the R Studio guys have outdone themselves. This is such a cool feature and is immensely helpful. I previously was adding print() statements to every single function in order to see the order of operations. Well done guys!

John Lueders

unread,
Oct 7, 2013, 5:47:15 PM10/7/13
to shiny-...@googlegroups.com
@ZJ Thank you very much for your response!  It was very helpful...I feel comfortable that my code is written in a way that will not cause it to fire more than it necessary.

@Dave Reiner I will check out the reactlog...I have not heard about that before...Thank you!



--
You received this message because you are subscribed to a topic in the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/shiny-discuss/1-t39ty1F5I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to shiny-discus...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply all
Reply to author
Forward
0 new messages