Formatting numbers with base R tools often degenerates into a major intellectual challenge for us little minds down here in the valley of tears. There are a number of options available and quite often it's hard to work out which one to use, when a more uncommon setting is needed. The Format() function wraps all these functions and tries to offer a simpler, less technical, but still flexible interface.

There's also an easygoing interface for format templates, defined as a list consisting of any accepted format features. This enables to define templates globally and easily change or modify them later.

Format(x, digits = NULL, sci = NULL, big.mark = NULL,
       ldigits = NULL, zero.form = NULL, na.form = NULL,
       fmt = NULL, align = NULL, width = NULL, lang = NULL, 
       eps = NULL, ...)

# S3 method for table
Format(x, digits = NULL, sci = NULL, big.mark = NULL,
       ldigits = NULL, zero.form = NULL, na.form = NULL,
       fmt = NULL, align = NULL, width = NULL, lang = NULL, 
       eps = NULL, ...)

# S3 method for matrix
Format(x, digits = NULL, sci = NULL, big.mark = NULL,
       ldigits = NULL, zero.form = NULL, na.form = NULL,
       fmt = NULL, align = NULL, width = NULL, lang = NULL, 
       eps = NULL, ...)

# S3 method for default
Format(x, digits = NULL, sci = NULL, big.mark = NULL,
       ldigits = NULL, zero.form = NULL, na.form = NULL,
       fmt = NULL, align = NULL, width = NULL, lang = NULL, 
       eps = NULL, ...)

Fmt(...)

as.fmt(...)

as.CDateFmt(fmt)

Arguments

x

an atomic numerical, typically a vector of real numbers or a matrix of numerical values. Factors will be converted to strings.

digits

integer, the desired (fixed) number of digits after the decimal point. Unlike formatC you will always get this number of digits even if the last digit is 0. Negative numbers of digits round to a power of ten (digits=-2 would round to the nearest hundred).

sci

integer. The power of 10 to be set when deciding to print numeric values in exponential notation. Fixed notation will be preferred unless the number is larger than 10^scipen. If just one value is set it will be used for the left border 10^(-scipen) as well as for the right one (10^scipen). A negative and a positive value can also be set independently. Default is getOption("scipen"), whereas scipen=0 is overridden.

big.mark

character; if not empty used as mark between every 3 decimals before the decimal point. Default is "" (none).

ldigits

number of leading zeros. ldigits=3 would make sure that at least 3 digits on the left side will be printed, say 3.4 will be printed as 003.4. Setting ldigits to 0 will yield results like .452 for 0.452. The default NULL will leave the numbers as they are (meaning at least one 0 digit).

zero.form

character, string specifying how zeros should be specially formatted. Useful for pretty printing 'sparse' objects. If set to NULL (default) no special action will be taken.

na.form

character, string specifying how NAs should be specially formatted. If set to NULL (default) no special action will be taken.

fmt

either a format string, allowing to flexibly define special formats or an object of class fmt, consisting of a list of Format arguments. See Details.

align

the character on whose position the strings will be aligned. Left alignment can be requested by setting sep = "\\l", right alignment by "\\r" and center alignment by "\\c". Mind the backslashes, as if they are omitted, strings would be aligned to the character l, r or c respectively. The default is NULL which would just leave the strings as they are.
This argument is send directly to the function StrAlign() as argument sep.

width

integer, the defined fixed width of the strings.

lang

optional value setting the language for the months and daynames. Can be either "local" for current locale or "engl" for english. If left to NULL, the DescToolsOption "lang" will be searched for and if not found "local" will be taken as default.

eps

a numerical tolerance used mainly for formatting p values, those less than eps are formatted as "< [eps]" (where '[eps]' stands for format(eps, digits)). Default is .Machine$double.eps.

...

further arguments to be passed to or from methods.

Details

Format() is the workhorse here and formats numbers and dates.

The argument fmt is very flexible and is used to generate a variety of different formats. When x is a date, it can take ISO-8601-date-and-time-format codes consisting of (d, m and y for day, month or year) and defining the combination of day month and year representation. Repeating the specific code defines the degree of abbreviation. The format 'yyyy-mm-dd' would yield a date as 2020-10-12.

