Skip to content
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

Remove "default" decoration and use the same way of decoration in all modules #846

Merged
merged 5 commits into from
Feb 18, 2025

Conversation

vedhav
Copy link
Contributor

@vedhav vedhav commented Feb 14, 2025

Closes #845

Changes:

  1. Removes the ability to have a "default" decoration applied to all output objects.
  2. Makes sure that all our modules follow the same decoration format: decorators = list(output_name = teal_transform_module(...))
  3. Improve the error message so the user knows that they have to provide the names from the available list of names.
Decorator examples that should be working
pkgload::load_all(".")

# ######################################################
#
#   _____                           _
#  |  __ \                         | |
#  | |  | | ___  ___ ___  _ __ __ _| |_ ___  _ __ ___
#  | |  | |/ _ \/ __/ _ \| '__/ _` | __/ _ \| '__/ __|
#  | |__| |  __/ (_| (_) | | | (_| | || (_) | |  \__ \
#  |_____/ \___|\___\___/|_|  \__,_|\__\___/|_|  |___/
#
#
#
#  Decorators
# #####################################################

plot_grob_decorator <- function(default_footnote = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption (grob)",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_footnote),
    server = function(id, data) {
      moduleServer(id, function(input, output, session) {
        logger::log_info("🟠 plot_grob with default: {default_footnote}!", namespace = "teal.modules.general")
        reactive({
          req(data(), input$footnote)
          logger::log_info("changing the footnote {default_footnote}", namespace = "teal.modules.general")
          teal.code::eval_code(data(), substitute(
            {
              footnote_grob <- grid::textGrob(footnote, x = 0, hjust = 0, gp = grid::gpar(fontsize = 10, fontface = "italic", col = "gray50"))
              # Arrange the plot and footnote
              .var_to_replace <- gridExtra::arrangeGrob(
                .var_to_replace,
                footnote_grob,
                ncol = 1,
                heights = grid::unit.c(grid::unit(1, "npc") - grid::unit(1, "lines"), grid::unit(1, "lines"))
              )
            },
            env = list(
              footnote = input$footnote,
              .var_to_replace = as.name(.var_to_replace)
            )
          ))
        })
      })
    }
  )
}
caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  print(.var_to_replace)
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute(
        {
          .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
        },
        env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
table_decorator <- function(.color1 = "#f9f9f9", .color2 = "#f0f0f0", .var_to_replace = "table") {
  teal_transform_module(
    label = "Table color",
    ui = function(id) {
      selectInput(
        NS(id, "style"),
        "Table Style",
        choices = c("Default", "Color1", "Color2"),
        selected = "Default"
      )
    },
    server = function(id, data) {
      moduleServer(id, function(input, output, session) {
        logger::log_info("🔵 Table row color called to action!", namespace = "teal.modules.general")
        reactive({
          req(data(), input$style)
          logger::log_info("changing the Table row color '{input$style}'", namespace = "teal.modules.general")
          teal.code::eval_code(data(), substitute(
            {
              .var_to_replace <- switch(style,
                "Color1" = DT::formatStyle(
                  .var_to_replace,
                  columns = attr(.var_to_replace$x, "colnames")[-1],
                  target = "row",
                  backgroundColor = .color1
                ),
                "Color2" = DT::formatStyle(
                  .var_to_replace,
                  columns = attr(.var_to_replace$x, "colnames")[-1],
                  target = "row",
                  backgroundColor = .color2
                ),
                .var_to_replace
              )
            },
            env = list(
              style = input$style,
              .var_to_replace = as.name(.var_to_replace),
              .color1 = .color1,
              .color2 = .color2
            )
          ))
        })
      })
    }
  )
}
head_decorator <- function(default_value = 6, .var_to_replace = "object") {
  teal_transform_module(
    label = "Head",
    ui = function(id) shiny::numericInput(shiny::NS(id, "n"), "Footnote", value = default_value),
    server = make_teal_transform_server(
      substitute(
        {
          .var_to_replace <- utils::head(.var_to_replace, n = n)
        },
        env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
treelis_subtitle_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute(
        {
          .var_to_replace <- update(.var_to_replace, sub = footnote)
        },
        env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute(
        {
          .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
        },
        env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
do_nothing_decorator <- teal_transform_module(server = function(id, data) moduleServer(id, function(input, output, session) data))

# ##########################################
#
#   _             _      _       _
#  | |           | |    | |     | |
#  | |_ ___  __ _| |  __| | __ _| |_ __ _
#  | __/ _ \/ _` | | / _` |/ _` | __/ _` |
#  | ||  __/ (_| | || (_| | (_| | || (_| |
#   \__\___|\__,_|_| \__,_|\__,_|\__\__,_|
#                ______
#               |______|
#
#  teal_data
# #########################################

data <- teal_data(join_keys = default_cdisc_join_keys[c("ADSL", "ADRS")])
data <- within(data, {
  require(nestcolor)
  ADSL <- rADSL
  ADRS <- rADRS
})

# For tm_outliers
fact_vars_adsl <- names(Filter(isTRUE, sapply(data[["ADSL"]], is.factor)))
vars <- choices_selected(variable_choices(data[["ADSL"]], fact_vars_adsl))

init(
  data = data,
  modules = modules(
    # ####################
    #
    #
    #
    #   _ __   ___ __ _
    #  | '_ \ / __/ _` |
    #  | |_) | (_| (_| |
    #  | .__/ \___\__,_|
    #  | |
    #  |_|
    #
    #  pca
    # ###################
    tm_a_pca(
      "PCA",
      dat = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data = data[["ADSL"]], c("BMRKR1", "AGE", "EOSDY")),
          selected = c("BMRKR1", "AGE")
        )
      ),
      decorators = list(
        elbow_plot = caption_decorator("I am a elbow_plot", "elbow_plot"),
        circle_plot = caption_decorator("I am a circle_plot", "circle_plot"),
        biplot = caption_decorator("I am a biplot", "biplot"),
        eigenvector_plot = caption_decorator("I am a eigenvector_plot", "eigenvector_plot")
      )
    ),
    ###############################################################################
    #
    #  _ __ ___  __ _ _ __ ___  ___ ___(_) ___  _ __
    # | '__/ _ \/ _` | '__/ _ \/ __/ __| |/ _ \| '_ \
    # | | |  __/ (_| | | |  __/\__ \__ \ | (_) | | | |
    # |_|  \___|\__, |_|  \___||___/___/_|\___/|_| |_|
    #            __|_|
    #
    # regression
    #
    ###############################################################################
    tm_a_regression(
      label = "Regression",
      response = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = "BMRKR1",
          selected = "BMRKR1",
          multiple = FALSE,
          fixed = TRUE
        )
      ),
      regressor = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variables:",
          choices = variable_choices(data[["ADSL"]], c("AGE", "SEX", "RACE")),
          selected = "AGE",
          multiple = TRUE,
          fixed = FALSE
        )
      ),
      decorators = list(
        plot = caption_decorator("I am a Regression", "plot")
      )
    ),
    # #######################################################
    #
    #                            _       _   _
    #                           (_)     | | (_)
    #    __ _ ___ ___  ___   ___ _  __ _| |_ _  ___  _ __
    #   / _` / __/ __|/ _ \ / __| |/ _` | __| |/ _ \| '_ \
    #  | (_| \__ \__ \ (_) | (__| | (_| | |_| | (_) | | | |
    #   \__,_|___/___/\___/ \___|_|\__,_|\__|_|\___/|_| |_|
    #
    #
    #
    #  association
    # ######################################################
    tm_g_association(
      ref = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(
            data[["ADSL"]],
            c("SEX", "RACE", "COUNTRY", "ARM", "STRATA1", "STRATA2", "ITTFL", "BMRKR2")
          ),
          selected = "RACE"
        )
      ),
      vars = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(
            data[["ADSL"]],
            c("SEX", "RACE", "COUNTRY", "ARM", "STRATA1", "STRATA2", "ITTFL", "BMRKR2")
          ),
          selected = "BMRKR2",
          multiple = TRUE
        )
      ),
      decorators = list(
        plot = plot_grob_decorator("I am a good grob (association)")
      )
    ),
    # ############################################
    #
    #   _     _                 _       _
    #  | |   (_)               (_)     | |
    #  | |__  ___   ____ _ _ __ _  __ _| |_ ___
    #  | '_ \| \ \ / / _` | '__| |/ _` | __/ _ \
    #  | |_) | |\ V / (_| | |  | | (_| | ||  __/
    #  |_.__/|_| \_/ \__,_|_|  |_|\__,_|\__\___|
    #
    #
    #
    #  bivariate
    # ###########################################
    tm_g_bivariate(
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "AGE")
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "SEX")
      ),
      row_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "ARM")
      ),
      col_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "COUNTRY")
      ),
      decorators = list(
        plot = caption_decorator("I am a Bivariate", "plot")
      )
    ),
    ###############################################################################
    #
    #     _ _     _        _ _           _   _
    #  __| (_)___| |_ _ __(_) |__  _   _| |_(_) ___  _ __
    # / _` | / __| __| '__| | '_ \| | | | __| |/ _ \| '_ \
    # | (_| | \__ \ |_| |  | | |_) | |_| | |_| | (_) | | | |
    #  \__,_|_|___/\__|_|  |_|_.__/ \__,_|\__|_|\___/|_| |_|
    #
    #  distribution
    ###############################################################################
    tm_g_distribution(
      dist_var = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1")),
          selected = "BMRKR1",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      strata_var = data_extract_spec(
        dataname = "ADSL",
        filter = filter_spec(
          vars = vars,
          multiple = TRUE
        )
      ),
      group_var = data_extract_spec(
        dataname = "ADSL",
        filter = filter_spec(
          vars = vars,
          multiple = TRUE
        )
      ),
      decorators = list(
        histogram_plot = caption_decorator("I am a Histogram", "histogram_plot"),
        qq_plot = caption_decorator("I am a QQ plot", "qq_plot"),
        summary_table = table_decorator("summary_table", .color1 = "#f0000055"),
        test_table = table_decorator("test_table", .color1 = "#f0000055")
      )
    ),
    # #############################################
    #
    #
    #
    #   _ __ ___  ___ _ __   ___  _ __  ___  ___
    #  | '__/ _ \/ __| '_ \ / _ \| '_ \/ __|/ _ \
    #  | | |  __/\__ \ |_) | (_) | | | \__ \  __/
    #  |_|  \___||___/ .__/ \___/|_| |_|___/\___|
    #                | |
    #                |_|
    #
    #  response
    # ############################################
    tm_g_response(
      label = "Response",
      response = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("BMRKR2", "COUNTRY")))
      ),
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("SEX", "RACE")), selected = "RACE")
      ),
      decorators = list(
        plot = caption_decorator("I am a Response", "plot")
      )
    ),
    #####################################################
    #
    #                 _   _                  _       _
    #                | | | |                | |     | |
    #   ___  ___ __ _| |_| |_ ___ _ __ _ __ | | ___ | |_
    #  / __|/ __/ _` | __| __/ _ \ '__| '_ \| |/ _ \| __|
    #  \__ \ (_| (_| | |_| ||  __/ |  | |_) | | (_) | |_
    #  |___/\___\__,_|\__|\__\___|_|  | .__/|_|\___/ \__|
    #                                 | |
    #                                 |_|
    #
    #  scatterplot
    # ####################################################
    tm_g_scatterplot(
      label = "Scatterplot",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2")))
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2")),
          selected = "BMRKR1"
        )
      ),
      color_by = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2", "RACE", "REGION1")),
          selected = NULL
        )
      ),
      size_by = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1")))
      ),
      row_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("BMRKR2", "RACE", "REGION1")),
          selected = NULL
        )
      ),
      col_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("BMRKR2", "RACE", "REGION1")),
          selected = NULL
        )
      ),
      decorators = list(
        plot = caption_decorator("I am a scatterplot", "plot")
      )
    ),
    # #######################################################################################
    #
    #                 _   _                  _       _                     _        _
    #                | | | |                | |     | |                   | |      (_)
    #   ___  ___ __ _| |_| |_ ___ _ __ _ __ | | ___ | |_   _ __ ___   __ _| |_ _ __ ___  __
    #  / __|/ __/ _` | __| __/ _ \ '__| '_ \| |/ _ \| __| | '_ ` _ \ / _` | __| '__| \ \/ /
    #  \__ \ (_| (_| | |_| ||  __/ |  | |_) | | (_) | |_  | | | | | | (_| | |_| |  | |>  <
    #  |___/\___\__,_|\__|\__\___|_|  | .__/|_|\___/ \__| |_| |_| |_|\__,_|\__|_|  |_/_/\_\
    #                                 | |
    #                                 |_|
    #
    #  scatterplot matrix
    # ######################################################################################
    tm_g_scatterplotmatrix(
      label = "Scatterplot matrix",
      variables = list(
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(data[["ADSL"]]),
            selected = c("AGE", "RACE", "SEX"),
            multiple = TRUE,
            ordered = TRUE
          )
        ),
        data_extract_spec(
          dataname = "ADRS",
          filter = filter_spec(
            label = "Select endpoints:",
            vars = c("PARAMCD", "AVISIT"),
            choices = value_choices(data[["ADRS"]], c("PARAMCD", "AVISIT"), c("PARAM", "AVISIT")),
            selected = "INVET - END OF INDUCTION",
            multiple = TRUE
          ),
          select = select_spec(
            choices = variable_choices(data[["ADRS"]]),
            selected = c("AGE", "AVAL", "ADY"),
            multiple = TRUE,
            ordered = TRUE
          )
        )
      ),
      decorators = list(
        plot = treelis_subtitle_decorator("I am a Scatterplot matrix", "plot")
      )
    ),
    # ##############################################################
    #
    #             _         _                    _       _
    #            (_)       (_)                  | |     | |
    #   _ __ ___  _ ___ ___ _ _ __   __ _     __| | __ _| |_ __ _
    #  | '_ ` _ \| / __/ __| | '_ \ / _` |   / _` |/ _` | __/ _` |
    #  | | | | | | \__ \__ \ | | | | (_| |  | (_| | (_| | || (_| |
    #  |_| |_| |_|_|___/___/_|_| |_|\__, |   \__,_|\__,_|\__\__,_|
    #                                __/ |_____
    #                               |___/______|
    #
    #  missing_data
    # #############################################################
    tm_missing_data(
      label = "Missing data",
      decorators = list(
        summary_plot = plot_grob_decorator("A", "summary_plot"),
        combination_plot = plot_grob_decorator("B", "combination_plot"),
        summary_table = table_decorator("table", .color1 = "#f0000055"),
        by_subject_plot = caption_decorator("I am a by_subject_plot", "by_subject_plot")
      )
    ),
    ######################################
    #
    #               _   _ _
    #              | | | (_)
    #    ___  _   _| |_| |_  ___ _ __ ___
    #   / _ \| | | | __| | |/ _ \ '__/ __|
    #  | (_) | |_| | |_| | |  __/ |  \__ \
    #   \___/ \__,_|\__|_|_|\___|_|  |___/
    #
    #
    #
    #  outliers
    # #####################################
    tm_outliers(
      outlier_var = list(
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            label = "Select variable:",
            choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1")),
            selected = "AGE",
            multiple = FALSE,
            fixed = FALSE
          )
        )
      ),
      categorical_var = list(
        data_extract_spec(
          dataname = "ADSL",
          filter = filter_spec(
            vars = vars,
            choices = value_choices(data[["ADSL"]], vars$selected),
            selected = value_choices(data[["ADSL"]], vars$selected),
            multiple = TRUE
          )
        )
      ),
      decorators = list(
        box_plot = caption_decorator("I am a good decorator", "box_plot"),
        density_plot = caption_decorator("I am a good decorator", "density_plot"),
        cumulative_plot = caption_decorator("I am a good decorator", "cumulative_plot"),
        table = table_decorator("#FFA500", "#800080")
      )
    ),
    # ########################################################
    #
    #                                 _        _     _
    #                                | |      | |   | |
    #    ___ _ __ ___  ___ ___ ______| |_ __ _| |__ | | ___
    #   / __| '__/ _ \/ __/ __|______| __/ _` | '_ \| |/ _ \
    #  | (__| | | (_) \__ \__ \      | || (_| | |_) | |  __/
    #   \___|_|  \___/|___/___/       \__\__,_|_.__/|_|\___|
    #
    #
    #
    #  cross-table
    # #######################################################
    tm_t_crosstable(
      label = "Cross Table",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], subset = function(data) {
            idx <- !vapply(data, inherits, logical(1), c("Date", "POSIXct", "POSIXlt"))
            return(names(data)[idx])
          }),
          selected = "COUNTRY",
          multiple = TRUE,
          ordered = TRUE
        )
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], subset = function(data) {
            idx <- vapply(data, is.factor, logical(1))
            return(names(data)[idx])
          }),
          selected = "SEX"
        )
      ),
      decorators = list(
        table = insert_rrow_decorator("I am a good new row")
      )
    )
  )
) |> shiny::runApp()

