Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to drop NAs from aggregated groups? #33

Open
tylerlittlefield opened this issue Mar 4, 2020 · 3 comments
Open

Option to drop NAs from aggregated groups? #33

tylerlittlefield opened this issue Mar 4, 2020 · 3 comments
Labels
enhancement New feature or request

Comments

@tylerlittlefield
Copy link

tylerlittlefield commented Mar 4, 2020

Take the following example:

library(reactable)

x <- data.frame(
  Group = letters[1:2],
  Value = NA
)

reactable(x, groupBy = "Group", columns = list(
  Value = colDef(
    aggregate = "count",
    format = list(
      aggregated = colFormat(suffix = " selected")
    )
  )
))

image

Is it possible to drop the NAs from the count? So instead the group would read "a (0)" and the value would read "0 Selected".

My particular use case is that I am using this in a shiny app as a kind of "filter summary". As the user starts selecting things from specific inputs, I collect them in the table above. But when the app is first initialized, nothing is selected and so my solution has been to only render specific groups once they are selected. Ideally, I'd like the table to render even if nothing is selected and display groups with count 0.

@glin
Copy link
Owner

glin commented Mar 7, 2020

You can drop NAs from the count using a custom aggregate function, like:

library(reactable)

x <- data.frame(
  Group = letters[1:2],
  Value = c(NA, 0)
)

reactable(x, groupBy = "Group", columns = list(
  Value = colDef(
    aggregate = JS("function(values) {
      const isNotNA = function(x) { return x != null && x !== 'NA' }
      return values.filter(isNotNA).length
    }"),
    format = list(
      aggregated = colFormat(suffix = " selected")
    )
  )
))

screenshot of table

However, there's no way to drop rows completely from a group. The group value could easily be made customizable and take a render function, allowing you to display "a (0)". But the row would still be expandable with that one NA row in the group.

I think what would fit better is a tree table with separate parent and child rows. That's not built into React Table, but it's something I've thought of adding before. In the meantime, you may be able to use expandable details + nested tables like in this example: https://glin.github.io/reactable/articles/cookbook/cookbook.html#nested-tables

For groups with 0 selected, you can return NULL from the details renderer to disable row expansion:

library(reactable)

x <- data.frame(
  Group = letters[1:2],
  Value = c(0, 2)
)

reactable(x, columns = list(
  Group = colDef(
    cell = function(value, index) {
      sprintf("%s (%s)", value, x$Value[index])
    },
    detail = function(index) {
      if (x$Value[index] > 0) {
        reactable(iris, outlined = TRUE)
      }
    }
  ),
  Value = colDef(
    format = colFormat(suffix = " selected")
  )
))

screenshot of table

@tylerlittlefield
Copy link
Author

tylerlittlefield commented Mar 9, 2020

Awesome, thank you for the thorough response. We have gone with the nested table route, specifically something based on this example.

This has been such a fun package to play with!

@glin
Copy link
Owner

glin commented May 15, 2021

It's still not possible to drop rows from a group, but at least you can now customize the group value (1297d0c).

  • colDef() gains a grouped argument to customize rendering for grouped cells in groupBy columns (#33, #94, #148).

Here's an example of excluding numeric NAs from the row count:

data <- data.frame(
  Group = c("a", "a", "b"),
  Value = c(1, NA, NA)
)

reactable(data, groupBy = "Group", columns = list(
  Group = colDef(
    grouped = JS("function(cellInfo) {
      const nonNAValues = cellInfo.subRows.filter(function(row) {
        return typeof row['Value'] === 'number'
      })
      return cellInfo.value + ' (' + nonNAValues.length + ')'
    }")
  ),
  Value = colDef(na = "NA")
))

reactable output

Or if the values are a character/date column, you can adjust this to filter out non-string values:

data <- data.frame(
  Group = c("a", "a", "b"),
  Value = c("X", NA, NA)
)

reactable(data, groupBy = "Group", columns = list(
  Group = colDef(
    grouped = JS("function(cellInfo) {
      const nonNAValues = cellInfo.subRows.filter(function(row) {
        return typeof row['Value'] === 'string'
      })
      return cellInfo.value + ' (' + nonNAValues.length + ')'
    }")
  ),
  Value = colDef(na = "NA")
))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants