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

selecting updates #1611

Merged
merged 1 commit into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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.

Loading