'shiny-busy'

905 views
Skip to first unread message

Martin Loos

unread,
Jan 14, 2014, 2:48:51 PM1/14/14
to shiny-...@googlegroups.com
Would like to use a panel conditioned on the state of shiny being busy, i.e.: condition="$('html').attr('class')=='shiny-busy'" .
Several threads have been posted on this issue, and people seem to have no problem to get it run,e.g.

However, I am missing something in my code, the conditioned panel would simply not appear. I suppose it is something very basic that I am missing here? I minimized my application to the following:

# server.R #####################################
shinyServer(function(input, output, session){
  output$a<-renderText("sleepy")
  observe({ 
    if(input$calculate){
Sys.sleep(5)
output$a<-renderText("slept a while")
}
  })
})
# ui.R ########################################
shinyUI(
pageWithSidebar(
headerPanel("test"), sidebarPanel(),
mainPanel(
textOutput("a"),
actionButton("calculate","Calculate"),
conditionalPanel(condition="$('html').attr('class')=='shiny-busy'",
tags$h5("Shiny seems busy...")
)
)
))
##############################################

Any ideas? Thanks in advance!

Patrick Toche

unread,
Jan 15, 2014, 12:33:57 AM1/15/14
to shiny-...@googlegroups.com
I made a basic demo on how I understand actionButtons work. Note that I'm a newbie and I went through the steps to teach myself, so this is shared with no guarantee of correctness. I'd add that if someone spots something wrong, it would be nice to let me know.

library("shiny")

I couldn't answer your question about: 

condition="$('html').attr('class')=='shiny-busy'"

Martin Loos

unread,
Jan 15, 2014, 2:57:16 AM1/15/14
to shiny-...@googlegroups.com
Hi Patrick

