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

Add significant figures support to fmt_scientific() and vec_fmt_scientific() #1411

Merged
merged 13 commits into from
Aug 18, 2023
62 changes: 54 additions & 8 deletions R/format_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -586,10 +586,10 @@ fmt_number <- function(

# Set the `formatC_format` option according to whether number
# formatting with significant figures is to be performed
if (!is.null(n_sigfig)) {
if (!is.null(n_sigfig) && !is.na(n_sigfig[1])) {

# Stop function if `n_sigfig` does not have a valid value
validate_n_sigfig(n_sigfig)
validate_n_sigfig(n_sigfig = n_sigfig)

formatC_format <- "fg"
} else {
Expand Down Expand Up @@ -1136,11 +1136,12 @@ fmt_integer <- function(
#'
#' @section Examples:
#'
#' Use the [`exibble`] dataset to create a **gt** table. Format the `num` column
#' as partially numeric and partially in scientific notation. This is done with
#' two separate calls of [fmt_number()] and `fmt_scientific()`. We'll use the
#' expressions `num > 500` and `num <= 500` in the functions' respective `rows`
#' arguments.
#' Let's use the [`exibble`] dataset to create a simple **gt** table. We'll
#' elect to the `num` column as partially numeric and partially in scientific
#' notation. This is done with two separate calls of [fmt_number()] and
#' `fmt_scientific()`. We'll use the expressions `num > 500` and `num <= 500` in
#' the functions' respective `rows` arguments to target formatting to specific
#' cells.
#'
#' ```r
#' exibble |>
Expand All @@ -1163,6 +1164,37 @@ fmt_integer <- function(
#' `r man_get_image_tag(file = "man_fmt_scientific_1.png")`
#' }}
#'
#' The [`constants`] table contains a plethora of data on the fundamental
#' physical constant and most values (in the units used) are either very small
#' or very large, so scientific formatting is suitable. The values differ in the
#' degree of measurement precision and separate columns (`sf_value` and
#' `sf_uncert`) contain the exact number of significant figures for each
#' measurement value and the associated uncertainty value. We can use the
#' `n_sigfig` argument of `fmt_scientific()` in conjunction with the
#' [from_column()] helper to get the correct number of significant digits for
#' each value.
#'
#' ```r
#' constants |>
#' dplyr::filter(grepl("Planck", name)) |>
#' gt() |>
#' fmt_scientific(
#' columns = value,
#' n_sigfig = from_column(column = "sf_value")
#' ) |>
#' fmt_scientific(
#' columns = uncert,
#' n_sigfig = from_column(column = "sf_uncert")
#' ) |>
#' cols_hide(columns = starts_with("sf")) |>
#' fmt_units(columns = units) |>
#' sub_missing(missing_text = "")
#' ```
#'
#' \if{html}{\out{
#' `r man_get_image_tag(file = "man_fmt_scientific_2.png")`
#' }}
#'
#' @family data formatting functions
#' @section Function ID:
#' 3-3
Expand All @@ -1180,6 +1212,7 @@ fmt_scientific <- function(
columns = everything(),
rows = everything(),
decimals = 2,
n_sigfig = NULL,
drop_trailing_zeros = FALSE,
drop_trailing_dec_mark = TRUE,
scale_by = 1.0,
Expand All @@ -1202,6 +1235,7 @@ fmt_scientific <- function(
# Supports parameters:
#
# - decimals
# - n_sigfig
# - drop_trailing_zeros
# - drop_trailing_dec_mark
# - scale_by
Expand Down Expand Up @@ -1247,6 +1281,7 @@ fmt_scientific <- function(
columns = {{ columns }},
rows = resolved_rows_idx[i],
decimals = p_i$decimals %||% decimals,
n_sigfig = p_i$n_sigfig %||% n_sigfig,
drop_trailing_zeros = p_i$drop_trailing_zeros %||% drop_trailing_zeros,
drop_trailing_dec_mark = p_i$drop_trailing_dec_mark %||% drop_trailing_dec_mark,
scale_by = p_i$scale_by %||% scale_by,
Expand Down Expand Up @@ -1306,6 +1341,17 @@ fmt_scientific <- function(
}
}

# If `n_sigfig` is defined (and not `NA`) modify the number of
# decimal places and keep all trailing zeros
if (!is.null(n_sigfig) && !is.na(n_sigfig[1])) {

# Stop function if `n_sigfig` does not have a valid value
validate_n_sigfig(n_sigfig = n_sigfig)

decimals <- n_sigfig - 1
drop_trailing_zeros <- FALSE
}

# Pass `data`, `columns`, `rows`, and the formatting
# functions as a function list to `fmt()`
fmt(
Expand Down Expand Up @@ -3727,7 +3773,7 @@ round_gt <- function(x, digits = 0) {
#'
#' ```r
#' exibble |>
#' select(currency) |>
#' dplyr::select(currency) |>
#' gt() |>
#' fmt_currency(
#' currency = "euro",
Expand Down
2 changes: 2 additions & 0 deletions R/format_vec.R
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ vec_fmt_integer <- function(
vec_fmt_scientific <- function(
x,
decimals = 2,
n_sigfig = NULL,
drop_trailing_zeros = FALSE,
drop_trailing_dec_mark = TRUE,
scale_by = 1.0,
Expand Down Expand Up @@ -654,6 +655,7 @@ vec_fmt_scientific <- function(
columns = "x",
rows = everything(),
decimals = decimals,
n_sigfig = n_sigfig,
drop_trailing_zeros = drop_trailing_zeros,
drop_trailing_dec_mark = drop_trailing_dec_mark,
scale_by = scale_by,
Expand Down
Binary file modified images/man_fmt_scientific_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/man_fmt_scientific_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion man/fmt_currency.Rd

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

53 changes: 48 additions & 5 deletions man/fmt_scientific.Rd

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

12 changes: 12 additions & 0 deletions man/vec_fmt_scientific.Rd

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

11 changes: 11 additions & 0 deletions tests/testthat/test-fmt_engineering.R
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,17 @@ test_that("The `fmt_engineering()` function works correctly", {
) %>%
gt()

# Format the `num` column to exactly 4 decimal places
expect_equal(
(tab_2 %>%
fmt_engineering(columns = "num", decimals = 4, exp_style = "E") %>%
render_formats_test("default"))[["num"]],
c(
"-34.9000E12", "-3.4530E03", "-234.0000E-06", "0.0000E00",
"75.3400E-06", "82.7940E03", "716.0000E12"
)
)

# Format the `num` column and force the sign on the 'm' part of the
# notation; extract in the default context and compare to expected values
expect_equal(
Expand Down
12 changes: 6 additions & 6 deletions tests/testthat/test-fmt_number.R
Original file line number Diff line number Diff line change
Expand Up @@ -666,11 +666,12 @@ test_that("The `fmt_number()` function format to specified significant figures",
# Expect an error if the length of `n_sigfig` is not 1
expect_error(fmt_number(tab, columns = num, n_sigfig = c(1, 2)))

# Expect an error if `n_sigfig` is NA
expect_error(tab %>% fmt_number(columns = num, n_sigfig = NA))
expect_error(tab %>% fmt_number(columns = num, n_sigfig = NA_integer_))
expect_error(tab %>% fmt_number(columns = num, n_sigfig = NA_real_))
expect_error(tab %>% fmt_number(columns = num, n_sigfig = NA_integer_))
# Don't expect an error if `n_sigfig` is NA (if `n_sigfig` has NA) then
# `decimals` is used
expect_error(regexp = NA, tab %>% fmt_number(columns = num, n_sigfig = NA))
expect_error(regexp = NA, tab %>% fmt_number(columns = num, n_sigfig = NA_integer_))
expect_error(regexp = NA, tab %>% fmt_number(columns = num, n_sigfig = NA_real_))
expect_error(regexp = NA, tab %>% fmt_number(columns = num, n_sigfig = NA_integer_))

# Expect an error if `n_sigfig` is not numeric
expect_error(tab %>% fmt_number(columns = num, n_sigfig = "3"))
Expand All @@ -686,7 +687,6 @@ test_that("The `fmt_number()` function format to specified significant figures",
expect_error(tab %>% fmt_number(columns = num, n_sigfig = -1L))
})


test_that("The `drop_trailing_dec_mark` option works in select `fmt_*()` functions", {

# These numbers will be used in tests with `drop_trailing_dec_mark = FALSE`
Expand Down
56 changes: 56 additions & 0 deletions tests/testthat/test-fmt_scientific.R
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,62 @@ test_that("The `fmt_scientific()` function works correctly", {
)
)

# Format the `num` column to exactly 4 decimal places
expect_equal(
(tab %>%
fmt_scientific(columns = "num_1", decimals = 4, exp_style = "E") %>%
render_formats_test("default"))[["num_1"]],
c(
"1.8362E03", "2.7634E03", "9.3729E02", "6.4300E02",
"2.2320E00", "0.0000E00", "-2.3240E01"
)
)

# Format the `num` column to exactly 6 significant figures
expect_equal(
(tab %>%
fmt_scientific(columns = "num_1", n_sigfig = 6, exp_style = "E") %>%
render_formats_test("default"))[["num_1"]],
c(
"1.83623E03", "2.76339E03", "9.37290E02", "6.43000E02", "2.23200E00",
"0.00000E00", "-2.32400E01"
)
)

# Verify that setting `drop_trailing_zeros` to TRUE has no effect when
# using significant figures
expect_equal(
(tab %>%
fmt_scientific(
columns = "num_1",
n_sigfig = 6,
drop_trailing_zeros = TRUE,
exp_style = "E"
) %>%
render_formats_test("default"))[["num_1"]],
c(
"1.83623E03", "2.76339E03", "9.37290E02", "6.43000E02", "2.23200E00",
"0.00000E00", "-2.32400E01"
)
)

# Should `n_sigfig` be set to `NA` then significant figures cannot be
# used and any value for `decimals` is no longer ignored
expect_equal(
(tab %>%
fmt_scientific(
columns = "num_1",
decimals = 8,
n_sigfig = NA,
exp_style = "E"
) %>%
render_formats_test("default"))[["num_1"]],
c(
"1.83623000E03", "2.76339000E03", "9.37290000E02", "6.43000000E02",
"2.23200000E00", "0.00000000E00", "-2.32400000E01"
)
)

# Format the `num_1` column to 2 decimal places, use a period for the
# digit grouping separators and a comma for the decimal mark, use
# all other defaults; extract `output_df` in the HTML context and
Expand Down