Skip to content
Open
Show file tree
Hide file tree
Changes from 8 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
27 changes: 22 additions & 5 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 @@ -295,13 +306,13 @@
"Treatment or Control not found in Arm Variable. Perhaps they have been filtered out?"
))

q1 <- obj %>%

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=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 314 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=314,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 315 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=315,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 +343,13 @@
})
)

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"]])
set_chunk_dims(pws, decorated_output_q)
})
}
30 changes: 24 additions & 6 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 @@ -344,7 +356,7 @@
bquote(group_labels <- setNames(.(group_labels), .(input$groups)))
}

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

Check warning on line 359 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=359,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 +386,13 @@
})
)

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"]])
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