@vedhav vedhav added the core label Feb 14, 2025
Copy link
Contributor

github-actions bot commented Feb 14, 2025

badge

Code Coverage Summary

Filename                      Stmts    Miss  Cover    Missing
--------------------------  -------  ------  -------  --------------------------------------
R/tm_a_pca.R                    885     885  0.00%    136-1155
R/tm_a_regression.R             773     773  0.00%    175-1052
R/tm_data_table.R               207     207  0.00%    100-356
R/tm_file_viewer.R              173     173  0.00%    47-255
R/tm_front_page.R               144     133  7.64%    77-247
R/tm_g_association.R            341     341  0.00%    156-572
R/tm_g_bivariate.R              686     422  38.48%   328-810, 851, 962, 979, 997, 1008-1030
R/tm_g_distribution.R          1112    1112  0.00%    153-1410
R/tm_g_response.R               365     365  0.00%    174-617
R/tm_g_scatterplot.R            730     730  0.00%    257-1091
R/tm_g_scatterplotmatrix.R      295     276  6.44%    195-527, 588, 602
R/tm_missing_data.R            1126    1126  0.00%    121-1424
R/tm_outliers.R                1035    1035  0.00%    160-1346
R/tm_t_crosstable.R             260     260  0.00%    160-469
R/tm_variable_browser.R         832     827  0.60%    89-1078, 1116-1299
R/utils.R                       151     135  10.60%   89-274, 304-340, 352-361, 366, 380-399
R/zzz.R                           2       2  0.00%    2-3
TOTAL                          9117    8802  3.46%

