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

Reduce unwanted reactivity on filter panel changes #593

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion R/FilterStates.R
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ FilterStates <- R6::R6Class( # nolint
# create a new FilterState
fstate <- init_filter_state(
x = data[, slice$varname, drop = TRUE],
# data_reactive is a function which eventually calls get_call(sid).
# data_reactive is a function which eventually depends on the reactiveVal reactive_call().
# This chain of calls returns column from the data filtered by everything
# but filter identified by the sid argument. FilterState then get x_reactive
# and this no longer needs to be a function to pass sid. reactive in the FilterState
Expand Down
8 changes: 7 additions & 1 deletion R/FilteredDataset.R
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ FilteredDataset <- R6::R6Class( # nolint
private$dataname <- dataname
private$keys <- keys
private$label <- if (is.null(label)) character(0) else label
private$reactive_call <- reactiveVal()

# function executing reactive call and returning data
private$data_filtered_fun <- function(sid = "") {
Expand All @@ -53,7 +54,7 @@ FilteredDataset <- R6::R6Class( # nolint
}
env <- new.env(parent = parent.env(globalenv()))
env[[dataname]] <- private$dataset
filter_call <- self$get_call(sid)
filter_call <- private$reactive_call()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't work for filter-counts which has non-empty sid as an argument. Let me explain briefly how sid works and why you can't cache these object in FilteredDataset.

For given FilterState(s) configuration there are two kind of calls (and data) produced in the same time. When the filter is modified possibly multiple calls of data_filtered_fun are invoked. This means that this can't be cached here because this function needs to be called several times with different sid.

  1. All FilterState are combined into one call and it is returned to the module. For this case your current solution works just perfect
image
  1. reactive counts in a single (each) FilterState are calculated on data filtered by every filter but not "this" filter.
image

Why are counts so weird?
When you filter single column you'd like to still see the counts of the unfiltered ranges. If we don't show these counts user wouldn't know how many observations are outside of the filtered range.

correct incorrect

Even more technical explaination here

example app
# options(teal.log_level = "TRACE", teal.show_js_log = TRUE)
library("teal.slice")
library(teal)
library(scda)
library(SummarizedExperiment)

data <- teal_data() |> within({
  # MAE <- hermes::multi_assay_experiment
  ADSL <- synthetic_cdisc_data("latest")$adsl
  ADSL$empty <- NA
  ADSL$logical1 <- FALSE
  ADSL$logical <- sample(c(TRUE, FALSE), size = nrow(ADSL), replace = TRUE)
  ADSL$numeric <- rnorm(nrow(ADSL))
  ADSL$categorical <- sample(letters[1:10], size = nrow(ADSL), replace = TRUE)
  ADSL$date <- Sys.Date() + seq_len(nrow(ADSL))
  ADSL$datetime <- Sys.time() + seq_len(nrow(ADSL)) * 3600 * 12

  ADSL$numeric[sample(1:nrow(ADSL), size = 10, )] <- NA
  ADSL$numeric[sample(1:nrow(ADSL), size = 10, )] <- Inf
  ADSL$logical[sample(1:nrow(ADSL), size = 10, )] <- NA
  ADSL$date[sample(1:nrow(ADSL), size = 10, )] <- NA
  ADSL$datetime[sample(1:nrow(ADSL), size = 10, )] <- NA
  ADSL$categorical[sample(1:nrow(ADSL), size = 10, )] <- NA

  ADTTE <- synthetic_cdisc_data("latest")$adtte
  ADRS <- synthetic_cdisc_data("latest")$adrs
})

teal.data::datanames(data) <- c(
  #  "MAE",
  "ADSL", "ADTTE", "ADRS"
)
teal.data::join_keys(data) <- teal.data::default_cdisc_join_keys[teal.data::datanames(data)]

app <- init(
  data = data,
  modules = list(
    example_module("mod1"),
    modules(
      example_module("mod2")
    )
  ),
  filter = teal_slices(
    teal_slice("ADSL", "numeric", id = "numeric1"),
    teal_slice("ADSL", "numeric", id = "numeric2"),
    module_specific = TRUE,
    mapping = list(
      mod1 = "numeric1",
      mod2 = "numeric2"
    ),
    count_type = "all"
  )
)

runApp(app)

eval_expr_with_msg(filter_call, env)
get(x = dataname, envir = env)
}
Expand Down Expand Up @@ -301,6 +302,10 @@ FilteredDataset <- R6::R6Class( # nolint
}
)

observeEvent(self$get_call(), ignoreNULL = FALSE, {
private$reactive_call(self$get_call())
})

observeEvent(self$get_filter_state(), {
shinyjs::hide("filter_count_ui")
shinyjs::show("filters")
Expand Down Expand Up @@ -374,6 +379,7 @@ FilteredDataset <- R6::R6Class( # nolint
dataname = character(0),
keys = character(0),
label = character(0),
reactive_call = NULL, # reactiveVal

# Adds `FilterStates` to the `private$filter_states`.
# `FilterStates` is added once for each element of the dataset.
Expand Down
2 changes: 1 addition & 1 deletion R/FilteredDatasetDataframe.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ DataframeFilteredDataset <- R6::R6Class( # nolint
env <- new.env(parent = parent.env(globalenv()))
env[[dataname]] <- private$dataset
env[[parent_name]] <- parent()
filter_call <- self$get_call(sid)
filter_call <- private$reactive_call()
eval_expr_with_msg(filter_call, env)
get(x = dataname, envir = env)
}
Expand Down
Loading