本文介绍了闪亮的应用程序不反映更新RData文件中的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我每天都会通过cron作业为我闪亮的应用程序更新我的RData文件。但是,闪亮的应用程序在大多数情况下不会拾取更新,并且会一直显示旧RData文件中的旧数据。

这里是最小的可重现示例。当从我的桌面执行data_processing.R时,它工作正常。然而,当它在Rshiny服务器上完成时,Shiny应用程序不会读取更新的日期和时间戳。

data_processing.R

rm(list=ls())
df <- iris
data_update_date_time <- Sys.time()
save.image("working_dataset.RData", compress = TRUE)

server.R

load("working_dataset.RData")

function(input, output, session) {

  # Combine the selected variables into a new data frame
  selectedData <- reactive({
    df[, c(input$xcol, input$ycol)]
  })

  clusters <- reactive({
    kmeans(selectedData(), input$clusters)
  })

  output$plot1 <- renderPlot({
    palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
              "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"))

    par(mar = c(5.1, 4.1, 0, 1))
    plot(selectedData(),
         col = clusters()$cluster,
         pch = 20, cex = 3)
    points(clusters()$centers, pch = 4, cex = 4, lwd = 4)
  })

  ## Data update date and time stamp
  output$update_date_time <- renderPrint(data_update_date_time)

}

ui.R

pageWithSidebar(
  headerPanel('Iris k-means clustering'),
  sidebarPanel(
    selectInput('xcol', 'X Variable', names(iris)),
    selectInput('ycol', 'Y Variable', names(iris),
                selected=names(iris)[[2]]),
    numericInput('clusters', 'Cluster count', 3,
                 min = 1, max = 9),
    br(),
    h4("Date update date time"),
    textOutput("update_date_time")
  ),
  mainPanel(
    plotOutput('plot1')
  )
)

感谢您百忙之中抽出时间。

推荐答案

编辑

shiny包中实际上有一个名为reactiveFileReader的函数,它执行您正在寻找的操作:定期检查文件"上次修改"的时间或大小是否发生了变化,并相应地重新读取。但是,此函数只能在server上下文中使用,因此每个连接到您的应用的用户将至少读取一次该文件。我答案中的选项3和4没有这些低效率。

此处的原始答案

首先也是最重要的一点是,SHILY无法跟踪文件更改AFAIK。无论何时

,您的实现都会重新加载.RData文件
  1. shiny-server通过bash或
  2. 重新启动
  3. 重新加载全局变量,因为应用程序在某个时候变得空闲。

无法判断第二个条件何时满足。因此,我主张使用以下四个选项之一。从Easy排序,您最好了解自己的闪亮!

选项1:将LOAD语句放入服务器

这里,每当新用户连接到应用程序时,都会重新加载图像。但是,如果您的.RData文件很大,这可能会减慢您的应用程序速度。如果速度不是问题,我会选择这个解决方案,因为它既简单又干净。

# server.R
function(input, output, session) {
  load("working_dataset.RData")
  ...
}

每当用户刷新页面时也将重新读取数据()

选项2:只要您想重新导入数据,就重新启动SHINY-SERVER

(另请参阅@shosacos Answer)。这将强制重新加载.Rdata文件。

$ sudo systemctl restart shiny-server
同样,这可能会减慢您的生产过程,具体取决于应用程序的复杂性。此方法的一个优点是,如果将数据加载到global.R中,还可以使用导入的数据构建UI。(我假定您没有提供您提供的代码)。

选项3:根据"上次修改时间"导入

这里的想法是在用户连接到应用程序时检查.RData是否已更改。为此,您必须使用包含上次导入版本的时间戳的"全局"变量。以下代码未经测试,但应该可以让您了解如何实现此功能。

# server.R
last_importet_timestamp <- reactiveVal("")

function(input,output,session){
  current_timestamp <- file.info(rdata_path)$mtime

  if(last_importet_timestamp() != current_timestamp){
    # use parent.frame(2) to make data available in other sessions
    load(rdata_path, envir = parent.fame(2))
    # update last_importet_timestamp
    last_importet_timestamp(current_timestamp)
  }

  ...
}
速度方面,这应该比前两个版本更高效。每个时间戳导入数据的次数永远不会超过一次(除非重新启动SHINY服务器或变为空闲)。

选项4:"反应性导入"

基本上与选项3相同,但将每隔50ms检查一次文件的更改。以下是此方法的完整工作示例。请注意,除非检测到"上次修改"中的更改,否则不会加载数据,因此产生的开销不会太差。

library(shiny)

globalVars <- reactiveValues()

rdata_path = "working_dataset.RData"

server <- function(input, output, session){
  observe({
    text = input$text_in
    save(text = text, file = rdata_path, compress = TRUE)
  })
  observe({
    invalidateLater(50, session)
    req(file.exists(rdata_path))
    modified <- file.info(rdata_path)$mtime
    imported <- isolate(globalVars$last_imported)
    if(!identical(imported, modified)){
      tmpenv <- new.env()
      load(rdata_path, envir = tmpenv)
      globalVars$workspace <- tmpenv
      globalVars$last_imported <- modified
    }
  })
  output$text_out <- renderText({
    globalVars$workspace$text
  })
}

ui <- fluidPage(
  textInput("text_in", "enter some text to save in Rdata", "default text"),
  textOutput("text_out")
)

shinyApp(ui, server)

如果您觉得globalVars$workspace$text使用不方便,可以使用with直接访问globalVars$workspace的内容。

  output$text_out <- renderText({
    with(globalVars$workspace, {
      paste(text, "suffix")
    })
  })

这篇关于闪亮的应用程序不反映更新RData文件中的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 07:56