Inconsistent digits beyond decimal when combined with scientific notation kableExtra table R markdown

My problem comes from having columns that I want to format differently. I would like the same # of digits beyond the decimal point on all column, but on the final column the p-value column I'd like scientific notation to show for the really small numbers. I'd still like to have the same # of digits shown for the scientific notation beyond the decimal.

library(kableExtra)

k.table <- mlr_table3 %>%
  mutate(P_value= cell_spec((formatC(x=P_value, digits=3, width = 3, format='g', flag = "-", drop0trailing = TRUE, preserve.width = "common")), "html", color = ifelse(P_value <= 0.05, yes="red", no="blue"), escape = F)) %>% 
  mutate_if(is.numeric, function(x) {
    cell_spec((formatC(x,digits=2, width=3, format="f", flag="-", drop0trailing = FALSE)), "html")
  }) %>%
  kable("html", escape = FALSE, align = "l", caption = "Summarized linear model with SSC Data") %>%
  kable_styling(c("striped", "bordered"), full_width = F) %>%
  column_spec(1, bold = T)

print.knitr_kable(k.table)

Right now the table looks like this

Summarized linear model with SSC Data
term	 estimate	 std.error	 statistic	 P_value
(Intercept)	14.93	0.35	43.24	1.06e-173
Cortland	-5.58	1.00	-5.58	3.86e-08
Fire 	    -4.00	1.68	-2.38	0.0179
Frost   	-1.64	1.09	-1.51	0.132
Haral   	-5.32	1.09	-4.90	1.28e-06
HoneyA  	-4.81	1.11	-4.35	1.63e-05
HoneyB	    -0.97	1.09	-0.89	0.373
Sake	    -2.12	1.09	-1.95	0.0517
Mac	        -1.88	1.14	-1.65	0.1
Sweet       -1.71	1.09	-1.57	0.116

It would really help if you supplied a reproducible example, since I don't know what your un-formatted numbers are. However, adding some arbitrary extra precision for demonstration, how about something like this:

suppressPackageStartupMessages(library(tidyverse))

formatme <- tribble(
  ~estimate, ~P_value, 
   14.93423,  1.064325e-173, 
   -5.58189,  3.863223e-08 , 
   -4.00146,  0.01792431   , 
   -1.64129,  0.1321123    , 
   -5.32435,  1.282435e-06 , 
   -4.81021,  1.634358e-05 , 
   -0.97118,  0.373213     , 
   -2.12204,  0.051729     , 
   -1.88072,  0.1          , 
   -1.71032,  0.116
)

formatme %>% 
mutate(
  P_value = if_else(
    P_value < 0.01, 
    formatC(P_value, digits = 2, format = "e"), 
    formatC(P_value, digits = 2, format = "f", drop0trailing = FALSE)
  )
) %>% 
mutate_if(
  is.numeric, 
  function(x) {
    formatC(x, digits = 2, format = "f", drop0trailing = FALSE)
  }
)
#> # A tibble: 10 x 2
#>    estimate P_value  
#>    <chr>    <chr>    
#>  1 14.93    1.06e-173
#>  2 -5.58    3.86e-08 
#>  3 -4.00    0.02     
#>  4 -1.64    0.13     
#>  5 -5.32    1.28e-06 
#>  6 -4.81    1.63e-05 
#>  7 -0.97    0.37     
#>  8 -2.12    0.05     
#>  9 -1.88    0.10     
#> 10 -1.71    0.12

Notes

  • You'd want to choose your own threshold for the conditional application of formats to P_value — I just guessed at a reasonable value.
  • I simplified some of the formatC options, but since I don't know exactly what your actual data look like and what you want, you might need to add some back. However, since you're outputting as HTML (via kableExtra), setting width and left-adjustment (flag = "-") won't do much, because HTML ignores extra whitespace.
  • I left out the calls to kableExtra::cell_spec because your problem is with formatC, and I wanted to make the above reprex output clearer. Here's what the example looks like with the kableExtra bits:
formatme %>% 
  mutate(
    P_value = cell_spec(
      if_else(
        P_value < 1e-02, 
        formatC(P_value, digits = 2, format = "e"),
        formatC(P_value, digits = 2, format = "f")
      ),
      format = "html",
      color = ifelse(P_value <= 0.05, yes = "red", no = "blue"),
      escape = F
    )
  ) %>%
  mutate_if(
    is.numeric, 
    function(x) {
      cell_spec(
        formatC(x, digits = 2, format = "f", drop0trailing = FALSE),
        format = "html"
      )
    }
  )
3 Likes