|
| 1 | + |
| 2 | +format_num <- local({ |
| 3 | + |
| 4 | + pretty_num <- function(number, style = c("default", "nopad", "6")) { |
| 5 | + |
| 6 | + style <- switch( |
| 7 | + match.arg(style), |
| 8 | + "default" = pretty_num_default, |
| 9 | + "nopad" = pretty_num_nopad, |
| 10 | + "6" = pretty_num_6 |
| 11 | + ) |
| 12 | + |
| 13 | + style(number) |
| 14 | + } |
| 15 | + |
| 16 | + compute_num <- function(number, smallest_prefix = "y") { |
| 17 | + prefixes0 <- c("y","z","a","f","p","n","u","m","", "k", "M", "G", "T", "P", "E", "Z", "Y") |
| 18 | + zeroshif0 <- 9L |
| 19 | + |
| 20 | + stopifnot( |
| 21 | + is.numeric(number), |
| 22 | + is.character(smallest_prefix), |
| 23 | + length(smallest_prefix) == 1, |
| 24 | + !is.na(smallest_prefix), |
| 25 | + smallest_prefix %in% prefixes0 |
| 26 | + ) |
| 27 | + |
| 28 | + limits <- c(999950 * 1000 ^ (seq_len(length(prefixes0)) - (zeroshif0 + 1L))) |
| 29 | + nrow <- length(limits) |
| 30 | + low <- match(smallest_prefix, prefixes0) |
| 31 | + zeroshift <- zeroshif0 + 1L - low |
| 32 | + prefixes <- prefixes0[low:length(prefixes0)] |
| 33 | + limits <- limits[low:nrow] |
| 34 | + nrow <- nrow - low + 1 |
| 35 | + |
| 36 | + neg <- number < 0 & !is.na(number) |
| 37 | + number <- abs(number) |
| 38 | + mat <- matrix( |
| 39 | + rep(number, each = nrow), |
| 40 | + nrow = nrow, |
| 41 | + ncol = length(number) |
| 42 | + ) |
| 43 | + mat2 <- matrix(mat < limits, nrow = nrow, ncol = length(number)) |
| 44 | + exponent <- nrow - colSums(mat2) - (zeroshift - 1L) |
| 45 | + in_range <- function(exponent) { |
| 46 | + max(min(exponent, nrow - zeroshift, na.rm = FALSE), 1L - zeroshift, na.rm = TRUE) |
| 47 | + } |
| 48 | + if (length(exponent)) { |
| 49 | + exponent <- sapply(exponent, in_range) |
| 50 | + } |
| 51 | + res <- number / 1000 ^ exponent |
| 52 | + prefix <- prefixes[exponent + zeroshift] |
| 53 | + |
| 54 | + ## Zero number |
| 55 | + res[number == 0] <- 0 |
| 56 | + prefix[number == 0] <- prefixes[zeroshift] |
| 57 | + |
| 58 | + ## NA and NaN number |
| 59 | + res[is.na(number)] <- NA_real_ |
| 60 | + res[is.nan(number)] <- NaN |
| 61 | + prefix[is.na(number)] <- "" # prefixes0[low] is meaningless # Includes NaN as well |
| 62 | + |
| 63 | + data.frame( |
| 64 | + stringsAsFactors = FALSE, |
| 65 | + amount = res, |
| 66 | + prefix = prefix, |
| 67 | + negative = neg |
| 68 | + ) |
| 69 | + } |
| 70 | + |
| 71 | + pretty_num_default <- function(number) { |
| 72 | + szs <- compute_num(number) |
| 73 | + amt <- szs$amount |
| 74 | + sep <- " " |
| 75 | + |
| 76 | + ## String. For fractions we always show two fraction digits |
| 77 | + res <- character(length(amt)) |
| 78 | + int <- is.na(amt) | abs(amt - as.integer(amt)) <= .Machine$double.eps |
| 79 | + res[int] <- format( |
| 80 | + ifelse(szs$negative[int], -1, 1) * amt[int], |
| 81 | + scientific = FALSE |
| 82 | + ) |
| 83 | + res[!int] <- sprintf("%.2f", ifelse(szs$negative[!int], -1, 1) * amt[!int]) |
| 84 | + |
| 85 | + format(paste(res, szs$prefix, sep = sep), justify = "right") |
| 86 | + } |
| 87 | + |
| 88 | + pretty_num_nopad <- function(number) { |
| 89 | + sub("^\\s+", "", pretty_num_default(number)) |
| 90 | + } |
| 91 | + |
| 92 | + pretty_num_6 <- function(number) { |
| 93 | + szs <- compute_num(number, smallest_prefix = "y") |
| 94 | + amt <- round(szs$amount, 2) |
| 95 | + sep <- " " |
| 96 | + |
| 97 | + na <- is.na(amt) |
| 98 | + nan <- is.nan(amt) |
| 99 | + neg <- !na & !nan & szs$negative |
| 100 | + l10p <- !na & !nan & !neg & amt < 10 |
| 101 | + l100p <- !na & !nan & !neg & amt >= 10 & amt < 100 |
| 102 | + b100p <- !na & !nan & !neg & amt >= 100 |
| 103 | + l10n <- !na & !nan & neg & amt < 10 |
| 104 | + l100n <- !na & !nan & neg & amt >= 10 & amt < 100 |
| 105 | + b100n <- !na & !nan & neg & amt >= 100 |
| 106 | + |
| 107 | + famt <- character(length(amt)) |
| 108 | + famt[na] <- " NA" |
| 109 | + famt[nan] <- " NaN" |
| 110 | + famt[l10p] <- sprintf("%.2f", amt[l10p]) |
| 111 | + famt[l100p] <- sprintf("%.1f", amt[l100p]) |
| 112 | + famt[b100p] <- sprintf(" %.0f", amt[b100p]) |
| 113 | + famt[l10n] <- sprintf("-%.1f", amt[l10n]) |
| 114 | + famt[l100n] <- sprintf(" -%.0f", amt[l100n]) |
| 115 | + famt[b100n] <- sprintf("-%.0f", amt[b100n]) |
| 116 | + |
| 117 | + sub(" $", " ", paste0(famt, sep, szs$prefix)) |
| 118 | + } |
| 119 | + |
| 120 | + structure( |
| 121 | + list( |
| 122 | + .internal = environment(), |
| 123 | + pretty_num = pretty_num, |
| 124 | + compute_num = compute_num |
| 125 | + ), |
| 126 | + class = c("standalone_num", "standalone") |
| 127 | + ) |
| 128 | +}) |
0 commit comments