Diff against main

Filename                      Stmts    Miss  Cover
--------------------------  -------  ------  --------
R/tm_a_pca.R                     -1      -1  +100.00%
R/tm_a_regression.R              -1      -1  +100.00%
R/tm_g_association.R             -1      -1  +100.00%
R/tm_g_bivariate.R               -1       0  -0.09%
R/tm_g_distribution.R            -1      -1  +100.00%
R/tm_g_response.R                -1      -1  +100.00%
R/tm_g_scatterplot.R             -1      -1  +100.00%
R/tm_g_scatterplotmatrix.R       -1      -1  +0.02%
R/tm_missing_data.R              -1      -1  +100.00%
R/tm_outliers.R                  -1      -1  +100.00%
R/tm_t_crosstable.R              -1      -1  +100.00%
R/utils.R                       -15      -1  -7.48%
TOTAL                           -26     -11  -0.15%

Results for commit: 2183ecd

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

Copy link
Contributor

Unit Tests Summary

  1 files   22 suites   13m 17s ⏱️
144 tests 144 ✅ 0 💤 0 ❌
475 runs  475 ✅ 0 💤 0 ❌

Results for commit 40d8f5c.

Copy link
Contributor

github-actions bot commented Feb 14, 2025

Unit Tests Summary

  1 files   22 suites   12m 47s ⏱️
