【问题标题】:r - create reactive filter that is applied to an uploaded csv file in shinyr - 创建反应式过滤器,以闪亮的方式应用于上传的 csv 文件
【发布时间】:2019-03-03 19:00:26
【问题描述】:

我正在尝试创建一个闪亮的应用程序,用户可以在其中上传 .csv 文件,然后在该数据帧上应用过滤器,然后使用 ggplot2 进行绘图。不幸的是,当我尝试从应该上传的 .csv 中的变量创建选择输入菜单时,我偶然发现了一个问题。

为了创建一个简单的示例,我们可以将 diamonds 数据集从 ggplot2 导出为 .csv 文件:

write.csv(diamonds, "diamonds.csv")

然后创建闪亮的应用程序:

library(shiny)
library(shinyWidgets)
library(ggplot2)

ui <- fluidPage(
    titlePanel("test shiny"),

    # Sidebar with a slider input for number of bins
    sidebarLayout(sidebarPanel(
        fileInput('file1', 'Choose file to upload',
                  accept = c(
                      'text/csv',
                      'text/comma-separated-values',
                      'text/tab-separated-values',
                      'text/plain',
                      '.csv',
                      '.tsv'
                  )
        ),
        tags$hr(),
        pickerInput(
            inputId = "caratx",
            label = "Choose carat",
            choices = c("Select all", unique(user_data$carat)),
            multiple = TRUE
        ),
        selectInput(
            inputId = "clarityx",
            label = "Choose distance: ",
            choices = unique(user_data$clarity)
        )
    ),
    mainPanel(plotOutput("endplot"))
    ))

# Define server logic 
server <- function(input, output) {

    output$endplot <- renderPlot({
        inFile <- input$file1

        if (is.null(inFile))
            return(NULL)

        user_data <- read.csv(inFile$datapath, header = T,
                              sep = ",", quote = input$quote)

        validate(
            need(input$entityx, 'Please select at least one carat'),
            need(input$indicatorx, 'Please select at least one clarity')
        )

        if (input$caratx %in% "Select all") {
            user_data <- user_data %>%
                filter(carat %in% input$caratx)
        } else {
            user_data <- user_data %>%
                filter(carat %in% input$caratx) %>%
                filter(clarity %in% input$clarityx) 
        }

        user_data %>% 
            ggplot(aes(x = `cut`)) +
            geom_point(aes(y = price), color = "red") +
            geom_point(aes(y = depth), color = "blue")
        })
}

# Run the application 
shinyApp(ui = ui, server = server)

这是输出:

Error in unique(user_data$carat) : object 'user_data' not found

有没有办法让这个工作?

非常感谢!

【问题讨论】:

标签: r shiny


【解决方案1】:

正如@kwiscion 正确评论的那样,您提出的实际问题应该通过将user_data 转换为反应式并使用uiOutput+renderUI 渲染输入来解决。

但不幸的是,您的代码还有一些其他错误使其无法重现:

  • 样本数据集应该是diamonds,而不是cars
  • input$quote 在您的代码中不存在,因此我删除了对它的引用
  • 您的代码中的某些函数需要包含library(dplyr)
  • input$entityxinput$indicatorx 不存在

以上 4 个错误与您的问题无关,但使您的问题更难回答且时间更长。今后,请尽量确保您发布的代码正确且可重现。

以下是您的问题的答案,它解决了上述 4 个问题并实施了@kwiscion 的两个建议

library(shiny)
library(shinyWidgets)
library(ggplot2)
library(dplyr)

ui <- fluidPage(
  titlePanel("test shiny"),

  # Sidebar with a slider input for number of bins
  sidebarLayout(sidebarPanel(
    fileInput('file1', 'Choose file to upload',
              accept = c(
                'text/csv',
                'text/comma-separated-values',
                'text/tab-separated-values',
                'text/plain',
                '.csv',
                '.tsv'
              )
    ),
    tags$hr(),
    uiOutput("caratx_input"),
    uiOutput("clarityx_input")
  ),
  mainPanel(plotOutput("endplot"))
  ))

