Open gogonzo opened 2 years ago
Instead of replacing what we currently have with dm
let's think about how we can support dm in the filter panel. I recommend first looking into how to make filter panel work with dm and then go to the data models. It goes to what I think should be the API of a teal module (so raw data passed independently of the filter state with a possibility of the filtering state being applied to the data inside the module).
@kpagacz Do you think about having FilteredData.dm
? Could you elaborate more how would you expect this to look like?
Having dm in the filter panel could be a obstacle to have independent datasets reactivity. dm
is one object so every change in the object (filter in any dataset) will trigger reactivity of the whole object, as we can't separate each dataset from the reactivity map.
See the example - change the filter in IRIS and ADSL-related output will wait for computation. Currently in the filter panel only child/parents datasets reactively-depended, other are unconnected.
library(shiny)
library(dm)
library(scda)
ADSL <- synthetic_cdisc_data("latest")$adsl
ADTTE <- synthetic_cdisc_data("latest")$adtte
ADRS <- synthetic_cdisc_data("latest")$adrs
IRIS <- iris
IRIS$id <- seq_len(nrow(IRIS))
dm <- dm(ADSL, ADTTE, ADRS, IRIS) |>
dm_add_pk(ADSL, teal.data::get_cdisc_keys("ADSL")) |>
dm_add_pk(ADTTE, teal.data::get_cdisc_keys("ADTTE")) |>
dm_add_pk(ADRS, teal.data::get_cdisc_keys("ADRS")) |>
dm_add_pk(IRIS, "id") |>
dm_add_fk(table = ADTTE, columns = teal.data::get_cdisc_keys("ADSL"), ref_table = ADSL) |>
dm_add_fk(table = ADRS, columns = teal.data::get_cdisc_keys("ADSL"), ref_table = ADSL)
shinyApp(
ui = fluidPage(
sidebarPanel(
selectInput("Species", "Select species", choices = unique(iris$Species), selected = "Setosa"),
verbatimTextOutput("ADSL_rows"),
verbatimTextOutput("iris_rows")
)
),
server = function(input, output, session) {
filtered_data <- eventReactive(input$Species, {
dm_filter(dm, IRIS, Species %in% input$Species)
})
filtered_adsl <- reactive(filtered_data()[["ADSL"]])
filtered_iris <- reactive(filtered_data()[["IRIS"]])
output$ADSL_rows <- renderText({
print("ADSL triggered")
Sys.sleep(2)
nrow(filtered_adsl())
})
output$iris_rows <- renderText({
print("IRIS triggered")
Sys.sleep(2)
nrow(filtered_iris())
})
}
)
I have an opinion that dm
can fix some of our problems but will introduce other:
FilterPanel - We can't build any reactivity between datasets which will trigger re-computation of all reactives regardless of datasets they are using. Specifically, in our case it means that each module within app will be affected by the change in any dataset. We might consider though usage of the same datasets in all modules, which is not a good idea as users requested filter-panel display being module specific. UPDATE: Above is not necessary true - bindCache can actually handle if particular datasets changed.
If we allow "choices_selected" from multiple datasets, then dm wouldn't help us so much with the merge - when one selects duplicated variable names from different datasets then dm
renames them automatically, making them hard to track in the merged dataset (unless our merge_datasets module will provide this information about renamed variables)
Blocked by https://github.com/insightsengineering/teal/issues/628 - we need more insights about how chevron and teal fits together.
dm
object to manage relationships between data.frames object.dm
be primary data object passed to the teal_module?Some initial research
ADSL <- synthetic_cdisc_data("latest")$adsl ADTTE <- synthetic_cdisc_data("latest")$adtte ADRS <- synthetic_cdisc_data("latest")$adrs IRIS <- iris IRIS$id <- seq_len(nrow(IRIS))
dm <- dm(ADSL, ADTTE, ADRS, IRIS) |> dm_add_pk(ADSL, teal::get_cdisc_keys("ADSL")) |> dm_add_pk(ADTTE, teal::get_cdisc_keys("ADTTE")) |> dm_add_pk(ADRS, teal::get_cdisc_keys("ADRS")) |> dm_add_pk(IRIS, "id") |> dm_add_fk(table = ADTTE, columns = teal::get_cdisc_keys("ADSL"), ref_table = ADSL) |> dm_add_fk(table = ADRS, columns = teal::get_cdisc_keys("ADSL"), ref_table = ADSL)
Check metadata
dm
throws an error if the primary keys are duplicateddm
holds data in list, so the data is copied by referenceFilters can be added to metadata with the
dm_filter
dm
dm
object is mutabledm
operations preserve attributesattr(joined, "label") formatters::var_labels(joined)