在Shiny

时间:2017-08-29 23:27:09

标签: r shiny

我正在学习Shiny并开发一个简单的应用程序。程序的开始将允许用户导入CSV文件,然后根据需要应用过滤器变量。他们只能在此阶段使用因子作为过滤变量。我在迭代的基础上应用过滤器。因此,可以根据因子级别应用过滤器,然后应用其他因子级别,依此类推,直到完成。

我能找到的能够对无效数据帧进行子集化的最佳应用是将数据帧应用为无功值。这似乎有效,但我有几个问题,我无法弄清楚如何解决。

1)鉴于过滤是一个迭代过程,我想跟踪并打印出在过滤过程中应用的每个变量和级别。我能想到的最好方法是创建一个全局变量(<<&lt ;-)并使用renderText在点击apply filter按钮后打印出内容。问题是renderText只是在屏幕上闪烁并迅速消失。我包含了一个打印到控制台语句,用于验证文本是否正确保存。我相信这是从应用于反应数据框和更新过程的过滤器发生的,但我无法弄清楚如何阻止文本消失在屏幕上?

2)当我试图在闪亮代码的末尾保存出被动数据帧时,我得到以下错误"警告:$:$运算符错误对原子向量"无效。我尝试了几件事情,但并不是真的明白这里发生了什么,因为对象"文件$ dfSource"是不是正常的反应数据帧dfSource()?

下面的闪亮应用程序使用虹膜数据,因此更容易使用/测试。我不知道将数据框应用于无效值是否是编程的最佳方式,或者是否有更简单的方法来完成所有这些 - 只是尝试在这里学习最佳方法。

library(shiny)
allfilters <- c()

ui <- (fluidPage(

# Application title
titlePanel("Filter Data"),

# Input Forms
sidebarLayout(
sidebarPanel(
    h3("Data"),
        checkboxInput("selectFilter", label = "Apply Filter Variable", value = FALSE),
        uiOutput("selectFilterVar"),
    uiOutput("selectFilterGroup"),
    helpText("Apply filter to data"),
    uiOutput("selectFilterButton"),
    helpText("Reset data to total"),
    uiOutput("selectResetButton"),   
    h3("Download Data"),    
        helpText("Download Data"),
        downloadButton("downloadData", "Download File")
    ),

# Output Forms
mainPanel(
  tabsetPanel(
     tabPanel("Summary",
     h2("Output Summary"),
     textOutput("ncases"),
     textOutput("selectedfilters")))
  )
  )
))

server <- (function(input, output, session) {

data <- iris
file <- reactiveValues(dfSource = data)

## Select Filter Variable
output$selectFilterVar <- renderUI({
       req(file$dfSource)
       if (input$selectFilter){
       selectInput("filterVar", "Select Filter Variable", multiple = FALSE, choices = sort(names(file$dfSource[, sapply(file$dfSource, is.factor), drop = FALSE])))
}         
})         

# Select Filter Group(s)
output$selectFilterGroup <- renderUI({
        req(file$dfSource)
        req(input$filterVar)
        if (input$selectFilter){
        selectInput("filterGroup", "Select Filter Group", multiple = TRUE, choices = sort(unique(file$dfSource[,input$filterVar])))
}
})

# Apply Filter Button
output$selectFilterButton <- renderUI({
         req(file$dfSource)
         if (input$selectFilter) {
          actionButton("filterButton", "Apply Filter")
}
})

# Apply filter group to data
    observeEvent(input$filterButton, {
    temp <- file$dfSource[(file$dfSource[,input$filterVar] %in% c(input$filterGroup)),]
    file$dfSource <- temp
})

# Reset Total Sample Button
output$selectResetButton <- renderUI({
         req(file$dfSource)
         if (input$selectFilter) {
          actionButton("resetButton", "Reset Total")
}
})

# Reset data to total sample
    observeEvent(input$resetButton, {
    file$dfSource <- data
    updateCheckboxInput(session, "selectFilter", value = FALSE)
    allfilters <- NULL
})

## Summary number of cases
output$ncases <- renderText({
  req(file$dfSource)
  mainTitle <- paste("Number of cases =" , nrow(file$dfSource))
  return(mainTitle)  
})

## Capture selected filter variables in global object
testfilter <- eventReactive(input$filterButton, {
     appliedfilter <- paste0(input$filterVar, "(", input$filterGroup,")")
      if (is.null(allfilters)) {
        allfilters <<- paste("Selected Filters:", appliedfilter)
        } else {
        allfilters <<- paste(allfilters, "&", appliedfilter)
   }
   return(allfilters)
   })

# Print out filter variables in global object
output$selectedfilters <- renderText({
    filteroutput <- testfilter()
    print(filteroutput)
    return(filteroutput)
})

## Save out case data file
output$downloadData <- downloadHandler(
    filename = function() {
      paste("data-", Sys.Date(), ".csv", sep="")
    },
    content = function(file) {
    write.csv(file$dfSource, file)
    }
  )

})

shinyApp(ui, server)

1 个答案:

答案 0 :(得分:0)

1)将它存储为全局变量可能不是一个好主意(闪亮的范围已经足够复杂了!)。您已经拥有reactiveValues个对象,为什么不使用它?

然而,仅此一点是不够的;问题似乎是eventReactive - 我不太清楚为什么。

这有效:

# this replaces the testfilter eventReactive
observeEvent(input$filterButton, {
  appliedfilter <- paste0(input$filterVar, "(", input$filterGroup,")")
  if (is.null(file$allfilters)) {
    file$allfilters <- paste("Selected Filters:", appliedfilter)
  } else {
    file$allfilters <- paste(file$allfilters, "&", appliedfilter)
  }
 })

# Print out filter variables in global object
output$selectedfilters <- renderText({
  filteroutput <- file$allfilters
  print(filteroutput)
  return(filteroutput)
})

2)错误在您传递给downloadHandler的内容函数中。该参数名为file,会隐藏file reactiveValues。这有效:

  ## Save out case data file
  output$downloadData <- downloadHandler(
    filename = function() {
      paste("data-", Sys.Date(), ".csv", sep="")
    },
    content = function(filetarget) {
      write.csv(file$dfSource, filetarget)
    }
  )

PS ad 1:最好存储过滤器,而不是存储过滤后的数据框和列出过滤器的字符串。如果您的用户改变主意,他们必须从头开始,但如果您存储过滤器,则可以使用表格或类似内容来删除/编辑单个过滤器。您可以只存储一个双元素向量列表,然后迭代列表以过滤数据。