我已经使用lapply创建了一个动态的FileInput。当我想读取文件时,我也在观察者中使用了lapply。
在这里使用lapply的问题是,每次我上传新文件时都会触发该问题,因此,如果上传了新文件,则会一次又一次读取所有文件。
在这里,我提供了一个Hello World应用程序。 lapply函数取决于我为简单起见而省略的输入参数。
library(shiny)
ui <- fluidPage(
titlePanel("Hello World"),
sidebarLayout(
sidebarPanel(),
mainPanel(
lapply(1:2, function(i) {
fileInput(
paste0("file", i),
label = NULL,
multiple = F,
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"
),
buttonLabel = paste("File", i)
)
}),
verbatimTextOutput("list")
)
)
)
server <- function(input, output) {
r <- reactiveValues()
observe({
lapply(1:2, function(i) {
file <- input[[paste0("file",i)]]
if(is.null(file)) return()
isolate({
r$file[[paste(i)]] <- readr::read_csv2(file = file$datapath)
})
})
})
output$list <- renderPrint(reactiveValuesToList(r))
}
shinyApp(ui = ui, server = server)
如何替换循环或对lapply添加要求?
答案 0 :(得分:1)
虽然我在评论中开始了 cache-invalidation 的道路,但我认为还有其他一些方法可能对您更有效,因为您有固定数量的fileInput
字段:交换{代码中的{1}}和lapply
行(以及其他一些调整)。
observe
说明:
server <- function(input, output) {
lapply(paste0("file", 1:2), function(nm) {
observeEvent(input[[ nm ]], {
req(input[[nm]], file.exists(input[[nm]]$datapath))
readr::read_csv2(file = input[[nm]]$datapath)
})
})
}
将不会对"file1"
做出反应。"file2"
放在paste0(...)
的数据中而不是函数中来简化了输入名称的定义,尽管这样做同样容易
lapply
lapply(1:2, function(i) {
nm <- paste0("file", i)
# ...
})
的外部中定义nm
很重要,这与延迟的求值和名称空间搜索顺序有关。几年前,我就为此而pre之以鼻,并被Joe Cheng弄清楚:您不能使用observeEvent
循环,它一定是这样的保护环境的操作。 N.B .:这是一段代码,还远远不够完整:让for
或observe
读取数据然后丢弃它是错误的……它丢失了一些东西。理想情况下,这实际上应该是observeEvent
或reactive
块,或者处理后的数据应存储在eventReactive
或reactiveValues
中。例如:
reactiveVal
(还有关于防御性编程的另一条注释:您无法完美地控制server <- function(input, output) {
mydata <- lapply(paste0("file", 1:2), function(nm) {
observeEvent(input[[ nm ]], {
req(input[[nm]], file.exists(input[[nm]]$datapath))
readr::read_csv2(file = input[[nm]]$datapath)
})
})
observe({
# the following are identical, the latter more declarative
mydata[[1]]
mydata[["file1"]]
})
}
对文件的反应……由于某种原因,它可能会出错。下一步是将其包装在readr::read_csv2
中其中tryCatch(..., error = function(e) { errfun(e); NULL; })
对错误消息做一些有意义的(将其记录和/或在模式弹出窗口中提供给用户),然后返回errfun(e)
,以便下游的反应堆可以使用NULL
,并且不会尝试处理req(mydata[[1]])
。
NULL