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

如何实现Shiny App生成并保存可交互3D HTML图?

解决Shiny中rgl保存3D交互HTML为空的问题

问题根源

原代码使用open3d()会唤起桌面端的rgl可视化窗口,但Shiny服务器端的rglwidget()无法捕获这个桌面窗口的3D场景,导致保存的HTML文件内容为空。此外,直接用字符串拼接路径存在跨系统兼容性风险。

修正后的代码

# Libraries ---------------------------------------------------------------
library(shiny)
library(shinyDirectoryInput)
library(tidyverse)
library(rgl)

# START: UI ---------------------------------------------------------------
ui <- fluidPage(
  titlePanel(strong("Data Analysis App")),
  sidebarLayout(
    sidebarPanel(
      h3(em("Save Analysis")),
      directoryInput('directory', label = '选择保存文件夹'),
      h3(em("Run Analysis")),
      br(),
      actionButton("run_button", label = "开始生成")
    ),
    mainPanel(
      h1("操作说明"),
      br(),
      p("1) 选择3D图的保存目录"),
      br(),
      p("2) 点击「开始生成」按钮")
    )
  )
)

# START: Server -----------------------------------------------------------
server <- function(input, output, session) {
  
  # 目录选择逻辑
  observeEvent(
    ignoreNULL = TRUE,
    eventExpr = input$directory,
    handlerExpr = {
      if (input$directory > 0) {
        selected_directory <- choose.dir(default = readDirectoryInput(session, 'directory'))
        updateDirectoryInput(session, 'directory', value = selected_directory)
      }
    }
  )
  
  # 点击按钮生成并保存3D图
  observeEvent(input$run_button, {
    # 用file.path保证跨系统路径正确
    file_path <- file.path(readDirectoryInput(session, 'directory'), "test.html")
    
    # 创建无界面rgl设备,避免弹出桌面窗口,同时让场景可被rglwidget捕获
    rgl.open(useNULL = TRUE)
    
    # 绘制3D图
    plot3d(x = iris$Sepal.Length,
           y = iris$Sepal.Width,
           z = iris$Petal.Length)
    
    # 保存为交互式HTML
    htmlwidgets::saveWidget(
      rglwidget(width = 800, height = 800),
      file = file_path,
      libdir = "HTML-dependencies",
      selfcontained = FALSE
    )
    
    # 关闭rgl设备释放资源
    rgl.close()
  })
}

shinyApp(ui = ui, server = server)

关键修正点

  • 替换open3d()为rgl.open(useNULL = TRUE):创建无界面的rgl渲染设备,让3D场景在Shiny服务器端生成,确保rglwidget()能正确捕获场景内容。
  • 使用file.path()拼接路径:自动适配Windows/macOS/Linux的路径分隔符,避免路径错误。
  • 添加rgl.close():生成完成后关闭rgl设备,释放系统资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 21:55:31