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

R Shiny每日从Google Drive更新图表:加载位置与优化问询

R Shiny 定期更新图表的实现疑问

初始工作流与疑问

我的工作流是:每日运行R脚本清理数据,生成Plotly图表(耗时数百毫秒,不宜在Shiny应用内生成,避免影响用户体验),将图表保存为.RData文件存储到Google Drive。需要让R Shiny应用每日从Google Drive获取该文件更新图表。

疑问:获取.RData文件的操作应该放在global文件还是server端?这个选择对用户加载速度有什么影响?

初始示意代码

library(shiny)
library(plotly)
library(googledrive)

# Define UI
ui <- fluidPage(
  titlePanel("Load Plotly Plot from Google Drive"),
  mainPanel(
    plotlyOutput("loaded_plot")
  )
)

# Define server logic
server <- function(input, output, session) {
  
  MyPlot <- observe({   
    invalidateLater(86400000, session) 
    
    #auth Google Drive
    drive_auth()
    
    #download plot from Google Drive
    drive_download("plot.RData")

  })
  
  # Render the plotly plot
  output$loaded_plot <- renderPlotly({
    MyPlot
  })
  
}

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

更新后的工作流与优化疑问

因googledrive包的下载仅支持本地存储,我调整了工作流,已实现通过定期检查Google Sheet来更新的功能,示例中每30秒检查一次。目前将MyPlot的更新逻辑放在reactivePoll中,想咨询这个实现方式是否可以更优雅?

更新后的代码

# * Global

library(shiny)
library(plotly)
library(googledrive)
library(googlesheets4)

# Function plotly plot
plotly_scatter <- function(df, x, y) {
  
  fig <- plot_ly(df) 
  
  fig <- fig %>% 
    add_lines(type = 'scatter', mode = "lines",
              x = ~x, y = ~y)
  
  return(fig)
}

data_frame <- reactivePoll(
  intervalMillis = 30000,
  session = NULL,
  checkFunc = function() {
    #authentication
    drive_auth()
    gs4_auth(token = drive_token())
    
    #Read in Google Sheet
    gs_file<- drive_get('df')
    gs_data <<- read_sheet(gs_file)
    
    #Create plotly plot
    MyPlot <<- plotly_scatter(gs_data, x, y)
    
  }
)


# * UI
ui <- fluidPage(
  titlePanel("Load Plotly Plot from Google Drive"),
  mainPanel(
    plotlyOutput("loaded_plot")
  )
)

# * Server
server <- function(input, output, session) {
  
    
    # Render the plotly plot
    output$loaded_plot <- renderPlotly({
      MyPlot
    })

}

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

解答

关于初始疑问:global vs server端的选择

  1. 放在global文件:
    • 优点:global.R代码在应用启动时仅运行一次,所有用户共享下载的图表数据,不会重复触发Google Drive请求,节省资源,用户加载速度快。
    • 缺点:若需每日更新,需结合定时任务(如later包)实现全局定时刷新,或重启应用触发下载。
  2. 放在server端:
    • 若每个用户会话独立执行下载:新用户加载时需等待下载完成,体验差,还会消耗额外的Google Drive请求配额。
    • 若结合全局缓存(如memoise包):可避免重复下载,同时支持灵活的定时更新,但需处理缓存过期逻辑。

对用户加载速度的影响:

  • 放在global:首次启动下载一次,后续用户直接读取本地缓存,加载快;但更新逻辑相对固定。
  • 放在server端(无缓存):每个新用户都要等待下载,加载慢;带全局缓存则和global方式体验接近,但实现更灵活。

关于更新后reactivePoll的优化建议

当前代码有几个可优化的点,让实现更优雅且稳定:

  1. 避免全局变量赋值(<<-):全局变量在多用户环境下易出现竞态问题,建议让reactivePoll直接返回生成好的图表,而非赋值给全局变量。
  2. 分离检查与数据处理逻辑:checkFunc仅做轻量的更新判断(如获取Google Sheet的最后修改时间),valueFunc负责实际读取数据和生成图表,减少不必要的计算。
  3. 提前完成认证:认证操作无需每次检查都执行,可放在global.R中,应用启动时完成一次即可(建议使用服务账号认证,避免交互式操作)。
  4. 明确参数传递:绘图函数的x、y参数需指定具体列名,避免依赖全局变量。

优化后的示例代码:

# Global.R
library(shiny)
library(plotly)
library(googledrive)
library(googlesheets4)

# 提前完成服务账号认证(替换为你的密钥路径)
drive_auth(path = "service_account_key.json")
gs4_auth(token = drive_token())

# 定义绘图函数
plotly_scatter <- function(df, x_col, y_col) {
  plot_ly(df) %>% 
    add_lines(type = 'scatter', mode = "lines",
              x = ~.data[[x_col]], y = ~.data[[y_col]])
}

# 定义reactivePoll获取更新后的图表
get_updated_plot <- reactivePoll(
  intervalMillis = 30000,
  session = NULL,
  # 检查函数:仅获取文件修改时间判断是否更新
  checkFunc = function() {
    gs_file <- drive_get("df")
    as.character(drive_reveal(gs_file, "modified_time")$modified_time)
  },
  # 取值函数:仅当文件更新时执行,读取数据并生成图表
  valueFunc = function() {
    gs_file <- drive_get("df")
    gs_data <- read_sheet(gs_file)
    plotly_scatter(gs_data, x_col = "x", y_col = "y") # 替换为实际列名
  }
)

# UI.R
ui <- fluidPage(
  titlePanel("Load Plotly Plot from Google Drive"),
  mainPanel(
    plotlyOutput("loaded_plot")
  )
)

# Server.R
server <- function(input, output, session) {
  output$loaded_plot <- renderPlotly({
    get_updated_plot()
  })
}

shinyApp(ui = ui, server = server)

优化点说明:

  • 移除全局变量,reactivePoll直接返回图表对象,避免多用户冲突。
  • checkFunc仅做轻量检查,减少不必要的网络请求和计算。
  • 认证操作提前完成,减少重复执行的开销。
  • 参数传递更明确,避免潜在的作用域问题。

内容的提问来源于stack exchange,提问作者H. berg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 16:34:51