No, this is just the discussion I referred to above ... it doesn`t solve my problem - but thnxs!

Martin Loos

unread,
Jan 15, 2014, 4:04:12 AM1/15/14
to shiny-...@googlegroups.com
...and anyway, my actionButton works - its just about the conditional panel not showing up while shiny is busy calculating!



Am Dienstag, 14. Januar 2014 20:48:51 UTC+1 schrieb Martin Loos:

Patrick Toche

unread,
Jan 15, 2014, 5:56:26 AM1/15/14
to shiny-...@googlegroups.com
my actionButton works - its just about the conditional panel not showing up while shiny is busy calculating!

Have you tested the app with a condition like the one I have in my demo? It works like you describe, but conditions on something else. If your app works that way, then it's just a question of getting the correct syntax inside condition = "", but it doesn't display properly, there may be other problems. 

For instance, you overwrite output$a, is that a good approach? Inside your observe, you might add input$calculate before the condition, etc.. Try to reduce the problem to getting the javascript syntax right. 

Sorry about citing the very same exchange you cited. What is shiny-busy anyway?

Stéphane Laurent

unread,
Jan 15, 2014, 10:39:38 AM1/15/14
to shiny-...@googlegroups.com
In the post you mention, the condition is $('html').hasClass('shiny-busy')

Martin Loos

unread,
Jan 15, 2014, 10:47:54 AM1/15/14
to shiny-...@googlegroups.com
yes, it reacts - e.g., just by replacing the condition

"$('html').hasClass('recalculating')"

with its opposite

"!$('html').hasClass('recalculating')"


But I need to know why the conditinal panel does not react on the former ... aargggg

Martin Loos

unread,
Jan 15, 2014, 11:35:37 AM1/15/14
to shiny-...@googlegroups.com
sorry, yes - well observed, wrong copypaste. Again, using the above ui.R and server.R, I tried it with:

condition="!$('html').hasClass('shiny-busy')" -> reacts on shiny being not busy
condition="$('html').hasClass('shiny-busy')" -> does not react on shiny being busy

Again, I would also like the latter to react and do not understand why it does not.

Stéphane Laurent

unread,
Jan 15, 2014, 4:14:47 PM1/15/14
to shiny-...@googlegroups.com

condition="!$('html').hasClass('shiny-busy')" -> reacts on shiny being not busy
condition="$('html').hasClass('shiny-busy')" -> does not react on shiny being busy

Not sure to understand what you mean. If you don't get the expected behaviour, perhaps this only works in the header (as in the post you mentionned) ?

Martin Loos

unread,
Jan 15, 2014, 4:28:30 PM1/15/14
to shiny-...@googlegroups.com
Thanks Stéphane

The point is: the conditional panel set up with the above code (cp. first posting) does not appear when shiny is busy, although I follow the same JS syntax for the conditional statement as in the mentioned thread. 
(a) I have placed the conditional panel in the headerPanel and/or (b) within the tag$header(...), (c) I have tried it both with condition="$('html').hasClass('shiny-busy')" and  "$('html').attr('class')=='shiny-busy'", (d) I have checked the actionButton that turns shinyinto being busy to work, etc.   ... but that conditional panel will simply not appear. 
?

Stéphane Laurent

unread,
Jan 15, 2014, 5:01:35 PM1/15/14
to shiny-...@googlegroups.com
Ok I see. There are some problems in your code. Try this:


library(shiny)

runApp(
  list(
    server=function(input, output, session){
  time_consuming_task <- reactive({
    if(input$calculate>0) Sys.sleep(5)
    return(input$calculate)
  })
  output$a<-renderText(paste("slept a while -", time_consuming_task()))
},
    ui=pageWithSidebar(
      headerPanel("test"), sidebarPanel(),
      mainPanel(
        textOutput("a"),
        actionButton("calculate","Calculate"),
        conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                         tags$h5("Shiny seems busy...")
        )
      )
    )
  )
)



Martin Loos

unread,
Jan 16, 2014, 3:25:55 AM1/16/14
to shiny-...@googlegroups.com
Stéphane, great - your script works perfectly. Thanks very much for your help!

So, as I understand it now, the html class 'shiny-busy' only occurs for reactive expressions and not for observers? 
Is it because observers cannot be used as input to other reactive expressions and, thus, no invalidation arises?

Anyway, thank you!

Stéphane Laurent

unread,
Jan 16, 2014, 1:20:53 PM1/16/14
to shiny-...@googlegroups.com
No, I don't think we can say that the busy status doesn't occur when there is a current job inside an observer. Your code was strange for me and I don't know how to explain why it didn't render the expected behaviour.

In my example there is a reactive object (output$a) which waits to be updated once some job will be terminated, and I think the busy status occurs in such cases. 

Frankly, I don't know, and unfortunately I'm currently too busy now to investigate this question. 

I would appreciate too if an expert gives a precise definition of the 'shiny-busy' class. 

Patrick Toche

unread,
Jan 16, 2014, 2:19:28 PM1/16/14
to shiny-...@googlegroups.com
Nice one Stéphane.

I'm taking this opportunity to learn too. I think I have discovered good reasons to rely on observe() and isolate() rather than reactive(), though I suppose that mileage will vary depending on the purpose of the app.

I took Stéphane's code and added a few bells and whistles to keep track of what was going on. Namely, I added a numericInput box in which the user can add the delay to be passed to Sys.sleep (totally weird, but it's a demo for learning), and then I attempted to keep track of the total delay when different values of the argument of Sys.sleep were used. 

I couldn't get it to work with a simple reactive() like the one you are using. One problem was that Sys.sleep was triggered as soon as the number in the numericInput box was changed and not just when the actionButton was actioned. Another problem was that without isolate-ing various bits of the code, the numbers were all wrong. 

I haven't tested extensively, but I think the code below does the calculations right most of the time. If it doesn't, please fix it and get back to me ;-)

I have commented out the code based on a reactive, you can experiment to see what happens to the simple math of keeping track of the delay if you uncomment it. 

I use an observe() like so. It is instructive to see what happens if you remove each of the isolate()  and if you remove both, and if you remove the if(is.null(..)){return()}: the math is wrong, each time for different reasons.

observe({
input$trigger
if(is.null(input$trigger) || input$trigger == 0){return()} # needed for math below
delayValues$total <- isolate(delayValues$total) + isolate(input$delay)
})

Likewise if you don't wrap your Sys.sleep into an isolate, it will trigger even if the actionButton is not actioned (in this case the math is not updated).

But for your purpose the reactive() approach may well be satisfactory.

library("shiny")

Patrick Toche

unread,
Jan 16, 2014, 2:24:50 PM1/16/14
to shiny-...@googlegroups.com
I haven't tested extensively, but I think the code below does the calculations right most of the time. If it doesn't, please fix it and get back to me ;-)

One thing the current code doesn't get right is the statement "Expect to wait about 10 seconds."  after you change from, say, 10 to 5 seconds: it doesn't update properly. I should have tested more. Don't have time to look at it again now... But while the warning is incorrect when you transition, the total time calculated seems to be correct.
Reply all
Reply to author
Forward
0 new messages