-
-
Notifications
You must be signed in to change notification settings - Fork 13
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
Updates "Decorators" to use name-based execution and new wrappers #812
Changes from 21 commits
fb08fbf
82aeea5
6561d03
0b3b10b
8e262c3
929f45f
ff7d3c2
7a96181
e7cb0f1
b29e8d1
72b5d05
7b8b8c0
ea3f729
6d5dea3
668af66
ea8d583
2f9f79b
bb52cf6
943c260
039c37a
337c2af
f9c1d7b
9ec4381
34bc4cd
6f02f63
33614b7
64b61cf
64ccbce
1c8d0d7
e4ad8a2
4d10d23
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# nocov start | ||
roxygen_decorators_param <- function(module_name) { | ||
paste( | ||
sep = " ", | ||
lifecycle::badge("experimental"), | ||
" (`list` of `teal_transform_module`, named `list` of `teal_transform_module` or", | ||
"`NULL`) optional, if not `NULL`, decorator for tables or plots included in the module.", | ||
"When a named list of `teal_transform_module`, the decorators are applied to the", | ||
"respective output objects.\n\n", | ||
"Otherwise, the decorators are applied to all objects, which is equivalent as using the name `default`.\n\n", | ||
sprintf("See section \"Decorating `%s`\"", module_name), | ||
"below for more details." | ||
) | ||
} | ||
|
||
roxygen_ggplot2_args_param <- function(...) { | ||
paste( | ||
sep = " ", | ||
"(`ggplot2_args`) optional, object created by [`teal.widgets::ggplot2_args()`]", | ||
"with settings for all the plots or named list of `ggplot2_args` objects for plot-specific settings.", | ||
"The argument is merged with options variable `teal.ggplot2_args` and default module setup.\n\n", | ||
sprintf( | ||
"List names should match the following: `c(\"default\", %s)`.\n\n", | ||
paste("\"", unlist(rlang::list2(...)), "\"", collapse = ", ", sep = "") | ||
), | ||
"For more details see the vignette: `vignette(\"custom-ggplot2-arguments\", package = \"teal.widgets\")`." | ||
) | ||
} | ||
|
||
# nocov end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,20 +13,40 @@ | |
#' It controls the font size for plot titles, axis labels, and legends. | ||
#' - If vector of `length == 1` then the font sizes will have a fixed size. | ||
#' - while vector of `value`, `min`, and `max` allows dynamic adjustment. | ||
#' @templateVar ggnames "Elbow plot", "Circle plot", "Biplot", "Eigenvector plot" | ||
#' @template ggplot2_args_multi | ||
#' @param ggplot2_args `r roxygen_ggplot2_args_param("Elbow plot", "Circle plot", "Biplot", "Eigenvector plot")` | ||
#' @param decorators `r roxygen_decorators_param("tm_a_pca")` | ||
Comment on lines
+16
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this sorcery : p? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's the recommended way for dealing with It's all about having the It's nice to have, but I'm more than happy to revert this and keep it simple as it was (ggplot2_args back to template and shared |
||
#' | ||
#' @inherit shared_params return | ||
#' | ||
#' @section Decorating `tm_a_pca`: | ||
#' | ||
#' This module generates the following objects, which can be modified in place using decorators: | ||
#' - `plot` (`ggplot2`) | ||
#' - `elbow_plot` (`ggplot2`) | ||
#' - `circle_plot` (`ggplot2`) | ||
#' - `biplot` (`ggplot2`) | ||
#' - `eigenvector_plot` (`ggplot2`) | ||
#' | ||
#' Decorators can be applied to all outputs or only to specific objects using a | ||
#' named list of `teal_transform_module` objects. | ||
#' The `"default"` name is reserved for decorators that are applied to all outputs. | ||
#' See code snippet below: | ||
#' | ||
#' ``` | ||
#' tm_a_pca( | ||
#' ..., # arguments for module | ||
#' decorators = list( | ||
#' default = list(teal_transform_module(...)), # applied to all outputs | ||
#' elbow_plot = list(teal_transform_module(...)), # applied only to `elbow_plot` output | ||
#' circle_plot = list(teal_transform_module(...)) # applied only to `circle_plot` output | ||
#' biplot = list(teal_transform_module(...)) # applied only to `biplot` output | ||
#' eigenvector_plot = list(teal_transform_module(...)) # applied only to `eigenvector_plot` output | ||
#' ) | ||
#' ) | ||
#' ``` | ||
#' | ||
#' For additional details and examples of decorators, refer to the vignette | ||
#' `vignette("decorate-modules-output", package = "teal")` or the [`teal_transform_module()`] documentation. | ||
#' | ||
#' | ||
#' @examplesShinylive | ||
#' library(teal.modules.general) | ||
#' interactive <- function() TRUE | ||
|
@@ -165,7 +185,9 @@ tm_a_pca <- function(label = "Principal Component Analysis", | |
checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) | ||
checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) | ||
|
||
checkmate::assert_list(decorators, "teal_transform_module", null.ok = TRUE) | ||
available_decorators <- c("elbow_plot", "circle_plot", "biplot", "eigenvector_plot") | ||
decorators <- normalize_decorators(decorators, available_decorators) | ||
assert_decorators(decorators, null.ok = TRUE, available_decorators) | ||
# End of assertions | ||
|
||
# Make UI args | ||
|
@@ -240,7 +262,22 @@ ui_a_pca <- function(id, ...) { | |
choices = args$plot_choices, | ||
selected = args$plot_choices[1] | ||
), | ||
ui_transform_teal_data(ns("decorate"), transformators = args$decorators) | ||
conditionalPanel( | ||
condition = sprintf("input['%s'] == 'Elbow plot'", ns("plot_type")), | ||
ui_decorate_teal_data(ns("d_elbow_plot"), decorators = subset_decorators("elbow_plot", args$decorators)) | ||
), | ||
conditionalPanel( | ||
condition = sprintf("input['%s'] == 'Circle plot'", ns("plot_type")), | ||
ui_decorate_teal_data(ns("d_circle_plot"), decorators = subset_decorators("circle_plot", args$decorators)) | ||
), | ||
conditionalPanel( | ||
condition = sprintf("input['%s'] == 'Biplot'", ns("plot_type")), | ||
ui_decorate_teal_data(ns("d_biplot"), decorators = subset_decorators("biplot", args$decorators)) | ||
), | ||
conditionalPanel( | ||
condition = sprintf("input['%s'] == 'Eigenvector plot'", ns("plot_type")), | ||
ui_decorate_teal_data(ns("d_eigenvector_plot"), decorators = subset_decorators("eigenvector_plot", args$decorators)) | ||
) | ||
), | ||
teal.widgets::panel_item( | ||
title = "Pre-processing", | ||
|
@@ -565,7 +602,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl | |
) | ||
|
||
cols <- c(getOption("ggplot2.discrete.colour"), c("lightblue", "darkred", "black"))[1:3] | ||
plot <- ggplot(mapping = aes_string(x = "component", y = "value")) + | ||
elbow_plot <- ggplot(mapping = aes_string(x = "component", y = "value")) + | ||
geom_bar( | ||
aes(fill = "Single variance"), | ||
data = dplyr::filter(elb_dat, metric == "Proportion of Variance"), | ||
|
@@ -642,7 +679,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl | |
y = sin(seq(0, 2 * pi, length.out = 100)) | ||
) | ||
|
||
plot <- ggplot(pca_rot) + | ||
circle_plot <- ggplot(pca_rot) + | ||
geom_point(aes_string(x = x_axis, y = y_axis)) + | ||
geom_label( | ||
aes_string(x = x_axis, y = y_axis, label = "label"), | ||
|
@@ -874,7 +911,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl | |
qenv, | ||
substitute( | ||
expr = { | ||
plot <- plot_call | ||
biplot <- plot_call | ||
}, | ||
env = list( | ||
plot_call = Reduce(function(x, y) call("+", x, y), pca_plot_biplot_expr) | ||
|
@@ -883,8 +920,8 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl | |
) | ||
} | ||
|
||
# plot pc_var ---- | ||
plot_pc_var <- function(base_q) { | ||
# plot eigenvector_plot ---- | ||
plot_eigenvector <- function(base_q) { | ||
pc <- input$pc | ||
ggtheme <- input$ggtheme | ||
|
||
|
@@ -950,7 +987,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl | |
expr = { | ||
pca_rot <- pca$rotation[, pc, drop = FALSE] %>% | ||
dplyr::as_tibble(rownames = "Variable") | ||
plot <- plot_call | ||
eigenvector_plot <- plot_call | ||
}, | ||
env = list( | ||
pc = pc, | ||
|
@@ -960,27 +997,54 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl | |
) | ||
} | ||
|
||
# plot final ---- | ||
output_q <- reactive({ | ||
req(computation()) | ||
teal::validate_inputs(iv_r()) | ||
teal::validate_inputs(iv_extra, header = "Plot settings are required") | ||
# qenvs --- | ||
output_q <- lapply( | ||
list( | ||
elbow_plot = plot_elbow, | ||
circle_plot = plot_circle, | ||
biplot = plot_biplot, | ||
eigenvector_plot = plot_eigenvector | ||
), | ||
function(fun) { | ||
reactive({ | ||
req(computation()) | ||
teal::validate_inputs(iv_r()) | ||
teal::validate_inputs(iv_extra, header = "Plot settings are required") | ||
fun(computation()) | ||
}) | ||
} | ||
) | ||
|
||
switch(input$plot_type, | ||
"Elbow plot" = plot_elbow(computation()), | ||
"Circle plot" = plot_circle(computation()), | ||
"Biplot" = plot_biplot(computation()), | ||
"Eigenvector plot" = plot_pc_var(computation()), | ||
decorated_q <- mapply( | ||
function(obj_name, q) { | ||
srv_decorate_teal_data( | ||
id = sprintf("d_%s", obj_name), | ||
data = q, | ||
decorators = subset_decorators(obj_name, decorators), | ||
expr = reactive({ | ||
substitute(print(.plot), env = list(.plot = as.name(obj_name))) | ||
}), | ||
expr_is_reactive = TRUE | ||
) | ||
}, | ||
names(output_q), | ||
output_q | ||
) | ||
averissimo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# plot final ---- | ||
decorated_output_q <- reactive({ | ||
switch(req(input$plot_type), | ||
"Elbow plot" = decorated_q$elbow_plot(), | ||
"Circle plot" = decorated_q$circle_plot(), | ||
"Biplot" = decorated_q$biplot(), | ||
"Eigenvector plot" = decorated_q$eigenvector_plot(), | ||
stop("Unknown plot") | ||
) | ||
}) | ||
|
||
decorated_output_q_no_print <- srv_transform_teal_data("decorate", data = output_q, transformators = decorators) | ||
decorated_output_q <- reactive(within(decorated_output_q_no_print(), expr = print(plot))) | ||
|
||
plot_r <- reactive({ | ||
req(output_q()) | ||
decorated_output_q()[["plot"]] | ||
plot_name <- gsub(" ", "_", tolower(req(input$plot_type))) | ||
req(decorated_output_q())[[plot_name]] | ||
}) | ||
|
||
pws <- teal.widgets::plot_with_settings_srv( | ||
|
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.
See https://roxygen2.r-lib.org/articles/reuse.html?q=template#superseded
man-roxygen
folder is a very old way of placing the template, if we want to keep using templates we should move toman/roxygen
folderThere 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 should we create a separate issue?
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.
For other repos yes, although it's a low priority until it's really deprecated (not only twice superseded)
man-roxygen
folder on the root folderFor this one, depends on this PR and how we deal with
@param decorators
if we keep as is, the change can tag along.