conditional style of gt summary row in R - r

I have the following table.
I would like to put yellow highlight only in the cells in the "my_sum" row when the value is greater than 0. How can I do this for grouped data? I assume some type of function to recognize the grouping in the data put into the tab_style?
Here is my reprex
library(gt)
library(tidyverse)
tibble(cars = c("honda", "honda",
"ford", "ford"),
mpg = c(24, 22,
NA, NA),
wt = c(NA, NA,
3432, 4234)
) %>%
group_by(cars) %>%
gt() %>%
fmt_missing(columns = everything(),
missing_text = "") %>%
summary_rows(
groups = TRUE,
columns = c(mpg:wt),
fns = list("my_sum" = ~sum(., na.rm = TRUE)),
missing_text = "",
formatter = fmt_number,
decimals = 0
) %>%
grand_summary_rows(
columns = c(mpg:wt),
fns = list("my_big_sum" = ~sum(., na.rm = TRUE)),
missing_text = "",
formatter = fmt_number,
decimals = 0
) %>%
tab_options(
row_group.font.weight = "bold"
) %>%
tab_style(
style = list(
cell_fill(color = "#d4ebf2")
),
locations = cells_grand_summary(
columns = c("mpg", "wt")
)
) %>%
tab_style(
style = list(
cell_fill(color = "#FFFFE0")
),
locations = cells_summary(
columns = c("mpg", "wt")
)
)

this answer is a bit hacky and manual but it works. first you save your table as an object. then you can directly access the table styles and manually modify them.
library(gt)
library(tidyverse)
tibble(cars = c("honda", "honda",
"ford", "ford"),
mpg = c(24, 22,
NA, NA),
wt = c(NA, NA,
3432, 4234)
) %>%
group_by(cars) %>%
gt() %>%
fmt_missing(columns = everything(),
missing_text = "") %>%
summary_rows(
groups = TRUE,
columns = c(mpg:wt),
fns = list("my_sum" = ~sum(., na.rm = TRUE)),
missing_text = "",
formatter = fmt_number,
decimals = 0 ) %>%
grand_summary_rows(
columns = c(mpg:wt),
fns = list("my_big_sum" = ~sum(., na.rm = TRUE)),
missing_text = "",
formatter = fmt_number,
decimals = 0
) %>%
tab_options(
row_group.font.weight = "bold"
) %>%
tab_style(
style = list(
cell_fill(color = "#d4ebf2")
),
locations = cells_grand_summary(
columns = c("mpg", "wt")
)
) %>%
tab_style(
style = list(
cell_fill(color = "#FFFFE0")
),
locations = cells_summary(
columns = c("mpg", "wt"),
rows = "my_sum" )
) -> t1
x1 <- t1$`_styles`$styles[4]
x2 <- t1$`_styles`$styles[3]
x2[[1]]$cell_fill$color <- "#FFFFFF"
t1$`_styles`$styles[3] <- x1
t1$`_styles`$styles[4] <- x2
t1$`_styles`$styles[6] <- x1
t1$`_styles`$styles[5] <- x2

Related

How to customize background colors based on (characters, NA) contents in multiple columns using gt

