我正在开发一个闪亮的应用程序,由于我的数据的嵌套结构,reactable包非常有用。它允许我在更高级别的类别中折叠和汇总行,并且只有在需要时才展开以显示“子行”。
对于仅1个嵌套级别(例如,makes中的汽车模型),聚合函数(unique、count等)来自reactable的开箱即用的工作很好。然而,当添加额外的嵌套级别时,事情就会崩溃,甚至像unique这样的聚合器也会出现重复的值(!)。我怀疑这是因为子类别并不都汇集在一个平面结构中,只对所有子类别执行一个聚合步骤,而是唯一的值仍然是子类别特定的,然后只是连接在一起,导致重复。这个问题也会影响到其他聚合器,不仅仅是unique。
我在下面的R中添加了一个MWE,因为我一直无法修复这个问题。由于JS也远不是我的强项,我无法插入任何JS来更灵活地修复这个问题,正如here所建议的那样。如何调整下面的聚合器以获得正确显示的输出(即无重复)?
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)
}发布于 2020-09-15 07:43:32
我认为这可以通过使用聚合器来解决,因为您现在正在使用它们,然后通过colDef的aggregated参数提供一个自定义的JavaScript渲染器。其想法是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-08-28 19:10:56
要获取0(3), 1(8),您需要
groupBy = c("cyl", "am")

https://stackoverflow.com/questions/63622632
复制相似问题