0

我正在开发一个 Shiny 应用程序,reactable由于我的数据的嵌套结构,该程序包非常有用。它允许我折叠和汇总更高级别类别中的行,并且仅在需要时展开以显示“子行”。

对于只有 1 个嵌套级别(例如,制造商中的汽车模型),来自工作的聚合函数(等)unique开箱即用。但是,当添加额外的嵌套级别时,事情就会崩溃,甚至聚合器也会出现重复值(!)。我怀疑这是因为子类别并非全部汇集在一个平面结构中,仅对所有子类别执行 1 个聚合步骤,而是唯一的值仍然是子类别特定的,然后只是连接在一起,导致重复。此问题也会影响其他聚合器,而不仅仅是.countreactableuniqueunique

我在 R 下面添加了一个 MWE,因为我无法解决这个问题。由于 JS 也远不是我的强项,所以我无法插入任何 JS 来更灵活地解决这个问题,正如这里所建议的那样。如何调整下面的聚合器以获得正确显示的输出(即不重复)?

library(shiny)
library(shinydashboard)
library(reactable)
library(stringr)

if (interactive()) {
  
  ui <- shinyUI(basicPage(
    box(title = "mtcars data",
        width = 12,
        reactableOutput("car_tab")
    )
  ))
  
  server <- function(input, output, session) {
    output$car_tab <- renderReactable({
      
      df <- mtcars
      df$make <- str_extract(rownames(df), "[[:alpha:]]+")
      df$model <- rownames(df)
      rownames(df) <- NULL
      df <- df[ , c("make", "model", "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")]
      
      reactable(df,
                groupBy = c("cyl", "am", "make"),
                columns = list(
                  cyl = colDef(name = "Number of cylinders"),
                  am = colDef(name = "Transmission",
                              aggregate = "frequency"),
                  make = colDef(name = "Make",
                                aggregate = "frequency"),
                  model  = colDef(name = "Model",
                                  aggregate = "unique"),
                  mpg = colDef(name = "Miles/gallon",
                               aggregate = "mean",
                               format = colFormat(digits = 2)),
                  disp = colDef(name = "Displacement"),
                  hp = colDef(name = "Horsepower"),
                  drat = colDef(name = "Rear axle ratio"),
                  wt = colDef(name = "Weight"),
                  qsec = colDef(name = "1/4 mile time"),
                  vs = colDef(name = "Engine",
                              aggregate = "count"),
                  gear = colDef(name = "Number of forward gears"),
                  carb = colDef(name = "Number of carburetors")
                )
      )
    })
  }
  
  shinyApp(ui = ui, server = server)
  
}
4

2 回答 2

1

我认为这可以通过使用聚合器来解决,就像您刚才使用它们一样,然后通过aggregated参数提供自定义 JavaScript 渲染器colDef。这个想法是reactable通过内置操作符进行聚合,并使用自定义渲染器在聚合单元格中呈现输出。

自定义 JavaScript 渲染器应该接受一个看起来像的字符串0, 0(2), 1(6), 1(2)并进行一些字符串操作以生成类似0(3), 1(8).

如果 JavaScript 函数像这样定义并保存在 R 变量中,则可以重用:

jsRenderer <- "
    function(cellInfo) {
        const handleBrackets = (item) => {
            const currentName = item.replace(/\\([0-9]+\\)/g, '')
            const currentCountsArr = item.match(/\\(([0-9]+)\\)/)
            let currentCount = 1
            if (currentCountsArr && currentCountsArr.length === 2) {
                currentCount = parseInt(currentCountsArr[1], 10)
            }
            return {
                currentName,
                currentCount
            }
        }

        const getCounts = (input) => {
            const trimmedInput = input.replace(/\\s+/g, '')
            const items = trimmedInput.split(',')
            const namesWithoutBrackets = trimmedInput.replace(/\\(([0-9]+)\\)/g, '').split(',')
            const itemObj = items.reduce((prev, current, index) => {
                const itemWithoutBrackets = handleBrackets(current)
                let {
                    currentName,
                    currentCount
                } = itemWithoutBrackets

                if (namesWithoutBrackets.indexOf(currentName) !== index) {
                    currentCount += prev[currentName]
                }

                return {
                    ...prev,
                    ...{
                        [currentName]: currentCount
                    }
                }

            }, {})

            const stringToSanitize = Object.entries(itemObj).reduce((prevString, currentKeyValue) => {
                return prevString.concat(`${currentKeyValue[0]}(${currentKeyValue[1]}), `)
            }, '')

            return stringToSanitize.slice(0, -2)
        }

        return (getCounts(cellInfo.value))
    }
"

然后,您可以提供这个呈现colDef如下:

colDef(name = "Transmission", aggregate = "frequency", aggregated = jsRenderer)

在您的 MWE 中,结果显示如下:

Merc(2),
Toyota(2),
Datsun(1),
Fiat(2),
Honda(1),
Porsche(1),
Lotus(1),
Volvo(1)
于 2020-09-14T23:43:32.237 回答
0

要获得0(3), 1(8),您需要

groupBy = c("cyl", "am")

输出

于 2020-08-28T11:10:55.580 回答