options(knitr.kable.NA = "-")
# order puts blue and vermillion first and leaves out black and grey
okabe_ito_order <- c(5, 6, 3, 7, 2, 1, 4)
brewer <- function(name) {
function(n) RColorBrewer::brewer.pal(max(n, 3), name)[seq_len(n)]
}
palettes <- list(
"Okabe-Ito (ggokabeito)" = function(n) {
ggokabeito::palette_okabe_ito(order = okabe_ito_order)[seq_len(n)]
},
"RColorBrewer Dark2" = brewer("Dark2"),
"RColorBrewer Set2" = brewer("Set2"),
"RColorBrewer Paired" = brewer("Paired"),
"khroma muted" = function(n) unname(khroma::color("muted")(n)),
"viridis" = function(n) viridisLite::viridis(n),
"rcartocolor Safe" = function(n) rcartocolor::carto_pal(n, "Safe")
)
worst_case_distance <- function(make_palette, n) {
colors <- tryCatch(
make_palette(n),
error = function(e) NULL,
warning = function(w) NULL
)
if (is.null(colors) || length(colors) < n || anyNA(colors)) {
return(NA_real_)
}
# viridis adds an alpha channel; palette_check() wants plain "#rrggbb"
colors <- substr(as.character(colors), 1, 7)
# the first row is normal vision; the rest are the simulated deficiencies
min(colorblindcheck::palette_check(colors)$min_dist[-1])
}
expand.grid(palette = names(palettes), groups = c(3, 5, 7, 10)) |>
tibble::as_tibble() |>
dplyr::rowwise() |>
dplyr::mutate(
distance = worst_case_distance(palettes[[as.character(palette)]], groups)
) |>
dplyr::ungroup() |>
tidyr::pivot_wider(
names_from = groups,
values_from = distance,
names_prefix = "n = "
) |>
knitr::kable(digits = 1)