Skip to content

Commit

Permalink
Merge pull request #14 from Boehringer-Ingelheim/6-include-several-fi…
Browse files Browse the repository at this point in the history
…lters-in-dvmanager

6 include several filters in dvmanager
  • Loading branch information
zsigmas authored Oct 8, 2024
2 parents ac5a942 + 7dced15 commit 1db2186
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 76 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Imports:
bslib (>= 0.3.0),
purrr (>= 0.3.4),
dplyr (>= 1.0.3),
dv.filter (>= 1.0.0),
dv.filter (>= 3.0.1),
lubridate (>= 1.7.9.2),
shinymeta (>= 0.2.0.1),
shinyjs (>= 2.0.0),
Expand Down
60 changes: 54 additions & 6 deletions R/app_server.R
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ app_server_ <- function(input, output, session, opts) {
startup_msg <- opts[["startup_msg"]]
reload_period <- opts[["reload_period"]]

datasets_filters_info <- get_dataset_filters_info(data, filter_data)

# Check if dataset must be reloaded in the next session
check_data_reload(reload_period)

Expand Down Expand Up @@ -121,18 +123,64 @@ app_server_ <- function(input, output, session, opts) {
}
})

filtered_values <- dv.filter::data_filter_server(
global_filtered_values <- dv.filter::data_filter_server(
"global_filter",
shiny::reactive(unfiltered_dataset()[[filter_data]])
)

dataset_filters <- local({
l <- vector(mode = "list", length = length(datasets_filters_info))
names(l) <- names(datasets_filters_info)
for (idx in seq_along(datasets_filters_info)) {
l[[idx]] <- local({
curr_dataset_filter_info <- datasets_filters_info[[idx]]
dv.filter::data_filter_server(
curr_dataset_filter_info[["id"]],
shiny::reactive({
unfiltered_dataset()[[curr_dataset_filter_info[["name"]]]] %||% data.frame()
})
)
})
}

l
})

filtered_dataset <- shinymeta::metaReactive({
# dv.filter returns a logical vector. This contemplates the case of empty lists
shiny::req(is.logical(filtered_values()))
log_inform("New filter applied")
filtered_key_values <- unfiltered_dataset()[[filter_data]][[filter_key]][filtered_values()] # nolint
purrr::map(
unfiltered_dataset(),
shiny::req(is.logical(global_filtered_values()))

# Depend on all datasets
purrr::walk(dataset_filters, ~ .x())

# We do not react to changed in unfiltered dataset, otherwise when a dataset changes
# We filter the previous dataset which in the best case produces and extra reactive beat
# and in the worst case produces an error in (mvbc)
# We don't want to control the error in (mvbc) because filtered dataset only changes when filter changes
ufds <- shiny::isolate(unfiltered_dataset())

curr_dataset_filters <- dataset_filters[intersect(names(dataset_filters), names(ufds))]

# Current dataset must be logical with length above 0
# Check dataset filters check all datafilters are initialized
purrr::walk(curr_dataset_filters, ~ shiny::req(checkmate::test_logical(.x(), min.len = 1)))

filtered_key_values <- ufds[[filter_data]][[filter_key]][global_filtered_values()]

fds <- ufds

# Single dataset filtering
fds[names(curr_dataset_filters)] <- purrr::imap(
fds[names(curr_dataset_filters)],
function(val, nm) {
# (mvbc)
fds[[nm]][dataset_filters[[nm]](), , drop = FALSE]
}
)

# Global dataset filtering
global_filtered <- purrr::map(
fds,
~ dplyr::filter(.x, .data[[filter_key]] %in% filtered_key_values) # nolint
)
})
Expand Down
41 changes: 37 additions & 4 deletions R/app_ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ app_ui <- function(id) {

data <- get_config("data")
module_list <- get_config("module_list")
filter_data <- get_config("filter_data")

log_inform("Initializing HTML template UI")
log_inform(glue::glue(
Expand All @@ -30,6 +31,23 @@ app_ui <- function(id) {
log_inform(glue::glue("Available modules (N): {length(module_list)}"))
log_inform(glue::glue("Dataset options (N): {length(data)}"))


dataset_filters_ui <- local({
datasets_filters_info <- get_dataset_filters_info(data, filter_data)
purrr::map(
datasets_filters_info,
function(entry) {
shiny::div(
id = entry[["id_cont"]],
class = "filter-control filter-filters",
shiny::tags[["label"]](entry[["name"]]),
dv.filter::data_filter_ui(ns(entry[["id"]])),
shiny::hr(style = "border-top: 2px solid gray; height: 10px;")
)
}
)
})

collapsable_ui <-
shiny::div(
class = "menu-contents",
Expand All @@ -44,10 +62,25 @@ app_ui <- function(id) {
shiny::selectInput(ns("selector"), label = NULL, choices = names(data))
)),
shiny::div(
id = ns("shiny_filter"),
class = "c-well",
shiny::tags$label("Filters", class = "text-primary"),
dv.filter::data_filter_ui(ns("global_filter"))
class = "c-well shiny_filter",
shiny::tags$label("Global Filter", class = "text-primary"),
# shiny::tags$button(
# id = ns("global_button"),

Check warning on line 68 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=68,col=15,[commented_code_linter] Commented code should be removed.

Check warning on line 68 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=68,col=15,[commented_code_linter] Commented code should be removed.
# class = "btn btn-primary filter_button",

Check warning on line 69 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=69,col=15,[commented_code_linter] Commented code should be removed.

Check warning on line 69 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=69,col=15,[commented_code_linter] Commented code should be removed.
# shiny::span("Global Filter"),

Check warning on line 70 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=70,col=15,[commented_code_linter] Commented code should be removed.

Check warning on line 70 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=70,col=15,[commented_code_linter] Commented code should be removed.
# # shiny::span("TAG", class = "dv_hidden badge"),

Check warning on line 71 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=71,col=15,[commented_code_linter] Commented code should be removed.

Check warning on line 71 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=71,col=15,[commented_code_linter] Commented code should be removed.
# # shiny::span(class = "caret"),

Check warning on line 72 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=72,col=15,[commented_code_linter] Commented code should be removed.

Check warning on line 72 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=72,col=15,[commented_code_linter] Commented code should be removed.
# # onclick = sprintf("dv_manager.hide_filters('%s')", ns("global_button"))

Check warning on line 73 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=73,col=15,[commented_code_linter] Commented code should be removed.

Check warning on line 73 in R/app_ui.R

View workflow job for this annotation

GitHub Actions / Shared / Lintr 🔍 / ghcr.io/boehringer-ingelheim/r_4.3.2_cran_2024.01.12:latest

file=R/app_ui.R,line=73,col=15,[commented_code_linter] Commented code should be removed.
# ),
shiny::div(
class = "filter-control filter-filters",
dv.filter::data_filter_ui(ns("global_filter"))
)
),
shiny::div(
class = "c-well shiny_filter",
shiny::tags$label("Dataset Filter", class = "text-primary"),
dataset_filters_ui
)
)
)
Expand Down
27 changes: 25 additions & 2 deletions R/pharmaverse_data.R
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
get_pharmaverse_data <- function(dataset) {
if (!rlang::is_installed("pharmaverseadam")) stop("Please, install.package('pharmaverseadam')")

chr2fct <- function(x) {
x[] <- purrr::map(x, ~ if (is.character(.x)) factor(.x) else .x)
x
}

cd2fct <- function(x) {
x[] <- purrr::imap(x, ~ if (endsWith(.y, "CD")) factor(.x) else .x)
x
}

if (dataset == "adsl") {
return(pharmaverseadam::adsl)
res <- pharmaverseadam::adsl |>
chr2fct() |>
cd2fct()
return(res)
}
if (dataset == "adae") {
return(pharmaverseadam::adae)
res <- pharmaverseadam::adae |>
chr2fct() |>
cd2fct()
return(res)
}
if (dataset == "adlb") {
res <- pharmaverseadam::adlb |>
chr2fct() |>
cd2fct()
return(res)
}
stop("Unknown dataset")
}
25 changes: 24 additions & 1 deletion R/testing_module.R
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ mod_simple <- function(dataset, module_id) {

run_mock_app <- function() {
run_app(
data = list("D1" = list(adsl = get_pharmaverse_data("adsl"))),
data = list("D1" = list(adsl = get_pharmaverse_data("adsl"), adae = get_pharmaverse_data("adae"))),
module_list = list(
"Simple" = mod_simple(mm_dispatch("filtered_dataset", "adsl"), "mod1"),
"Simple2" = mod_simple(mm_dispatch("unfiltered_dataset", "adsl"), "mod2")
Expand All @@ -135,6 +135,29 @@ run_mock_app <- function() {
)
}

run_mock_app_two_datasets <- function() {
run_app(
data = list(
"D1" = list(
adsl = get_pharmaverse_data("adsl"),
adae = get_pharmaverse_data("adae")
),
"D2" = list(
adsl = get_pharmaverse_data("adsl"),
adae = get_pharmaverse_data("adae"),
adlb = get_pharmaverse_data("adlb")
)
),
module_list = list(
"Simple" = mod_simple(mm_dispatch("filtered_dataset", "adsl"), "mod1"),
"Simple2" = mod_simple(mm_dispatch("unfiltered_dataset", "adsl"), "mod2"),
"Simple3" = mod_simple(mm_dispatch("filtered_dataset", "adae"), "mod3")
),
filter_data = "adsl",
filter_key = "USUBJID"
)
}

########## URL READING

url_reader_UI <- function(id) { # nolint
Expand Down
28 changes: 28 additions & 0 deletions R/utils_helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,31 @@ create_options_modal <- function(session, input, ns) {
easyClose = TRUE
)
}

#' Get the set of all possible data table names for filtering
get_data_tables_names <- function(data) {
nm <- character(0)
for (idx in seq_along(data)) {
curr_data <- if (is.function(data[[idx]])) data[[idx]]() else data[[idx]]
nm <- union(nm, names(curr_data))
}
return(nm)
}

get_dataset_filters_info <- function(data, filter_data) {
dataset_filter_names <- setdiff(get_data_tables_names(data), filter_data)
purrr::map(
dataset_filter_names,
function(nm) {
name <- nm
hash <- digest::digest(nm, "murmur32")
id <- sprintf("dataset_filter_%s", hash)
cont_id <- paste0(id, "_cont")
list(name = nm, id = id, hash = hash, id_cont = cont_id)
}
) |> purrr::set_names(dataset_filter_names)
}

`%||%` <- function(x, y) {
if (!is.null(x)) x else y
}
2 changes: 1 addition & 1 deletion inst/app/www/css/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ input[type="checkbox"]#click {
flex-direction: column;
justify-content: flex-start;

#shiny_filter {
.shiny_filter {
flex: 1 0 auto;
display: flex;
flex-direction: column;
Expand Down
8 changes: 5 additions & 3 deletions inst/validation/specs.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ fs_spec <- specs_list(
"modification_dates_display" = "The earliest and latest modification dates of all the data tables are displayed for the active dataset",
"date_unavailability_message" = "If no date is available for any of the data tables in the loaded dataset the system displays a 'Date unavailable' message",
"data_reloading" = "dv.manager allows the reloading of the data after a specific amount of time.",
"filtering_menu_display" = "The sidebar menu will display a filtering menu using the datafilter module (GUI).",
"active_dataset_filtering" = "The active dataset can be filtered through the datafilter module.",
"filtering_menu_display" = "The sidebar menu will display a filtering menu/s using the datafilter module (GUI).",
"active_dataset_filtering" = "The active dataset can be filtered.",
"global_filtering" = "A global filter will be available in dv.manager. One table of the dataset will be used to filter all other tables in the dataset and itself by using a common field among them.",
"single_filtering" = "All data tables, with exception of the one used in the global filter, will have its own independent filter that only affects itself. These filters will not influence other datasets.",
"bookmarking_features" = "Bookmarking will include:
- the identity of the loaded dataset
- the set of filters applied to the loaded dataset
Expand Down Expand Up @@ -75,7 +77,7 @@ or a positive numeric value which is then interpreted as a lubridate duration ob
- ids of the modules in module_list are not repeated. Otherwise it throws an informative error.",
"startup_message_check" = "- startup_message is null or a shiny::modalDialog. Otherwise it throws an informative error.",
"azure_options_check" = "-azure_options: must be a list with all the required fields or NULL. Otherwise an error is thrown.",
"filtering_menu" = "- A filtering menu that is an instance of datafilter",
"filtering_menus" = "- A filtering menu that is an/several instances of datafilter",
"dataset_selector" = "- A dataset selector that:
- contains one entry per entry in the data parameters list
- when changed will load the selected dataset in the application
Expand Down
67 changes: 18 additions & 49 deletions inst/www/css/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,25 @@ input[type="checkbox"]#click {
opacity: 1;
}

#shiny_filter_panel {
#shiny_filter_panel {
height: 94vh;
display: flex;
flex-direction: column;
justify-content: flex-start;

#shiny_filter {
flex: 1 0 auto;
display: flex;
flex-direction: column;
justify-content: flex-start;
overflow-y: auto;
overflow-x: hidden;

.shiny_filter{
.dropdown-menu.open{
min-width: min-content;
position: fixed;
left: $sidebar-width-open;
top: 25vh;
max-height: 75vh !important;
.inner.open{
max-height: 75vh !important;
}
}

}

.c-well {
min-height: 20px;
padding: 15px;
Expand All @@ -234,45 +241,7 @@ input[type="checkbox"]#click {

#dataset_selector {
flex: 0 0 auto;
}
}

#global_filter-filters {
margin-top: 1rem;
.dropdown-menu {
left: $sidebar-width-open;
}
}

#global_filter-controls {
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
margin-right: -15px;
flex: 1 10 1vh;
min-height: 7.5rem;
padding: 25px 15px 15px !important;
margin-right: -15px !important;
margin-left: -15px !important;

.dropdown-menu {
position: fixed;
top: 25vh;
left: $sidebar-width-open;
min-width: min-content;

&.open {
left: 320px;
min-height: max-content;
height: max-content;
}

&.inner {
position: inherit;
min-height: max-content;
overflow-x: hidden;
overflow-y: auto;
}
max-height: 200px;
}
}

Expand Down
20 changes: 20 additions & 0 deletions inst/www/js/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,23 @@ $(document).ready(function () {
}
});
});

// const dv_manager = {
// hide_filters: function(button_id) {
// var button = document.getElementById(button_id);
// var tag = button.querySelectorAll("span")[1];
// var container = button.nextElementSibling;
// var hidden = container.classList.toggle("dv_hidden");
// var controls_container = container.querySelectorAll(":scope > div")[2];
// var active_filters = controls_container.querySelectorAll(":scope > div").length;

// tag.textContent=active_filters;

// if (hidden) {
// tag.classList.remove("dv_hidden");
// } else {
// tag.classList.add("dv_hidden");
// }
// }
// };

Loading

0 comments on commit 1db2186

Please sign in to comment.