Based on the code and data from this link, we can set background colors for the cells of multiple columns based on string contents using gt package:
library(gt)
library(tidyverse)
id <- c(1,2,3,4,5)
res1 <- c("true", "true", "false", "true", "false")
res2 <- c("false", NA, NA, "true", "true")
res3 <- c("true", NA, NA, "true", "true")
df <- data.frame(id, res1, res2, res3)
df %>%
gt() %>%
data_color(
columns = c("res1", "res2", 'res3'),
colors = c("green", "red", 'gray'),
apply_to = "fill",
autocolor_text = FALSE)
But as you may noticed, for res3, the color for true is green instead of red as in other two columns. If I hope to set red for true, green for false and gray for NA, for these 3 columns, if in case, they have other values such as yes, no, etc., just keep as original.
How could we solve this problem? Many thanks at advance.
Update1: an alternative solution with tab_style(), but not concise:
df %>%
gt() %>%
tab_style(
style = list(
cell_fill(color = 'red')
),
locations = cells_body(
columns = res1,
rows = res1 == "true"
)
) %>%
tab_style(
style = list(
cell_fill(color = 'red')
),
locations = cells_body(
columns = res2,
rows = res2 == "true"
)
) %>%
tab_style(
style = list(
cell_fill(color = 'red')
),
locations = cells_body(
columns = res3,
rows = res3 == "true"
)
) %>%
tab_style(
style = list(
cell_fill(color = 'green')
),
locations = cells_body(
columns = res1,
rows = res1 == "false"
)
) %>%
tab_style(
style = list(
cell_fill(color = 'green')
),
locations = cells_body(
columns = res2,
rows = res2 == "false"
)
) %>%
tab_style(
style = list(
cell_fill(color = 'green')
),
locations = cells_body(
columns = res3,
rows = res3 == "false"
)
) %>%
tab_style(
style = list(
cell_fill(color = 'gray')
),
locations = cells_body(
columns = res1,
rows = res1 == NA
)
) %>%
tab_style(
style = list(
cell_fill(color = 'gray')
),
locations = cells_body(
columns = res2,
rows = res2 == NA
)
) %>%
tab_style(
style = list(
cell_fill(color = 'gray')
),
locations = cells_body(
columns = res3,
rows = res3 == NA
)
)
Update2: How to correctly set gray color for NA cells?
cols <- c('res1', 'res2', 'res3')
df %>%
# mutate_each_(funs(factor(.)), cols)
mutate_at(cols, factor) %>%
gt() %>%
data_color(
columns = cols,
colors = scales::col_factor(
palette = c('green', 'red', 'gray'),
domain = c('false', 'true', NA)
),
apply_to = "fill",
autocolor_text = FALSE
)
Update3: I set palette = c("green", "red", 'yellow'), domain = c("false", "true", '-'), why it's not shown green for false, red for true, and yellow for -?
id <- c(1, 2, 3, 4, 5)
res1 <- c("true", "true", "false", "true", "false")
res2 <- c("false", NA, NA, "true", "-")
res3 <- c("true", NA, NA, "true", "true")
df <- data.frame(id, res1, res2, res3)
df %>%
mutate_at(cols, factor) %>%
gt() %>%
data_color(
columns = cols,
colors = scales::col_factor(
palette = c("green", "red", 'yellow'),
domain = c("false", "true", '-'),
na.color = 'gray'
),
apply_to = "fill",
autocolor_text = FALSE
)
References:
Set background color if one cell's (of multiple columns) content is specific string using gt package
With regard to Update 2, the version with character strings, this should work:
df %>%
mutate_at(cols, factor) %>%
gt() %>%
data_color(
columns = cols,
colors = scales::col_factor(
palette = c("green", "red"),
domain = c("false", "true")
),
apply_to = "fill",
autocolor_text = FALSE
)
It's not a good idea to store your logical values as character strings. If you use TRUE and FALSE values instead, gt() works as designed to give you the table coloring you want.
id <- c(1,2,3,4,5)
res1 <- c(TRUE, TRUE, FALSE, TRUE, FALSE)
res2 <- c(FALSE, NA, NA, TRUE, TRUE)
res3 <- c(TRUE, NA, NA, TRUE, TRUE)
df2 <- data.frame(id, res1, res2, res3)
df2 %>%
gt() %>%
data_color(
columns = c(res1, res2, res3),
colors = scales::col_factor(
palette = c("green", "red"),
domain = c(FALSE, TRUE)
),
apply_to = "fill",
autocolor_text = FALSE
)
If there's some reason you have to have the logicals as character strings you'll need to convert them to a factor and adjust the domain argument in data_color().

Missing diacritics in GT table output

