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. The displaydiffers from the default display for data frames, seevignette("digits") for an overview over the differences.This display works for many, but not for all use cases.
The easiest way to customize the display of numbers and other data ina tibble is to define options. See?pillar::pillar_optionsfor a comprehensive overview.
tibble(x =123.4567)#> # A tibble: 1 × 1#> x#> <dbl>#> 1 123.4567old<-options(pillar.sigfig =7)tibble(x =123.4567)#> # A tibble: 1 × 1#> x#> <dbl>#> 1 123.4567# Restore old options, see also rlang::local_options() for a more elegant wayoptions(old)This changes the display of all columns. Read on to see how toospecify display options on a column-by-column basis.
The newnum() constructor allows creating vectors thatbehave like numbers but allow customizing their display. Below a fewexamples are shown, see?num for a comprehensive overview.Similarly,char() allows customizing the display ofcharacter columns.
num(-1:3,notation ="sci")#> <pillar_num(sci)[5]>#> [1] -1e0 0 1e0 2e0 3e0tibble(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"),char =char(paste(LETTERS,collapse =" "),shorten ="mid"))#> # A tibble: 5 × 7#> x4 x1 usd percent eng si char#> <num:.4!> <num:.1> USD % [e-3] <si> <char>#> 1 800.5000 800.5 800.50 8.05 1 123 m A B C D E F G … T U V W X Y Z#> 2 900.5000 900.5 900.50 9.05 10 1.23 A B C D E F G … T U V W X Y Z#> 3 1000.5000 1000.5 1000.50 10.05 100 12.3 A B C D E F G … T U V W X Y Z#> 4 1100.5000 1100.5 1100.50 11.05 1000 123 A B C D E F G … T U V W X Y Z#> 5 1200.5000 1200.5 1200.50 12.05 10000 1.23k A B C D E F G … T U V W X Y ZThe pillar package that is responsible for the display of tibblestries hard to get the number display right, however it is impossible toaccommodate all use cases. Whenever the default formatting does not suitthe application,num() orchar() allowredefining the formatting for individual columns. The formattingsurvives most data transformations.
Currently, formatting must be applied manually for each column. Thefollowing pattern may help doing this consistently for all columns in atibble, or for some columns based on their name.
library(dplyr,warn.conflicts =FALSE)markets<-as_tibble(EuStockMarkets)%>%mutate(time =time(EuStockMarkets),.before =1)markets#> # A tibble: 1,860 × 5#> time DAX SMI CAC FTSE#> <dbl> <dbl> <dbl> <dbl> <dbl>#> 1 1991.496 1628.75 1678.1 1772.8 2443.6#> 2 1991.5 1613.63 1688.5 1750.5 2460.2#> 3 1991.504 1606.51 1678.6 1718 2448.2#> 4 1991.508 1621.04 1684.1 1708.1 2470.4#> 5 1991.512 1618.16 1686.6 1723.1 2484.7#> 6 1991.515 1610.61 1671.6 1714.3 2466.8#> 7 1991.519 1630.75 1682.9 1734.5 2487.9#> 8 1991.523 1640.17 1703.6 1757.4 2508.4#> 9 1991.527 1635.47 1697.5 1754 2510.5#> 10 1991.531 1645.89 1716.3 1754.3 2497.4#> # ℹ 1,850 more rowsmarkets%>%mutate(across(-time,~num(.x,digits =3)))#> # A tibble: 1,860 × 5#> time DAX SMI CAC FTSE#> <dbl> <num:.3!> <num:.3!> <num:.3!> <num:.3!>#> 1 1991.496 1628.750 1678.100 1772.800 2443.600#> 2 1991.5 1613.630 1688.500 1750.500 2460.200#> 3 1991.504 1606.510 1678.600 1718.000 2448.200#> 4 1991.508 1621.040 1684.100 1708.100 2470.400#> 5 1991.512 1618.160 1686.600 1723.100 2484.700#> 6 1991.515 1610.610 1671.600 1714.300 2466.800#> 7 1991.519 1630.750 1682.900 1734.500 2487.900#> 8 1991.523 1640.170 1703.600 1757.400 2508.400#> 9 1991.527 1635.470 1697.500 1754.000 2510.500#> 10 1991.531 1645.890 1716.300 1754.300 2497.400#> # ℹ 1,850 more rowsnumFormatting numbers is useful for presentation of results. If definedearly on in the analysis, the formatting options survive mostoperations. It is worth defining output options that suit your data onceearly on in the process, to benefit from the formatting throughout theanalysis. We are working on seamlessly applying this formatting to thefinal presentation (plots, tables, …).
When applying arithmetic operations on numbers created bynum(), the result inherits the formatting of the firstnum object.
num(1)+2#> <pillar_num[1]>#> [1] 31+num(2)#> <pillar_num[1]>#> [1] 31L+num(2)#> <pillar_num[1]>#> [1] 3num(3.23456,sigfig =4)-num(2)#> <pillar_num:4[1]>#> [1] 1.235num(4,sigfig =2)*num(3,digits =2)#> <pillar_num:2[1]>#> [1] 12num(3,digits =2)*num(4,sigfig =2)#> <pillar_num:.2![1]>#> [1] 12.00-num(2)#> <pillar_num[1]>#> [1] -2Similarly, for mathematical operations, the formatting isinherited.
In some cases, the ideal formatting changes after a transformation.num() can be applied repeatedly, the last setting wins.
Thevar() function is one of the examples where theformatting is lost:
Themedian() function is worse, it breaks fornum() objects:
One way to recover is to applynum() to the result:
num(var(x),notation ="eng")#> <pillar_num(eng)[1]>#> [1] 2.333333e0num(median(as.numeric(x)),notation ="eng")#> <pillar_num(eng)[1]>#> [1] 2e0For automatic recovery, we can also define our version ofvar(), or even overwrite the base implementation. Note thatthis pattern is still experimental and may be subject to change:
var_<-function(x, ...) { out<-var(vctrs::vec_proxy(x), ...) vctrs::vec_restore(out, x)}var_(x)#> <pillar_num(eng)[1]>#> [1] 2.333333e0This pattern can be applied to all functions that lose theformatting. Themake_restore() function defined below is afunction factory that consumes a function and returns a derivedfunction: