Home > Back-end >  PDF Kable Overlapping Striping/Highlighting
PDF Kable Overlapping Striping/Highlighting

Time:09-30

I'm using kable to produce tables for an Rmarkdown PDF document. I want to highlight certain cells based on their value, and every other row has a stripe. The image below shows this, as well as the issue I'm having (taken from my Adobe PDF reader). As you can see, the highlight color in the middle row (for Chinstrap penguins) is not quite even with the other two. This is a small issue but is enough to make the table look a bit janky, so I'm hoping someone can help me find a fix, or at least explain the cause.

Table view in Adobe

What's odd is that this issue seems to depend on which PDF reader I view the document in. The initial image came from Adobe, but when I open the file in SumatraPDF (the default viewer that my RStudio knits to) the highlighting is consistent for all rows (see next image). This behavior doesn't seem to depend on zoom level in the PDF viewer, but could be related to another setting I'm not aware of.

Table view in SumatraPDF

The issue itself seems to be caused by the light blue striping rather than the highlight itself, because when I remove the striping all three highlights are even in both PDF viewers. This behavior can also be demonstrated without the extra highlighting by instead adding cell borders to the table using column_spec(c(2:3), width = "2.1cm", border_right = T) as shown in the final image. In two of three rows, the 2nd column's right border is covered up by the striping (this also happens with the built-in striping feature in kableExtra). One interesting thing to note here is that this does seem to depend on PDF viewer zoom level. The image below came from Adobe at my default view (75.5), but when I change the zoom to between 100 and 200 all cell borders are correct, and then disappear again after that. My code is below, thanks for your help!

enter image description here

Reproducible Example

---
title: "Kable Highlighting Issue"
output: pdf_document
header-includes:
- \usepackage{booktabs}
- \usepackage{longtable}
- \usepackage{array}
- \usepackage{multirow}
- \usepackage{wrapfig}
- \usepackage{float}
- \usepackage{colortbl}
- \usepackage{pdflscape}
- \usepackage{tabu}
- \usepackage{threeparttable}
- \usepackage{threeparttablex}
- \usepackage[normalem]{ulem}
- \usepackage{makecell}
- \usepackage{titling}
- \usepackage{graphicx}
---
knitr::opts_chunk$set(echo = TRUE)
library(palmerpenguins)
library(dplyr)
library(stringr)
library(knitr)
library(kableExtra)

#create table data
table_data <- penguins %>%
  group_by(species) %>%
  summarise(bill_length_mm= round(mean(bill_length_mm, na.rm = TRUE), digits=2),
            bill_depth_mm= round(mean(bill_depth_mm, na.rm = TRUE), digits=2)) %>%
  mutate(across(everything(), as.character)) %>%
  rename(length= bill_length_mm, depth= bill_depth_mm) #_ is an escaped character in Latex

#add general table striping
#the default Kable striping feature will overwrite the highlighting, so this is an alternative way to add that
#perhaps there's something simpler?
for (row in c(1,3)){
  for (col in c(1,3)){
    table_data[row,col] <- cell_spec(table_data[row,col], "latex", background = "#ddf1f7")
  }
}

#add table highlighting if bill length > 40mm 
for (p in table_data$species){
  row <- which(table_data[1]==p)
  
  if (table_data[row, 2] > 40){
    table_data[row, 2] <- cell_spec(table_data[row, 2], "latex", background = "#00cc66")
  } else {
    table_data[row, 2] <- cell_spec(table_data[row, 2], "latex", background = "#ff704d")
  }
}

#create table
penguin_table <- kable(table_data, format = "latex", booktabs = TRUE, linesep="", escape = FALSE, align=c("l","c","c")) %>%
  kable_styling(latex_options = c("scale_down", "hold_position"), position = "center", font_size =12) %>%
  row_spec(0, bold = TRUE, hline_after = TRUE) %>%
  column_spec(1, width = "5cm") %>%
  column_spec(c(2:3), width = "2.1cm")

penguin_table

Session Info

R version 4.0.3 (2020-10-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19042)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] kableExtra_1.3.4     knitr_1.33           stringr_1.4.0       
[4] dplyr_1.0.4          palmerpenguins_0.1.0

loaded via a namespace (and not attached):
 [1] pillar_1.4.7      compiler_4.0.3    tools_4.0.3       digest_0.6.27    
 [5] evaluate_0.14     lifecycle_1.0.0   tibble_3.0.4      viridisLite_0.3.0
 [9] pkgconfig_2.0.3   rlang_0.4.10      DBI_1.1.0         cli_2.4.0        
[13] rstudioapi_0.13   xfun_0.23         httr_1.4.2        xml2_1.3.2       
[17] generics_0.1.0    vctrs_0.3.5       systemfonts_1.0.1 webshot_0.5.2    
[21] tidyselect_1.1.0  svglite_2.0.0     glue_1.4.2        R6_2.5.0         
[25] rmarkdown_2.8     purrr_0.3.4       magrittr_2.0.1    scales_1.1.1     
[29] ellipsis_0.3.1    htmltools_0.5.0   assertthat_0.2.1  rvest_0.3.6      
[33] colorspace_2.0-0  stringi_1.5.3     munsell_0.5.0     crayon_1.3.4

CodePudding user response:

Rendering a pdf_document relies on generating intermediate latex code, which gets processed in your latex interpreter to build a document. For any issue with your pdf document, I can recommend looking at the underlying latex code (by adding keep_tex as output argument.

In your case, table code is generated, with the following lines:

\midrule
\cellcolor[HTML]{ddf1f7}{Adelie} & \cellcolor[HTML]{ff704d}{38.79} & \cellcolor[HTML]{ddf1f7}{18.35}\\
Chinstrap & \cellcolor[HTML]{00cc66}{48.83} & 18.42\\
\cellcolor[HTML]{ddf1f7}{Gentoo} & \cellcolor[HTML]{00cc66}{47.5} & \cellcolor[HTML]{ddf1f7}{14.98}\\
\bottomrule

What causes the issues is that the \cellcolor leads to colored boxes being drawn of the final pdf. Adobe reader has some trouble rendering those nicely at various zoom levels, and you'll find that bordering boxes compete a bit over which pixel gets which color. The 'white' row has no background color set, so the red/green box has no other box to compete with, and gets a bit more space to be rendered.

For further background on the latex issues causing this, you might want to look here

Since you're already manually adding cell_spec to your rows, why not explicitly set the background color of your even rows to white?

for (row in 1:nrow(table_data)){
  color = ifelse(row %%2 ==1, "#ddf1f7", "#ffffff")
  for (col in c(1,3)){
    table_data[row,col] <- cell_spec(table_data[row,col], "latex", background = color)
  }
}

This will yields a nice, crisp table, where at least all space-competing issues are solved equally.

  • Related