I know this question has been asked and answered so many time over but I can't find the answer that applies to my custom function. I've modified gtExtras::gt_plt_bar_stack()
and have everything in place except the bars aren't ordered correctly. The correct bar is colored in my example below, but it isn't in the middle as it should be based on the data frame supplied to it.
Code:
library(ggplot2)
library(gt)
library(dplyr)
library(glue)
# CUSTOM FUNCTION ---
gt_bar_stack_minimal <- function(gt_object, column) {
stopifnot("Table must be a gt_tbl" = "gt_tbl" %in% class(gt_object))
var_sym <- rlang::enquo(column)
col_vals <- gt_index(gt_object, {{ column }})
bar_fx <- function(values) {
if (is.null(values) || length(values) < 3) return("<div></div>")
numeric_vals <- as.numeric(values[1:3])
middle_color <- values[4] %||% "black" # Default to black if no color is provided
palette <- c("lightgrey", middle_color, "lightgrey") # First and last are always lightgrey
df <- tibble(x = numeric_vals, fill = palette, order = 1:3) # How do I presever this order
# Troubleshooting order
print(df)
plot_out <- ggplot(df, aes(x = factor(1), y = x, fill = I(fill))) +
# geom_col(width = 1, color = "white") +
geom_bar(stat = "identity", width = 1, color = "white") +
coord_flip() +
theme_void() +
theme(legend.position = "none", plot.margin = margin(0, 0, 0, 0, "pt"))
out_name <- tempfile(fileext = ".svg")
ggsave(out_name, plot = plot_out, dpi = 25.4, height = 5, width = 70, units = "mm", device = "svg")
img_plot <- readLines(out_name) %>% paste0(collapse = "") %>% gt::html()
on.exit(file.remove(out_name), add = TRUE)
img_plot
}
text_transform(gt_object, locations = cells_body({{ column }}), fn = function(x) lapply(col_vals, bar_fx))
}
# EXAMPLE USAGE ---
ex_df <- tibble(
x = c("Example 1", "Example 2", "Example 3", "Example 4"),
list_data = list(c(30, 20, 50, "blue"), c(30, 30, 40, "red"), c(30, 40, 30, "purple"), c(30, 50, 20, "orange"))
)
ex_tab <- ex_df %>%
gt() %>%
gt_bar_stack_minimal(column = list_data)
ex_tab
You have to map order
on the group
aes to stack the bars in that order. Otherwise the group
aes is set and the bars get stacked according to the fill
aes, i.e. the color names. Also note that I dropped the coord_flip
by switching x
and y`:
plot_out <- ggplot(df, aes(x = x, y = factor(1), fill = I(fill), group = order)) +
geom_col(
width = 1,
color = "white",
position = position_stack(reverse = TRUE)
) +
theme_void() +
theme(legend.position = "none", plot.margin = margin(0, 0, 0, 0, "pt"))