144 tests 107 ✅ 37 💤 0 ❌
474 runs  437 ✅ 37 💤 0 ❌

Results for commit 2183ecd.

♻️ This comment has been updated with latest results.

Copy link
Contributor

github-actions bot commented Feb 14, 2025

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
shinytest2-tm_a_pca 💚 $116.36$ $-1.53$ $0$ $0$ $0$ $0$
shinytest2-tm_outliers 💚 $110.00$ $-1.79$ $0$ $0$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
examples 💀 $0.01$ $-0.01$ example_normalize_decorators.Rd

Results for commit 1080cca

♻️ This comment has been updated with latest results.

@m7pr
Copy link
Contributor

m7pr commented Feb 17, 2025

Tested with

Code
pkgload::load_all("../teal")
pkgload::load_all(".")

# ######################################################
#
#   _____                           _
#  |  __ \                         | |
#  | |  | | ___  ___ ___  _ __ __ _| |_ ___  _ __ ___
#  | |  | |/ _ \/ __/ _ \| '__/ _` | __/ _ \| '__/ __|
#  | |__| |  __/ (_| (_) | | | (_| | || (_) | |  \__ \
#  |_____/ \___|\___\___/|_|  \__,_|\__\___/|_|  |___/
#
#
#
#  Decorators
# #####################################################

