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

DT::datatable中plotly图表初始宽度不一致问题求助

问题:Shiny中DT表格内Plotly图表初始宽度不一致

Shiny应用中含plotly图表的DT表格宽度不一致

表格内的Plotly图表初始渲染时宽度不一致,仅第一行图表占满列宽。调整窗口大小后所有图表会自动适配为正常宽度,且该问题在不同浏览器中均存在。期望所有图表从初始渲染时就保持一致的最大宽度。

复现代码

library(shiny)
library(plotly)

ui <- fluidPage(
  htmltools::findDependencies(plotlyOutput("pl")),
  DT::DTOutput("dt")
)

server <- function(input, output, session) {
  output$dt <- DT::renderDT({
    df <- data.frame(
      x=paste0("plot",1:4),
      z=sapply(1:4, function(ii) {
        as.character(plotlyOutput(paste0("plotly", ii), height = 100))
      })
    )
    DT::datatable(df, escape = FALSE,
                  options = list(
                    preDrawCallback = V8::JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                    drawCallback = V8::JS('function() { Shiny.bindAll(this.api().table().node()); } ')
                  ))
  })
  output$plotly1 <- renderPlotly(plot_ly(iris, x=~Sepal.Width, y=~Sepal.Length, color=~Species, type = "scatter") |> plotly::layout(title = list(text= "plotly1")))
  output$plotly2 <- renderPlotly(plot_ly(iris, x=~Sepal.Width, y=~Sepal.Length, color=~Species, type = "scatter") |> plotly::layout(title = list(text= "plotly2")))
  output$plotly3 <- renderPlotly(plot_ly(iris, x=~Sepal.Width, y=~Sepal.Length, color=~Species, type = "scatter") |> plotly::layout(title = list(text= "plotly3")))
  output$plotly4 <- renderPlotly(plot_ly(iris, x=~Sepal.Width, y=~Sepal.Length, color=~Species, type = "scatter") |> plotly::layout(title = list(text= "plotly4")))
}

shinyApp(ui, server)

解决方案

方法1:强制设置Plotly容器与图表宽度

在创建plotlyOutput时显式指定宽度为100%,同时在图表的layout中也配置宽度为100%,确保容器和图表都占满所在列的宽度:

修改生成plotlyOutput的代码:

z=sapply(1:4, function(ii) {
  as.character(plotlyOutput(paste0("plotly", ii), height = 100, width = "100%"))
})

同时更新每个renderPlotly中的layout配置:

# 以plotly1为例,其余三个同理
output$plotly1 <- renderPlotly(
  plot_ly(iris, x=~Sepal.Width, y=~Sepal.Length, color=~Species, type = "scatter") |> 
    plotly::layout(title = list(text= "plotly1"), width = "100%")
)

方法2:在DT绘制完成后触发Plotly重绘

利用DT的drawCallback,在表格渲染完成后遍历所有Plotly图表,调用relayout方法强制重计算宽度:

修改DT的options中的drawCallback:

options = list(
  preDrawCallback = V8::JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
  drawCallback = V8::JS('function() { 
    Shiny.bindAll(this.api().table().node()); 
    // 遍历所有Plotly容器,触发宽度适配
    document.querySelectorAll(".plotly").forEach(function(el) {
      if(Plotly) Plotly.relayout(el, {width: el.offsetWidth});
    });
  } ')
)

方法3:用CSS强制约束容器宽度

在UI中添加自定义CSS样式,强制所有Plotly输出容器的宽度为100%,优先级设为最高:

ui <- fluidPage(
  tags$style(HTML("
    .plotly {
      width: 100% !important;
    }
  ")),
  htmltools::findDependencies(plotlyOutput("pl")),
  DT::DTOutput("dt")
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 11:13:11