Skip to content
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

Zooming and dezooming in the browser makes plot be recalculated #2373

Closed
ColinFay opened this issue Apr 9, 2019 · 4 comments
Closed

Zooming and dezooming in the browser makes plot be recalculated #2373

ColinFay opened this issue Apr 9, 2019 · 4 comments

Comments

@ColinFay
Copy link
Contributor

ColinFay commented Apr 9, 2019

I think this is somehow related to #937, but if you open a Shiny App and zoom / dezoom with ctrl + and ctrl -, the plot is recalculated, which can make the UX bad for (relatively) time-consuming plots.

Minimal reprex :

library(shiny)
ui <- function(request){
  plotOutput('plot')
}

server <- function(input, output, session){
  output$plot <- renderPlot({
    hist(
      iris[sample(1:150, 10),]$Sepal.Width
    )
  })
}

shinyApp(ui, server)

Then in the browser, when I zoom dezoom, a new plot is drawn.

shinyresize

You can still prevent with:

library(shiny)
ui <- function(request){
  plotOutput('plot')
}

server <- function(input, output, session){
  plot_this <- reactive({
    iris[sample(1:150, 10),]$Sepal.Width
  })
  output$plot <- renderPlot({
    hist(
      plot_this()
    )
  })
}

shinyApp(ui, server)

But is it something that could be natively prevented?

@ColinFay ColinFay changed the title Zooming and dezooming browser makes plot Zooming and dezooming in the browser makes plot be recalculated Apr 9, 2019
@cpsievert
Copy link
Collaborator

cpsievert commented Apr 9, 2019

I think you're looking for execOnResize = FALSE? That other issue is about preventing resizing altogether. With execOnResize = FALSE, the plot is still resized on the client, but it will prevent the reactive from becoming invalidated on resize:

output$plot <- renderPlot(execOnResize = FALSE, {
   hist(iris[sample(1:150, 10),]$Sepal.Width)
})

@ColinFay
Copy link
Contributor Author

ColinFay commented Apr 9, 2019

Hey @cpsievert,

Thanks a lot for the trick, but the issue is not with resize (moving the width of the window) but with the window zoom in zoom out (pressing ctrl + or ctrl - in your browser). In the case of zooming, the reactive is still invalidated with execOnResize = FALSE

Here's the difference (no re-execution on windows resizing, but re-execution on zoom)

resizezoom

@wch
Copy link
Collaborator

wch commented Apr 9, 2019

The redraw happens because when you press ctrl-+ or -, the browser reports that the width of the plotOutput div has changed.

The execOnResize option does prevent the reactive code from re-executing. For example, if you run this app, you'll see that it prints running renderPlot only one time, no matter how many times you resize the window.

library(shiny)
shinyApp(
  basicPage(plotOutput('plot')),
  function(input, output, session){
    output$plot <- renderPlot(execOnResize = FALSE, {
      message("running renderPlot")
      hist(iris[sample(1:150, 10),]$Sepal.Width)
    })
  }
)

Even though the user code (that is, the code that you provide to renderPlot) is only executed one time, R does need to redraw the plot when it is resized. Here's how it works: when the plot is first drawn, Shiny tells R to record the drawing commands and saves them. Later, when the plot is resized, Shiny tells R to replay the drawing commands but with a new image size. This is done using recordPlot() and replayPlot(). For some types of plots, replaying the plot can be slow. Plots made with ggplot2 are prone to this, but future versions of ggplot2 should be significantly faster.

If you want to avoid redraws and re-execution, see renderCachedPlot, and specifically the sizePolicy parameter. Also see this article about plot caching in general: http://shiny.rstudio.com/articles/plot-caching.html

@wch wch closed this as completed Apr 9, 2019
@widdershiny
Copy link

Hi @wch ,

I am also experiencing something like described; when I ctrl+mouse-wheel to zoom in on my app, all of my plots are invalidated and re-drawn, but this doesn't happen if I just resize the browser area. I have a case where my app starts and there are no cached plots, and so I'm not entirely sure how to handle that. Regardless, I have tried execOnResize = FALSE and this doesn't catch the case where I'm zooming.

The solution provided by @ColinFay in his original post (putting the plot data into its own reactive context) did the trick. I'm pretty new to the reactive world, and I'm wondering if this behaviour is because Shiny simply treats the zoom event a bit differently than a resize event?

I understand this issue is closed... please let me know if I should post this elsewhere!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants