You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Shiny中Plotly仪表盘无法占满fluidRow高度,底部留白求助

解决Shiny中Plotly仪表盘在fluidRow底部留白的问题

我在R Shiny应用的fluidRow里放置了4个Plotly仪表盘(gauge),但每个图表底部始终存在难以消除的留白,超出了fluidRow的高度。已在多处设置height="100%"但问题未解决,期望仪表盘能占满fluidRow高度,且fluidRow无需固定高度,可随窗口缩放。

问题代码

main_content_MATDetail <- mainPanel(
 
  fluidRow(
    style = "background-color: #f0f0f0; height:200px",
    column(3, plotlyOutput("OAGuage", height="100%") %>% withSpinner(color = "#12436D")),
    column(3, plotlyOutput("UAGuage") %>% withSpinner(color = "#12436D")),
    column(3, plotlyOutput("AAGuage") %>% withSpinner(color = "#12436D")),
    column(3, plotlyOutput("PAGuage") %>% withSpinner(color = "#12436D"))
  )
)

ui <- fluidPage(
 tabsetPanel(
   id = "main_tabs",
     tabPanel("Details ",
            titlePanel(div("Details", style = "font-size:18px;")),
            
             main_content_MATDetail
               ))
 
) #end of fluid page

server <- function(input, output, session){
 
    count_more<-9
    count_less<-17
    denominator<-(count_more+count_less)
    prop_better <- (100 * count_less/denominator)
    
    output$OAGuage <- renderPlotly({
        
        fig <- plot_ly(
            domain = list(x = c(0, 1), y = c(0, 1)),
            value = prop_better,
            title = list(text = "A"),
            type = "indicator",
              gauge = list(
               
                bar = list(
                    color = case_when(
                        prop_better >= 75 ~ "green",
                        prop_better >= 50 & prop_better < 75 ~ "orange",
                        TRUE ~ "red"
                    )
                ),
                axis = list(range = list(0, 100),
                            tickvals = c(0, 25, 50, 75, 100),
                            ticktext = c("0", "25", "50", "75", "100"))
            ),
            mode = "gauge+number" 
        ) 
        
        fig <- fig %>%
            layout(
                margin = list(l=0,r=0),
                paper_bgcolor = "#f0f0f0",
                font = list(color = "darkblue", family = "Arial"))
        
    })
    
    output$AAGuage <- renderPlotly({
         fig <- plot_ly(
            domain = list(x = c(0, 1), y = c(0, 1)),
            value = prop_better,
            title = list(text = "B"),
            type = "indicator",
            color="black",
            # plot_bgcolor = "#f0f0f0",
            gauge = list(
                # bar = list(color = "darkblue"),
                # bgcolor = "#f0f0f0",
                bar = list(
                    color = case_when(
                        prop_better >= 75 ~ "green",
                        prop_better >= 50 & prop_better < 75 ~ "orange",
                        TRUE ~ "red"
                    )
                ),
                axis = list(range = list(0, 100),
                            tickvals = c(0, 25, 50, 75, 100),
                            ticktext = c("0", "25", "50", "75", "100"))
            ),
            mode = "gauge+number" 
        ) 
        
        fig <- fig %>%
            layout(
                margin = list(l=0,r=0),
                height="100%",
                paper_bgcolor = "#f0f0f0",
                font = list(color = "darkblue", family = "Arial"))
        
    })
    
    output$UAGuage <- renderPlotly({
        fig <- plot_ly(
            domain = list(x = c(0, 1), y = c(0, 1)),
            value = prop_better,
            title = list(text = "C"),
            type = "indicator",
            color="black",
            # plot_bgcolor = "#f0f0f0",
            gauge = list(
                # bar = list(color = "darkblue"),
                # bgcolor = "#f0f0f0",
                bar = list(
                    color = case_when(
                        prop_better >= 75 ~ "green",
                        prop_better >= 50 & prop_better < 75 ~ "orange",
                        TRUE ~ "red"
                    )
                ),
                axis = list(range = list(0, 100),
                            tickvals = c(0, 25, 50, 75, 100),
                            ticktext = c("0", "25", "50", "75", "100"))
            ),
            mode = "gauge+number"
        ) 
        
        fig <- fig %>%
            layout(
                margin = list(l=0,r=0),
                paper_bgcolor = "#f0f0f0",
                font = list(color = "darkblue", family = "Arial"))
        
    })
    
    output$PAGuage <- renderPlotly({
        fig <- plot_ly(
            domain = list(x = c(0, 1), y = c(0, 1)),
            value = prop_better,
            title = list(text = "D"),
            type = "indicator",
            color="black",
     
            gauge = list(
               
                bar = list(
                    color = case_when(
                        prop_better >= 75 ~ "green",
                        prop_better >= 50 & prop_better < 75 ~ "orange",
                        TRUE ~ "red"
                    )
                ),
                axis = list(range = list(0, 100),
                            tickvals = c(0, 25, 50, 75, 100),
                            ticktext = c("0", "25", "50", "75", "100"))
            ),
            mode = "gauge+number" 
        ) 
        
        fig <- fig %>%
            layout(
                margin = list(l=0,r=0),
                paper_bgcolor = "#f0f0f0",
                font = list(color = "darkblue", family = "Arial"))
        
    })
}


