'Kable table: how to keep duplicate rownames, add arrows to indicate effect direction and add values to the pack_rows header row
I am trying to format an ANOVA style output for my paper using kableExtra
. I want to make it automatic to avoid mistakes.
I need to glue together several ANOVA tables from different models using the same response variables. I did this using pack_rows
but since the variables' names are the same, they get numbered. I also want to round the p-values and make the significant values bold. I managed to automatize only the first (following fixp
function here)
I also want to include an extra column with R2 for the entire model which would be shown in the same row as the pack_rows
heading.
Summary:
I want my kable
table to do:
- keep the duplicate rownames without numbering them
- round the p-values, substitute very small values with <0.001, and make significant values bold
- add arrows indicating the effect direction (in my real data some of the variables are multi-level factors so double arrow is necessary, otherwise I would go for +/-)
- add a column with values on the same level as the
pack_rows
heading
What I tried:
- save rownames for each table separately as well as add it directly to
kable(file, rownames=c())
- managed to round the p-values but when the small ones are substituted with <0.001, they become factor and
column_spec
doesn't work on it if I want to make bold values less than 0.05 - not sure if it is even possible
- tried with
row_packs(extra_latex_after)
but it doesn't work. Not even sure what it does
Any help much appreciated!
An example using the airquality
data:
knitr::opts_chunk$set(echo = TRUE)
library(ggplot2)
head(airquality)
library(MuMIn)
library(tidyverse)
library(kableExtra)
library(lme4)
lm1 <- lmer(Temp ~ Ozone*Solar.R+
(1|Month), data=airquality)
table1 <- car::Anova(lm1, type = 2, test.statistic="F")
rsq1 <- r.squaredGLMM(lm1)
table1$`F` <- as.numeric(table1$`F`)
table1$Df <- as.numeric(table1$Df)
table1$`Pr(>F)` <- as.numeric(table1$`Pr(>F)`)
lm2 <- lmer(Wind ~ Ozone*Solar.R+
(1|Month), data=airquality)
table2 <- car::Anova(lm2, type = 2, test.statistic="F")
rsq2 <- r.squaredGLMM(lm2)
table2$`F` <- as.numeric(table2$`F`)
table2$Df <- as.numeric(table2$Df)
table2$`Pr(>F)` <- as.numeric(table2$`Pr(>F)`)
fixp <- function(x, dig=3){
x <- as.data.frame(x)
if(substr(names(x)[ncol(x)],1,2) != "p-value")
warning("The name of the last column didn't start with Pr. This may indicate that p-values weren't in the last row, and thus, that this function is inappropriate.")
x[,ncol(x)] <- round(x[,ncol(x)], dig)
for(i in 1:nrow(x)){
if(x[i,ncol(x)] == 0)
x[i,ncol(x)] <- paste0("< .", paste0(rep(0,dig-1), collapse=""), "1")
}
x
}
kable(rbind(fixp((table1[, c(1,2,4)])), fixp((table2[, c(1,2,4)]))), digits=3, format="html",
booktabs=T)%>%
kable_styling() %>%
pack_rows("Sleep", 1, 3, extra_latex_after = `r rsq1[,2]`) %>%
pack_rows("Body weight", 4, 6, extra_latex_after = `r rsq2[,2]`)
Table copied from HTML version to XLS and the last two columns added + bold p-values:
(when I upload this to R and make a kable
table, the last column has just the heading and values are in column 2)
Solution 1:[1]
Some ideas for 2) via the broom::tidy()
and 3)
library(kableExtra)
library(broom)
library(dplyr)
table_tidy <- table1 %>% broom::tidy() %>% rbind(table2 %>% broom::tidy())
cell_bold <- table_tidy %>% pull(p.value) < 0.05
table_tidy %>% mutate(across("p.value", ~ifelse(.x <0.001, "<0.001", as.character(round(.x, 3))))) %>%
# arrows
mutate(effect_direction = case_when(
statistic < 0 ~ "-",
statistic > 0 ~ "+",
statistic == 0 ~ "\\Updownarrow"
)) %>%
kbl(.,digits=3, format="html", booktabs=T)%>%
kable_styling() %>%
column_spec(5, bold = cell_bold)%>%
pack_rows("Sleep", 1, 3) %>%
pack_rows("Body weight", 4, 6)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |