dynamically adjust height and/or width of shiny-plotly output based on window size
Asked Answered
A

3

16

I would like to have the height and width of the plotlyOutput adjusted to the current window size. I have tried to use the below but of no use.

ShinyUi <- fluidPage(
  
  # Application title
  titlePanel("title"),
  
  sidebarLayout(
    sidebarPanel(
      ... inputs ...
    ),
    
    mainPanel(
          plotlyOutput("distPlot", height = 'auto', width = 'auto')
      )
  ))

ShinyServer <- function(input, output, session) {
  
   output$distPlot <- renderPlotly({
    
    p <- ggplot(dataShow, aes(x=dataShow$X, y=dataShow$Y))  + 
geom_point(shape=1, alpha = 0.5, color = "grey50")

    ggplotly(p)
    
  })
  
}


# Run the application 
shinyApp(ui = ShinyUi, server = ShinyServer)

Would you know of any other options to use maybe in server function instead of the above UI function usage?

Smaller Window: enter image description here

Expanded Window:enter image description here

Abbevillian answered 2/6, 2017 at 8:58 Comment(7)
are you already using fluidPage() ?Redhead
@BigDataScientist Please look at the code structure included in the updated post.Abbevillian
What do you mean when you say shiny-plotly output height and width adjusted to the current window size? Do you want it do occupy certain ratio of your screen size?Sitra
@Sitra It should resize according to the available window properties. Or in other words, it should occupy 75% of the window area all the time. For more clearer picture, I have added the figures both before and after increasing the browser window size.Abbevillian
One way which is tedious and requires js would be to get the window size and pass it to ggplotly function. Refer to this link to get the window size.Sitra
@Sitra I am looking for renderPlotly or plotlyOutput options. The mentioned sources are not useful in my case.Abbevillian
For those interested: I left a simple approach below.Rehearing
S
20

It does not answer your question but in line to my comments you can add the plot height and width to the ggplotly function using the js from this link.

I have prepared a minimal example of what you are want.

library(shiny)
library(plotly)

ShinyUi <- fluidPage(
  tags$head(tags$script('
                        var dimension = [0, 0];
                        $(document).on("shiny:connected", function(e) {
                        dimension[0] = window.innerWidth;
                        dimension[1] = window.innerHeight;
                        Shiny.onInputChange("dimension", dimension);
                        });
                        $(window).resize(function(e) {
                        dimension[0] = window.innerWidth;
                        dimension[1] = window.innerHeight;
                        Shiny.onInputChange("dimension", dimension);
                        });
                        ')),

      plotlyOutput("distPlot", width = "auto")

  )

ShinyServer <- function(input, output, session) {


  #To make the responsive to the change in UI size
  observeEvent(input$dimension,{

    output$distPlot <- renderPlotly({

      p <- ggplot(iris, aes(x = Sepal.Length, y=Sepal.Width))  +
        geom_point(shape=1, alpha = 0.5, color = "grey50")
      ggplotly(p, width = (0.95*as.numeric(input$dimension[1])), height = as.numeric(input$dimension[2]))

    })

  })

}


# Run the application 
shinyApp(ui = ShinyUi, server = ShinyServer)

The output you get is as follows: enter image description here

Now when you make the window even smaller you still get a plot which occupies the whole screen (no scrollbars!) as follows: enter image description here

Sitra answered 8/6, 2017 at 13:31 Comment(2)
Yes, Thanks. Though it does not answer my question, it provided useful ways of achieving the solution. (If there is no another straightforward answer in next few days, I will accept this as a (workaround) answer.)Abbevillian
I feel like he answered your question, for the most part. It doesn't look like the plotly library for R has a simple means for you to achieve this. His solution was more elegant than my own; yet to find something as good.Strike
R
2

We can simply use relative css units:

library(shiny)
library(plotly)

ui <- fluidPage(
  plotlyOutput("plot", width = "90vw", height = "90vh")
)

server <- function(input, output, session) {
  output$plot <- renderPlotly({plot_ly(x = 1:10, y = 1:10, type = "scatter", mode = "lines+markers")})
}

shinyApp(ui, server)

result

Rehearing answered 5/10, 2023 at 14:50 Comment(1)
I think this is exactly the simple answer that @Abbevillian was looking for, it was certainly what I was looking for. Thanks @ismirsehregal! In my case, I am using it in a navbarPage with a sidebarLayout and just a simple mainPanel(plotOutput("Line_Chart", width = "80vw", height = "90vh"))) i.e., you don't necessarily need a fluidPage with plotlyOutput. I did not make any size arguments in the server.R fileProulx
S
1

Foreward

Please see the post by @SBista first.

I simply want to add to that response for a special use case: to lower the frequency of times Shiny attempts to re-render a visualization as the window is slowly resized by grabbing one of the edges of the window with the mouse and resizing that way. For me, render time took awhile, and without this additional code, it was doing several re-renders back to back from just one window resize.

Answer

Inside my ui.R I have a tags$script with the following JS string:

console.log("INFO: Loaded ui.R custom JS.");

// VARS
const REFRESH_RATE_MIN_SECONDS = 1.5;
var dimension = [0, 0];
var notRecentlyRendered = true;
var midRender = false;
var timeNow = Date.now();
var lastRendered;
var nowDiffMs;

// METHODS
$(document).on("shiny:connected", function(e) {
    dimension[0] = window.innerWidth;
    dimension[1] = window.innerHeight;
    Shiny.onInputChange("dimension", dimension);
})

$(window).resize(function(e) {
    timeNow = Date.now();
    firstRender = (typeof(lastRendered) === "undefined");

    if (firstRender === true) {
      nowDiffMs = timeNow - lastRendered;
      refreshRateMinMs = REFRESH_RATE_MIN_SECONDS * 1000;
      notRecentlyRendered = nowDiffMs > refreshRateMinMs;
    }

    if ((midRender === false) && (notRecentlyRendered === true)) {
      console.log("INFO: Adjusting figure height.");
      dimension[0] = window.innerWidth;
      dimension[1] = window.innerHeight;
      midRender = true;
      Shiny.onInputChange("dimension", dimension);
    }
})

In my server.R file I have my observable:

observeEvent(input$dimension,{
    output$multi_indicator_facility <- renderPlotly({
      plot.multi_indicator_facility(input)
})

In another file where I have plot.multi_indicator_facility(), which goes roughly as follows:

gg = ggplot(...)  # ... = a lot of code
ggp = ggplotly(gg, height=figure.height)  # I took figure.height from input$dimension
# More JS within R: 
ggp = onRender(
      ggp, '
      function(el) { 
        console.log("Rendered.");
        lastRendered = Date.now();
        midRender = false;
      }
    ')
return(ggp)

Also don't forget to include the htmlwidgets lib to use onRender.

library('htmlwidgets')  # <-- include this somewhere (e.g. server.R)
Strike answered 13/4, 2021 at 3:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.