plot_grob_decorator <- function(default_footnote = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption (grob)",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_footnote),
    server = function(id, data) {
      moduleServer(id, function(input, output, session) {
        logger::log_info("🟠 plot_grob with default: {default_footnote}!", namespace = "teal.modules.general")
        reactive({
          req(data(), input$footnote)
          logger::log_info("changing the footnote {default_footnote}", namespace = "teal.modules.general")
          teal.code::eval_code(data(), substitute(
            {
              footnote_grob <- grid::textGrob(footnote, x = 0, hjust = 0, gp = grid::gpar(fontsize = 10, fontface = "italic", col = "gray50"))
              # Arrange the plot and footnote
              .var_to_replace <- gridExtra::arrangeGrob(
                .var_to_replace,
                footnote_grob,
                ncol = 1,
                heights = grid::unit.c(grid::unit(1, "npc") - grid::unit(1, "lines"), grid::unit(1, "lines"))
              )
            },
            env = list(
              footnote = input$footnote,
              .var_to_replace = as.name(.var_to_replace)
            )))
        })
      })
    }
  )
}
caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
table_decorator <- function(.color1 = "#f9f9f9", .color2 = "#f0f0f0", .var_to_replace = "table") {
  teal_transform_module(
    label = "Table color",
    ui = function(id) {
      selectInput(
        NS(id, "style"),
        "Table Style",
        choices = c("Default", "Color1", "Color2"),
        selected = "Default"
      )
    },
    server = function(id, data) {
      moduleServer(id, function(input, output, session) {
        logger::log_info("🔵 Table row color called to action!", namespace = "teal.modules.general")
        reactive({
          req(data(), input$style)
          logger::log_info("changing the Table row color '{input$style}'", namespace = "teal.modules.general")
          teal.code::eval_code(data(), substitute({
            .var_to_replace <- switch(
              style,
              "Color1" = DT::formatStyle(
                .var_to_replace,
                columns = attr(.var_to_replace$x, "colnames")[-1],
                target = "row",
                backgroundColor = .color1
              ),
              "Color2" = DT::formatStyle(
                .var_to_replace,
                columns = attr(.var_to_replace$x, "colnames")[-1],
                target = "row",
                backgroundColor = .color2
              ),
              .var_to_replace
            )
          }, env = list(
            style = input$style,
            .var_to_replace = as.name(.var_to_replace),
            .color1 = .color1,
            .color2 = .color2
          )))
        })
      })
    }
  )
}
head_decorator <- function(default_value = 6, .var_to_replace = "object") {
  teal_transform_module(
    label = "Head",
    ui = function(id) shiny::numericInput(shiny::NS(id, "n"), "Footnote", value = default_value),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- utils::head(.var_to_replace, n = n)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
treelis_subtitle_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- update(.var_to_replace, sub = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
do_nothing_decorator <- teal_transform_module(server = function(id, data) moduleServer(id, function(input, output, session) data))

# ##########################################
#
#   _             _      _       _
#  | |           | |    | |     | |
#  | |_ ___  __ _| |  __| | __ _| |_ __ _
#  | __/ _ \/ _` | | / _` |/ _` | __/ _` |
#  | ||  __/ (_| | || (_| | (_| | || (_| |
#   \__\___|\__,_|_| \__,_|\__,_|\__\__,_|
#                ______
#               |______|
#
#  teal_data
# #########################################

data <- teal_data(join_keys = default_cdisc_join_keys[c("ADSL", "ADRS")])
data <- within(data, {
  require(nestcolor)
  ADSL <- rADSL
  ADRS <- rADRS
})

# For tm_outliers
fact_vars_adsl <- names(Filter(isTRUE, sapply(data[["ADSL"]], is.factor)))
vars <- choices_selected(variable_choices(data[["ADSL"]], fact_vars_adsl))

init(
  data = data,
  modules = modules(
    ######################################
    #
    #               _   _ _
    #              | | | (_)
    #    ___  _   _| |_| |_  ___ _ __ ___
    #   / _ \| | | | __| | |/ _ \ '__/ __|
    #  | (_) | |_| | |_| | |  __/ |  \__ \
    #   \___/ \__,_|\__|_|_|\___|_|  |___/
    #
    #
    #
    #  outliers
    # #####################################
    tm_outliers(
      outlier_var = list(
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            label = "Select variable:",
            choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1")),
            selected = "AGE",
            multiple = FALSE,
            fixed = FALSE
          )
        )
      ),
      categorical_var = list(
        data_extract_spec(
          dataname = "ADSL",
          filter = filter_spec(
            vars = vars,
            choices = value_choices(data[["ADSL"]], vars$selected),
            selected = value_choices(data[["ADSL"]], vars$selected),
            multiple = TRUE
          )
        )
      ),
      decorators = list(
        box_plot = caption_decorator("I am a good decorator", "box_plot"),
        density_plot = caption_decorator("I am a good decorator", "density_plot"),
        cumulative_plot = caption_decorator("I am a good decorator", "cumulative_plot"),
        table = table_decorator("#FFA500", "#800080")
      )
    ),
    # #######################################################
    #
    #                            _       _   _
    #                           (_)     | | (_)
    #    __ _ ___ ___  ___   ___ _  __ _| |_ _  ___  _ __
    #   / _` / __/ __|/ _ \ / __| |/ _` | __| |/ _ \| '_ \
    #  | (_| \__ \__ \ (_) | (__| | (_| | |_| | (_) | | | |
    #   \__,_|___/___/\___/ \___|_|\__,_|\__|_|\___/|_| |_|
    #
    #
    #
    #  association
    # ######################################################
    tm_g_association(
      ref = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(
            data[["ADSL"]],
            c("SEX", "RACE", "COUNTRY", "ARM", "STRATA1", "STRATA2", "ITTFL", "BMRKR2")
          ),
          selected = "RACE"
        )
      ),
      vars = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(
            data[["ADSL"]],
            c("SEX", "RACE", "COUNTRY", "ARM", "STRATA1", "STRATA2", "ITTFL", "BMRKR2")
          ),
          selected = "BMRKR2",
          multiple = TRUE
        )
      ),
      decorators = list(plot = plot_grob_decorator("I am a good grob (association)"))
    ),
    # ########################################################
    #
    #                                 _        _     _
    #                                | |      | |   | |
    #    ___ _ __ ___  ___ ___ ______| |_ __ _| |__ | | ___
    #   / __| '__/ _ \/ __/ __|______| __/ _` | '_ \| |/ _ \
    #  | (__| | | (_) \__ \__ \      | || (_| | |_) | |  __/
    #   \___|_|  \___/|___/___/       \__\__,_|_.__/|_|\___|
    #
    #
    #
    #  cross-table
    # #######################################################
    tm_t_crosstable(
      label = "Cross Table",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], subset = function(data) {
            idx <- !vapply(data, inherits, logical(1), c("Date", "POSIXct", "POSIXlt"))
            return(names(data)[idx])
          }),
          selected = "COUNTRY",
          multiple = TRUE,
          ordered = TRUE
        )
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], subset = function(data) {
            idx <- vapply(data, is.factor, logical(1))
            return(names(data)[idx])
          }),
          selected = "SEX"
        )
      ),
      decorators = list(table = insert_rrow_decorator("I am a good new row"))
    ),
    # #######################################################################################
    #
    #                 _   _                  _       _                     _        _
    #                | | | |                | |     | |                   | |      (_)
    #   ___  ___ __ _| |_| |_ ___ _ __ _ __ | | ___ | |_   _ __ ___   __ _| |_ _ __ ___  __
    #  / __|/ __/ _` | __| __/ _ \ '__| '_ \| |/ _ \| __| | '_ ` _ \ / _` | __| '__| \ \/ /
    #  \__ \ (_| (_| | |_| ||  __/ |  | |_) | | (_) | |_  | | | | | | (_| | |_| |  | |>  <
    #  |___/\___\__,_|\__|\__\___|_|  | .__/|_|\___/ \__| |_| |_| |_|\__,_|\__|_|  |_/_/\_\
    #                                 | |
    #                                 |_|
    #
    #  scatterplot matrix
    # ######################################################################################
    tm_g_scatterplotmatrix(
      label = "Scatterplot matrix",
      variables = list(
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(data[["ADSL"]]),
            selected = c("AGE", "RACE", "SEX"),
            multiple = TRUE,
            ordered = TRUE
          )
        ),
        data_extract_spec(
          dataname = "ADRS",
          filter = filter_spec(
            label = "Select endpoints:",
            vars = c("PARAMCD", "AVISIT"),
            choices = value_choices(data[["ADRS"]], c("PARAMCD", "AVISIT"), c("PARAM", "AVISIT")),
            selected = "INVET - END OF INDUCTION",
            multiple = TRUE
          ),
          select = select_spec(
            choices = variable_choices(data[["ADRS"]]),
            selected = c("AGE", "AVAL", "ADY"),
            multiple = TRUE,
            ordered = TRUE
          )
        )
      ),
      decorators = list(plot = treelis_subtitle_decorator("I am a Scatterplot matrix", "plot"))
    ),
    # #############################################
    #
    #
    #
    #   _ __ ___  ___ _ __   ___  _ __  ___  ___
    #  | '__/ _ \/ __| '_ \ / _ \| '_ \/ __|/ _ \
    #  | | |  __/\__ \ |_) | (_) | | | \__ \  __/
    #  |_|  \___||___/ .__/ \___/|_| |_|___/\___|
    #                | |
    #                |_|
    #
    #  response
    # ############################################
    tm_g_response(
      label = "Response",
      response = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("BMRKR2", "COUNTRY")))
      ),
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("SEX", "RACE")), selected = "RACE")
      ),
      decorators = list(plot = caption_decorator("I am a Response", "plot"))
    ),
    # ############################################
    #
    #   _     _                 _       _
    #  | |   (_)               (_)     | |
    #  | |__  ___   ____ _ _ __ _  __ _| |_ ___
    #  | '_ \| \ \ / / _` | '__| |/ _` | __/ _ \
    #  | |_) | |\ V / (_| | |  | | (_| | ||  __/
    #  |_.__/|_| \_/ \__,_|_|  |_|\__,_|\__\___|
    #
    #
    #
    #  bivariate
    # ###########################################
    tm_g_bivariate(
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "AGE")
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "SEX")
      ),
      row_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "ARM")
      ),
      col_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]]), selected = "COUNTRY")
      ),
      decorators = list(plot = caption_decorator("I am a Bivariate", "plot"))
    ),
    # ####################
    #
    #
    #
    #   _ __   ___ __ _
    #  | '_ \ / __/ _` |
    #  | |_) | (_| (_| |
    #  | .__/ \___\__,_|
    #  | |
    #  |_|
    #
    #  pca
    # ###################
    tm_a_pca(
      "PCA",
      dat = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data = data[["ADSL"]], c("BMRKR1", "AGE", "EOSDY")),
          selected = c("BMRKR1", "AGE")
        )
      ),
      decorators = list(elbow_plot = caption_decorator("I am a PCA", "elbow_plot"))
    ),
    #####################################################
    #
    #                 _   _                  _       _
    #                | | | |                | |     | |
    #   ___  ___ __ _| |_| |_ ___ _ __ _ __ | | ___ | |_
    #  / __|/ __/ _` | __| __/ _ \ '__| '_ \| |/ _ \| __|
    #  \__ \ (_| (_| | |_| ||  __/ |  | |_) | | (_) | |_
    #  |___/\___\__,_|\__|\__\___|_|  | .__/|_|\___/ \__|
    #                                 | |
    #                                 |_|
    #
    #  scatterplot
    # ####################################################
    tm_g_scatterplot(
      label = "Scatterplot",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2")))
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2")),
          selected = "BMRKR1"
        )
      ),
      color_by = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2", "RACE", "REGION1")),
          selected = NULL
        )
      ),
      size_by = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1")))
      ),
      row_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("BMRKR2", "RACE", "REGION1")),
          selected = NULL
        )
      ),
      col_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("BMRKR2", "RACE", "REGION1")),
          selected = NULL
        )
      ),
      decorators = list(plot = caption_decorator("I am a scatterplot", "plot"))
    ),
    # ##############################################################
    #
    #             _         _                    _       _
    #            (_)       (_)                  | |     | |
    #   _ __ ___  _ ___ ___ _ _ __   __ _     __| | __ _| |_ __ _
    #  | '_ ` _ \| / __/ __| | '_ \ / _` |   / _` |/ _` | __/ _` |
    #  | | | | | | \__ \__ \ | | | | (_| |  | (_| | (_| | || (_| |
    #  |_| |_| |_|_|___/___/_|_| |_|\__, |   \__,_|\__,_|\__\__,_|
    #                                __/ |_____
    #                               |___/______|
    #
    #  missing_data
    # #############################################################
    tm_missing_data(
      label = "Missing data",
      decorators = list(
        summary_plot = plot_grob_decorator("A", "summary_plot"),
        combination_plot = plot_grob_decorator("B", "combination_plot"),
#        table = insert_rrow_decorator("I am a good new row"),                       ### SOMETHING IS OFF IN HERE
        by_subject_plot = caption_decorator("Caption XX", "by_subject_plot")
      )
    ),
    example_module(decorators = list(object = head_decorator(6)))
  )
) |> shiny::runApp()