Date Codes
d day of the month without leading zero (1 - 31)
ddday of the month with leading zero (01 - 31)
dddabbreviated name for the day of the week (e.g. Mon) in the current user's language
ddddfull name for the day of the week (e.g. Monday) in the current user's language
m month without leading zero (1 - 12)
mmmonth with leading zero (01 - 12)
mmm abbreviated month name (e.g. Jan) in the current user's language
mmmmfull month name (e.g. January) in the current user's language
y year without century, without leading zero (0 - 99)
yy year without century, with leading zero (00 - 99)
yyyy year with century. For example: 2005

The function as.CDateFmt() converts ISO-8601 codes into the C-format codes used in base R.
So as.CDateFmt("yyyy mm dd") yields "%Y %m %d".

Even more variability is needed to display numeric values. For the most frequently used formats there are the following special codes available:

Code
escientificforces scientific representation of x, e.g. 3.141e-05. The number of digits,
alignment and zero values are further respected.
eng
engineeringforces scientific representation of x, but only with powers that are a multiple of 3.engabb
engineering abbr.same as eng, but replaces the exponential representation by codes,
e.g. M for mega (1e6). See d.prefix.%
percentwill divide the given number by 100 and append the %-sign (without a separator).
pp-value
will wrap the function format.pval and return a p-value format.
Use eps to define the threshold to switch to a < 000 representation.
fracfractionswill (try to) convert numbers to fractions. So 0.1 will be displayed as 1/10.
See fractions().
*
significancewill produce a significance representation of a p-value consisting of * and .,
while the breaks are set according to the used defaults e.g. in lm as
[0, 0.001] = ***
(0.001, 0.01] = **
(0.01, 0.05] = *
(0.05, 0.1] = .
(0.1,1] = p*

fmt can as well be an object of class fmt consisting of a list out of the arguments above. This allows to store and manage the full format in variables or as options (in DescToolsOptions()) and use it as format template subsequently.

Finally fmt can also be a function in x, which makes formatting very flexible.

New formats can be created by means of as.fmt(). This works quite straight on. We can use any of the arguments from Format() and combine them to a list.
The following code will define a new format template named "myNumFmt" of the class "fmt". Provided to Format() this will result in a number displayed with 2 fixed digits and a comma as big mark:

myNumFmt <- as.fmt(digits=2, big.mark=",")
Format(12222.89345, fmt=myNumFmt) = 12,222.89

The latter returns the same result as if the arguments would have been supplied directly:
Format(12222.89345, digits=2, big.mark=",").

