首页 > 解决方案 > DT::renderTable() 显示“未找到匹配记录”和“显示 0 到 0 个条目(从 x 个总条目过滤)”

问题描述

我正在开发一个应用程序,用户可以在其中选择数据框的列和行以及用于进一步分析的转换方法。按下“应用”按钮后,应显示 3 个表格:

  1. 包含原始数据的表
  2. 包含选定原始数据的表
  3. 具有转换数据的表(未选择的列应完全从分析中排除,行不应显示在转换表中)。

不幸的是,当将列从“cyl”、“disp”、“hp”(3 列)更改为“mpg”、“cyl”、“disp”、“hp”、“drat”(5 列)时,表 2。和 3. 将显示 3 个列标题和“未找到匹配的记录”应该显示行的位置,以及“显示 0 到 0 个条目(从 x 个总条目过滤)”-> 所以没有更新该列标题。

回调下载按钮也无法正常工作。有时它会下载 html 文件或根本不显示。

我在下面放了一个代码示例(尽可能简化)。行按应有的方式显示。可能是因为数据点较少(原始数据帧大约有 100 x 30 000 个数据点)。

library(shiny)
library(DT)
library(shinyWidgets)
library(shinyjs)

transformDataFrame <- function(dataFrame, method = "none") {
  transformedSamplesData <- dataFrame[,2:ncol(dataFrame)]
  if(method == "none") {
    # no transformation
  } else if(method == "add1") {
    transformedSamplesData <- transformedSamplesData + 1
  } else if(method == "add2") {
    transformedSamplesData <- transformedSamplesData + 2
  } else {
    return(NULL)
  }
  dataFrame[,2:ncol(dataFrame)] <- transformedSamplesData
  return(dataFrame)
}

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      selectInput(inputId = "selectNormalization", label = "Select normalization",
                  choices = c("none" = "none",
                              "Add 1" = "add1",
                              "Add 2" = "add2"),
                  selected = "none", multiple = F),
      pickerInput(inputId = "selectSamples", label = "Select samples",
                  choices = NULL, selected = "", multiple = TRUE,
                  options = list(`live-search`=TRUE,
                                 `actions-box`=TRUE,
                                 `none-selected-text`="No sample selected",
                                 `selected-text-format`="count",
                                 `count-selected-text`="{0} out of {1} samples")),
      selectInput(inputId = "selectFilter", label = "Select gene filter",
                  choices = c("none" = "none",
                              "Select rows" = "rows"),
                  selected = "none", multiple = F),
      div(actionButton(inputId = "buttonResetFilter", label = "Reset"),
          style="display:inline-block"),
      span(actionButton(inputId = "buttonApplyFilter", label = "Apply"),
                   style = "float:right")),
    mainPanel(
      tabsetPanel(tabPanel("Input data",
                           #style = 'overflow-x: scroll',
                           uiOutput("inputUI")),
                  tabPanel("Filtered raw data",
                           uiOutput("filteredUI")),
                  tabPanel("Transformed data",
                           uiOutput("transformedUI"))))))

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

    inputData <- reactive({
      newCars <- data.frame(rownames(mtcars))
      newCars[,2:6] <- data.frame(mtcars[,1:5], row.names = NULL)
      names(newCars) <- c("Name", names(mtcars[,1:5]))
      sampleNames <- names(newCars)[2:ncol(newCars)]
      updatePickerInput(session = session, inputId = "selectSamples",
                        choices = sampleNames, selected = sampleNames)
      return(newCars)
    })

    userSelection <- dataTableProxy('rawTable')

    selectedSamples <- reactive({
      sampleColumns <- which(names(inputData()) %in% input$selectSamples)
      return(sampleColumns)
    })

    selectedRows <- reactive({
      selectedRows <- input$rawTable_rows_selected
      if (length(selectedRows)) {
        return(sort(selectedRows))
      } else {
        return(0)
      }
    })

    selectedGenes <- reactive({
      if(length(input$selectSamples)>0) {
        if (input$selectFilter=="none") {
          numberOfRows <- nrow(inputData())
          return(c(1:numberOfRows))
        } else if (input$selectFilter=="rows" && (!selectedRows()==0)) {
          return(selectedRows())
        }
      } else { # no samples selected || no file uploaded
        return(NULL)
      }
    })

    subsetData <- reactiveValues(rawData = NULL, transformedData = NULL)

    observeEvent(input$buttonApplyFilter, {
      if(length(input$selectSamples)>0 && length(selectedGenes())>0) {
        subsetData$transformedData <- NULL
        selectedSamplesData <- inputData()[,c(1, selectedSamples()), drop = FALSE]
        transformedSamplesData <- transformDataFrame(selectedSamplesData, input$selectNormalization)
        subsetData$rawData <- selectedSamplesData[selectedGenes(), , drop = FALSE]
        subsetData$transformedData <- transformedSamplesData[selectedGenes(), , drop = FALSE]
      } else {# no samples selected || no file uploaded
        subsetData$rawData <- NULL
        subsetData$transformedData <- NULL
        return(NULL)
      }
    })

    output$rawTable <- DT::renderDataTable({
      DT::datatable(inputData(),
                    extensions=c('Buttons', 'Scroller', 'FixedHeader', 'Responsive', 'ColReorder'),
                    options=list(lengthMenu = c(25, 50, 100),
                                 pageLength=25,
                                 dom='<"row"<"col-sm-4"l><"col-sm-4"B><"col-sm-4"f>>rtip',
                                 buttons=I('colvis'),
                                 fixedHeader=TRUE,
                                 colReorder=list(realtime=FALSE),
                                 scrollY=500))
    })

    output$selectedTable <- DT::renderDataTable({
      input$buttonApplyFilter
      DT::datatable(subsetData$rawData,
                    selection='none',
                    callback=JS("$('div.saveSelected').append($('#downloadSelected'));"),
                    extensions=c('FixedColumns', 'FixedHeader', 'Scroller'), #'Buttons',
                    options=list(dom='<"row"<"col-sm-8"<"div.saveSelected">><"col-sm-4"f>>rtip',
                                 scrollX=TRUE,
                                 fixedColumns=list(leftColumns=2),
                                 fixedHeader=TRUE,
                                 scrollY=500,
                                 scroller=TRUE))
    })

    output$transformedTable <- DT::renderDataTable({
      input$buttonApplyFilter
      DT::datatable(subsetData$transformedData,
                    selection='none',
                    callback=JS("$('div.saveTransformed').append($('#downloadTransformed'));"),
                    extensions=c('FixedColumns', 'FixedHeader', 'Scroller'), #'Buttons',
                    options=list(dom='<"row"<"col-sm-8"<"div.saveTransformed">><"col-sm-4"f>>rtip',
                                 scrollX=TRUE,
                                 fixedColumns=list(leftColumns=2),
                                 fixedHeader=TRUE,
                                 scrollY=500,
                                 scroller=TRUE))
    })

    output$inputUI <- renderUI({
        tagList(DT::dataTableOutput("rawTable"))
    })

    output$filteredUI <- renderUI({
        tagList(downloadButton(outputId = "downloadSelected", label = "Save table (selected data)"),
                DT::dataTableOutput("selectedTable"))
    })

    output$transformedUI <- renderUI({
        tagList(downloadButton(outputId = "downloadTransformed", label = "Save table (transformed data)"),
                DT::dataTableOutput("transformedTable"))
    })

    observeEvent(input$buttonResetFilter, {
      updateSelectInput(inputId = "selectNormalization", label = "Select normalization",
                        choices = c("none" = "none",
                                    "Add 1" = "add1",
                                    "Add 2" = "add2"),
                        selected = "none", multiple = F)
      numberOfCol <- ncol(inputData())
      sampleNames <- names(inputData())[2:numberOfCol]
      updatePickerInput(session = session, inputId = "selectSamples",
                        choices = sampleNames, selected = sampleNames)
      updateSelectInput(inputId = "selectFilter", label = "Select gene filter",
                        choices = c("none" = "none",
                                    "Select rows" = "rows"),
                        selected = "none", multiple = F)
      userSelection %>% selectRows(NULL)
      subsetData$rawData <- NULL
      subsetData$transformedData <- NULL
    })

    output$downloadSelected <- downloadHandler(
      filename = function() {
        paste("data_selection_", format(Sys.time(), "%Y-%m-%d-%H%M"), ".csv", sep="")},
      content = function(file) {
        write.csv(subsetData$rawData, file, row.names=FALSE)},
      contentType = "text/csv"
    )

    output$downloadTransformed <- downloadHandler(
      filename = function() {
        paste("data_transformation_", format(Sys.time(), "%Y-%m-%d-%H%M"), ".csv", sep="")},
      content = function(file) {
        write.csv(subsetData$transformedData, file, row.names=FALSE)},
      contentType = "text/csv"
    )
}

shinyApp(ui, server)

我的第一种方法是将 reactiveValues$x 更改为,subsetDataX <- reactive({ ... })但我不希望每次用户更改输入时都计算这些值。此外,我尝试replace(proxy, data)了,但没有效果。

如果有人知道如何解决这个问题或者可以给我一个提示,我会很高兴。

提前致谢!薇薇安

标签: rshinydt

解决方案


推荐阅读