# Formatting numbers

R
function
A showcase of the function I use to format numbers.
Published

May 17, 2024

This blog post covers the function I use to format numbers. It’s kinda work-in-progress / test place for my function because I know I’m not happy with it yet and, as you can see below, I’ll show what output it produces for many different numbers, so I can also use it to see if it does what I want it to do.

Run the following setup code if you want to follow along.

Code
``library(tidyverse)``

## The function

Below is the function I use. It has 4 arguments:

• `x`: The number to format
• `trailing_digits`: This is a bit of a weird one. It refers to how many decimals you want, excluding leading zeroes in the decimal part of the number. I often want a number like 0.002121 to be rounded to 0.0021 instead of 0.00, so instead of simply referring to the number of digits, I call it trailing digits.
• `digits`: This one forces the number of decimals, so setting this to 2 will always show (only) 2 digits
• `omit_zero`: For numbers that can only range from -1 to 1, the leading zero is often non-informative, so this argument removes that leading zero.
Code
``````format_number <- function(
x,
trailing_digits = 2,
digits = NULL,
omit_zero = FALSE) {
# Convert the number to a string to use regex to extract different parts
# of the number (e.g., decimals)
string <- as.character(x)

# Extract and count decimals
decimals <- stringr::str_extract(string, "(?<=\\.).+")
decimals_n <- dplyr::if_else(is.na(decimals), 0, stringr::str_length(decimals))

# Count number of leading zeroes in the decimals
zeroes <- stringr::str_extract(string, "(?<=\\.)0+")
zeroes_n <- dplyr::if_else(is.na(zeroes), 0, stringr::str_length(zeroes))

# If digits are set, it overrules trailing digits
if (!is.null(digits)) {
output <- format(round(x, digits), nsmall = digits)
} else {
trailing_digits <- dplyr::if_else(
decimals_n > trailing_digits,
trailing_digits + zeroes_n,
trailing_digits
)

output <- x |>
round(digits = trailing_digits) |>
purrr::map2_chr(trailing_digits, formatC, format = "f")
}

# Remove leading zero
if (omit_zero) output <- stringr::str_remove(output, "^0")

# Replace NAs with NA
output <- dplyr::if_else(stringr::str_detect(output, "NA"), NA, output)

return(output)
}``````

## Testing it out

The table below shows what kind of output is produced by the function depending on its input. It serves as an illustration of how the function works and as a test for me to see whether the function does what I want it to do.

Number `trailing_digits` `digits` `omit_zero` Result
1 0 - `FALSE` 1
1 2 - `FALSE` 1.00
1 - 2 `FALSE` 1.00
1.0 2 - `FALSE` 1.00
1.02 1 - `FALSE` 1.02
1.02 - 1 `FALSE` 1.0
1.02 2 - `FALSE` 1.02
1.0234 2 - `FALSE` 1.023
1.00234 2 - `FALSE` 1.0023
1.00020345 2 - `FALSE` 1.00020
0.123 2 - `TRUE` .12
0.123 2 - `FALSE` 0.12
`NA` 2 - `FALSE` NA
1.23, 4.56 1 - `FALSE` 1.2, 4.6

## Limitations

The function isn’t complete yet. For example, I should also add something to deal with very large or very small numbers. I’ll update the post when I make adjustments to the function.