-
-
Notifications
You must be signed in to change notification settings - Fork 15
introduce decorators for tm_missing_data
#809
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
introduce decorators for tm_missing_data
#809
Conversation
…1187_decorate_output@main
tm_missing_datatm_missing_data
|
This PR contains specific case where there is multiple outputs. We need to think whether we expose N decorators for N outputs, or we expose one decorator parameter and make user to put |
R/tm_missing_data.R
Outdated
|
|
||
|
|
||
| decorated_summary_plot_q <- srv_transform_teal_data(id = "decorator", data = summary_plot_q, transformators = decorators) | ||
| decorated_summary_plot_grob_q <- reactive({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
R/tm_missing_data.R
Outdated
| }) | ||
|
|
||
| combination_plot_r <- reactive(combination_plot_q()[["g"]]) | ||
| decorated_combination_plot_q <- srv_transform_teal_data(id = "decorator", data = combination_plot_q, transformators = decorators) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@m7pr I converted this PR to the new srv_transform_teal_data
|
Thanks @averissimo for some updates. unable to find an inherited method for function ‘eval_code’ for signature ‘object = "NULL", code = "{"’
|
…1187_decorate_output@main
|
I think my example had an issue in the decorator. I should use if (exists('combination_plot_top')) {
combination_plot_top <- combination_plot_top + ggplot2::labs(caption = footnote_str)
}instead if (exists(combination_plot_top)) {
combination_plot_top <- combination_plot_top + ggplot2::labs(caption = footnote_str)
} |
|
Ok, I updated the example from the opening comment of this PR. Now it's ready to be merged |
|
There is a problem with this module when it has more than 1 decorator. It doesn't appear in the UI, but an error is thrown on the console. I was investigating this, but couldn't understand last Friday It is especially troubling as:
# tm_missing_data
pkgload::load_all("../teal")
pkgload::load_all(".")
footnote_dec <- teal_transform_module(
label = "Footnote",
ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote for Combination Plot", value = "I am a good decorator"),
server = function(id, data) {
moduleServer(id, function(input, output, session) {
logger::log_info("🟢 Footnote called to action!", namespace = "teal.modules.general")
reactive(
within(data(), {
# footnote_str <- footnote
# logger::log_info("🟢 {ls() |> paste(collapse = ', ')}", namespace = "teal.modules.general")
# if (exists("combination_plot_top")) {
# combination_plot_top <- combination_plot_top + ggplot2::labs(caption = paste0(footnote_str, "1"))
# }
# if (exists("combination_plot_bottom")) {
# combination_plot_bottom <- combination_plot_bottom + ggplot2::labs(caption = paste0(footnote_str, "2"))
# }
# if (exists("summary_plot_top")) {
# summary_plot_top <- summary_plot_top + ggplot2::labs(caption = paste0(footnote_str, "3"))
# }
# if (exists("summary_plot_bottom")) {
# summary_plot_bottom <- summary_plot_bottom + ggplot2::labs(caption = paste0(footnote_str, "4"))
# }
# if (exists("by_subject_plot")) {
# by_subject_plot <- by_subject_plot + ggplot2::labs(caption = paste0(footnote_str, "5"))
# }
}, footnote = input$footnote)
)
})
}
)
custom_table_decorator_interactive <- teal_transform_module(
ui = function(id) {
ns <- NS(id)
div(
selectInput(
ns("style"),
"Table Style",
choices = c("Default", "Striped", "Hover"),
selected = "Default"
)
)
},
server = function(id, data) {
moduleServer(id, function(input, output, session) {
reactive({
req(data(), input$style)
within(data(), {
# if (exists("table")) {
# style_str <- style
# logger::log_fatal("has table!! {style_str}", namespace = "teal.modules.general")
# if (style_str == "Striped") {
# table <- DT::formatStyle(
# table,
# columns = attr(table$x, "colnames")[-1],
# target = 'row',
# backgroundColor = '#f9f9f9'
# )
# } else if (style_str == "Hover") {
# table <- DT::formatStyle(
# table,
# columns = attr(table$x, "colnames")[-1],
# target = 'row',
# backgroundColor = '#f0f0f0'
# )
# }
# }
}, style = input$style)
})
})
}
)
# CDISC example data
data <- teal_data()
data <- within(data, {
require(nestcolor)
ADSL <- rADSL
ADRS <- rADRS
})
join_keys(data) <- default_cdisc_join_keys[names(data)]
app <- init(
data = data,
modules = modules(
tm_missing_data(decorators = list(footnote_dec, custom_table_decorator_interactive))
# tm_missing_data()
)
)
if (interactive()) {
shinyApp(app$ui, app$server)
} |
| #' @return A flat list with all decorators to include. | ||
| #' It can be an empty list if none of the scope exists in `decorators` argument. | ||
| #' @keywords internal | ||
| subset_decorators <- function(scope, decorators) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After A LOT of debugging I solved the issue on this module and I was rethinking our decision on relying on the same decorators for all "outputs".
I'm proposing we allow 3 types of values in decorators argument (similar to the initial code from a week and half ago):
listofteal_transform_module(keep current list-like approach)- Named
listthat can allow for customizationslist(default = list(...))is protected and applies to alllist(summary_plot = list(...))only applies decorator forsummary_plot
- Also allow named
listofteal_transform_module
We could limit to just 1. and 2., or even just 2.. WDYT?
Why?
It seems odd to have all UIs on tm_missing_data, in particular, having plot-like decorators UI that do nothing on a table output.
Note: the PR also extracts the qenv generation from the main shiny module into smaller and logic-only modules. I opted for using modules instead of just passing input to keep with good Shiny practices.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@averissimo yeah, so I think we could meet and rethink. I actually am having still various thoughs on how we should to it, depending on how the module is built. I think the named list of decorators would be the most appriopiate. I wonder how that changes the server logic.
Thanks for working on this module and having this fixed
| ) | ||
| } | ||
| }, | ||
| ui_decorate_teal_data(ns("dec_summary_plot"), decorators = subset_decorators("summary_plot", decorators)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
subset_decorators("summary_plot", decorators) will return all from default plus the summary_plot related.
We can use either the names of the objects, or more generic ones
| if (checkmate::test_list(decorators, "teal_transform_module", null.ok = TRUE)) { | ||
| decorators <- if (checkmate::test_names(names(decorators), subset.of = c("default", available_decorators))) { | ||
| lapply(decorators, list) | ||
| } else { | ||
| list(default = decorators) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conversion of decorators object if it is a flat list of teal_transform_module, it will preserve current behavior.
…1187_decorate_output@main




Part of #863
Updated working example
Old ~Working~ Example