Many report functions (e.g. TOne()) in DescTools use three default formats for counts (named "abs"), numeric values ("num") and percentages ("per"). These formats can be set by the user as options (see DescToolsOptions(). For other purposes any number of any named formats can be defined.

Fmt() is used to access and edit already defined Formats. It can directly adapt defined properties and returns the format template. Fmt("num", digits=1, sci=10) will use the current version of the numeric format and change the digits to 1 and the threshold to switch to scientifc presentation to numbers >1e10 and <1e-10. Format templates can be altered using their names. With Fmt(abs=Fmt("abs", big.mark=" ")) the format template for count values "abs" will be overwritten with the new values and stored as option for the current session.

The formats can as well be organized as options. DescToolsOptions("fmt") would display the currently defined formats. This mechanic works analogously to the options() procedure of base R. So to store the current settings we can use

opt <- DescToolsOptions("fmt")
... do some stuff like redefining the global formats ...
DescToolOptions(opt)  

The last command resets the options and so we have again the initial definitions for the format templates.

Value

the formatted values as characters.

If x was a matrix, then a the result will also be a matrix. (Hope this will not surprise you...)

Author

Andri Signorell <andri@signorell.net>

Examples

Format(as.Date(c("2014-11-28", "2014-1-2")), fmt="ddd, d mmmm yyyy")
#> [1] Fri, 28 November 2014  Thu,  2 January 2014
Format(as.Date(c("2014-11-28", "2014-1-2")), fmt="ddd, d mmmm yyyy", lang="engl")
#> [1] Fri, 28 November 2014  Thu,  2 January 2014

x <- pi * 10^(-10:10)

Format(x, digits=3, fmt="%", sci=NA)
#>  [1]             0.000%             0.000%             0.000%             0.000%
#>  [5]             0.000%             0.003%             0.031%             0.314%
#>  [9]             3.142%            31.416%           314.159%          3141.593%
#> [13]         31415.927%        314159.265%       3141592.654%      31415926.536%
#> [17]     314159265.359%    3141592653.590%   31415926535.898%  314159265358.979%
#> [21] 3141592653589.793%
Format(x, digits=4, sci=c(4, 6), ldigits=0, width=9, align=".")
#>  [1]    3.1416e-10    3.1416e-09    3.1416e-08    3.1416e-07     .0000    
#>  [6]     .0000         .0003         .0031         .0314         .3142    
#> [11]    3.1416       31.4159      314.1593     3141.5927        3.1416e+04
#> [16]    3.1416e+05    3.1416e+06    3.1416e+07    3.1416e+08    3.1416e+09
#> [21]    3.1416e+10


# format a matrix
m <- matrix(runif(100), nrow=10,
            dimnames=list(LETTERS[1:10], LETTERS[1:10]))

Format(m, digits=1)
#>     A   B   C   D   E   F   G   H   I   J
#> A 0.6 0.7 0.1 0.7 0.3 0.8 0.9 0.0 0.4 0.9
#> B 0.9 0.3 0.5 0.6 1.0 0.6 0.8 0.8 0.8 0.1
#> C 0.9 0.4 0.3 0.3 0.4 0.6 0.3 0.5 0.2 0.3
#> D 0.3 0.6 0.8 0.3 0.9 0.7 0.8 0.1 0.2 1.0
#> E 0.3 0.3 0.9 0.8 0.6 0.9 0.6 0.2 0.2 0.2
#> F 0.6 0.7 0.2 0.6 0.4 0.4 0.9 0.2 0.3 0.4
#> G 0.2 0.0 0.1 0.0 0.6 0.4 0.0 0.2 0.8 0.3
#> H 0.5 0.9 0.8 0.3 0.5 0.3 0.5 0.9 0.2 0.5
#> I 0.5 0.5 1.0 0.2 0.1 0.4 0.1 0.5 0.1 0.3
#> J 1.0 0.7 0.3 0.6 0.9 0.6 0.3 0.0 1.0 0.3

# engineering format
Format(x, fmt="eng",  digits=2)
#>  [1] 314.16e-12   3.14e-09  31.42e-09 314.16e-09   3.14e-06  31.42e-06
#>  [7] 314.16e-06   3.14e-03  31.42e-03 314.16e-03   3.14e+00  31.42e+00
#> [13] 314.16e+00   3.14e+03  31.42e+03 314.16e+03   3.14e+06  31.42e+06
#> [19] 314.16e+06   3.14e+09  31.42e+09
Format(x, fmt="engabb", ldigits=2, digits=2)
#>  [1] 314.16 p  03.14 n  31.42 n 314.16 n  03.14 u  31.42 u 314.16 u  03.14 m
#>  [9]  31.42 m 314.16 m   03.14    31.42   314.16   03.14 k  31.42 k 314.16 k
#> [17]  03.14 M  31.42 M 314.16 M  03.14 G  31.42 G
# combine with grams [g]
paste(Format(x, fmt="engabb", ldigits=2, digits=2), "g", sep="")
#>  [1] "314.16 pg" "03.14 ng"  "31.42 ng"  "314.16 ng" "03.14 ug"  "31.42 ug" 
#>  [7] "314.16 ug" "03.14 mg"  "31.42 mg"  "314.16 mg" "03.14 g"   "31.42 g"  
#> [13] "314.16 g"  "03.14 kg"  "31.42 kg"  "314.16 kg" "03.14 Mg"  "31.42 Mg" 
#> [19] "314.16 Mg" "03.14 Gg"  "31.42 Gg" 

# example form symnum
pval <- rev(sort(c(outer(1:6, 10^-(1:3)))))
noquote(cbind(Format(pval, fmt="p"), Format(pval, fmt="*")))
#>       [,1]   [,2]
#>  [1,] 0.6000     
#>  [2,] 0.5000     
#>  [3,] 0.4000     
#>  [4,] 0.3000     
#>  [5,] 0.2000     
#>  [6,] 0.1000 .   
#>  [7,] 0.0600 .   
#>  [8,] 0.0500 *   
#>  [9,] 0.0400 *   
#> [10,] 0.0300 *   
#> [11,] 0.0200 *   
#> [12,] 0.0100 **  
#> [13,] 0.0060 **  
#> [14,] 0.0050 **  
#> [15,] 0.0040 **  
#> [16,] 0.0030 **  
#> [17,] 0.0020 **  
#> [18,] 0.0010 *** 

# use Fmt() to get and define new formats stored as option
Fmt()                        # all defined formats
#> $abs
#>  Description:   Number format for counts
#>  Definition:    digits=0, big.mark="'"
#>  Example:       314'159
#> 
#> $per
#>  Description:   Percentage number format
#>  Definition:    digits=1, fmt='%'
#>  Example:       31415926.5%
#> 
#> $num
#>  Description:   Number format for floats
#>  Definition:    digits=3, big.mark="'"
#>  Example:       314'159.265
#> 
Fmt("abs")                   # only format named "abs"
#>  Description:   Number format for counts
#>  Definition:    digits=0, big.mark="'"
#>  Example:       314'159
Fmt("nexist")                # only format named "nexist" (nonexisting)
#> NULL
Fmt("abs", "per", "nexist")
#> $abs
#>  Description:   Number format for counts
#>  Definition:    digits=0, big.mark="'"
#>  Example:       314'159
#> 
#> $per
#>  Description:   Percentage number format
#>  Definition:    digits=1, fmt='%'
#>  Example:       31415926.5%
#> 
#> $<NA>
#> NULL
#> 
Fmt("abs", digits=3)         # get Fmt("abs") and overwrite digits
#>  Description:   Number format for counts
#>  Definition:    digits=3, big.mark="'"
#>  Example:       314'159.265
Fmt("abs", na.form="-")      # get Fmt("abs") and add user defined na.form
#>  Description:   Number format for counts
#>  Definition:    digits=0, big.mark="'", na.form="-"
#>  Example:       314'159

# define totally new format and store as option
Fmt(nob=as.fmt(digits=10, na.form="nodat"))
#> $abs
#>  Description:   Number format for counts
#>  Definition:    digits=0, big.mark="'"
#>  Example:       314'159
#> 
#> $per
#>  Description:   Percentage number format
#>  Definition:    digits=1, fmt='%'
#>  Example:       31415926.5%
#> 
#> $num
#>  Description:   Number format for floats
#>  Definition:    digits=3, big.mark="'"
#>  Example:       314'159.265
#> 

# overwrite an existing format
Fmt(nob=Fmt("nob", digits=5))
#> $abs
#>  Description:   Number format for counts
#>  Definition:    digits=0, big.mark="'"
#>  Example:       314'159
#> 
#> $per
#>  Description:   Percentage number format
#>  Definition:    digits=1, fmt='%'
#>  Example:       31415926.5%
#> 
#> $num
#>  Description:   Number format for floats
#>  Definition:    digits=3, big.mark="'"
#>  Example:       314'159.265
#> 
#> $nob
#>  Description:   Number format
#>  Definition:    digits=10, na.form='nodat'
#>  Example:       314159.2653589793
#> 
Fmt("nob")
#>  Description:   Number format
#>  Definition:    digits=5, na.form='nodat'
#>  Example:       314159.26536

# change the character to be used as the decimal point
opt <- options(OutDec=",")
Format(1200, digits=2, big.mark = ".")
#> [1] 1.200,00
options(opt)