Skip to content

Commit

Permalink
selecting updates (#1611)
Browse files Browse the repository at this point in the history
  • Loading branch information
ddsjoberg authored Mar 10, 2024
1 parent c2358b2 commit 59da845
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 56 deletions.
10 changes: 0 additions & 10 deletions R/assign_summary_type.R
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,3 @@ assign_summary_type <- function(data, variables, value, type = NULL, cat_thresho
NULL
}

.add_summary_type_as_attr <- function(data, type) {
type <- type[names(type) %in% names(data)]
type_names <- names(type)

for (i in seq_along(type)) {
attr(data[[type_names[i]]], "gtsummary.type") <- type[[i]]
}

data
}
66 changes: 62 additions & 4 deletions R/select_helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,27 @@ NULL
all_continuous <- function(continuous2 = TRUE) {
types <- if (continuous2) c("continuous", "continuous2") else "continuous"

where(function(x) isTRUE(attr(x, "gtsummary.type") %in% types))
where(function(x) isTRUE(attr(x, "gtsummary.summary_type") %in% types))
}

#' @rdname select_helpers
#' @export
all_continuous2 <- function() {
where(function(x) isTRUE(attr(x, "gtsummary.type") %in% "continuous2"))
where(function(x) isTRUE(attr(x, "gtsummary.summary_type") %in% "continuous2"))
}

#' @rdname select_helpers
#' @export
all_categorical <- function(dichotomous = TRUE) {
types <- if (dichotomous) c("categorical", "dichotomous") else "categorical"

where(function(x) isTRUE(attr(x, "gtsummary.type") %in% types))
where(function(x) isTRUE(attr(x, "gtsummary.summary_type") %in% types))
}

#' @rdname select_helpers
#' @export
all_dichotomous <- function() {
where(function(x) isTRUE(attr(x, "gtsummary.type") %in% "dichotomous"))
where(function(x) isTRUE(attr(x, "gtsummary.summary_type") %in% "dichotomous"))
}

# #' @rdname select_helpers
Expand Down Expand Up @@ -101,6 +101,7 @@ all_stat_cols <- function(stat_0 = TRUE) {
}
}


