Tibbles print numbers with three significant digits by default, switching to scientific notation if the available space is too small. Underlines are used to highlight groups of three digits. This display works for many, but not for all use cases.

Per-column number formatting

The new num() constructor allows creating vectors that behave like numbers but allow customizing their display.

num(-1:3, notation = "sci")
#> <pillar_num(sci)[5]>
#> [1] -1e0  0    1e0  2e0  3e0

tibble(
  x4 = num(8:12 * 100 + 0.5, digits = 4),
  x1 = num(8:12 * 100 + 0.5, digits = -1),
  usd = num(8:12 * 100 + 0.5, digits = 2, label = "USD"),
  percent = num(8:12 / 100 + 0.0005, label = "%", scale = 100),
  eng = num(10^(-3:1), notation = "eng", fixed_exponent = -Inf),
  si = num(10^(-3:1) * 123, notation = "si")
)
#> # A tibble: 5 x 6
#>          x4       x1     usd percent      eng      si
#>   <num:.4!> <num:.1>     USD       %    <eng>    <si>
#> 1  800.5000    800.5  800.50    8.05     1e-3 123   m
#> 2  900.5000    900.5  900.50    9.05    10e-3   1.23 
#> 3 1000.5000   1000.5 1000.50   10.0    100e-3  12.3  
#> 4 1100.5000   1100.5 1100.50   11.0   1000e-3 123    
#> 5 1200.5000   1200.5 1200.50   12.0  10000e-3   1.23k

Computing on num

Formatting numbers is useful for presentation of results. If defined early on in the analysis, the formatting options survive most operations. It is worth defining output options that suit your data once early on in the process, to benefit from the formatting throughout the analysis. We are working on seamlessly applying this formatting to the final presentation (plots, tables, …).

Arithmetics

num(1) + 2
#> <pillar_num[1]>
#> [1] 3
1 + num(2)
#> <pillar_num[1]>
#> [1] 3
1L + num(2)
#> <pillar_num[1]>
#> [1] 3
num(3.23456, sigfig = 4) - num(2)
#> <pillar_num:4[1]>
#> [1] 1.235
num(4, sigfig = 2) * num(3, digits = 2)
#> <pillar_num:2[1]>
#> [1] 12
num(3, digits = 2) * num(4, sigfig = 2)
#> <pillar_num:.2![1]>
#> [1] 12.00
-num(2)
#> <pillar_num[1]>
#> [1] -2

Mathematics

min(num(1:3, label = "$"))
#> <pillar_num{$}[1]>
#> [1] 1
mean(num(1:3, notation = "eng"))
#> <pillar_num(eng)[1]>
#> [1] 2e0
sin(num(1:3, label = "%", scale = 100))
#> <pillar_num{%}*100[3]>
#> [1] 84.1 90.9 14.1

Recovery

The var() function is one of the examples where the formatting is lost:

x <- num(c(1, 2, 4), notation = "eng")
var(x)
#> [1] 2.333333

One way to recover is to apply num() to the result:

num(var(x), notation = "eng")
#> <pillar_num(eng)[1]>
#> [1] 2.33e0

For automatic recovery, we can also define our version of var(), or even override the base implementation:

var_ <- function(x, ...) {
  out <- var(x, ...)
  vctrs::vec_restore(out, vctrs::vec_proxy(x))
}
var_(x)
#> <pillar_num(eng)[1]>
#> [1] 2.33e0

This pattern can be applied to all functions that lose the formatting. The make_restore() function defined below is a function factory that consumes a function and returns a derived function:

make_restore <- function(fun) {
  force(fun)
  function(x, ...) {
    out <- fun(x, ...)
    vctrs::vec_restore(out, vctrs::vec_proxy(x))
  }
}

var_ <- make_restore(var)
sd_ <- make_restore(sd)

var_(x)
#> <pillar_num(eng)[1]>
#> [1] 2.33e0
sd_(x)
#> <pillar_num(eng)[1]>
#> [1] 1.53e0