Skip to content

Commit 668af66

Browse files
committed
feat: tm_outliers
1 parent 6d5dea3 commit 668af66

File tree

2 files changed

+114
-73
lines changed

2 files changed

+114
-73
lines changed

R/tm_outliers.R

Lines changed: 112 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
#' This module generates the following objects, which can be modified in place using decorators:
2323
#' - `box_plot` (`ggplot2`)
2424
#' - `density_plot` (`ggplot2`)
25-
#' - `cum_dist_plot` (`ggplot2`)
25+
#' - `cumulative_plot` (`ggplot2`)
26+
#' - `table` ([DT::datatable()])
2627
#'
2728
#' For additional details and examples of decorators, refer to the vignette
2829
#' `vignette("decorate-modules-output", package = "teal")` or the [`teal_transform_module()`] documentation.
@@ -178,8 +179,15 @@ tm_outliers <- function(label = "Outliers Module",
178179
checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE)
179180
checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE)
180181

181-
checkmate::assert_list(decorators, "teal_transform_module", null.ok = TRUE)
182-
182+
available_decorators <- c("box_plot", "density_plot", "cumulative_plot", "table")
183+
if (checkmate::test_list(decorators, "teal_transform_module", null.ok = TRUE)) {
184+
decorators <- if (checkmate::test_names(names(decorators), subset.of = c("default", available_decorators))) {
185+
lapply(decorators, list)
186+
} else {
187+
list(default = decorators)
188+
}
189+
}
190+
assert_decorators(decorators, null.ok = TRUE, names = available_decorators)
183191
# End of assertions
184192

185193
# Make UI args
@@ -322,7 +330,19 @@ ui_outliers <- function(id, ...) {
322330
uiOutput(ns("ui_outlier_help"))
323331
)
324332
),
325-
ui_transform_teal_data(ns("decorate"), transformators = args$decorators),
333+
conditionalPanel(
334+
condition = paste0("input['", ns("tabs"), "'] == 'Boxplot'"),
335+
ui_decorate_teal_data(ns("d_box_plot"), decorators = subset_decorators("box_plot", args$decorators))
336+
),
337+
conditionalPanel(
338+
condition = paste0("input['", ns("tabs"), "'] == 'Density Plot'"),
339+
ui_decorate_teal_data(ns("d_density_plot"), decorators = subset_decorators("density_plot", args$decorators))
340+
),
341+
conditionalPanel(
342+
condition = paste0("input['", ns("tabs"), "'] == 'Cumulative Distribution Plot'"),
343+
ui_decorate_teal_data(ns("d_cumulative_plot"), decorators = subset_decorators("cumulative_plot", args$decorators))
344+
),
345+
ui_decorate_teal_data(ns("d_table"), decorators = subset_decorators("table", args$decorators)),
326346
teal.widgets::panel_item(
327347
title = "Plot settings",
328348
selectInput(
@@ -585,7 +605,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
585605
)
586606
)
587607