I am using GT package in R to create tables for my diploma thesis and I ran into a problem. The diploma is to be written in the czech language.
When GT draws the table it does not display the letter ě properly and shows e instead.
The code for GT table:
desc_sex[,2:ncol(desc_sex)] %>% gt(rowname_col = "sex"
) %>% tab_stubhead(
label = html("Kategorie")
) %>% cols_align(
align = "center",
columns = everything()
) %>% cols_label(
n = html("n"),
procent = html("%")
) %>% tab_row_group(
label = html("<b>Sledované regiony celkem"),
rows = 7:9
) %>% tab_row_group(
label = html("<b>Krajský soud v Ostravě"),
rows = 4:6
) %>% tab_row_group(
label = html("<b>Městský soud v Praze"),
rows = 1:3
) %>% summary_rows(
groups = T,
fns = list(
Celkem = ~sum(.)),
formatter = fmt_number,
decimals = 0
)
Here are the data in CSV compliant format:
"reg_reside","sex","n","procent","single"
"MSPH","Muž",93,46.5,52
"MSPH","Žena",83,41.5,34
"MSPH","Manželský pár",24,12,0
"KSOS","Muž",113,56.5,51
"KSOS","Žena",68,34,30
"KSOS","Manželský pár",19,9.5,0
"Celkem","Muž",206,51.5,103
"Celkem","Žena",151,37.8,64
"Celkem","Manželský pár",43,10.8,0
Here is how the output looks in GT - the mistake is in Ostrave (should be Ostravě) and Mestsky (should be Městský):
You can try using html entities like i.e. ě = &ecaron;
desc_sex[,2:ncol(desc_sex)] %>%
gt(rowname_col = "sex") %>%
tab_stubhead(label = html("Kategorie")) %>%
cols_align(align = "center",columns = everything()) %>%
cols_label(n = html("n"),
procent = html("%")) %>%
tab_row_group(label = html("<b>Sledované regiony celkem"),
rows = 7:9) %>%
tab_row_group(label = html("<b>Krajský soud v Ostrav&ecaron;"),
rows = 4:6) %>%
tab_row_group(label = html("<b>M&ecaron;stský soud v Praze"),
rows = 1:3) %>%
summary_rows(groups = T,
fns = list(Celkem = ~sum(.)),
formatter = fmt_number,
decimals = 0)

Set the alignment of columns based on their data type using gt package

Given a data sample and gt code to plot table below:
df <- structure(list(category = c("food", "food", "food", "food", "electronic product",
"electronic product", "electronic product", "electronic product"
), type = c("vegetable", "vegetable", "fruit", "fruit", "computer",
"computer", "other", "other"), variable = c("cabbage", "radish",
"apple", "pear", "monitor", "mouse", "camera", "calculator"),
price = c(6, 5, 3, 2.9, 2000, 10, 600, 35), quantity = c(2L,
4L, 5L, 10L, 1L, 3L, NA, 1L)), class = "data.frame", row.names = c(NA,
-8L))
To plot:
dt <- df %>%
group_by(category) %>%
gt() %>%
tab_header(
title = md("Category name")
)%>%
tab_style(
locations = cells_column_labels(columns = everything()),
style = list(
#Give a thick border below
cell_borders(sides = "bottom", weight = px(3)),
#Make text bold
cell_text(weight = "bold")
)
) %>%
tab_style(
locations = cells_row_groups(groups = everything()),
style = list(
cell_text(weight = "bold")
)
) %>%
cols_align(align = "center", columns = everything())
dt
Out:
Now I hope to custom cols_align() to align columns type, variable, price and quantity based on their datatype, if the datatype is character using center, if is number then using left.
How could I modify the code achieve that? Thanks.
cols_align() accepts tidyselect semantics, so you can use:
library(dplyr)
library(gt)
df %>%
group_by(category) %>%
gt() %>%
tab_header(
title = md("Category name")
)%>%
tab_style(
locations = cells_column_labels(columns = everything()),
style = list(
#Give a thick border below
cell_borders(sides = "bottom", weight = px(3)),
#Make text bold
cell_text(weight = "bold")
)
) %>%
tab_style(
locations = cells_row_groups(groups = everything()),
style = list(
cell_text(weight = "bold")
)
) %>%
cols_align(align = "center", columns = where(is.character)) %>%
cols_align(align = "left", columns = where(is.numeric))

gt summary rows - position label in existing column

