闪亮的应用程序不反映更新RData文件中的更改

时间:2017-10-12 21:36:41

标签: r shiny

我每天通过我的闪亮应用程序的cron作业更新我的RData文件。 但是,闪亮的应用程序不会在大多数情况下选择更新并继续显示旧RData文件中的旧数据。

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

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')
  )
)

感谢您抽出宝贵时间。

3 个答案:

答案 0 :(得分:7)

修改

reactiveFileReader包中实际上有一个名为shiny的函数,可以完全满足您的要求:定期检查文件&#34;最后一次修改&#34;时间或大小相应地改变和重新读取。但是,此功能只能在server上下文中使用,因此对于连接到您应用的每个用户,该文件至少会被读取一次。我的答案中的选项3和4没有这些低效率。

来自

的原始答案

首先,闪亮没有办法跟踪文件变化AFAIK。您的实现只要

重新加载.RData文件
  1. shiny-server通过bash或
  2. 重新启动
  3. 因为应用程序在某个时刻变得空闲而重新加载全局变量。
  4. 当满足第二个条件时,没有办法说出来。因此,我主张使用以下四种选项之一。从简单排序,你最了解你的闪亮!

    选项1:将load语句放在服务器

    此处,只要新用户与应用程序连接,就会重新加载图片。但是,如果您的.RData文件很大,这可能会降低您的应用速度。如果速度不是问题,我会选择这个解决方案,因为它很容易和干净。

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

    每当用户刷新页面时,也会重新读取数据( F5

    选项2:每当要重新导入数据时重新启动shiny-server

    另见@shosacos回答)。这会强制重新加载.Rdata文件。

    $ sudo systemctl restart shiny-server
    

    同样,这可能会降低您的制作流程,具体取决于您的应用的复杂程度。这种方法的一个优点是,如果您在global.R中加载数据,还可以使用导入的数据来构建ui 。 (我假设你没有给出你给的代码)。

    选项3:根据&#34;最后修改&#34;

    导入

    这里的想法是在用户连接到应用时检查.RData是否已更改。要做到这一点,你将不得不使用&#34;全球&#34;包含上次导入版本的时间戳的变量。以下代码未经测试,但应该让您了解如何实现此功能。

    # 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) 
      }
    
      ...
    }
    

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

    选项4:导入&#34;反应&#34;

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

    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")
        })
      })
    

答案 1 :(得分:1)

如果在处理新的* .RData后重新启动闪亮服务器,它会起作用。我不会把它放进闪亮的服务器,因为那时

1)其变量对UI不可见

2)每个打开应用程序的用户都需要等待RData加载完成。

答案 2 :(得分:0)

该应用由闪亮服务器缓存,除非在与该闪亮应用相关联的.R文件之一中检测到更改,否则它不会更新该应用。 hack是对您的应用程序代码进行微妙的更改(例如,切换库的加载顺序),以提示闪亮的服务器重置缓存,从而包含更新的.RData文件。