Skip to content
Open
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
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Suggests:
withr (>= 3.0.0)
Remotes:
insightsengineering/osprey
insightsengineering/teal
Config/Needs/verdepcheck: insightsengineering/osprey, rstudio/shiny,
insightsengineering/teal, insightsengineering/teal.slice,
insightsengineering/teal.transform, mllg/checkmate, tidyverse/dplyr,
Expand Down
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# teal.osprey 0.4.0.9002

### Enhancements
- All `tm_g_*` modules accept `transformators` (input data transforms in the filter sidebar) and `decorators` (plot output transforms in the encoding panel).

# teal.osprey 0.4.0


Expand Down
9 changes: 9 additions & 0 deletions R/argument_convention.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@
#' @param plot_width (`numeric(3)`)\cr
#' vector to indicate default value, minimum and maximum values.
#'
#' @param transformators (`list` of `teal_transform_module`) optional,
#' input data transforms applied after filtering (UI in the filter sidebar under
#' **Transform Data**). See `vignette("transform-input-data", package = "teal")`.
#'
#' @param decorators `r lifecycle::badge("experimental")`
#' (named `list` of `teal_transform_module`) optional,
#' decorators for the module `plot` output. See [decorate_module_section] for which
#' object types are supported per module.
#'
#' @return the [teal::module()] object.
Comment thread
m7pr marked this conversation as resolved.
#'
#' @name argument_convention
Expand Down
64 changes: 64 additions & 0 deletions R/decorate_module_section.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#' Decorating and transforming `teal.osprey` modules
#'
#' @description
#' Documentation for the `transformators` and `decorators` arguments accepted by all
#' `tm_g_*` modules in this package.
#'
#' @section Decorating Module:
#'
#' All `teal.osprey` plot modules expose a single decoratable output object named `plot`.
#' Decorators are passed as a named `list` of [`teal::teal_transform_module()`] objects;
#' the name of each list element must match the output object name (`"plot"`).
#'
#' ```r
#' tm_g_waterfall(
#' ...,
#' decorators = list(
#' plot = teal::teal_transform_module(...) # applied only to `plot`
#' )
#' )
#' ```
#'
#' Decorator UI controls appear in the module **encoding** panel. Decorators run in the
#' module server after the plot is created and before it is rendered.
#'
#' **Important:** decorators must not change the class of `plot`. Use transformations
#' appropriate to the object type returned by the underlying [osprey] function.
#'
#' | Module | Output | Typical class of `plot` |
#' |--------|--------|-------------------------|
#' | `tm_g_spiderplot` | `plot` | `ggplot` |
#' | `tm_g_butterfly` | `plot` | `grob` / `gtable` |
#' | `tm_g_waterfall` | `plot` | `grob` / `gtable` |
#' | `tm_g_swimlane` | `plot` | `grob` / `gtable` |
#' | `tm_g_patient_profile` | `plot` | `grob` (`cowplot` layout) |
#' | `tm_g_ae_oview` | `plot` | `grob` |
#' | `tm_g_ae_sub` | `plot` | `grob` |
#' | `tm_g_events_term_id` | `plot` | `grob` |
#' | `tm_g_heat_bygrade` | `plot` | `grob` / `gtable` |
#'
#' - For **`ggplot`** outputs (`tm_g_spiderplot` only), use `ggplot2` modifiers
#' (for example via [`teal::make_teal_transform_server()`]).
#' - For **`grob`** outputs (all other modules), use [`tern::decorate_grob()`] or
#' other grid-compatible adjustments. Applying `ggplot2` layers to `plot` in
#' those modules will fail silently or break rendering.
#'
#' Four modules (`tm_g_ae_oview`, `tm_g_ae_sub`, `tm_g_events_term_id`, `tm_g_heat_bygrade`)
#' also provide built-in title and footnote controls via [`ui_g_decorate()`] and
#' [`srv_g_decorate()`]. User-defined decorators run **before** that built-in decoration step.
#'
#' @section Transforming input data:
#'
#' All `tm_g_*` modules also accept `transformators`, a named `list` of
#' [`teal::teal_transform_module()`] objects that modify module **input** data after
#' filtering. Their UI appears in the app filter sidebar under **Transform Data**.
#'
#' See `vignette("transform-input-data", package = "teal")` for transformators and
#' `vignette("transform-module-output", package = "teal")` for decorators.
#'
#' A demo app using every module with both mechanisms is in
#' `system.file("examples", "app_decorators_transformators.R", package = "teal.osprey")`.
#'
#' @name decorate_module_section
#' @keywords internal
NULL
42 changes: 31 additions & 11 deletions R/tm_g_ae_oview.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#' sub-groups (e.g. Serious events, Related events, etc.)
#'
#' @inherit argument_convention return
#' @inheritSection decorate_module_section Decorating Module
#' @inheritSection decorate_module_section Transforming input data
#' @inheritSection teal::example_module Reporting
#'
#' @export
Expand Down Expand Up @@ -80,7 +82,8 @@
fontsize = c(5, 3, 7),
plot_height = c(600L, 200L, 2000L),
plot_width = NULL,
transformators = list()) {
transformators = list(),
decorators = list()) {
message("Initializing tm_g_ae_oview")
checkmate::assert_class(arm_var, classes = "choices_selected")
checkmate::assert_class(flag_var_anl, classes = "choices_selected")
Expand All @@ -103,6 +106,8 @@
plot_width[1],
lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width"
)
assert_transformators(transformators)
teal::assert_decorators(decorators, "plot")
Comment thread
m7pr marked this conversation as resolved.

