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

How to filter missing/empty values #145

Closed
adayim opened this issue Apr 26, 2021 · 4 comments
Closed

How to filter missing/empty values #145

adayim opened this issue Apr 26, 2021 · 4 comments
Labels
enhancement New feature or request

Comments

@adayim
Copy link

adayim commented Apr 26, 2021

I want to use this package for data quality check. So some times I want to filter rows with missing values. But it seems like the filtering does not allow for missing/empty value filtering. Is there any way to do that? I have pasted my code below and it's really simple one. And is it possible to write filtering expression in the filtering box or only the value is supported?

library(reactable)

rows <- 1000
dates <- seq.Date(as.Date("2018-01-01"), as.Date("2018-12-01"), "day")
data <- data.frame(
  index = seq_len(rows),
  date = sample(dates, rows, replace = TRUE),
  city = sample(names(precip), rows, replace = TRUE),
  state = sample(rownames(USArrests), rows, replace = TRUE),
  temp = round(runif(rows, 0, 100), 1),
  stringsAsFactors = FALSE
)

data[, c(2:5)] <- lapply(data[, c(2:5)], function(x){
  x[sample(1:length(x), floor(runif(1, 0, 100)))] <- NA
  x
})

reactable(
  data,
  filterable = TRUE,
  minRows = 10,
  highlight = TRUE,
)
@adayim adayim changed the title How to filter missing values How to filter missing/empty values Apr 28, 2021
@glin
Copy link
Owner

glin commented May 1, 2021

Hi, this isn't possible with the built-in filters today, but it may be possible when custom filtering gets added (related: #90). Right now, the filters only support string matching on the value.

For alternatives, you could write a custom filter in Shiny if it's possible to use Shiny. Or you could use Crosstalk with an external filter for missing values. I don't think it's possible to filter missing values with the built-in Crosstalk filters, but you could write a custom filter to do that (reference). Here's a quick example of a custom checkbox that filters missing temp values, which you can adapt:

library(reactable)
library(crosstalk)
library(htmltools)

rows <- 1000
dates <- seq.Date(as.Date("2018-01-01"), as.Date("2018-12-01"), "day")
data <- data.frame(
  index = seq_len(rows),
  date = sample(dates, rows, replace = TRUE),
  city = sample(names(precip), rows, replace = TRUE),
  state = sample(rownames(USArrests), rows, replace = TRUE),
  temp = round(runif(rows, 0, 100), 1),
  stringsAsFactors = FALSE
)

data[, c(2:5)] <- lapply(data[, c(2:5)], function(x){
  x[sample(1:length(x), floor(runif(1, 0, 100)))] <- NA
  x
})

shared_data <- SharedData$new(data)

tbl <- reactable(
  shared_data,
  filterable = TRUE,
  minRows = 10,
  highlight = TRUE,
)

checkbox_filter <- function(id, label, shared_data, group, value) {
  values <- shared_data$data()[[group]]
  keys <- shared_data$key()[which(values %in% value)]
  
  script <- sprintf("
    window['__ct__%s'] = (function() {
      const handle = new window.crosstalk.FilterHandle('%s')
      const keys = %s
      return {
        filter: function(value) {
          if (!value) {
            handle.clear()
          } else {
            handle.set(keys)
          }
        }
      }
    })()
  ", id, shared_data$groupName(), jsonlite::toJSON(keys))
  
  div(
    tags$input(
      id = id,
      type = "checkbox",
      onclick = sprintf("window['__ct__%s'].filter(this.checked)", id)
    ),
    tags$label(`for` = id, label),
    tags$script(HTML(script))
  )
}

browsable(
  div(
    checkbox_filter("filter_temp", "Filter missing temperatures", shared_data, "temp", NA),
    tbl
  )
)

reactable output with checkbox filter

@glin glin added the enhancement New feature or request label May 1, 2021
@adayim
Copy link
Author

adayim commented May 4, 2021

Thanks, this is helpful. But providing a method for filtering any variables with missing or empty values would be more appreciated. I used DT package instead to deal with this and I found a solution for that. The basic idea is to replace the missing or empty values and return a custom one instead, may be render as "missing" value. Maybe consider all the missing, empty values as "missing"? And for space only values? This becomes complicated. Don't know a better way for that.

@glin
Copy link
Owner

glin commented May 8, 2022

Custom filtering is now possible in the latest development version (v0.2.3.9000):

  • Column filtering and table searching can now be customized. Learn more in the Custom Filtering guide.
    • reactable() gains a searchMethod argument to use a custom JavaScript function for global table searching (#222).
    • colDef() gains a filterMethod argument to use a custom JavaScript function for column filtering (#9, #90, #145).
    • colDef() gains a filterInput argument to render a custom filter input for column filtering (#9).

My example from earlier is now easier to do with reactable only, no Crosstalk or Shiny needed. Here's a modified version of the checkbox filter using a custom filter method that I've added to the docs: https://glin.github.io/reactable/articles/custom-filtering.html#external-checkbox-filter

You could also filter for missing values in other ways, like writing a custom filter method that understands a custom keyword/expression to show missing values only, and return rows with NA/null values.

@glin glin closed this as completed May 8, 2022
@adayim
Copy link
Author

adayim commented May 9, 2022

Fantastic, thank you. I will give it a try.

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