588-
if (length(categorical_var) > 0) {
608+
qenv <- if (length(categorical_var) > 0) {
589609
qenv <- teal.code::eval_code(
590610
qenv,
591611
substitute(
@@ -641,7 +661,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
641661
)
642662
}
643663

644-
qenv <- teal.code::eval_code(
664+
teal.code::eval_code(
645665
qenv,
646666
substitute(
647667
expr = {
@@ -669,16 +689,29 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
669689
tidyr::pivot_longer(-categorical_var_name) %>%
670690
tidyr::pivot_wider(names_from = categorical_var, values_from = value) %>%
671691
tibble::column_to_rownames("name")
672-
summary_table
673692
},
674693
env = list(
675694
categorical_var = categorical_var,
676695
categorical_var_name = as.name(categorical_var)
677696
)
678697
)
679698
)
699+
} else {
700+
within(qenv, summary_table <- data.frame())
680701
}
681702

703+
# Datatable is generated in qenv to allow for output decoration
704+
qenv <- within(qenv, {
705+
table <- DT::datatable(
706+
summary_table,
707+
options = list(
708+
dom = "t",
709+
autoWidth = TRUE,
710+
columnDefs = list(list(width = "200px", targets = "_all"))
711+
)
712+
)
713+
})
714+
682715
if (length(categorical_var) > 0 && nrow(qenv[["ANL_OUTLIER"]]) > 0) {
683716
shinyjs::show("order_by_outlier")
684717
} else {
@@ -688,26 +721,8 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
688721
qenv
689722
})
690723

691-
output$summary_table <- DT::renderDataTable(
692-
expr = {
693-
if (iv_r()$is_valid()) {
694-
categorical_var <- as.vector(merged$anl_input_r()$columns_source$categorical_var)
695-
if (!is.null(categorical_var)) {
696-
DT::datatable(
697-
common_code_q()[["summary_table"]],
698-
options = list(
699-
dom = "t",
700-
autoWidth = TRUE,
701-
columnDefs = list(list(width = "200px", targets = "_all"))
702-
)
703-
)
704-
}
705-
}
706-
}
707-
)
708-
709724
# boxplot/violinplot # nolint commented_code
710-
boxplot_q <- reactive({
725+
box_plot_q <- reactive({
711726
req(common_code_q())
712727
ANL <- common_code_q()[["ANL"]]
713728
ANL_OUTLIER <- common_code_q()[["ANL_OUTLIER"]]
@@ -947,7 +962,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
947962
teal.code::eval_code(
948963
qenv,
949964
substitute(
950-
expr = cum_dist_plot <- plot_call +
965+
expr = cumulative_plot <- plot_call +
951966
geom_point(data = outlier_points, aes(x = outlier_var_name, y = y, color = is_outlier_selected)) +
952967
scale_color_manual(values = c("TRUE" = "red", "FALSE" = "black")) +
953968
labs + ggthemes + themes,
@@ -962,37 +977,61 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
962977
)
963978
})
964979

965-
final_q <- reactive({
966-
req(input$tabs)
967-
tab_type <- input$tabs
968-
result_q <- if (tab_type == "Boxplot") {
969-
boxplot_q()
970-
} else if (tab_type == "Density Plot") {
971-
density_plot_q()
972-
} else if (tab_type == "Cumulative Distribution Plot") {
973-
cumulative_plot_q()
974-
}
975-
# used to display table when running show-r-code code
976-
# added after the plots so that a change in selected columns doesn't affect
977-
# brush selection.
978-
teal.code::eval_code(
979-
result_q,
980-
substitute(
981-
expr = {
982-
columns_index <- union(
983-
setdiff(names(ANL_OUTLIER), c("is_outlier_selected", "order")),
984-
table_columns
985-
)
986-
ANL_OUTLIER_EXTENDED[ANL_OUTLIER_EXTENDED$is_outlier_selected, columns_index]
987-
},
988-
env = list(
989-
table_columns = input$table_ui_columns
980+
current_tab_r <- reactive({
981+
switch(req(input$tabs),
982+
"Boxplot" = "box_plot",
983+
"Density Plot" = "density_plot",
984+
"Cumulative Distribution Plot" = "cumulative_plot"
985+
)
986+
})
987+
988+
post_expr <- reactive({
989+
substitute(
990+
expr = {
991+
columns_index <- union(
992+
setdiff(names(ANL_OUTLIER), c("is_outlier_selected", "order")),
993+
table_columns
990994
)
991-
)
995+
ANL_OUTLIER_EXTENDED[ANL_OUTLIER_EXTENDED$is_outlier_selected, columns_index]
996+
print(.plot)
997+
},
998+
env = list(table_columns = input$table_ui_columns, .plot = as.name(current_tab_r()))
992999
)
9931000
})
9941001

995-
decorated_final_q <- srv_transform_teal_data("decorate", data = final_q, transformators = decorators)
1002+
decorated_q <- mapply(
1003+
function(obj_name, q) {
1004+
srv_decorate_teal_data(
1005+
id = sprintf("d_%s", obj_name),
1006+
data = q,
1007+
decorators = subset_decorators(obj_name, decorators),
1008+
expr = post_expr,
1009+
expr_is_reactive = TRUE
1010+
)
1011+
},
1012+
rlang::set_names(c("box_plot", "density_plot", "cumulative_plot")),
1013+
c(box_plot_q, density_plot_q, cumulative_plot_q)
1014+
)
1015+
1016+
decorated_final_q_no_table <- reactive(decorated_q[[req(current_tab_r())]]())
1017+
1018+
decorated_final_q <- srv_decorate_teal_data(
1019+
"d_table",
1020+
data = decorated_final_q_no_table,
1021+
decorators = subset_decorators("table", decorators),
1022+
expr = table
1023+
)
1024+
1025+
output$summary_table <- DT::renderDataTable(
1026+
expr = {
1027+
if (iv_r()$is_valid()) {
1028+
categorical_var <- as.vector(merged$anl_input_r()$columns_source$categorical_var)
1029+
if (!is.null(categorical_var)) {
1030+
decorated_final_q()[["table"]]
1031+
}
1032+
}
1033+
}
1034+
)
9961035

9971036
# slider text
9981037
output$ui_outlier_help <- renderUI({
@@ -1042,25 +1081,22 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
10421081
}
10431082
})
10441083

1045-
boxplot_r <- reactive({
1084+
box_plot_r <- reactive({
10461085
teal::validate_inputs(iv_r())
1047-
req(boxplot_q())
1048-
decorated_final_q()[["box_plot"]]
1086+
req(decorated_q$box_plot())[["box_plot"]]
10491087
})
10501088
density_plot_r <- reactive({
10511089
teal::validate_inputs(iv_r())
1052-
req(density_plot_q())
1053-
decorated_final_q()[["density_plot"]]
1090+
req(decorated_q$density_plot())[["density_plot"]]
10541091
})
10551092
cumulative_plot_r <- reactive({
10561093
teal::validate_inputs(iv_r())
1057-
req(cumulative_plot_q())
1058-
decorated_final_q()[["cum_dist_plot"]]
1094+
req(decorated_q$cumulative_plot())[["cumulative_plot"]]
10591095
})
10601096

10611097
box_pws <- teal.widgets::plot_with_settings_srv(
10621098
id = "box_plot",
1063-
plot_r = boxplot_r,
1099+
plot_r = box_plot_r,
10641100
height = plot_height,
10651101
width = plot_width,
10661102
brushing = TRUE
@@ -1106,16 +1142,20 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var,
11061142
ANL_OUTLIER_EXTENDED <- common_code_q()[["ANL_OUTLIER_EXTENDED"]]
11071143
ANL <- common_code_q()[["ANL"]]
11081144

1109-
plot_brush <- if (tab == "Boxplot") {
1110-
boxplot_r()
1111-
box_pws$brush()
1112-
} else if (tab == "Density Plot") {
1113-
density_plot_r()
1114-
density_pws$brush()
1115-
} else if (tab == "Cumulative Distribution Plot") {
1116-
cumulative_plot_r()
1117-
cum_density_pws$brush()
1118-
}
1145+
plot_brush <- switch(current_tab_r(),
1146+
box_plot = {
1147+
box_plot_r()
1148+
box_pws$brush()
1149+
},
1150+
density_plot = {
1151+
density_plot_r()
1152+
density_pws$brush()
1153+
},
1154+
cumulative_plot = {
1155+
cumulative_plot_r()
1156+
cum_density_pws$brush()
1157+
}
1158+
)
11191159

11201160
# removing unused column ASAP
11211161
ANL_OUTLIER$order <- ANL$order <- NULL

man/tm_outliers.Rd

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)