args <- as.list(environment())

Expand All @@ -113,7 +118,8 @@
label = label,
dataname = dataname,
plot_height = plot_height,
plot_width = plot_width
plot_width = plot_width,
decorators = decorators
),
ui = ui_g_ae_oview,
ui_args = args,
Expand Down Expand Up @@ -180,6 +186,10 @@
selected = "left",
multiple = FALSE
),
teal::ui_transform_teal_data(
ns("decorator"),
transformators = select_decorators(args$decorators, "plot")
),
ui_g_decorate(
ns(NULL),
fontsize = args$fontsize,
Expand All @@ -195,7 +205,8 @@
dataname,
label,
plot_height,
plot_width) {
plot_width,
decorators) {
checkmate::assert_class(data, "reactive")
checkmate::assert_class(isolate(data()), "teal_data")

Expand Down Expand Up @@ -226,12 +237,7 @@
iv
})

decorate_output <- srv_g_decorate(
id = NULL, plt = plot_r,
plot_height = plot_height, plot_width = plot_width
)
font_size <- decorate_output$font_size
pws <- decorate_output$pws
font_size <- reactive(input$fontsize)

observeEvent(list(input$diff_ci_method, input$conf_level), {
req(!is.null(input$diff_ci_method) && !is.null(input$conf_level))
Expand Down Expand Up @@ -295,13 +301,13 @@
"Treatment or Control not found in Arm Variable. Perhaps they have been filtered out?"
))

q1 <- obj %>%

Check warning on line 304 in R/tm_g_ae_oview.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_ae_oview.R,line=304,col=19,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
teal.code::eval_code(
code = as.expression(c(
bquote(anl_labels <- formatters::var_labels(.(as.name(dataname)), fill = FALSE)),
bquote(
flags <- .(as.name(dataname)) %>%

Check warning on line 309 in R/tm_g_ae_oview.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_ae_oview.R,line=309,col=47,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
select(all_of(.(input$flag_var_anl))) %>%

Check warning on line 310 in R/tm_g_ae_oview.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_ae_oview.R,line=310,col=57,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
rename_at(vars(.(input$flag_var_anl)), function(x) paste0(x, ": ", anl_labels[x]))
)
))
Expand Down Expand Up @@ -332,7 +338,21 @@
})
)

