【问题标题】:Generating multiple graphs/plots from uploaded files in Shiny从 Shiny 中上传的文件生成多个图形/绘图
【发布时间】:2020-03-22 03:44:06
【问题描述】:

我是 Shiny 的新手(使用 R 工作了几个月),我正在尝试弄清楚处理多个上传文件的“闪亮”方式是什么。

我的目标是有一个用户可以上传多个文件的界面。必须从这些文件中生成大量图表形式的报告。根据我在 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)

这是我想要的伪代码示例:

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

这是我现在拥有的伪代码,效率不高。

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

}

【问题讨论】:

  • 你好,恩佐利马。即使您删除了很多不必要的代码,实际上仍然有很多代码与实际问题并不真正相关,据我所知,这就是如何生成多个输出(例如,表格和绘图) 从单个对象。肯定有“闪亮”的方法可以做到这一点,但用一个更简单的可重现示例来证明这一点要容易得多。
  • 我把它剪掉了。这样更好吗?

标签: r shiny


【解决方案1】:

我将不得不同意 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)

如果我对您的理解正确,您希望避免为每个上传的文件重复代码。 为了循环您的文件/数据集,我们必须将它们收集到一个数据结构中。

这样做的一种方法是允许上传多个文件:

fileInput(..., multiple = TRUE)

用户界面:

您可以在renderUI() 中使用循环创建的 ui 端:

output$plots <- renderUI({
  lapply(paste("people", 1:length(data)), plotOutput)
})

服务器端:

您可以通过循环创建的服务器端:

output[[paste("people", nr)]] <- renderPlot({
          plot(plotData)
})

本地分配

最后你将不得不使用local() 来避免只获取循环最后一次迭代的数据:

      local({
        LOCAL_VARIABLE <- data[[nr]]
        ....
      })

完整的可重现示例:

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)

编辑:

重用导入(和转换)的数据:

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)

【讨论】:

  • 我认为我最初的问题并不清楚。输入文件将包含不同类型的信息。例如,包含“人员”的文件和包含有关他们的信息的单独文件“信息”。我交叉引用这些文件来创建一个图。我删除了所有这些代码,因为 heds1 说没有必要。但我不想循环输入,我需要 4 个单独的输入字段和 4 个单独的名称。我只说服务器端代码。
  • 好的一方明白了。您可以详细说明您将在哪个阶段复制代码?如果用户第二次/第三次上传文件会是这种情况吗?您会替换“旧”图还是要在新图旁边显示“新”图?
  • 用户应该上传“people.csv”和“info.csv”。如果他们上传不同的“people.csv”,它应该只是替换旧的“people”数据框。重申:没有为我的请求上传 2 people.csv 文件这样的事情。每个文件一次可以有 1 个。
  • 您能否详细说明您将在哪个阶段复制代码? (或避免重复,..)
  • 我已经更新了原始问题。在服务器端,我必须为我想要的每个输出导入上传的文件。我想导入一次文件,然后对它们进行不同的操作,并为每个操作提供一个输出。现在,我必须重复代码为我所做的每一个输出导入文件。
猜你喜欢
  • 2020-05-20
  • 2021-01-18
  • 1970-01-01
  • 2017-07-20
  • 2017-03-03
  • 1970-01-01
  • 2021-11-23
相关资源
最近更新 更多