I have created a gt table and I want to have a row at the bottom of the table with the sum of all the columns. I want to position this so that the row label "total" sits within an existing column (the column catchment in my example) rather than out to the side. How do I do this?
library(gt) # package for making tables
library(tidyverse)
library(webshot)
webshot::install_phantomjs()
Lake_name <- c("Okareka", "Okaro", "Okataina", "Rerewhakaaitu", "Rotokakahi", "Rotomahana", "Tarawera", "Tikitapu")
Lake_labels <- c("\u14ckareka", "\u14ckaro", "\u14ckataina", "Rerewhakaaitu", "Rotokakahi", "Rotomahana", "Tarawera", "Tikitapu")
#define catchment areas
LIDAR_areas <- c(19778484, 3679975, 62923350, 52941258, 19195848, 83698343, 145261086, 5728184) # m^2
White_SW_areas <- c(19963914.610, 3675087.968, 66900327.220, 54581284.030, 19207814.960, 83724917.460, 144895034.400, 5689356.743)
White_GW_areas <- c(12485786, 3675525, 70924376, 15180499, 13491567, 101632751, 159285183, 5604187)
Catchment_Areas <- as_tibble(cbind(Lake_labels, LIDAR_areas, White_SW_areas, White_GW_areas))
Catchment_Areas$LIDAR_areas <- as.numeric(Catchment_Areas$LIDAR_areas)
Catchment_Areas$White_SW_areas <- as.numeric(Catchment_Areas$White_SW_areas)
Catchment_Areas$White_GW_areas <- as.numeric(Catchment_Areas$White_GW_areas)
f <- function(x){(x/1000000)}
Catchment_Areas <- Catchment_Areas %>% mutate(across(c(LIDAR_areas, White_GW_areas, White_SW_areas), f))
Catchment_Areas_Table <-
Catchment_Areas %>%
gt() %>%
tab_header(title = md("**Catchment Areas (m<sup>2</sup> x 10<sup>6</sup>)**")) %>%
fmt_number(columns = c(LIDAR_areas, White_GW_areas, White_SW_areas), decimals = 2) %>%
cols_align(columns = c(LIDAR_areas, White_GW_areas, White_SW_areas), align = "right") %>%
cols_label(Lake_labels = "Catchment", LIDAR_areas = "Surface Water (LIDAR)", White_SW_areas = "Surface Water (White 2020)", White_GW_areas = "Groundwater (White 2020)") %>%
tab_style( # add black underline
style = list(
cell_borders(
sides = c("bottom"),
color = "black",
weight = px(2)
)#,
#cell_fill(color = "grey")
),
locations = list(
cells_column_labels(
columns = gt::everything()
)
)
) %>%
tab_style( # add black underline
style = list(
cell_borders(
sides = c("top"),
color = "black",
weight = px(2)
)#,
#cell_fill(color = "grey")
),
locations = list(
cells_title()
)
)
Catchment_Areas_Table %>% summary_rows(columns = c(LIDAR_areas, White_GW_areas, White_SW_areas), fns = list(Total = "sum"))
Option 1: Move your "Catchment"/Lake_labels column into `gt(rowname_col = "Lake_labels"), this moves them into the "stub" and aligns with the summary calculations.
Option 2: Pre-calculate the summary rows ahead of time. This means you can treat the summary row as another other cell value.
Reprex below (note that I converted your dataframe to a tribble so it's more compact to reprex, datapasta::tribble_paste() is amazing for this):
library(gt) # package for making tables
library(tidyverse)
library(webshot)
Catchment_Areas <- tibble::tribble(
~Lake_labels, ~LIDAR_areas, ~White_SW_areas, ~White_GW_areas,
"Ōkareka", 19.778484, 19.96391461, 12.485786,
"Ōkaro", 3.679975, 3.675087968, 3.675525,
"Ōkataina", 62.92335, 66.90032722, 70.924376,
"Rerewhakaaitu", 52.941258, 54.58128403, 15.180499,
"Rotokakahi", 19.195848, 19.20781496, 13.491567,
"Rotomahana", 83.698343, 83.72491746, 101.632751,
"Tarawera", 145.261086, 144.8950344, 159.285183,
"Tikitapu", 5.728184, 5.689356743, 5.604187
)
### Option 1
Catchment_Areas_Table <-
Catchment_Areas %>%
gt(rowname_col = "Lake_labels") %>%
tab_header(title = md("**Catchment Areas (m<sup>2</sup> x 10<sup>6</sup>)**")) %>%
fmt_number(columns = c(LIDAR_areas, White_GW_areas, White_SW_areas), decimals = 2) %>%
cols_align(columns = c(LIDAR_areas, White_GW_areas, White_SW_areas), align = "right") %>%
cols_label(Lake_labels = "Catchment", LIDAR_areas = "Surface Water (LIDAR)",
White_SW_areas = "Surface Water (White 2020)", White_GW_areas = "Groundwater (White 2020)") %>%
tab_style( # add black underline
style = list(
cell_borders(
sides = c("bottom"),
color = "black",
weight = px(2)
) # ,
# cell_fill(color = "grey")
),
locations = list(
cells_column_labels(
columns = gt::everything()
)
)
) %>%
tab_style( # add black underline
style = list(
cell_borders(
sides = c("top"),
color = "black",
weight = px(2)
)
),
locations = list(
cells_title(),
cells_stub(rows = 1)
)
) %>%
summary_rows(
columns = c(LIDAR_areas, White_GW_areas, White_SW_areas),
fns = list(Total = "sum")
)
#> Warning in if ((loc$groups %>% rlang::eval_tidy()) == "title") {: the condition
#> has length > 1 and only the first element will be used
gtsave(Catchment_Areas_Table, "rowname_tab.png")
### Option 2
# Create summary ahead of time, add to bottom of the existing df.
Catchment_Areas_Sum <- Catchment_Areas %>%
add_row(
Catchment_Areas %>%
summarise(across(LIDAR_areas:last_col(), sum)) %>%
mutate(Lake_labels = "Total")
)
Catchment_Areas_Table_Sum <-
Catchment_Areas_Sum %>%
gt() %>%
tab_header(title = md("**Catchment Areas (m<sup>2</sup> x 10<sup>6</sup>)**")) %>%
fmt_number(columns = c(LIDAR_areas, White_GW_areas, White_SW_areas), decimals = 2) %>%
cols_align(columns = c(LIDAR_areas, White_GW_areas, White_SW_areas), align = "right") %>%
cols_label(Lake_labels = "Catchment", LIDAR_areas = "Surface Water (LIDAR)",
White_SW_areas = "Surface Water (White 2020)", White_GW_areas = "Groundwater (White 2020)") %>%
tab_style( # add black underline
style = list(
cell_borders(
sides = c("bottom"),
color = "black",
weight = px(2)
)
),
locations = list(
cells_column_labels(
columns = gt::everything()
)
)
) %>%
tab_style( # add black underline
style = list(
cell_borders(
sides = c("top"),
color = "black",
weight = px(2)
)
),
locations = list(
cells_title()
)
) %>%
tab_style(
style = cell_borders(
sides = c("top"), color = "black", weight = px(2)
),
locations = list(
cells_body(rows = Lake_labels == "Total")
)
)
#> Warning in if ((loc$groups %>% rlang::eval_tidy()) == "title") {: the condition
#> has length > 1 and only the first element will be used
gtsave(Catchment_Areas_Table_Sum, "pre_sum_tab.png")
Created on 2021-10-29 by the reprex package (v2.0.1)

How to color one cell with kableExtra

I am just trying to highlight one cell in my table with kableExtra. The issue that I am having is that some of my cells have $s and ()s. Here is what it looks like
df3 <- data.frame(
"Bitcoin Price:" = c("Snow Panther B1+", "ASICminer 8 nano", "S9", "Avalon 921", "Dragonmint T1", "Edit E11++"),
"3000" = c("($270.71)", "($3376.85)", "($115.80)", "($530.81)", "($1108.14)", "($1035.42)"),
"6000" = c("$1050.37", "($1004.31)", "$666.06", "$547.62", "($245.39)", "$1337.12"),
"9000" = c("$2371.44", "$1368.24", "$1447.92", "$1626.04", "$617.35", "$3709.66"),
stringsAsFactors = FALSE, check.names=FALSE)
I have tried this but it doesn't work
df3 %>%
mutate(
`6000`[,2] = cell_spec(`6000`[,2], color = "red", bold = T)
) %>%
select("Bitcoin Price:", everything()) %>%
kable(align = "c", escape = F) %>%
kable_styling("hover", "striped", full_width = F) %>%
add_header_above(c(" " = 1, "Current Difficulty" = 3)) %>%
add_footnote(c("Statistics Calculated 2019"), notation = "symbol")
Does anyone have any suggestions? I feel like I am close. I am trying to make the cells with the value ($1004.31), red.
Is this what you are looking for?
df3 %>%
mutate(`6000` = cell_spec(`6000`, "html",color = ifelse(`6000` == "($1004.31)", "red", "grey"))) %>%
select("Bitcoin Price:", everything()) %>%
kable(align = "c", escape = F) %>%
kable_styling("hover", "striped", full_width = F) %>%
add_header_above(c(" " = 1, "Current Difficulty" = 3)) %>%
add_footnote(c("Statistics Calculated 2019"), notation = "symbol")

Resources