我是 Shiny 的新手(与 R 一起工作了几个月),我试图弄清楚处理多个上传文件的“Shiny”方式是什么。
我的目标是拥有一个用户可以上传多个文件的界面。必须从这些文件中以大量图表和绘图的形式生成报告。从我在 Shiny 教程中学到的,在服务器端,所有对象都是相互隔离的(意味着它们不能被读取,除非你显式调用另一个函数)。
正如您在下面的代码中看到的那样,这意味着我必须为每个图复制处理代码。这似乎效率低下。处理这个问题的“闪亮”方式是什么?
另外,我遗漏了一堆对于示例来说不是绝对必要的代码。本质上,我需要做更多的处理,我不想为每个情节复制所有代码。
我特别询问服务器端代码。我想读入包含不同内容的多个文件。服务器端代码中的操作只是占位符,我实际上并不想绑定任何东西,但我把它放在那里以保持代码简单。我希望能够对导入的数据框做任何我想做的事情。
library(shiny)
# Define UI for application
ui <- fluidPage(
# Sidebar with file input
sidebarLayout(
sidebarPanel(
fileInput("people", NULL, multiple = FALSE, accept = ".csv",
buttonLabel = "Browse...", placeholder = "people file"),
fileInput("info", NULL, multiple = FALSE, accept = ".csv",
buttonLabel = "Browse...", placeholder = "info file"),
),
# Show the results of the data processing
mainPanel(
imageOutput("plot"),
tableOutput("base_data")
)
)
)
# Define server logic required to process the data
server <- function(input, output) {
output$base_data <- renderTable({
if(is.null(input$people) | is.null(input$info)) {
} else {
people_file <- input$people
info_file <- input$info
people <- read.csv(people_file$datapath, stringsAsFactors = F, encoding = "UTF-8-BOM")
info <- read.csv(info_file$datapath, stringsAsFactors = F, fileEncoding = "UTF-8-BOM")
rbind(people, info)
}
})
output$plot <- renderImage({
if(is.null(input$people) | is.null(input$info)) {
outfile <- tempfile(fileext='.png')
png(outfile, width = 1200, height = 800, res = 200)
dev.off()
list(src = outfile, width = 1200, height = 800)
} else {
people_file <- input$people
info_file <- input$info
people <- read.csv(people_file$datapath, stringsAsFactors = F, encoding = "UTF-8-BOM")
info <- read.csv(info_file$datapath, stringsAsFactors = F, fileEncoding = "UTF-8-BOM")
outfile <- tempfile(fileext='.png')
png(outfile, width = 1200, height = 800, res = 200)
plot(nrow(people), nrow(info), type="b")
dev.off()
list(src = outfile, width = 1200, height = 800, alt = "questions"))
}
}, deleteFile = TRUE)
}
# Run the application
shinyApp(ui = ui, server = server)
Run Code Online (Sandbox Code Playgroud)
这是我想要的伪代码示例:
[[ui]]
fileInput("people")
fileInput("info")
show(plot)
show(plot2)
show(df)
[[serverside]]
files <- source(input) {
people <- read.csv(input$people, stringsAsFactors = F, encoding = "UTF-8-BOM")
info <- read.csv(input$info, stringsAsFactors = F, encoding = "UTF-8-BOM")
}
contents <- plot(output) {
some_function(files$people, files$info)
plot(contents)
}
contents2 <- plot(output) {
some_other_function(files$people, files$info)
plot2 <- plot(contents2)
}
df <- table(output) {
cbind(files$people, files$info)
}
Run Code Online (Sandbox Code Playgroud)
这是我现在拥有的伪代码,效率不高。
[[ui]]
fileInput("people")
fileInput("info")
show(plot)
show(plot2)
show(df)
[[serverside]]
contents <- plot(input, output) {
people <- read.csv(input$people, stringsAsFactors = F, encoding = "UTF-8-BOM")
info <- read.csv(input$info, stringsAsFactors = F, encoding = "UTF-8-BOM")
contents <- some_function(people, info)
plot(contents)
}
contents2 <- plot(input, output) {
people <- read.csv(input$people, stringsAsFactors = F, encoding = "UTF-8-BOM")
info <- read.csv(input$info, stringsAsFactors = F, encoding = "UTF-8-BOM")
contents <- some_other_function(people,info)
plot(contents)
}
df <- table(input, output) {
people <- read.csv(input$people, stringsAsFactors = F, encoding = "UTF-8-BOM")
info <- read.csv(input$info, stringsAsFactors = F, encoding = "UTF-8-BOM")
cbind(people, info)
Run Code Online (Sandbox Code Playgroud)
}
我将不得不同意 heds1 这有点难以获得您想要的结果。由于我们无法访问您的 csv,我创建了一些虚拟的。
可重现的数据/ csvs:
write.csv2(x = 1:5, file = "people.csv", row.names = FALSE)
write.csv2(x = 6:10, file = "people2.csv", row.names = FALSE)
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,您希望避免为每个上传的文件重复代码。为了遍历您的文件/数据集,我们必须将它们收集在一种数据结构中。
这样做的一种方法是允许上传多个文件:
fileInput(..., multiple = TRUE)
Run Code Online (Sandbox Code Playgroud)
用户界面:
您可以使用循环创建的 ui 端renderUI():
output$plots <- renderUI({
lapply(paste("people", 1:length(data)), plotOutput)
})
Run Code Online (Sandbox Code Playgroud)
服务器端:
您可以使用循环创建的服务器端:
output[[paste("people", nr)]] <- renderPlot({
plot(plotData)
})
Run Code Online (Sandbox Code Playgroud)
本地分配
最后,您将不得不使用local()以避免仅采用循环最后一次迭代的数据:
local({
LOCAL_VARIABLE <- data[[nr]]
....
})
Run Code Online (Sandbox Code Playgroud)
完全可重现的示例:
library(shiny)
write.csv2(x = 1:5, file = "people.csv", row.names = FALSE)
write.csv2(x = 6:10, file = "people2.csv", row.names = FALSE)
ui <- fluidPage(
fileInput(inputId = "people", label = NULL, accept = ".csv",
buttonLabel = "Browse...", placeholder = "people file", multiple = TRUE),
uiOutput("plots")
)
server <- function(input, output, session) {
observeEvent(input$people, {
data <- lapply(input$people$datapath, read.csv2)
for(nr in 1:length(data)){
local({
plotData <- data[[nr]]
output[[paste("people", nr)]] <- renderPlot({
plot(plotData)
})
})
}
output$plots <- renderUI({
lapply(paste("people", 1:length(data)), plotOutput)
})
})
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)
编辑:
重用导入(和转换)的数据:
library(shiny)
write.csv2(x = 1:5, file = "people.csv", row.names = FALSE)
ui <- fluidPage(
fileInput(inputId = "people", label = NULL, accept = ".csv",
buttonLabel = "Browse...", placeholder = "people file", multiple = FALSE),
plotOutput("plot"),
tableOutput("table"),
verbatimTextOutput("text")
)
server <- function(input, output, session) {
global <- reactiveValues()
observeEvent(input$people, {
data <- read.csv2(input$people$datapath)
# DO LOTS OF OPERATIONS ON data
global$data <- data
# FROM HERE ON USE: global$data
})
output$plot <- renderPlot({
req(global$data)
plot(global$data)
})
output$table <- renderTable({
global$data
})
output$text <- renderText({
toString(global$data)
})
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)