rstudio / bslib

Tools for theming Shiny and R Markdown via Bootstrap 3, 4, or 5.
https://rstudio.github.io/bslib/
Other
490 stars 58 forks source link

plot is stretched when window is resized #1129

Open see24 opened 3 weeks ago

see24 commented 3 weeks ago

Describe the problem

If I create a plot with a width specified in renderPlot it works as expected when the page first renders. But if I resize the page the plot image is stretched to fill the whole space. If I generate a new plot it has the expected width again. In my actual use case this also happens after the first time an actionButton is pressed which is more problematic than if it only ever happened with window resizing.

library(shiny)
library(bslib)
# The with basic shiny behaves as expected
shinyApp(
  ui = fluidPage(
    sidebarLayout(
      sidebarPanel(
        actionButton("newplot", "New plot")
      ),
      mainPanel(
        plotOutput("plot")
      )
    )
  ),
  server = function(input, output) {
    output$plot <- renderPlot({
      input$newplot
      # Add a little noise to the cars data
      cars2 <- cars + rnorm(nrow(cars))
      plot(cars2)
    }, width = 400)
  }
)

# with bslib it doesn't
shinyApp(
  ui = page_sidebar(
    sidebar = sidebar(
      actionButton("newplot", "New plot")
    ),
    page_fluid(
      plotOutput("plot", fill = FALSE)
    )
  ),
server = function(input, output) {
  output$plot <- renderPlot({
    input$newplot
    # Add a little noise to the cars data
    cars2 <- cars + rnorm(nrow(cars))
    plot(cars2)
  }, 
  width = 400)
}
)

Before resize image

After resize image

Session Info


─ Session info ────────────────────────────────────────────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.4.1 (2024-06-14 ucrt)
 os       Windows 11 x64 (build 22631)
 system   x86_64, mingw32
 ui       RStudio
 language (EN)
 collate  English_United States.utf8
 ctype    English_United States.utf8
 tz       America/New_York
 date     2024-10-29
 rstudio  2024.09.0+375 Cranberry Hibiscus (desktop)
 pandoc   3.2 @ C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)

─ Packages ────────────────────────────────────────────────────────────────────────────────────────────────────────
 package     * version    date (UTC) lib source
 bsicons       0.1.2      2023-11-04 [1] CRAN (R 4.4.1)
 bslib       * 0.8.0.9000 2024-10-29 [1] Github (rstudio/bslib@85b0428)
 cachem        1.1.0      2024-05-16 [1] CRAN (R 4.4.1)
 callr         3.7.6      2024-03-25 [1] CRAN (R 4.4.1)
 cli           3.6.3      2024-06-21 [1] CRAN (R 4.4.1)
 clipr         0.8.0      2022-02-22 [1] CRAN (R 4.4.1)
 curl          5.2.1      2024-03-01 [1] CRAN (R 4.4.1)
 desc          1.4.3      2023-12-10 [1] CRAN (R 4.4.1)
 devtools      2.4.5      2022-10-11 [1] CRAN (R 4.4.1)
 digest        0.6.36     2024-06-23 [1] CRAN (R 4.4.1)
 ellipsis      0.3.2      2021-04-29 [1] CRAN (R 4.4.1)
 evaluate      0.24.0     2024-06-10 [1] CRAN (R 4.4.1)
 fansi         1.0.6      2023-12-08 [1] CRAN (R 4.4.1)
 fastmap       1.2.0      2024-05-15 [1] CRAN (R 4.4.1)
 fs            1.6.4      2024-04-25 [1] CRAN (R 4.4.1)
 glue          1.7.0      2024-01-09 [1] CRAN (R 4.4.1)
 htmltools     0.5.8.1    2024-04-04 [1] CRAN (R 4.4.1)
 htmlwidgets   1.6.4      2023-12-06 [1] CRAN (R 4.4.1)
 httpuv        1.6.15     2024-03-26 [1] CRAN (R 4.4.1)
 jquerylib     0.1.4      2021-04-26 [1] CRAN (R 4.4.1)
 jsonlite      1.8.8      2023-12-04 [1] CRAN (R 4.4.1)
 knitr         1.48       2024-07-07 [1] CRAN (R 4.4.1)
 later         1.3.2      2023-12-06 [1] CRAN (R 4.4.1)
 lifecycle     1.0.4      2023-11-07 [1] CRAN (R 4.4.1)
 magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.4.1)
 memoise       2.0.1      2021-11-26 [1] CRAN (R 4.4.1)
 mime          0.12       2021-09-28 [1] CRAN (R 4.4.0)
 miniUI        0.1.1.1    2018-05-18 [1] CRAN (R 4.4.1)
 pillar        1.9.0      2023-03-22 [1] CRAN (R 4.4.1)
 pkgbuild      1.4.4      2024-03-17 [1] CRAN (R 4.4.1)
 pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.4.1)
 pkgload       1.4.0      2024-06-28 [1] CRAN (R 4.4.1)
 processx      3.8.4      2024-03-16 [1] CRAN (R 4.4.1)
 profvis       0.3.8      2023-05-02 [1] CRAN (R 4.4.1)
 promises      1.3.0      2024-04-05 [1] CRAN (R 4.4.1)
 ps            1.7.7      2024-07-02 [1] CRAN (R 4.4.1)
 purrr         1.0.2      2023-08-10 [1] CRAN (R 4.4.1)
 R6            2.5.1      2021-08-19 [1] CRAN (R 4.4.1)
 ragg          1.3.2      2024-05-15 [1] CRAN (R 4.4.1)
 Rcpp          1.0.12     2024-01-09 [1] CRAN (R 4.4.1)
 remotes       2.5.0      2024-03-17 [1] CRAN (R 4.4.1)
 reprex        2.1.1      2024-07-06 [1] CRAN (R 4.4.1)
 rlang         1.1.4      2024-06-04 [1] CRAN (R 4.4.1)
 rmarkdown     2.27       2024-05-17 [1] CRAN (R 4.4.1)
 rstudioapi    0.16.0     2024-03-24 [1] CRAN (R 4.4.1)
 sass          0.4.9      2024-03-15 [1] CRAN (R 4.4.1)
 sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.4.1)
 shiny       * 1.8.1.1    2024-04-02 [1] CRAN (R 4.4.1)
 stringi       1.8.4      2024-05-06 [1] CRAN (R 4.4.0)
 stringr       1.5.1      2023-11-14 [1] CRAN (R 4.4.1)
 systemfonts   1.1.0      2024-05-15 [1] CRAN (R 4.4.1)
 textshaping   0.4.0      2024-05-24 [1] CRAN (R 4.4.1)
 tibble        3.2.1      2023-03-20 [1] CRAN (R 4.4.1)
 urlchecker    1.0.1      2021-11-30 [1] CRAN (R 4.4.1)
 usethis       3.0.0      2024-07-29 [1] CRAN (R 4.4.1)
 utf8          1.2.4      2023-10-22 [1] CRAN (R 4.4.1)
 vctrs         0.6.5      2023-12-01 [1] CRAN (R 4.4.1)
 withr         3.0.1      2024-07-31 [1] CRAN (R 4.4.1)
 xfun          0.45       2024-06-16 [1] CRAN (R 4.4.1)
 xtable        1.8-4      2019-04-21 [1] CRAN (R 4.4.1)
 yaml          2.3.10     2024-07-26 [1] CRAN (R 4.4.1)

 [1] C:/Users/EndicottS/AppData/Local/Programs/R/R-4.4.1/library