@m7pr
Copy link
Contributor

m7pr commented Feb 17, 2025

TODO:

Example doesn't cover

  • tm_a_regression
  • tm_g_distribution
  • tm_outliers

Code

  • fix table in tm_missing_data as you see fit
  • double check that documentation do not use decoraotrs = (name = list()
  • double check that name of the module is the same as name of the file

@vedhav
Copy link
Contributor Author

vedhav commented Feb 18, 2025

Current status of the decorators: Works fine (✅) Have issues (❌)

  • tm_a_pca - elbow_plot (✅), circle_plot (✅), biplot (✅), eigenvector_plot (❌)
  • tm_a_regression - plot (✅)
  • tm_g_association - plot (✅)
  • tm_g_bivariate - plot (✅)
  • tm_g_distribution - histogram_plot (✅), qq_plot (✅), summary_table (❌), test_table (❌)
  • tm_g_response - plot (✅)
  • tm_g_scatterplot - plot (✅)
  • tm_g_scatterplotmatrix - plot (✅)
  • tm_missing_data - summary_plot (✅), combination_plot (✅), by_subject_plot (✅), table (❌)
  • tm_outliers - box_plot (✅), density_plot (✅), cumulative_plot (✅), table (❌)
  • tm_t_crosstable - table (✅)

Copy link
Contributor

@m7pr m7pr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Vedha for the hard work on simplification of the decorators in here.
The examples work fine.
I think we can reuse those in the vignette.

For the modules that are failing in some objects, I would recommend to create separate issues. Would you be able to create those?

@vedhav
Copy link
Contributor Author

vedhav commented Feb 18, 2025

Thanks Marcin, Sure. Here are the issues for the failing modules: #848, #849, #850, #851

@vedhav vedhav merged commit 24d91dd into main Feb 18, 2025
29 checks passed
@vedhav vedhav deleted the 845-remove-default-decoration@main branch February 18, 2025 08:39
@github-actions github-actions bot locked and limited conversation to collaborators Feb 18, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Question]: Do we need the default in the decorators?
2 participants