##################################SHINY APP
shinyApp(ui = ui, server = server)

解决方案

问题根源在于Plotly仪表盘默认存在上下边距,且Shiny组件的高度设置未完全统一,fluidRow的固定高度限制了自适应能力。以下是具体修复步骤:

  • 统一plotlyOutput高度设置:给所有plotlyOutput添加height="100%",确保它们继承父容器高度
  • 消除Plotly图表的上下边距:在每个图表的layout中,将margin设置为list(l=0, r=0, t=0, b=0),移除默认的上下留白
  • 统一图表布局高度:给每个Plotly图表的layout添加height="100%",确保图表占满容器
  • 让fluidRow自适应高度:移除fluidRow的固定height:200px,改用min-height:200px保证最小高度,同时添加display: flex; align-items: stretch确保列内元素完全填充高度
  • 设置withSpinner继承高度:给withSpinner添加style="height:100%;",让加载动画容器也占满父元素

修改后的完整代码

main_content_MATDetail <- mainPanel(
  fluidRow(
    style = "background-color: #f0f0f0; min-height:200px; display: flex; align-items: stretch;",
    column(3, plotlyOutput("OAGuage", height="100%") %>% withSpinner(color = "#12436D", style="height:100%;")),
    column(3, plotlyOutput("UAGuage", height="100%") %>% withSpinner(color = "#12436D", style="height:100%;")),
    column(3, plotlyOutput("AAGuage", height="100%") %>% withSpinner(color = "#12436D", style="height:100%;")),
    column(3, plotlyOutput("PAGuage", height="100%") %>% withSpinner(color = "#12436D", style="height:100%;"))
  )
)

ui <- fluidPage(
  tabsetPanel(
    id = "main_tabs",
    tabPanel("Details ",
             titlePanel(div("Details", style = "font-size:18px;")),
             main_content_MATDetail
    ))
  
) #end of fluid page

server <- function(input, output, session){
  
  count_more<-9
  count_less<-17
  denominator<-(count_more+count_less)
  prop_better <- (100 * count_less/denominator)
  
  # 封装仪表盘生成函数,避免重复代码
  create_gauge <- function(title_text) {
    fig <- plot_ly(
      domain = list(x = c(0, 1), y = c(0, 1)),
      value = prop_better,
      title = list(text = title_text),
      type = "indicator",
      gauge = list(
        bar = list(
          color = case_when(
            prop_better >= 75 ~ "green",
            prop_better >= 50 & prop_better < 75 ~ "orange",
            TRUE ~ "red"
          )
        ),
        axis = list(range = list(0, 100),
                    tickvals = c(0, 25, 50, 75, 100),
                    ticktext = c("0", "25", "50", "75", "100"))
      ),
      mode = "gauge+number" 
    ) 
    
    fig %>%
      layout(
        margin = list(l=0, r=0, t=0, b=0),
        height = "100%",
        paper_bgcolor = "#f0f0f0",
        font = list(color = "darkblue", family = "Arial")
      )
  }
  
  output$OAGuage <- renderPlotly(create_gauge("A"))
  output$AAGuage <- renderPlotly(create_gauge("B"))
  output$UAGuage <- renderPlotly(create_gauge("C"))
  output$PAGuage <- renderPlotly(create_gauge("D"))
}

##################################SHINY APP
shinyApp(ui = ui, server = server)

另外,代码中封装了create_gauge函数,减少了重复代码,后续修改仪表盘样式只需调整这个函数即可。

内容的提问来源于stack exchange,提问作者sophieflo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:58:09