Get the Size of the Window in Shiny

Get the size of the window in Shiny

See the example below. It uses Javascript to detect the browser window size (initial size and any resize), and use Shiny.onInputChange to send the data to the server code for processing. It uses shiny:connected event to get the initial window size, as Shiny.onInputChange is not ready for use until shiny is connected.

library(shiny)

# Define UI for application that draws a histogram
ui <- shinyUI(fluidPage(

# Application title
titlePanel("Old Faithful Geyser Data"),

# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
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);
});
')),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),

# Show a plot of the generated distribution
mainPanel(
verbatimTextOutput("dimension_display"),
plotOutput("distPlot")
)
)
))

# Define server logic required to draw a histogram
server <- shinyServer(function(input, output) {
output$dimension_display <- renderText({
paste(input$dimension[1], input$dimension[2], input$dimension[2]/input$dimension[1])
})

output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)

# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
})

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

Utilizing Window Size Within Shiny Module

The issue is that input values accessed by modules are namespaced, while the input values set by Shiny.onInputChange are not.

So in the myPlot module, input$dimension gets myPlot-dimension but the input is actually just dimension.

One solution would be to make the namespaced id available to the script:

library(shiny)
library(plotly)

myPlotUI <- function(id, label = "My Plot") {
ns <- NS(id)
dimensionId <- ns("dimension")

tagList(
tags$head(tags$script(sprintf("
var dimensionId = '%s';
var dimension = [0, 0];

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

$(window).resize(function(e) {
dimension[0] = window.innerWidth;
dimension[1] = window.innerHeight;
Shiny.onInputChange(dimensionId, dimension);
});
", dimensionId))),

plotlyOutput(ns("myPlot"))
)
}

myPlot <- function(input, output, session) {
ns <- session$ns

output$myPlot <- renderPlotly({
plot_ly(midwest, x = ~percollege, color = ~state, type = "scatter",
width = (0.6 * as.numeric(input$dimension[1])),
height = (0.75 * as.numeric(input$dimension[2])))
})

}

server <- function(input, output, session){
callModule(myPlot, "myPlot")
}

ui <- fluidPage(
navlistPanel(
tabPanel("Dynamic Dimensions",
myPlotUI("myPlot"))
)
)

shinyApp(ui = ui, server = server)

Another solution that comes with a disclaimer: DANGER, undocumented, abuse-prone feature! You can actually get the root session from a module through session$rootScope(). Would not recommend unless you really have to, but just FYI.

library(shiny)
library(plotly)

myPlotUI <- function(id, label = "My Plot") {
ns <- NS(id)

tagList(
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(ns("myPlot"))
)
}

myPlot <- function(input, output, session) {
ns <- session$ns
rootInput <- session$rootScope()$input

output$myPlot <- renderPlotly({
plot_ly(midwest, x = ~percollege, color = ~state, type = "scatter",
width = (0.6 * as.numeric(rootInput$dimension[1])),
height = (0.75 * as.numeric(rootInput$dimension[2])))
})

}

server <- function(input, output, session){
callModule(myPlot, "myPlot")
}

ui <- fluidPage(
navlistPanel(
tabPanel("Dynamic Dimensions",
myPlotUI("myPlot"))
)
)

shinyApp(ui = ui, server = server)

In shiny, is it possible to get the size of an ui element in the server?

I found out that you can indeed access some information about the ui from the server.

To answer the question, you can get the width and height of an element created with plotOutput("plot1") using session$clientData[["output_plot1_width"]] and session$clientData[["output_plot1_height"]].

To get an exhaustive list of what info is available in a given session, go in debug-mode in a reactive expression in server.R (for instance in renderText() and type reactiveValuesToList(session$clientData).

Layout shiny app to set heights of elements to add up to 100% of window size

Add a height argument to your plotOutputs with 30vh (vertical height, essentially % of container). You can mess with the value to get it exactly where you want. More info on vh here.

    # Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot", height = '30vh'),
plotOutput("distPlot2", height = '30vh'),
plotOutput("distPlot3", height = '30vh')
)

Output

Scaling shiny plots to window height

Use CSS3. Declare your height in viewport units http://caniuse.com/#feat=viewport-units .
You should be able to declare them using the height argument in plotOutput however shiny::validateCssUnit doesnt recognise them so you can instead declare them in a style header:

library(shiny)
runApp(
list(server= function(input, output) {
output$myplot <- renderPlot({
hist(rnorm(1000))
})
}
, ui = pageWithSidebar(
headerPanel("window height check"),
sidebarPanel(
tags$head(tags$style("#myplot{height:100vh !important;}"))
),
mainPanel(
plotOutput("myplot")
)
)
)
)

This wont work in the shiny browser but should work correctly in a main browser.

Sample Image



Related Topics



Leave a reply



Submit