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