I am looking for rounding up behaviour for numbers like 0.1298 to be displayed as 0.130 while keeping the trailing zero as a significant digit. This also needs to work for tables where the length of the decimals is different. I use signif() to round the data and it works fine except R loses the trailing zero, but it is needed for accuracy. Is there a working function for this?
does anyone have a good idea for me? Thanks a lot already!
I have tried modifying signif
mod_signif <- function(x,digits) {
sprintf(paste0('%#.',3,'g'), signif(x,digits))}
and this works fine for numbers up to 5 decimal places, after which the scientific writing kicks in.
> mod_signif(0.129554,3)
[1] "0.130"
> mod_signif(0.0129554,3)
[1] "0.0130"
> mod_signif(0.00129554,3)
[1] "0.00130"
> mod_signif(0.000129554,3)
[1] "0.000130"
> mod_signif(0.0000129554,3)
[1] "1.30e-05"
I would expect 0.0000130 in this case
If I try to counteract this with the format() function, I start going in circles because then i am going back to numeric and lose the zero again....
You could use scales::label_number()
. Because of the way the labelers within the scales package work, this requires creating a function within the body of another function.
Also note that you'll need to do some simple arithmetic to convert from arguments that signif()
expects to those that label_number()
expects.
library(scales)
label_nicely <- function(number, digits){
## I stole this from the documentation for base::round
## Pretty neat, huh?
round_to <- digits - ceiling(log10(abs(number)))
value <- round(number, round_to)
## accuracy is expected to be (e.g.) 0.01 rather than, say, 3
accuracy_arg <- 1 / 10^round_to
## Construct a labeller within the function run
labeller <- label_number(accuracy = accuracy_arg)
label <- labeller(value)
return(label)
}
label_nicely(0.129554,3)
#> [1] "0.130"
label_nicely(0.0000129554, 3)
#> [1] "0.0000130"
Created on 2023-09-15 with reprex v2.0.2
Edit:
The description of base::round
tell us that signif(n, x)
is equivalent to round(n, x - ceiling(log10(abs(n)))
. Using that trick, we can convert from 'significant digits' to 'actual digits', which we can pass to the accuracy
argument of label_number()
to get the required behaviour.