Skip to content

Commit

Permalink
Merge pull request #1376 from rstudio/use-empty-table
Browse files Browse the repository at this point in the history
Use empty table as starting point for a gt table
  • Loading branch information
rich-iannone authored Jul 18, 2023
2 parents 4ef570e + f5c9207 commit d1e11e9
Show file tree
Hide file tree
Showing 12 changed files with 908 additions and 8 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ tests/testthat/test-cols_merge.R
tests/testthat/test-cols_width_rtf.R
tests/testthat/test-cols_width.R
tests/testthat/test-data_color.R
tests/testthat/test-empty_tbl.R
tests/testthat/test-escaping.R
tests/testthat/test-extract_cells.R
tests/testthat/test-fmt_auto.R
Expand Down
6 changes: 6 additions & 0 deletions R/build_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ build_data <- function(data, context) {
# Perform input object validation
stop_if_not_gt_tbl(data = data)

# For an empty table, ensure that some basic
# messaging is in place
if (is_gt_tbl_empty(data = data)) {
data <- adjust_gt_tbl_empty(data = data)
}

# Create `body` with rendered values; move
# input data cells to `body` that didn't have
# any rendering applied during `render_formats()`;
Expand Down
18 changes: 13 additions & 5 deletions R/dt_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ dt_data_init <- function(
rownames_to_column = NA
) {

# If the data table has rows but no columns, remove all of the rows
if (ncol(data_tbl) == 0 && nrow(data_tbl) > 0) {
data_tbl <- data_tbl[0, ]
}

if (!is.na(rownames_to_column)) {

data_rownames <- rownames(data_tbl)
Expand Down Expand Up @@ -166,8 +171,8 @@ dt_data_add_rows <- function(
if (is.null(stub_df_add[i, ][["group_label"]][[1]])) {

if (
stub_df_add[i, ][["group_id"]] %in%
stub_df_group_lookup[["group_id"]]
length(stub_df_group_lookup[["group_id"]]) > 0 &&
stub_df_add[i, ][["group_id"]] %in% stub_df_group_lookup[["group_id"]]
) {

# This case is where a `group_id` in the added rows already exists
Expand All @@ -180,9 +185,12 @@ dt_data_add_rows <- function(

} else {

# Migrate the text from a new group ID to a group label
stub_df_add[i, ][["group_label"]] <-
as.list(stub_df_add[i, ][["group_id"]])
if (!is.na(stub_df_add[i, ][["group_id"]])) {

# Migrate the text from a new group ID to a group label
stub_df_add[i, ][["group_label"]] <-
as.list(stub_df_add[i, ][["group_id"]])
}
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions R/dt_stub_df.R
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ dt_stub_df_init <- function(
built_group_label = rep(NA_character_, nrow(data_tbl))
)

# Handle case where table has no columns
if (ncol(data_tbl) < 1) {

data <- dt_stub_df_set(data = data, stub_df = stub_df)
return(data)
}

#
# Handle column of data specified as the `rowname_col`
#
Expand Down
111 changes: 110 additions & 1 deletion R/modify_columns.R
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,114 @@ cols_add <- function(
data_tbl <- dt_data_get(data = .data)
data_tbl_columns <- colnames(data_tbl)

#
# Special case where data table has no columns (and perhaps no rows); here,
# we allow for one or more columns to be added with an arbitrary number of
# rows, however, the number of rows should be consistent across the supplied
# columns
#

if (nrow(data_tbl) < 1 && ncol(data_tbl) < 1) {

# Generate boxhead rows that correspond to the new columns
updated_boxh_df <-
dt_boxhead_get(data = gt(dplyr::as_tibble(as.data.frame(list(...)))))

# Modify the internal boxhead data frame
.data <- dt_boxhead_set(data = .data, boxh = updated_boxh_df)

# Manually add rows to the empty data table (if there are indeed some rows)
if (nrow(dplyr::as_tibble(as.data.frame(list(...)))) > 0) {

.data <-
dt_data_add_rows(
data = .data,
row_data_list = list(...),
before = NULL,
after = NULL
)
}

# Update the internal data table object
.data <-
dt_data_set(
data = .data,
data_tbl = dplyr::as_tibble(as.data.frame(list(...)))
)

return(.data)
}

#
# Special case where data table has some columns (but no rows); here, we allow
# for one or more columns to be added with an arbitrary number of rows,
# however, the number of rows should be consistent across the supplied columns
#

if (nrow(data_tbl) < 1 && ncol(data_tbl) > 0) {

# Generate boxhead rows that correspond to the new columns
updated_boxh_df <-
dt_boxhead_get(data = gt(dplyr::as_tibble(as.data.frame(list(...)))))

updated_boxh_df <-
dplyr::bind_rows(
dt_boxhead_get(data = .data),
updated_boxh_df[
!(updated_boxh_df$var %in% dt_boxhead_get(data = .data)[["var"]]),
]
)

# Modify the internal boxhead data frame
.data <- dt_boxhead_set(data = .data, boxh = updated_boxh_df)

# Determine whether the supplied set of values is zero length
row_data_list_empty <-
all(
vapply(
seq_along(list(...)),
FUN.VALUE = logical(1),
USE.NAMES = FALSE,
FUN = function(x) {
length(list(...)[[x]]) < 1
}
)
)

if (row_data_list_empty) {

# Bind the zero-row tables together
updated_data_tbl <-
dplyr::bind_cols(
dt_data_get(data = .data),
dplyr::as_tibble(as.data.frame(list(...)))
)

# Update the internal data table object
.data <-
dt_data_set(
data = .data,
data_tbl = updated_data_tbl
)

return(.data)
}

# Manually add rows to the empty data table (if there are indeed some rows)
if (nrow(dplyr::as_tibble(as.data.frame(list(...)))) > 0) {

.data <-
dt_data_add_rows(
data = .data,
row_data_list = list(...),
before = NULL,
after = NULL
)
}

return(.data)
}

# Mutate the internal data table and get a vector of its column names
data_tbl_mutated <- dplyr::mutate(data_tbl, ...)
data_tbl_mutated_columns <- colnames(data_tbl_mutated)
Expand All @@ -1813,7 +1921,8 @@ cols_add <- function(
columns_new <- base::setdiff(data_tbl_mutated_columns, data_tbl_columns)

# Generate a table that has only the new columns
data_tbl_new_cols <- dplyr::select(data_tbl_mutated, columns_new)
data_tbl_new_cols <-
dplyr::select(data_tbl_mutated, dplyr::all_of(columns_new))

# Generate boxhead rows that correspond to the new columns
boxh_df_new_cols <- dt_boxhead_get(data = gt(data_tbl_new_cols))
Expand Down
36 changes: 35 additions & 1 deletion R/rows_add.R
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,21 @@ rows_add <- function(
return(.data)
}

# Get the column names from the internal dataset
# Get the internal dataset and a vector of its column names
data_tbl <- dt_data_get(data = .data)
data_tbl_columns <- colnames(data_tbl)

#
# Special case where data table has no columns (and no rows); here, we allow
# for one or more rows to be added with an arbitrary number of columns
#

if (nrow(data_tbl) < 1 && length(data_tbl_columns) < 1) {

.data <- cols_add(.data = .data, ...)

return(.data)
}

if (!is.null(.n_empty)) {

Expand Down Expand Up @@ -453,6 +466,27 @@ rows_add <- function(
cli::cli_abort("Expressions cannot be given to both `.before` and `.after`.")
}

#
# Special case where all components of `row_data_list` are empty (have
# zero length); in this case we need to return the data unchanged
#

row_data_list_empty <-
all(
vapply(
seq_along(row_data_list),
FUN.VALUE = logical(1),
USE.NAMES = FALSE,
FUN = function(x) {
length(row_data_list[[x]]) < 1
}
)
)

if (row_data_list_empty) {
return(.data)
}

dt_data_add_rows(
data = .data,
row_data_list = row_data_list,
Expand Down
Binary file modified R/sysdata.rda
Binary file not shown.
31 changes: 31 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,37 @@ is_gt_tbl_or_group <- function(data) {
inherits(data, "gt_tbl") || inherits(data, "gt_group")
}

is_gt_tbl_empty <- function(data) {
data_tbl <- dt_data_get(data = data)
ncol(data_tbl) == 0 && nrow(data_tbl) == 0
}

is_gt_tbl_empty_w_cols <- function(data) {
data_tbl <- dt_data_get(data = data)
ncol(data_tbl) > 0 && nrow(data_tbl) == 0
}

is_gt_tbl_empty_w_rows <- function(data) {
data_tbl <- dt_data_get(data = data)
ncol(data_tbl) == 0 && nrow(data_tbl) > 0
}

# Adjustments for a completely empty table (no columns and no rows)
adjust_gt_tbl_empty <- function(data) {

# Get the table's locale
tbl_locale <- dt_locale_get_value(data = data)

no_table_data_text <- get_locale_no_table_data_text(locale = tbl_locale)

data <- cols_add(data, no_data = no_table_data_text)
data <- tab_options(data, column_labels.hidden = TRUE)
data <- cols_align(data, align = "center", columns = no_data)
data <- cols_width(data, no_data ~ px(500))

data
}

#' Determines whether a character vector is non-empty
#'
#' @param x A character vector.
Expand Down
17 changes: 17 additions & 0 deletions R/utils_formatters.R
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,23 @@ get_locale_num_spellout <- function(locale = NULL) {
spelled_num[[locale]]
}

#' Get the `no_table_data_text` value based on a locale
#'
#' @param locale The user-supplied `locale` value, found in several `fmt_*()`
#' functions. This is expected as `NULL` if not supplied by the user.
#' @noRd
get_locale_no_table_data_text <- function(locale = NULL) {

# If `locale` is NULL then use the 'en' locale
if (is.null(locale)) {
locale <- "en"
}

# Get the correct `no_table_data_text` value from the
# `gt:::locales` lookup table
filter_table_to_value(locales, no_table_data_text, locale == {{ locale }})
}

get_locale_segments <- function(locale) {

if (!grepl("-", locale)) {
Expand Down
18 changes: 17 additions & 1 deletion data-raw/X03-locales.R
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,19 @@ for (i in seq_along(regional_currencies)) {
# Make corrections for specific currencies
regional_currencies_tbl[regional_currencies_tbl$territory_name == "CU", ][["currency_code"]] <- "CUP"

#
# Create a table of 'no-table-data' text from all possible languages
#

no_table_data <-
readr::read_csv(
"data-raw/no_table_data_text.csv",
col_types = cols(
lang_name = col_character(),
no_table_data_text = col_character()
)
)

#
# Join all tables together to generate a comprehensive locale metadata table
#
Expand All @@ -263,7 +276,8 @@ locales <-
locale_metadata_tbl %>%
left_join(chr_index_tbl, by = "locale") %>%
left_join(numbers_metadata_tbl, by = "locale") %>%
left_join(regional_currencies_tbl, by = "territory_name")
left_join(regional_currencies_tbl, by = "territory_name") %>%
left_join(no_table_data, by = "lang_name")

rm(parse_locale)
rm(i)
Expand Down Expand Up @@ -292,3 +306,5 @@ rm(currency_in_use)
rm(index_chr)
rm(n_regional_currencies)
rm(not_tender_j)
rm(no_table_data)

Loading

2 comments on commit d1e11e9

@github-actions
Copy link

Choose a reason for hiding this comment

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

@github-actions
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.