3

My problem here is, I think, an edge case for this type of problem. With that said, I've got some reproducible code here that might help a lot of people with similar issues they have, particularly the issue of changing a ggplot's plot height in RShiny (which is default set to 400px).

Here is a demo of a shiny app where the height of the ggplot is set equal to the width of the ggplot:

mydf = data.frame(x = 1:5, y = 1:5)

# User Interface
# =================
ui <- fluidPage(theme = shinytheme('united'),
                fluidRow(
                  column(width = 12, align = 'center',
                         plotOutput('myplot', height = 'auto')
                  )             
))
# ====

# Server Code 
# ==============
server <- shinyServer(function(input, output, session) {

  # 3. Create the chart
  # ===-===-===-===-===-===
  output$myplot <- renderPlot({

    ggplot(mydf, aes(x = x, y = x)) + geom_point()
  }, height = function() { session$clientData$output_myplot_width })
})
# ====

shinyApp(ui, server)

Play around with the width of the window launched by launching this shiny app. By setting height = 'auto' in the UI, and then setting height = function() { session$clientData$output_myplot_width } in the Server, the height is dynamically updated. Very good indeed.

I am working on something similar in plotly, however a significant constraint that I have is that I currently need to pass a parameter for height and width to my call of plotly(), due to the very specific way I am trying to display the markers on my plot. An example of what I am trying to do is as such:

mydf <- data.frame(x = 1:5, y = 1:5)
myplotlyfunction <- function(mydf, myplotheight) {
  plot_ly(mydf, height = myplotheight, width = myplotheight * 1.2) %>%
    add_trace(x = ~x, y = ~y, type = 'scatter', mode = 'markers')
}

# User Interface
# =================
ui <- fluidPage(theme = shinytheme('united'),
                fluidRow(
                  column(width = 12, align = 'center',
                         plotlyOutput('myplotly')
                  )
))
# ====

# Server Code
# ==============
server <- shinyServer(function(input, output, session) {

  # 3. Create the chart
  # ===-===-===-===-===-===
  output$myplotly <- renderPlotly({

    this.height <- 600
    myplotlyfunction(mydf, myplotheight = this.height)

  })
})
# ====

shinyApp(ui, server)

The specific reason why I need to pass a height and width parameter to the plot_ly() call is deserving of a post of its own, and unfortunately I haven't thought of a work around yet. Here is a real example of my plot_ly output -

enter image description here

At a high level, the marker size parameter for plot_ly scatter plots sets the marker sizes based on pixels, and my plot needs very specifically sized markers, and these marker sizes are therefore a function of the plot size.

Here is my attempt to make my plot_ly plots dynamic in Shiny, despite having to initially pass a fixed parameter to the plot_ly height. The idea is motivated on the initial ggplot() dynamic height function:

mydf <- data.frame(x = 1:5, y = 1:5)
myplotlyfunction <- function(mydf, myplotheight) {
  plot_ly(mydf, height = myplotheight, width = myplotheight * 1.2) %>%
    add_trace(x = ~x, y = ~y, type = 'scatter', mode = 'markers')
}

# User Interface
# =================
ui <- fluidPage(theme = shinytheme('united'),
                fluidRow(
                  column(width = 12, align = 'center',
                         plotlyOutput('myplotly', height = 'auto')
                  )
                ))
# ====

# Server Code
# ==============
server <- shinyServer(function(input, output, session) {

  # 3. Create the chart
  # ===-===-===-===-===-===
  output$myplotly <- renderPlotly({

    this.height <- function() { session$clientData$output_myplotly_width }
    myplotlyfunction(mydf, myplotheight = this.height)

  }, height = function() { session$clientData$output_myplotly_width })
})
# ====

shinyApp(ui, server)

This does not work, and in fact the app crashes right away.

Thank you a ton for anybody who made it to the end of this post. Any help is appreciated regarding how I can dynamically resize a plot_ly() plot in R Shiny, based on the height or width of the app window, given that the plot_ly function itself requires a height parameter. Thoughts on how to solve the underlying problem of needing a height parameter to plot_ly() in the first place are appreciated as well, but that's a separate issue (that I've posted about myself, here - Set marker size based on coordinate values, not pixels, in plotly R - and in other posts as well).

Once again, thanks a ton for any help!

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
Canovice
  • 9,012
  • 22
  • 93
  • 211
  • 1
    +1 mostly for the amazing plot... although I agree it is an interesting problem to solve. Given that controlling for height in html should be given equal weight to such things as 'dependency hell' *et al.* what is driving your search? Is there a specific use case that requires the plot to be dynamically resized after rendering? – Kevin Arseneau Dec 06 '17 at 00:49
  • 1
    Thanks. Mainly the issue is that I don't know the window size that users of my app have - this is a tool I plan to share with the public. Not everybody has the same laptop screen / number of pixels as I do. – Canovice Dec 06 '17 at 00:58
  • 1
    I understand that pain and will track this question to see how it develops. Not an answer to your specific problem, however, I used [this](https://stackoverflow.com/questions/36469631/how-to-get-leaflet-for-r-use-100-of-shiny-dashboard-height) question to guide me for a *leaflet* project I did and it may be of use for you. – Kevin Arseneau Dec 06 '17 at 01:06
  • You can have a look at the answer I gave [here](https://stackoverflow.com/a/44437161/5894457). It is a workaround solution to adjust height and width of plotly graph in R Shiny. – SBista Dec 06 '17 at 04:50
  • @SBista I actually came across this approach and did end up implementing something similar. I found it useful grabbing the pixel width and height of the window! – Canovice Dec 06 '17 at 06:15

0 Answers0