──────────────────
cpsievert commented 3 weeks ago

I think this is the behavior you're looking for (the default width is 100%, so the behavior you're seeing seems expected)?

shinyApp(
    ui = page_sidebar(
        sidebar = sidebar(
            actionButton("newplot", "New plot")
        ),
        plotOutput("plot", width = 400, fill = FALSE)
    ),
    server = function(input, output) {
        output$plot <- renderPlot({
            input$newplot
            # Add a little noise to the cars data
            cars2 <- cars + rnorm(nrow(cars))
            plot(cars2)
        }, 
            width = 400)
    }
)
see24 commented 3 weeks ago

That works for this example but in my actual use case I need to set the width on the server side using a function.

Here is a better reprex

shinyApp(
  ui = page_sidebar(
    sidebar = sidebar(
      actionButton("newplot", "New plot")
    ),
    plotOutput("plot", fill = FALSE)
  ),
  server = function(input, output) {

    counter <- reactiveValues(n = 1)

    observeEvent(input$newplot, {
      counter$n <- counter$n + 1
      })

    output$plot <- renderPlot({
      input$newplot
      # Add a little noise to the cars data
      par(mfrow = c(1,counter$n))

      for(i in 1:counter$n){
        cars2 <- cars + rnorm(nrow(cars))
        plot(cars2)
      }
    }, 
    width = function(){
      400*counter$n
    })
  }
)
cpsievert commented 3 weeks ago

In that case, you could set width = "auto" instead. But, I think what you really want is a different plotOutput("plot_i", width = 400) for each plot, then something like layout_column_wrap() to wrap the new plots onto new lines when needed.

see24 commented 3 weeks ago

No I want to adjust the width of the plot output based on the calculation I do on the server side and I want it to adjust appropriately to changes in window size like it does with basic shiny. In my real example I am using a faceted ggplot bar chart and the user can add any number of scenarios and re-run the model which adds another facet to the ggplot plot. Therefore, I want to control the width of the plot so the bars are not super wide when there are not very many scenarios and I need to have it all in one plot with coordinated legend etc.

Here is an example of what my actual plot looks like: image

cpsievert commented 3 weeks ago

In that case, you'll want a renderUI() that returns a plotOutput(width = 400*counter$n)

see24 commented 3 weeks ago

@cpsievert what you supplied is a useful workaround but I think that bslib is still not behaving as expected. Why doesn't it respect the width that is set it renderPlot in the way that shiny does? Is this difference documented somewhere?

I switched from plain shiny to access some of the awesome theming features that bslib has but it would be helpful if these sorts of differences were minimized and or explained.

cpsievert commented 3 weeks ago

That's true, I'm not sure we'd change the behavior at this point, but we could do more to document difference