I want to bold cells with minimum values for one of my data frames
which I combined to be one. I want the minimum value in each column to be bolded.
The below R code shows my Minimum Working Example (MWE). The table consists of columns of five (5) randomly generated values from the normal distribution. The first three (3) show when std dev =1
while the last three (3) show when std dev =2
. Each column is different based on its seed of generation and its std dev
.
---
title: "Min Value to be Bolded"
output: pdf_document
---
```{r}
set.seed(1)
df1 <- data.frame(
seed1 = rnorm(5, mean = 0, sd = 1),
seed2 = rnorm(5, mean = 0, sd = 1),
seed3 = rnorm(5, mean = 0, sd = 1)
)
set.seed(1)
df2 <- data.frame(
seed1 = rnorm(5, mean = 0, sd = 2),
seed2 = rnorm(5, mean = 0, sd = 2),
seed3 = rnorm(5, mean = 0, sd = 2)
)
df <- cbind(df1, df2)
df |>
knitr::kable(format = "html", table.attr = "style='width:100%;'", digits = 2, align = 'c', caption = "5 Random Numbers from the Normal Dist at diff set and std dev") |>
kableExtra::kable_styling(bootstrap_options = 'bordered') |>
kableExtra::add_header_above(c('$sd = 1$' = 3, '$sd$ = 2' = 3)) |>
row_spec(3, bold=T, hline_after = TRUE)
```
Instead of me to get the minimum values bold. I got the third row bold all through. I can get the values on R
like this:
lapply(df1, 2, FUN = min)
but I need help on how to get the cells bolded with kable
or kableExtral
.
Please note I do not mean to do that for the whole data frame, I only need it for just df1
or df2
.
You may add library(formattable)
and then
df |>
lapply(\(x){ifelse(x == min(x), cell_spec(round(x,2), bold = TRUE), round(x,2))}) |>
knitr::kable(format = "html", table.attr = "style='width:100%;'", digits = 2, align = 'c',
caption = "5 Random Numbers from the Normal Dist at diff set and std dev",
escape = FALSE) |>
kableExtra::kable_styling(bootstrap_options = 'bordered') |>
kableExtra::add_header_above(c('$sd = 1$' = 3, '$sd$ = 2' = 3))
Or, if you only want for df1
you may start by
df1 |> lapply(\(x){ifelse(x == min(x), cell_spec(round(x, 2), bold = TRUE), round(x, 2))}) |> cbind(df2) |>
And for df2
df1 |> cbind(df2 |> lapply(\(x){ifelse(x == min(x), cell_spec(round(x, 2), bold = TRUE), round(x, 2))})) |>
A remark: With my solution names of dataframe become all x
. You could add as.data.frame
after the lapply
to get the original names, but in this case they become changed because df
has the names duplicated which is not a suitable practice. Instead, using col.names
you may write the desired ones, for example
df |>
lapply(\(x){ifelse(x == min(x), cell_spec(round(x,2), bold = TRUE), round(x,2))}) |>
as.data.frame() |>
knitr::kable(format = "html", table.attr = "style='width:100%;'", digits = 2, align = 'c',
caption = "5 Random Numbers from the Normal Dist at diff set and std dev",
escape = FALSE, col.names = rep(c("seed1", "seed2", "seed3"), 2)) |>
kableExtra::kable_styling(bootstrap_options = 'bordered') |>
kableExtra::add_header_above(c('$sd = 1$' = 3, '$sd$ = 2' = 3))
Note also that as comment @phiver, I had to modify output: pdf_document
to output: html_document
, since otherwise code didn't work. To get a pdf
, the last lines of the code should be as follows (then it works):
knitr::kable(format = "latex", digits = 2, align = 'c',
caption = "5 Random Numbers from the Normal Dist at diff set and std dev",
escape = FALSE, col.names = rep(c("seed1", "seed2", "seed3"), 2)) |>
kableExtra::kable_styling(bootstrap_options = 'bordered', full_width = TRUE) |>
kableExtra::add_header_above(c('$sd = 1$' = 3, '$sd$ = 2' = 3))