plot_r <- reactive(output_q()[["plot"]])
set_chunk_dims(pws, output_q)
decorated_output_q <- teal::srv_transform_teal_data(
id = "decorator",
data = output_q,
transformators = select_decorators(decorators, "plot"),
expr = quote(plot)
)
plot_r <- reactive(decorated_output_q()[["plot"]])

decorate_output <- srv_g_decorate(
id = NULL,
plt = plot_r,
plot_height = plot_height,
plot_width = plot_width
)
pws <- decorate_output$pws
set_chunk_dims(pws, decorated_output_q)
})
}
47 changes: 33 additions & 14 deletions R/tm_g_ae_sub.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#' @author Molly He (hey59) \email{hey59@gene.com}
#'
#' @inherit argument_convention return
#' @inheritSection decorate_module_section Decorating Module
#' @inheritSection decorate_module_section Transforming input data
#' @inheritSection teal::example_module Reporting
#'
#' @export
Expand Down Expand Up @@ -56,7 +58,8 @@
plot_height = c(600L, 200L, 2000L),
plot_width = NULL,
fontsize = c(5, 3, 7),
transformators = list()) {
transformators = list(),
decorators = list()) {
message("Initializing tm_g_ae_sub")
checkmate::assert_class(arm_var, classes = "choices_selected")
checkmate::assert_class(group_var, classes = "choices_selected")
Expand All @@ -76,6 +79,8 @@
plot_width[1],
lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width"
)
assert_transformators(transformators)
teal::assert_decorators(decorators, "plot")

module(
label = label,
Expand All @@ -84,13 +89,15 @@
label = label,
dataname = dataname,
plot_height = plot_height,
plot_width = plot_width
plot_width = plot_width,
decorators = decorators
),
ui = ui_g_ae_sub,
ui_args = list(
arm_var = arm_var,
group_var = group_var,
fontsize = fontsize
fontsize = fontsize,
decorators = decorators
),
transformators = transformators,
datanames = c("ADSL", dataname)
Expand Down Expand Up @@ -156,6 +163,10 @@
max = 1,
value = 0.95
),
teal::ui_transform_teal_data(
ns("decorator"),
transformators = select_decorators(args$decorators, "plot")
),
ui_g_decorate(
ns(NULL),
fontsize = args$fontsize,
Expand All @@ -172,7 +183,8 @@
dataname,
label,
plot_height,
plot_width) {
plot_width,
decorators) {
checkmate::assert_class(data, "reactive")
checkmate::assert_class(shiny::isolate(data()), "teal_data")

Expand Down Expand Up @@ -206,14 +218,7 @@
iv
})

decorate_output <- srv_g_decorate(
id = NULL,
plt = plot_r,
plot_height = plot_height,
plot_width = plot_width
)
font_size <- decorate_output$font_size
pws <- decorate_output$pws
font_size <- reactive(input$fontsize)

observeEvent(input$arm_var, ignoreNULL = TRUE, {
arm_var <- input$arm_var
Expand Down Expand Up @@ -344,7 +349,7 @@
bquote(group_labels <- setNames(.(group_labels), .(input$groups)))
}

q1 <- teal.code::eval_code(obj, code = group_labels_call) %>%

Check warning on line 352 in R/tm_g_ae_sub.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_ae_sub.R,line=352,col=67,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
teal.code::eval_code(code = "")

teal.reporter::teal_card(q1) <- c(teal.reporter::teal_card(q1), "### Plot")
Expand Down Expand Up @@ -374,7 +379,21 @@
})
)

plot_r <- reactive(output_q()[["plot"]])
set_chunk_dims(pws, output_q)
decorated_output_q <- teal::srv_transform_teal_data(
id = "decorator",
data = output_q,
transformators = select_decorators(decorators, "plot"),
expr = quote(plot)
)
plot_r <- reactive(decorated_output_q()[["plot"]])

