-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from cregouby/master
- Loading branch information
Showing
11 changed files
with
487 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
|
||
format_num <- local({ | ||
|
||
pretty_num <- function(number, style = c("default", "nopad", "6")) { | ||
|
||
style <- switch( | ||
match.arg(style), | ||
"default" = pretty_num_default, | ||
"nopad" = pretty_num_nopad, | ||
"6" = pretty_num_6 | ||
) | ||
|
||
style(number) | ||
} | ||
|
||
compute_num <- function(number, smallest_prefix = "y") { | ||
prefixes0 <- c("y","z","a","f","p","n","u","m","", "k", "M", "G", "T", "P", "E", "Z", "Y") | ||
zeroshif0 <- 9L | ||
|
||
stopifnot( | ||
is.numeric(number), | ||
is.character(smallest_prefix), | ||
length(smallest_prefix) == 1, | ||
!is.na(smallest_prefix), | ||
smallest_prefix %in% prefixes0 | ||
) | ||
|
||
limits <- c( 999950 * 1000 ^ (seq_len(length(prefixes0) ) - (zeroshif0+1L))) | ||
nrow <- length(limits) | ||
low <- match(smallest_prefix, prefixes0) | ||
zeroshift <- zeroshif0 +1L - low | ||
prefixes <- prefixes0[low:length(prefixes0)] | ||
limits <- limits[low:nrow] | ||
nrow <- nrow - low + 1 | ||
|
||
neg <- number < 0 & !is.na(number) | ||
number <- abs(number) | ||
mat <- matrix( | ||
rep(number, each = nrow), | ||
nrow = nrow, | ||
ncol = length(number) | ||
) | ||
mat2 <- matrix(mat < limits, nrow = nrow, ncol = length(number)) | ||
exponent <- nrow - colSums(mat2) - (zeroshift -1L) | ||
in_range <- function(exponent) { | ||
max(min(exponent,nrow-zeroshift, na.rm = FALSE),1L-zeroshift, na.rm = TRUE) | ||
} | ||
if (length(exponent)) { | ||
exponent <- sapply(exponent, in_range) | ||
} | ||
res <- number / 1000 ^ exponent | ||
prefix <- prefixes[exponent + zeroshift] | ||
|
||
## Zero number | ||
res[number == 0] <- 0 | ||
prefix[number == 0] <- prefixes[zeroshift] | ||
|
||
## NA and NaN number | ||
res[is.na(number)] <- NA_real_ | ||
res[is.nan(number)] <- NaN | ||
prefix[is.na(number)] <- "" # prefixes0[low] is meaningless # Includes NaN as well | ||
|
||
data.frame( | ||
stringsAsFactors = FALSE, | ||
amount = res, | ||
prefix = prefix, | ||
negative = neg | ||
) | ||
} | ||
|
||
pretty_num_default <- function(number) { | ||
szs <- compute_num(number) | ||
amt <- szs$amount | ||
sep <- " " | ||
|
||
## String. For fractions we always show two fraction digits | ||
res <- character(length(amt)) | ||
int <- is.na(amt) | abs(amt - as.integer(amt)) <= .Machine$double.eps | ||
res[int] <- format( | ||
ifelse(szs$negative[int], -1, 1) * amt[int], | ||
scientific = FALSE | ||
) | ||
res[!int] <- sprintf("%.2f", ifelse(szs$negative[!int], -1, 1) * amt[!int]) | ||
|
||
format(paste(res, szs$prefix,sep = sep), justify = "right") | ||
} | ||
|
||
pretty_num_nopad <- function(number) { | ||
sub("^\\s+", "", pretty_num_default(number)) | ||
} | ||
|
||
pretty_num_6 <- function(number) { | ||
szs <- compute_num(number, smallest_prefix = "y") | ||
amt <- round(szs$amount,2) | ||
sep <- " " | ||
|
||
na <- is.na(amt) | ||
nan <- is.nan(amt) | ||
neg <- !na & !nan & szs$negative | ||
l10p <- !na & !nan & !neg & amt < 10 | ||
l100p <- !na & !nan & !neg & amt >= 10 & amt < 100 | ||
b100p <- !na & !nan & !neg & amt >= 100 | ||
l10n <- !na & !nan & neg & amt < 10 | ||
l100n <- !na & !nan & neg & amt >= 10 & amt < 100 | ||
b100n <- !na & !nan & neg & amt >= 100 | ||
|
||
famt <- character(length(amt)) | ||
famt[na] <- " NA" | ||
famt[nan] <- " NaN" | ||
famt[l10p] <- sprintf("%.2f", amt[l10p]) | ||
famt[l100p] <- sprintf("%.1f", amt[l100p]) | ||
famt[b100p] <- sprintf(" %.0f", amt[b100p]) | ||
famt[l10n] <- sprintf("-%.1f", amt[l10n]) | ||
famt[l100n] <- sprintf(" -%.0f", amt[l100n]) | ||
famt[b100n] <- sprintf("-%.0f", amt[b100n]) | ||
|
||
sub(" $"," ",paste0(famt, sep, szs$prefix)) | ||
} | ||
|
||
structure( | ||
list( | ||
.internal = environment(), | ||
pretty_num = pretty_num, | ||
compute_num = compute_num | ||
), | ||
class = c("standalone_num", "standalone") | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,13 @@ | ||
|
||
#' Prettier formatting of quantities | ||
#' | ||
#' Render quantities with a pretty, human-readable formatting. | ||
#' - Time intervals: '1337000' -> '15d 11h 23m 20s'. | ||
#' - Vague time intervals: '2674000' -> 'about a month ago'. | ||
#' - Bytes: '1337' -> '1.34 kB'. | ||
#' - p-values: '0.00001' -> '<0.0001'. | ||
#' - Colors: '#FF0000' -> 'red'. | ||
#' - Quantities: '1239437' -> '1.24 M'. | ||
#' @docType package | ||
#' @name prettyunits | ||
"_PACKAGE" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
|
||
#' Linear quantities in a human readable string | ||
#' | ||
#' Use `pretty_num()` to format numbers `compute_num()` is the underlying | ||
#' engine that may be useful for custom formatting. | ||
#' | ||
#' @param number Numeric vector, number related to a linear quantity. | ||
#' @param style Formatting style: | ||
#' * `"default"` is the original `pretty_num` formatting, and it always | ||
#' pads the output, so that all vector elements are of the same width, | ||
#' * `"nopad"` is similar, but does not pad the output, | ||
#' * `"6"` always uses 6 characters, | ||
#' The `"6"` style is useful if it is important that the output always | ||
#' has the same width (number of characters), e.g. in progress bars. | ||
#' See some examples below. | ||
#' @return Character vector, the formatted sizes. | ||
#' For `compute_num`, a data frame with columns `amount`, `prefix`, | ||
#' `negative`. | ||
#' | ||
#' @export | ||
#' @examples | ||
#' numbers <- c(1337, 1.3333e-5, 13333337, 1333333337, 133333333337) | ||
#' pretty_num(numbers) | ||
#' pretty_num(numbers, style = "nopad") | ||
#' pretty_num(numbers, style = "6") | ||
|
||
pretty_num <- format_num$pretty_num | ||
|
||
#' @rdname pretty_num | ||
#' @param smallest_prefix A character scalar, the smallest prefix to use. | ||
#' @export | ||
|
||
compute_num <- format_num$compute_num |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.