rbokeh icon indicating copy to clipboard operation
rbokeh copied to clipboard

grid_plot width is not dynamic

Open mattaws opened this issue 6 years ago • 2 comments

My grid_plot only uses half my page. it stretches if I specify the px width, but I want it to fill the page dynamically and responsively, regardless of screen resolution screen shot 2018-10-20 at 7 29 45 pm

I have tried to use width = '100%' in the figure, rbokeh output, and grid_plot settings. Examples below and I attached a screenshot of how the unspecificed (no px specified) outputs

Within dashboardBody: rbokehOutput("rt", width = "100%", height = "800px")

Within server output (it changes when I specify 1800, errors on '100%':

` output$rt <-

renderRbokeh({

  grid_plot(

    list(s1, s2, s3),

    ncol = 3,

    width = 1800, 

    height = 500,

    same_axes = FALSE

  )

})`

mattaws avatar Oct 21 '18 02:10 mattaws

rbokeh::grid_plot seems to only accept absolute values as width. A possible solution, not yet perfect at this stage, is to dynamically retrieve the width of the screen, then pass it to grid_plot. Building on top of this SO answer, we have something like this:

library(shinydashboard)
library(rbokeh)

bk1 <- figure() %>%
  ly_bar(variety, data = lattice::barley) %>%
  theme_axis("x", major_label_orientation = 90)

bk2 <- figure() %>%
  ly_points(Sepal.Length, Sepal.Width, data = iris,
            color = Species, glyph = Species,
            hover = list(Sepal.Length, Sepal.Width))


ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
    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);
                                });
                            ')),
    fluidRow(
      valueBox(10, "Box"),
      valueBox(20, "Box"),
      valueBox(30, "Box")
    ),
    fluidRow(
      box(width = 12,
          rbokehOutput("bk", width = "100%", height = "400px")
      )
    )
  )
)


server <- function(input, output, session) {
  
  output$bk <- renderRbokeh({
    print(input$dimension)
    grid_plot(list(bk1, bk2), width = input$dimension[1] )
  })
  
}

shinyApp(ui, server)

It requires some refinements: we don't need the height and it would be better to retrieve the width of the parent element rather than the window. Or there may be a better solution.

Atrebas avatar Oct 22 '18 22:10 Atrebas

For what it's worth, below is an updated version. It's a bit better with: (i) js code handled in an external file, (ii) width only, and (iii) sidebar collapsing taken into account. One drawback is that the plots are re-rendered each time the width changes. Here is the js code (should be in www/adjust_width.js). Disclaimer: I'm a js newbie.

var dimension = [500]; 
$(document).on("shiny:connected", function (e) {
    if ($("body").hasClass("sidebar-collapse")) {
        dimension[0] = window.innerWidth;
    } else {
        dimension[0] = window.innerWidth - 230;
    }
    Shiny.onInputChange("dimension", dimension);
});
$(window).resize(function (e) {
    if ($("body").hasClass("sidebar-collapse")) {
        dimension[0] = window.innerWidth;
    } else {
        dimension[0] = window.innerWidth - 230;
    }
    Shiny.onInputChange("dimension", dimension);
});

And the R code:

library(shinydashboard)
library(rbokeh)

## ---------------------------------
## bokeh figures

bk1 <- figure() %>%
  ly_bar(variety, data = lattice::barley) %>%
  theme_axis("x", major_label_orientation = 90)

bk2 <- figure() %>%
  ly_points(Sepal.Length, Sepal.Width, data = iris,
            color = Species, glyph = Species,
            hover = list(Sepal.Length, Sepal.Width))

## ---------------------------------
## ui

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
    ## ! adjust_width.js must be in the www folder
    tags$head(tags$script(src = "adjust_width.js")), 
    fluidRow(
      valueBox(10, "Box"),
      valueBox(20, "Box"),
      valueBox(30, "Box")
    ),
    box(width = 12, 
        rbokehOutput("bk", width = "100%")
    )
  )
)

## server

server <- function(input, output, session) {
  output$bk <- renderRbokeh({
    
    width = input$dimension[1] - 100
    if (length(width) == 0) { width = 500 } # starting value
    print(width)
    
    grid_plot(list(bk1, bk2), 
              width  = width,
              height = 400)
  })
}

## launch app

shinyApp(ui, server)

Atrebas avatar Oct 23 '18 16:10 Atrebas