decorate_output <- srv_g_decorate(
id = NULL,
plt = plot_r,
plot_height = plot_height,
plot_width = plot_width
)
pws <- decorate_output$pws
set_chunk_dims(pws, decorated_output_q)
})
}
31 changes: 26 additions & 5 deletions R/tm_g_butterfly.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#' used directly as filter.
#'
#' @inherit argument_convention return
#' @inheritSection decorate_module_section Decorating Module
#' @inheritSection decorate_module_section Transforming input data
#' @inheritSection teal::example_module Reporting
#'
#' @export
Expand Down Expand Up @@ -121,7 +123,8 @@
plot_width = NULL,
pre_output = NULL,
post_output = NULL,
transformators = list()) {
transformators = list(),
decorators = list()) {
message("Initializing tm_g_butterfly")
checkmate::assert_string(label)
checkmate::assert_string(dataname)
Expand All @@ -144,14 +147,22 @@
null.ok = TRUE,
.var.name = "plot_width"
)
assert_transformators(transformators)
teal::assert_decorators(decorators, "plot")

args <- as.list(environment())

module(
label = label,
datanames = c("ADSL", dataname),
server = srv_g_butterfly,
server_args = list(dataname = dataname, label = label, plot_height = plot_height, plot_width = plot_width),
server_args = list(
dataname = dataname,
label = label,
plot_height = plot_height,
plot_width = plot_width,
decorators = decorators
),
ui = ui_g_butterfly,
ui_args = args,
transformators = transformators
Expand Down Expand Up @@ -251,14 +262,18 @@
ns("legend_on"),
"Add legend",
value = a$legend_on
),
teal::ui_transform_teal_data(
ns("decorator"),
transformators = select_decorators(a$decorators, "plot")
)
),
pre_output = a$pre_output,
post_output = a$post_output
)
}

srv_g_butterfly <- function(id, data, dataname, label, plot_height, plot_width) {
srv_g_butterfly <- function(id, data, dataname, label, plot_height, plot_width, decorators) {
checkmate::assert_class(data, "reactive")
checkmate::assert_class(shiny::isolate(data()), "teal_data")

Expand Down Expand Up @@ -425,8 +440,8 @@
q1 <- teal.code::eval_code(
obj,
code = bquote({
ADSL <- ADSL[, .(adsl_vars)] %>% as.data.frame()

Check warning on line 443 in R/tm_g_butterfly.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_butterfly.R,line=443,col=42,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
ANL <- .(as.name(dataname))[, .(anl_vars)] %>% as.data.frame()

Check warning on line 444 in R/tm_g_butterfly.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_butterfly.R,line=444,col=56,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
})
)

Expand All @@ -434,8 +449,8 @@
q1 <- teal.code::eval_code(
q1,
code = bquote(
ANL <- quick_filter(.(filter_var), ANL) %>%

Check warning on line 452 in R/tm_g_butterfly.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_butterfly.R,line=452,col=55,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
droplevels() %>%

Check warning on line 453 in R/tm_g_butterfly.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_butterfly.R,line=453,col=30,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
as.data.frame()
)
)
Expand All @@ -444,7 +459,7 @@
q1 <- teal.code::eval_code(
q1,
code = bquote({
ANL_f <- left_join(ADSL, ANL, by = c("USUBJID", "STUDYID")) %>% as.data.frame()

Check warning on line 462 in R/tm_g_butterfly.R

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=R/tm_g_butterfly.R,line=462,col=73,[pipe_consistency_linter] Use the |> pipe operator instead of the %>% pipe operator.
ANL_f <- na.omit(ANL_f)
})
)
Expand Down Expand Up @@ -520,7 +535,13 @@
})
)

plot_r <- reactive(output_q()[["plot"]])
decorated_output_q <- teal::srv_transform_teal_data(
id = "decorator",
data = output_q,
transformators = select_decorators(decorators, "plot"),
expr = quote(plot)
)
plot_r <- reactive(decorated_output_q()[["plot"]])

# Insert the plot into a plot_with_settings module from teal.widgets
pws <- teal.widgets::plot_with_settings_srv(
Expand All @@ -530,6 +551,6 @@
width = plot_width
)

set_chunk_dims(pws, output_q)
set_chunk_dims(pws, decorated_output_q)
})
}
Loading
Loading