Colorblind-Safety
Let’s compare peRsian with the popular
viridis palette, which has specifically been designed to
handle colorblindness well, to put its the color difference scores into
perspective.
# Helper function to conveniently calculate scores and assign a palette name
calculate_palette_scores <- function(colors, palette_name, ...) {
check_results <- colorblindcheck::palette_check(colors, ...)
cbind(
data.frame(palette = palette_name),
check_results
)
}
First, we calculate the scores for viridis.
viridis_scores_df <- calculate_palette_scores(
viridisLite::viridis(8),
"viridis",
plot = TRUE
)

viridis_scores_df |>
knitr::kable(digits = 2)
| viridis |
normal |
8 |
12.45 |
28 |
28 |
12.45 |
46.62 |
100.32 |
| viridis |
deuteranopia |
8 |
12.45 |
28 |
24 |
8.43 |
39.97 |
90.16 |
| viridis |
protanopia |
8 |
12.45 |
28 |
25 |
5.34 |
41.44 |
93.43 |
| viridis |
tritanopia |
8 |
12.45 |
28 |
25 |
8.01 |
38.42 |
76.80 |
Let’s use the smallest difference in viridis as the
threshold to identify which palettes in peRsian we deem
“colorblind-safe”.
viridis_min_score <- min(viridis_scores_df$min_dist)
viridis_min_score
#> [1] 5.339964
# Create a dataframe with scores for all palettes in the package
persian_scores_df <- do.call(rbind, lapply(names(persian_palettes), function(palette_name) {
calculate_palette_scores(
persian_palette(palette_name),
palette_name,
tolerance = viridis_min_score
)
}))
Now we can use this information to only mark palettes as
colorblind-safe, where the smallest difference is above the threshold
across ALL different forms of visual perception.
# Keep only palettes where all entries are above threshold
palettes_above_threshold <- persian_scores_df |>
group_by(palette) |>
# Number of comparisons == Number of comparisons above threshold
filter(all(ncp == ndcp))
colorblind_safe_palettes <- palettes_above_threshold$palette |>
unique()
colorblind_safe_palettes
#> [1] "fery" "isfahan" "munich" "abbas" "berlin" "pooran" "hooshang"
Let’s also collect the names of all palettes that didn’t make it (use
these with caution!).
non_colorblind_safe_palettes <- names(persian_palettes)[!names(persian_palettes) %in% palettes_above_threshold$palette]
non_colorblind_safe_palettes
#> [1] "tehran" "hamburg" "leyli" "tabriz" "reyhaneh" "floral"
Ordering Palettes
Finally, we can order all palettes by their minimum color difference
(under full vision) to get a better overview of which ones are most
distinguishable and which ones may need more work.
persian_scores_df |>
filter(name == "normal") |>
arrange(desc(min_dist))
#> palette name n tolerance ncp ndcp min_dist mean_dist max_dist
#> 1 isfahan normal 6 5.339964 15 15 17.68255 35.80945 59.96357
#> 2 hooshang normal 4 5.339964 6 6 17.24044 33.19147 48.85390
#> 3 munich normal 7 5.339964 21 21 16.62231 40.89513 93.82743
#> 4 fery normal 8 5.339964 28 28 15.31689 44.03096 81.71196
#> 5 tehran normal 8 5.339964 28 28 14.66018 37.52704 71.85012
#> 6 pooran normal 6 5.339964 15 15 14.38322 35.29478 54.31265
#> 7 abbas normal 5 5.339964 10 10 13.88681 30.27786 66.84959
#> 8 leyli normal 9 5.339964 36 36 13.12127 28.13639 49.32902
#> 9 tabriz normal 6 5.339964 15 15 11.75663 27.51236 42.57928
#> 10 reyhaneh normal 4 5.339964 6 6 10.92315 22.65976 33.38325
#> 11 floral normal 5 5.339964 10 10 10.69823 22.98735 31.90445
#> 12 berlin normal 8 5.339964 28 28 10.24284 32.74987 51.84005
#> 13 hamburg normal 8 5.339964 28 28 10.06714 45.90776 81.61558
Palettes which may need adjustments:
persian_scores_df |>
filter(name == "normal") |>
arrange(min_dist)
#> palette name n tolerance ncp ndcp min_dist mean_dist max_dist
#> 1 hamburg normal 8 5.339964 28 28 10.06714 45.90776 81.61558
#> 2 berlin normal 8 5.339964 28 28 10.24284 32.74987 51.84005
#> 3 floral normal 5 5.339964 10 10 10.69823 22.98735 31.90445
#> 4 reyhaneh normal 4 5.339964 6 6 10.92315 22.65976 33.38325
#> 5 tabriz normal 6 5.339964 15 15 11.75663 27.51236 42.57928
#> 6 leyli normal 9 5.339964 36 36 13.12127 28.13639 49.32902
#> 7 abbas normal 5 5.339964 10 10 13.88681 30.27786 66.84959
#> 8 pooran normal 6 5.339964 15 15 14.38322 35.29478 54.31265
#> 9 tehran normal 8 5.339964 28 28 14.66018 37.52704 71.85012
#> 10 fery normal 8 5.339964 28 28 15.31689 44.03096 81.71196
#> 11 munich normal 7 5.339964 21 21 16.62231 40.89513 93.82743
#> 12 hooshang normal 4 5.339964 6 6 17.24044 33.19147 48.85390
#> 13 isfahan normal 6 5.339964 15 15 17.68255 35.80945 59.96357