New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
suspendWhenHidden is not sufficient to be able to render elements immediately #1409
Comments
Specifically talking about plots, the plots cannot render in advance because they have no width and height. So the renderPlot does run, it just gives up before getting to the user code. I believe you can confirm this by passing an explicit width and height to the renderPlot function--then it should execute. (You'd want to do plotOutput("foo", height="auto") in this case) If it's really important to run eagerly and maintain auto-resizing plots, then you can probably do that by using a combination of an eager reactive expression (a regular reactive expression that you set up a dedicated observer that does nothing but invoke it) that does the plotting in a png device and returns recordPlot, then your renderPlot would retrieve that value from the reactive expression and run replayPlot. I would give you sample code but I'm on my phone at the moment, let me or @wch know if you can't figure it out. |
On second thought if we felt this was a common case we could handle it in renderPlot. If we detect that the size info is zero or missing and suspendWhenHidden=FALSE we could use some default size. |
@jcheng5, I think I just found a second bug because However, I can confirm that exactly the same behavior (initial lag) occurs even when you specify size. E.g: library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
numericInput("nrow", "Number of obs", 50000),
tabsetPanel(
tabPanel("Daily",
plotOutput("DailyCandles")
),
tabPanel("Weekly",
plotOutput("WeeklyCandles", height = "300px")
)
))
)
# Define server logic required to draw a histogram
server <- shinyServer(function(input, output) {
df <- reactive({ data.frame(x = 1:input$nrow, y= rnorm(input$nrow)) })
output$DailyCandles <- renderPlot({
ggplot(df(),aes(x=x,y=y)) + geom_line()
})
output$WeeklyCandles <- renderPlot({
ggplot(df(),aes(x=x,y=y)) + geom_line()
})
outputOptions(output, "WeeklyCandles", suspendWhenHidden = FALSE)
})
# Run the application
shinyApp(ui = ui, server = server) |
But you are right that this is a plot/image-specific issue. I.e. with a table, for example, it works fine: library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
numericInput("nrow", "Number of obs", 50000),
tabsetPanel(
tabPanel("Daily",
plotOutput("DailyCandles")
),
tabPanel("Weekly",
tableOutput("WeeklyCandles")
)
))
)
# Define server logic required to draw a histogram
server <- shinyServer(function(input, output) {
df <- reactive({ data.frame(x = 1:input$nrow, y= rnorm(input$nrow)) })
output$DailyCandles <- renderPlot({
ggplot(df(),aes(x=x,y=y)) + geom_line()
})
output$WeeklyCandles <- renderTable({
head(df(), 10000)
#ggplot(df(),aes(x=x,y=y)) + geom_line()
})
outputOptions(output, "WeeklyCandles", suspendWhenHidden = FALSE)
})
# Run the application
shinyApp(ui = ui, server = server) |
Also, for the suggested hack of using recordPlot and replayPlot, I think I didn't follow you completely. Here's my sad attempt: library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
numericInput("nrow", "Number of obs", 50000),
tabsetPanel(
tabPanel("Daily",
plotOutput("DailyCandles")
),
tabPanel("Weekly",
plotOutput("WeeklyCandles", height = 300)
)
))
)
# Define server logic required to draw a histogram
server <- shinyServer(function(input, output) {
df <- reactive({ data.frame(x = 1:input$nrow, y= rnorm(input$nrow)) })
drawPlot <- reactive({
ggplot(df(),aes(x=x,y=y)) + geom_line()
recordPlot()
})
observe(drawPlot())
output$DailyCandles <- renderPlot({
ggplot(df(),aes(x=x,y=y)) + geom_line()
})
output$WeeklyCandles <- renderPlot({
plt <- isolate(drawPlot())
replayPlot(plt)
})
outputOptions(output, "WeeklyCandles", suspendWhenHidden = FALSE)
})
# Run the application
shinyApp(ui = ui, server = server) |
The initial lag should go away when you put the explicit width and height on renderPlot, not plotOutput. Sorry, still on my phone. :) |
Ok, got it. This works: library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
numericInput("nrow", "Number of obs", 50000),
tabsetPanel(
tabPanel("Daily",
plotOutput("DailyCandles")
),
tabPanel("Weekly",
plotOutput("WeeklyCandles")
)
))
)
# Define server logic required to draw a histogram
server <- shinyServer(function(input, output) {
df <- data.frame(x = 1:50000, y= rnorm(50000))
output$DailyCandles <- renderPlot({
ggplot(df,aes(x=x,y=y)) + geom_line()
})
output$WeeklyCandles <- renderPlot({
ggplot(df,aes(x=x,y=y)) + geom_line()
}, height = 450, width = 600)
outputOptions(output, "WeeklyCandles", suspendWhenHidden = FALSE)
})
# Run the application
shinyApp(ui = ui, server = server) So now, the only questions are:
|
We could make a simple change in if (is.null(width))
width <- 500
if (is.null(height))
height <- 400 @wch and I talked about doing this, but we worried it may break in edge cases and this is not a big enough priority to be working on it now... |
* Close #1409: don't supply width/height to the device if they aren't defined * Update news * Update unit tests to reflect that plotPNG()/startPNG() now handles NULL dimensions * Add a note about NULL dimensions on plotPNG() help page * Update news
suspendWhenHidden = FALSE
works great after an element has already been rendered before and it should be re-rendered eagerly, even when hidden. This can be useful when, for example, there are several tabs dependent on the same inputs and we want to re-render them all whenever these change (so the user does not notice any lag after the initial time). However, this will not work if the elements have never been rendered before (e.g. on app startup).Reproducible example:
We can either make it so that
suspendWhenHidden
also works here, or we can create a new construct for this (e.g. using Joe'sreactiveTrigger
?)Source: Mauro Herrada's comment on Disqus.
The text was updated successfully, but these errors were encountered: