--- title: "Analysis of Palette Colors" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Analysis of Palette Colors} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, fig.width = 9, fig.height = 3, comment = "#>" ) ``` ```{r setup} library(peRsian) library(dplyr) ``` While there is always a qualitative aspect to choosing colors for data visualizations, it's also possible to quantitatively assess how distinguishable the colors within a palette are. We can use the `colorblindcheck` package to evaluate how distinguishable the colors in each palette are, both under normal vision and various forms of colorblindness, which is particularly important for ensuring accessibility in visualizations. ## `peRsian` Palettes Let's start by listing all available palettes in the `peRsian` package. ```{r} names(persian_palettes) ``` Next, we can have a look at an evaluation of each palette using `colorblindcheck`. ```{r results='asis'} # Generate a subjeading and evaluation for each palette for(palette_name in names(persian_palettes)) { cat("\n\n### ", palette_name, "\n\n") colors <- persian_palette(palette_name) check_results <- colorblindcheck::palette_check(colors, plot = TRUE) check_results |> knitr::kable(digits = 2) |> print() } ``` ## Quantitative Comparison With the scores produced by `colorblindcheck`, we can now perform a proper quantitative analysis to check which palettes meet certain thresholds and which might need adjustments. ### 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. ```{r} # 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`. ```{r} viridis_scores_df <- calculate_palette_scores( viridisLite::viridis(8), "viridis", plot = TRUE ) viridis_scores_df |> knitr::kable(digits = 2) ``` Let's use the smallest difference in `viridis` as the threshold to identify which palettes in `peRsian` we deem "colorblind-safe". ```{r} viridis_min_score <- min(viridis_scores_df$min_dist) viridis_min_score ``` ```{r} # 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. ```{r} # 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 ``` Let's also collect the names of all palettes that didn't make it (use these with caution!). ```{r} non_colorblind_safe_palettes <- names(persian_palettes)[!names(persian_palettes) %in% palettes_above_threshold$palette] non_colorblind_safe_palettes ``` ### 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. ```{r} persian_scores_df |> filter(name == "normal") |> arrange(desc(min_dist)) ``` Palettes which may need adjustments: ```{r} persian_scores_df |> filter(name == "normal") |> arrange(min_dist) ```