# #' @rdname select_helpers
# #' @export
# all_interaction <- broom.helpers::all_interaction
Expand All @@ -112,3 +113,60 @@ all_stat_cols <- function(stat_0 = TRUE) {
# #' @rdname select_helpers
# #' @export
# all_contrasts <- broom.helpers::all_contrasts



#' Table Body Select Prep
#'
#' This function uses the information in `.$table_body` and adds them
#' as attributes to `data` (if passed). Once they've been assigned as
#' proper gtsummary attributes, gtsummary selectors like `all_continuous()`
#' will work properly.
#'
#' @param table_body a data frame from `.$table_body`
#' @param data an optional data frame the attributes will be added to
#'
#' @return a data frame
#' @keywords internal
select_prep <- function(table_body, data = NULL) {
# if data not passed, use table_body to construct one
if (is.null(data)) {
data <- dplyr::tibble(!!!rep_named(table_body$variable, character(0L)))
}

# only keeping rows that have corresponding column names in data
table_body <- table_body |> dplyr::filter(.data$variable %in% names(data))

# if table_body passed, add columns as attr to data
if (!is.null(table_body)) {
attr_cols <- intersect(names(table_body), c("summary_type", "test_name"))
for (v in attr_cols) {
df_attr <- table_body[c("variable", v)] |> unique() |> tidyr::drop_na()
for (i in seq_len(nrow(df_attr))) {
attr(data[[df_attr$variable[i]]], paste0("gtsummary.", v)) <- df_attr[[v]][i]
}
}
}

data
}


# converts a named list to a table_body format.
# the result of this fn will often be passed to `select_prep()`
#' Convert Named List to Table Body
#'
#' Many arguments in 'gtsummary' accept named lists. This function converts
#' a named list to the `.$table_body` format expected in `select_prep()`
#'
#' @param x named list
#' @param colname string of column name to assign. Default is `caller_arg(x)`
#'
#' @return `.$table_body` data frame
#' @keywords internal
#' @examples
#' type <- list(age = "continuous", response = "dichotomous")
#' gtsummary:::.list2tb(type, "summary_type")
.list2tb <- function(x, colname = caller_arg(x)) {
enframe(unlist(x), "variable", colname)
}
91 changes: 49 additions & 42 deletions R/tbl_summary.R
Original file line number Diff line number Diff line change
Expand Up @@ -193,58 +193,61 @@ tbl_summary <- function(data,
# first set default types, so selectors like `all_continuous()` can be used
# to recast the summary type, e.g. make all continuous type "continuous2"
default_types <- assign_summary_type(data, include, value)
data <- .add_summary_type_as_attr(data, default_types)
# process the user-passed type argument
cards::process_formula_selectors(data = data[include], type = type)
cards::process_formula_selectors(
data = select_prep(.list2tb(default_types, "summary_type"), data[include]),
type = type
)
# fill in any types not specified by user
type <- utils::modifyList(default_types, type)
} else {
type <- assign_summary_type(data, include, value)
}
data <- .add_summary_type_as_attr(data, type)

value <- .assign_default_values(data[include], value, type)
value <-
select_prep(.list2tb(type, "summary_type"), data[include]) |>
.assign_default_values(value, type)

# evaluate the remaining list-formula arguments ------------------------------
# processed arguments are saved into this env
cards::process_formula_selectors(
data = data[include],
statistic =
.ifelse1(
missing(statistic),
get_theme_element("TODO:fill-this-in", default = statistic),
statistic
),
include_env = TRUE
)
select_prep(.list2tb(type, "summary_type"), data[include]) |>
cards::process_formula_selectors(
statistic =
.ifelse1(
missing(statistic),
get_theme_element("TODO:fill-this-in", default = statistic),
statistic
),
include_env = TRUE
)

# add the calling env to the statistics
statistic <- .add_env_to_list_elements(statistic, env = caller_env())

cards::process_formula_selectors(
data = data[include],
label = label,
sort =
.ifelse1(
missing(sort),
get_theme_element("TODO:fill-this-in", default = sort),
sort
)
)
select_prep(.list2tb(type, "summary_type"), data[include]) |>
cards::process_formula_selectors(
label = label,
sort =
.ifelse1(
missing(sort),
get_theme_element("TODO:fill-this-in", default = sort),
sort
)
)

cards::process_formula_selectors(
data = data[include],
digits =
.ifelse1(
is_empty(digits),
get_theme_element("TODO:fill-this-in", default = assign_summary_digits(data, statistic, type)),
digits
)
)
select_prep(.list2tb(type, "summary_type"), data[include]) |>
cards::process_formula_selectors(
digits =
.ifelse1(
is_empty(digits),
get_theme_element("TODO:fill-this-in", default = assign_summary_digits(data, statistic, type)),
digits
)
)

# fill in unspecified variables
cards::fill_formula_selectors(
data[include],
select_prep(.list2tb(type, "summary_type"), data[include]),
statistic =
get_theme_element("TODO:fill-this-in", default = eval(formals(gtsummary::tbl_summary)[["statistic"]])),
sort =
Expand All @@ -256,7 +259,9 @@ tbl_summary <- function(data,
# fill each element of digits argument
# TODO: this needs to be updated to account for the scenario where there is a template override that may not fill in all the values
if (!missing(digits)) {
digits <- assign_summary_digits(data[include], statistic, type, digits = digits)
digits <-
select_prep(.list2tb(type, "summary_type"), data[include]) |>
assign_summary_digits(statistic, type, digits = digits)
}

# check inputs ---------------------------------------------------------------
Expand All @@ -271,7 +276,7 @@ tbl_summary <- function(data,
)

# sort requested columns by frequency
data <- .sort_data_infreq(data, sort, type)
data <- .sort_data_infreq(data, sort)

# save processed function inputs ---------------------------------------------
tbl_summary_inputs <- as.list(environment())
Expand All @@ -297,7 +302,7 @@ tbl_summary <- function(data,
},
# tabulate categorical summaries
cards::ard_categorical(
data,
select_prep(.list2tb(type, "summary_type"), data),
by = all_of(by),
variables = all_categorical(FALSE),
fmt_fn = digits,
Expand All @@ -306,7 +311,7 @@ tbl_summary <- function(data,
),
# tabulate dichotomous summaries
cards::ard_dichotomous(
data,
select_prep(.list2tb(type, "summary_type"), data),
by = all_of(by),
variables = all_dichotomous(),
fmt_fn = digits,
Expand All @@ -316,11 +321,13 @@ tbl_summary <- function(data,
),
# calculate categorical summaries
cards::ard_continuous(
data,
select_prep(.list2tb(type, "summary_type"), data),
by = all_of(by),
variables = all_continuous(),
statistic =
.continuous_statistics_chr_to_fun(statistic[select(data, all_continuous()) |> names()]),
.continuous_statistics_chr_to_fun(
statistic[select(select_prep(.list2tb(type, "summary_type"), data), all_continuous()) |> names()]
),
fmt_fn = digits,
stat_label = ~ default_stat_labels()
)
Expand Down Expand Up @@ -409,7 +416,7 @@ tbl_summary <- function(data,
)
}

.sort_data_infreq <- function(data, sort, type) {
.sort_data_infreq <- function(data, sort) {
# if no frequency sorts requested, just return data frame
if (every(sort, function(x) x %in% "alphanumeric")) {
return(data)
Expand All @@ -421,7 +428,7 @@ tbl_summary <- function(data,
}
}

.add_summary_type_as_attr(data, type)
data
}

.construct_summary_footnote <- function(card, include, statistic, type) {
Expand Down
25 changes: 25 additions & 0 deletions man/dot-list2tb.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions man/select_prep.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 59da845

Please sign in to comment.