Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Rounding in R without loosing the trailing zero, when it is part of the significant figure

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel


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….

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading