dfe-analytical-services / dfeR

Common R tasks in the Department for Education (DfE)
https://dfe-analytical-services.github.io/dfeR/
GNU General Public License v3.0
9 stars 2 forks source link

pretty_num to have an option of minimum number of digits #82

Open JT-39 opened 4 days ago

JT-39 commented 4 days ago

Is your feature request related to a problem? Please describe.

I want to be able to specify the minimum number of digits in pretty_num(). This is currently a functionality of base R format() which has an option nsmall described as "the minimum number of digits to the right of the decimal point in formatting real/complex numbers in non-scientific formats."

Describe the solution you'd like

Option in pretty_num() to specificy minimum number of digits.

Describe alternatives you've considered

Base R format()

Additional context

This would be really helpful in tables where, for example, values are rounded to 2dp. Currently pretty_num() will round 3.20 to 3.2 even with dp = 2, so this can make the value look odd in the table.

JT-39 commented 1 day ago

Possible solution.

Add a nsmall parameter to the comma_sep() function. Then add this as a parameter to pretty_num().

New comma_sep():

comma_sep <- function(number) {
  format(number, big.mark = ",", nsmall = 0L, trim = TRUE, scientific = FALSE)
}

New pretty_num():

pretty_num <- function(
    value,
    prefix = "",
    gbp = FALSE,
    suffix = "",
    dp = 2,
    ignore_na = FALSE,
    alt_na = FALSE,
    nsmall = 0L) { # Add nsmall argument
  # Check we're only trying to prettify a single value
  if (length(value) > 1) {
    stop("value must be a single value, multiple values were detected")
  }

.
.
.

  # Add suffix and prefix, plus convert to million or billion
  if (abs(num_value) >= 1.e9) {
    paste0(
      prefix,
      currency,
      comma_sep(round_five_up(abs(num_value) / 1.e9, dp = dp), nsmall = nsmall),
      " billion",
      suffix
    )
  } else if (abs(num_value) >= 1.e6) {
    paste0(
      prefix,
      currency,
            comma_sep(round_five_up(abs(num_value) / 1.e6, dp = dp), nsmall = nsmall),
      " million",
      suffix
    )
  } else {
    paste0(
      prefix,
      currency,
      comma_sep(round_five_up(abs(num_value), dp = dp), nsmall = nsmall),
      suffix
    )
  }
}

There could be an argument to have nsmall = NULL as default in pretty_num() and then set nsmall equal to the value of dp so that whatever the decimal place this number of decimal places will always be shown. Though this is quite strict as the decimal places shown will either always be the value of dp or nsmall (i.e., if set dp = 2 lose the ability to have one value as 3.12 and another as 3 (rounded from 3.00) as nsmall will force it show as 3.00.

  # If nsmall is not given, make same value as dp
  if (is.null(nsmall)) {
    nsmall <- dp
  }