# Define server logic 
server <- function(input, output) {
  file_data <- reactive({
    req(input$file1)
    read.csv(input$file1$datapath, header = TRUE,
             sep = ",")
  })

  output$caratx_input <- renderUI({
    req(file_data())
    pickerInput(
      inputId = "caratx",
      label = "Choose carat",
      choices = c("Select all", unique(file_data()$carat)),
      multiple = TRUE
    )
  })

  output$clarityx_input <- renderUI({
    req(file_data())
    selectInput(
      inputId = "clarityx",
      label = "Choose distance: ",
      choices = unique(file_data()$clarity)
    )
  })

  output$endplot <- renderPlot({
    req(file_data())

    validate(
      need(input$caratx, 'Please select at least one carat'),
      need(input$clarityx, 'Please select at least one clarity')
    )

    user_data <- file_data()
    if (input$caratx %in% "Select all") {
      user_data <- user_data %>%
        filter(carat %in% input$caratx)
    } else {
      user_data <- user_data %>%
        filter(carat %in% input$caratx) %>%
        filter(clarity %in% input$clarityx) 
    }

    user_data %>% 
      ggplot(aes(x = `cut`)) +
      geom_point(aes(y = price), color = "red") +
      geom_point(aes(y = depth), color = "blue")
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

【讨论】:

    【解决方案2】:

    你需要

    1. user_data 一个反应式表达式 (https://shiny.rstudio.com/tutorial/written-tutorial/lesson6/)
    2. 使用renderUI (https://shiny.rstudio.com/articles/dynamic-ui.html) 渲染pickerInput

    (完整代码如下)

    1. 当您想要计算并稍后使用取决于用户输入的值(在您的情况下为 user_data)时,您必须通过将计算放入 reactive({ }) 使其成为反应式表达式。然后你可以像函数一样引用值,即user_data()。所以你的情况是:
    user_data <- reactive({
          read.csv(input$file1$datapath, header = T,
                   sep = ",", quote = input$quote)
        })
    
    user_data() %>% ...
    

    此外,它必须从renderPlot() 中取出才能作为响应式工作。

    1. 要根据执行期间计算的值获得输入,您必须使用renderUI() 在服务器端呈现它:

    ui.R

    ...
    uiOutput('caratxui'),
    ...
    

    server.R

    ...
    output$caratxui <- renderUI({
            pickerInput(
                inputId = "caratx",
                label = "Choose carat",
                choices = c("Select all", unique(user_data()$carat)),
                multiple = TRUE
            )
    
        })
    ...
    

    完整代码:

    library(shiny)
    library(shinyWidgets)
    library(ggplot2)
    
    ui <- fluidPage(
        titlePanel("test shiny"),
    
        # Sidebar with a slider input for number of bins
        sidebarLayout(sidebarPanel(
            fileInput('file1', 'Choose file to upload',
                      accept = c(
                          'text/csv',
                          'text/comma-separated-values',
                          'text/tab-separated-values',
                          'text/plain',
                          '.csv',
                          '.tsv'
                      )
            ),
            tags$hr(),
            uiOutput('caratxui'),
            selectInput(
                inputId = "clarityx",
                label = "Choose distance: ",
                choices = unique(user_data$clarity)
            )
        ),
        mainPanel(plotOutput("endplot"))
        ))
    
    # Define server logic 
    server <- function(input, output) {
        user_data <- reactive({
          read.csv(input$file1$datapath, header = T,
                   sep = ",", quote = input$quote)
        })
    
        output$caratxui <- renderUI({
            pickerInput(
                inputId = "caratx",
                label = "Choose carat",
                choices = c("Select all", unique(user_data()$carat)),
                multiple = TRUE
            )
    
        })
    
        output$endplot <- renderPlot({
            validate(
                need(input$entityx, 'Please select at least one carat'),
                need(input$indicatorx, 'Please select at least one clarity')
            )
    
            user_data() %>%
                filter(carat %in% input$caratx) %>%
                filter(clarity %in% input$clarityx | 
                        input$caratx == "Select all") %>% 
                ggplot(aes(x = `cut`)) +
                geom_point(aes(y = price), color = "red") +
                geom_point(aes(y = depth), color = "blue")
            })
    }
    
    # Run the application 
    shinyApp(ui = ui, server = server)
    

    【讨论】:

    • 亲爱的@kwiscion,您提供的代码恐怕会返回相同的错误
    猜你喜欢
    • 1970-01-01
    • 2020-04-11
    • 2020-08-18
    • 2021-09-26
    • 1970-01-01
    • 2017-01-14
    • 2014-10-04
    • 2019-08-17
    • 2015-03-09
    相关资源
    最近更新 更多