【问题标题】:Shiny: Dynamic height adjustment of plotShiny:情节的动态高度调整
【发布时间】:2020-12-17 10:32:18
【问题描述】:

问题:在下面的 Shiny 应用中,用户可以根据选择输入添加显示在 valueboxes 中的信息。如果用户选择了所有可能的选项,那么 UI 将如屏幕截图所示。

问题: 绘图(与 valueboxes 在同一行)是否有可能调整高度(因此绘图的底部与最后一个 valuebox 的底部对齐)?

library(shiny)
library(shinydashboard)

ui <- dashboardPage(
  dashboardHeader(),
  
  dashboardSidebar(
    selectizeInput(
      inputId = "select",
      label = "Select country:",
      choices = c("CH", "JP", "GER", "AT", "CA", "HK"),
      multiple = TRUE)
  ),
  
  dashboardBody(
    fluidRow(column(2, uiOutput("ui1")),
             column(10, plotOutput("some_plot"))))#,
                # column(4, uiOutput("ui2")),
                # column(4, uiOutput("ui3")))
)

server <- function(input, output) {
  
  output$ui1 <- renderUI({
    req(input$select)
    
    lapply(seq_along(input$select), function(i) {
      fluidRow(
        valueBox(value = input$select[i],
                 subtitle = "Box 1",
                 width = 12)
      )
    })
  })
  
  output$some_plot <- renderPlot(
    plot(iris)
  )
}

shinyApp(ui = ui, server = server)

【问题讨论】:

  • 高度由plotOutput(height = "400px")控制(这是默认值)如果将其更改为height = "100%"会发生什么?
  • 很好的代表顺便说一句:)

标签: r shiny shinydashboard


【解决方案1】:

您可以在renderPlot 中调整高度。我已将最小值设置为 3 值框高度。因此,在您添加 3 个值框后,它开始增加高度。您可以根据需要对其进行修改。试试下面的代码。

  library(shiny)
  library(shinydashboard)
  
  ui <- dashboardPage(
    dashboardHeader(),
    
    dashboardSidebar(
      selectizeInput(
        inputId = "select",
        label = "Select country:",
        choices = c("CH", "JP", "GER", "AT", "CA", "HK"),
        multiple = TRUE)
    ),
    
    dashboardBody(
      fluidRow(column(2, uiOutput("ui1")),
               column(10, plotOutput("some_plot"))))#,
    
    # column(4, uiOutput("ui2")),
    # column(4, uiOutput("ui3")))
  )
  
  server <- function(input, output) {
    plotht <- reactiveVal(360)
    observe({
      req(input$select)
      nvbox <- length(input$select)
      if (nvbox > 3) {
        plotheight <- 360 + (nvbox-3)*120
      }else plotheight <- 360
      plotht(plotheight)
    })
    
    output$ui1 <- renderUI({
      req(input$select)
      
      lapply(seq_along(input$select), function(i) {
        fluidRow(
          valueBox(value = input$select[i],
                   subtitle = "Box 1",
                   width = 12)
        )
      })
    })
    
    observe({
      output$some_plot <- renderPlot({
        plot(iris)
      }, height=plotht())
    })
 
    
  }
  
  shinyApp(ui = ui, server = server)

【讨论】:

    【解决方案2】:

    这是我的尝试,基于this answer。这使用窗口大小侦听器来动态调整绘图的大小(可能通过在plotOutput 调用中使用inline = TRUE)。外层容器的宽度是固定的,所以可以直接引用,但是高度是动态的,所以我的解决方法是使用窗口高度减去50像素。只要有一个单独的情节元素,这似乎就可以工作,并且侧边栏没有被调整到情节的顶部,而不是旁边。

    窗口调整大小仅在半秒内没有变化后才调整大小,因此服务器在重绘调用中不会受到太多负担。如果尺寸尚未确定,该代码也不会绘制任何内容,因此没有初始绘图闪烁。

    library(shiny)
    
    ui <- fluidPage(
        ## Add a listener for the window height and plot container width
        tags$head(tags$script('
                            var winDims = [0, 0];
                            var plotElt = document;
                            $(document).on("shiny:connected", function(e) {
                                plotElt = document.getElementById("plotContainer");
                                winDims[0] = plotElt.clientWidth;
                                winDims[1] = window.innerHeight;
                                Shiny.onInputChange("winDims", winDims);
                            });
                            $(window).resize(function(e) {
                                winDims[0] = plotElt.clientWidth;
                                winDims[1] = window.innerHeight;
                                Shiny.onInputChange("winDims", winDims);
                            });
                        ')),
        titlePanel("Old Faithful Geyser Data"),
        sidebarLayout(
            sidebarPanel(
                sliderInput("bins",
                            "Number of bins:",
                            min = 1,
                            max = 50,
                            value = 30),
                sliderInput("height", label="Height",
                            min=100, max=900, value = 600)
            ),
            mainPanel(
                tags$div(id="plotContainer", ## Add outer container to make JS constant
                         ## Use an "inline" plot, so that width and height can be set server-side
                         plotOutput("distPlot", inline = TRUE))
            )
        )
    )
    
    server <- function(input, output) {
        ## reduce the amount of redraws on window resize
        winDims_d <- reactive(input$winDims) %>% debounce(500)
        ## fetch the changed window dimensions
        getWinX <- function(){
            print(input$winDims);
            if(is.null(winDims_d())) { 400 } else {
                return(winDims_d()[1])
            }
        }
        getWinY <- function(){
            if(is.null(winDims_d())) { 600 } else {
                return(winDims_d()[2] - 50)
            }
        }
        output$distPlot <- renderPlot({
            if(is.null(winDims_d())){
                ## Don't plot anything if we don't yet know the size
                return(NULL);
            }
            x    <- faithful[, 2]
            bins <- seq(min(x), max(x), length.out = input$bins + 1)
            hist(x, breaks = bins, col = 'darkgray', border = 'white')
        }, width = getWinX, height=getWinY)
    }
    
    shinyApp(ui = ui, server = server)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-13
      • 1970-01-01
      • 1970-01-01
      • 2012-02-10
      • 2011-11-25
      • 2015-03-25
      相关资源
      最近更新 更多