class: center, middle, inverse, title-slide # Optimizing selection of color palettes ### Computation Skills Workshop --- # What to color by <img src="index_files/figure-html/unnamed-chunk-2-1.png" width="864" /> --- # Categorical color scales <img src="images/hue-example.png" width="683" /><img src="images/hue-example2.png" width="683" /> .footnote[Sources: FiveThirtyEight, The Economist] --- # Sequential color scales <img src="images/seq-class-ex.png" width="683" /><img src="images/seq-unclass-ex.png" width="683" /> .footnote[Sources: New York Times, Datawrapper] --- # Diverging color scales <img src="images/div-class-ex.png" width="683" /><img src="images/div-unclass-ex.png" width="683" /> .footnote[Sources: Axios, Opportunity Atlas] --- # Highlighting/de-emphasizing <img src="images/highlight-zero.png" width="683" /><img src="images/deemphasize-cat.png" width="683" /><img src="images/bin-grad-na.png" width="683" /> .footnote[Sources: The Guardian, The Pudding, Bloomberg] --- # Choosing a color scale - Emphasis on interpretability and accessibility - Default palettes are less than desirable - Variables may require transformations --- # Default palette in `ggplot2` <img src="index_files/figure-html/unnamed-chunk-7-1.png" width="864" /> --- # Suboptimal default choices <img src="index_files/figure-html/unnamed-chunk-9-1.png" width="864" /> --- # Common forms of color vision deficiency ### Red-green - Deuteranomaly - Protanomaly - Protanopia and deuteranopia ### Blue-yellow - Tritanomaly - Tritanopia ### Complete color vision deficiency - Monochromacy --- # Inspecting for color vision deficiency <img src="index_files/figure-html/unnamed-chunk-10-1.png" width="864" /> --- # Inspecting for color vision deficiency ```r library(colorblindr) cvd_grid(plot = pen_fig) ``` <img src="index_files/figure-html/unnamed-chunk-12-1.png" width="864" /> --- # Inspecting for color deficiency <img src="index_files/figure-html/unnamed-chunk-13-1.png" width="864" /> --- # Inspecting for color deficiency <img src="index_files/figure-html/unnamed-chunk-14-1.png" width="864" /> --- # Inspecting for color deficiency <img src="index_files/figure-html/unnamed-chunk-15-1.png" width="864" /> --- # When to use quantitative or qualitative color scales? <img src="images/quant-qual.png" width="683" /> --- # Use hues for nominal variables <img src="images/unordered.png" width="683" /> --- # Use hues for nominal variables <img src="images/unemp-best.png" width="683" /> --- # Quantitative `\(\neq\)` continuous <img src="images/likert.png" width="683" /> --- # Shades to emphasize order <img src="images/treemap.png" width="683" /> --- # Overcomplicating graphs <img src="images/treemap-third-var.png" width="683" /> --- # Overcomplicating graphs <img src="index_files/figure-html/unnamed-chunk-22-1.png" width="864" /> --- # Correcting the graph <img src="index_files/figure-html/unnamed-chunk-23-1.png" width="864" /> --- # Encoding a new variable <img src="images/google-algorithm.png" width="683" /> .footnote[Graphic detail page "Google's algorithm" in The Economist from June 8th, 2019] --- # Double-encoded line chart <img src="images/double-encode-lines.png" width="683" /> --- # Shades to distinguish subcategories <img src="images/subcategories.png" width="683" /> --- # Stick to shades of one hue <img src="images/hues-single.png" width="683" /> --- # Implementing optimal color palettes in R - [`RColorBrewer`](https://colorbrewer2.org/) - [`viridis`](https://sjmgarnier.github.io/viridis/) --- # Color Brewer ## Sequential palettes <img src="index_files/figure-html/unnamed-chunk-28-1.png" width="864" /> --- # Color Brewer ## Qualitative palettes <img src="index_files/figure-html/unnamed-chunk-29-1.png" width="864" /> --- # `gss` ``` ## # A tibble: 1,974 × 221 ## year id wrkstat wrkslf wrkgvt marital sibs childs age educ degree ## <dbl> <dbl> <fct> <fct> <fct> <fct> <dbl> <dbl> <dbl> <fct> <fct> ## 1 2012 1 WORKING … SOMEON… PRIVATE Never … 1 0 22 4 ye… Bache… ## 2 2012 2 WORKING … SOMEON… PRIVATE Never … 2 0 21 12th… HS ## 3 2012 3 WORKING … SOMEON… PRIVATE Married 1 2 42 12th… HS ## 4 2012 4 <NA> SOMEON… PRIVATE Married 2 2 49 1 yr… HS ## 5 2012 5 RETIRED SOMEON… GOVERN… Separa… 0 3 70 4 ye… Bache… ## 6 2012 6 <NA> SOMEON… PRIVATE Widowed 4 2 50 7 ye… Bache… ## 7 2012 7 KEEPING … SOMEON… PRIVATE Married 2 2 35 3 ye… Junio… ## 8 2012 8 KEEPING … <NA> <NA> Separa… 2 3 24 11th… <HS ## 9 2012 9 KEEPING … <NA> <NA> Married 2 2 28 9th … <HS ## 10 2012 10 WORKING … SOMEON… PRIVATE Never … 0 0 28 5 ye… Bache… ## # … with 1,964 more rows, and 210 more variables: sex <fct>, race <fct>, ## # polviews <fct>, partyid <fct>, mobile16 <fct>, born <fct>, income06 <fct>, ## # rincom06 <fct>, region <fct>, size <dbl>, vote08_coded <fct>, pres08 <fct>, ## # natspac <fct>, natenvir <fct>, natheal <fct>, natcity <fct>, ## # natcrime <fct>, natdrug <fct>, nateduc <fct>, natrace <fct>, natarms <fct>, ## # nataid <fct>, natfare <fct>, natroad <fct>, natsoc <fct>, natmass <fct>, ## # natpark <fct>, natchld <fct>, natsci <fct>, natenrgy <fct>, eqwlth <dbl>, … ``` --- # `scale_*_brewer()` ```r ggplot(data = gss_polviews, mapping = aes(x = polviews, fill = polviews)) + geom_bar() + scale_fill_brewer(type = "seq") ``` <img src="index_files/figure-html/unnamed-chunk-32-1.png" width="864" /> --- # `scale_*_brewer()` ```r ggplot(data = gss_polviews, mapping = aes(x = polviews, fill = polviews)) + geom_bar() + scale_fill_brewer(type = "seq", guide = FALSE) ``` <img src="index_files/figure-html/unnamed-chunk-34-1.png" width="864" /> --- # Sequential palette ```r ggplot(data = gss_polviews, mapping = aes(x = polviews, fill = polviews)) + geom_bar() + scale_fill_brewer(palette = "OrRd", guide = FALSE) ``` <img src="index_files/figure-html/unnamed-chunk-35-1.png" width="864" /> --- # Qualitative palette ```r ggplot(data = gss_relig, mapping = aes(x = relig, fill = relig)) + geom_bar() + scale_fill_brewer(guide = FALSE) ``` <img src="index_files/figure-html/unnamed-chunk-37-1.png" width="864" /> --- # Qualitative palette ```r ggplot(data = gss_relig, mapping = aes(x = relig, fill = relig)) + geom_bar() + scale_fill_brewer(type = "qual", guide = FALSE) ``` <img src="index_files/figure-html/unnamed-chunk-38-1.png" width="864" /> --- # Quantitative color brewer palettes ```r ggplot(data = unemp_20, mapping = aes(fill = unemp)) + geom_sf() + scale_fill_distiller() ``` <img src="index_files/figure-html/unnamed-chunk-40-1.png" width="864" /> --- # Quantitative color brewer palettes ```r ggplot(data = unemp_20, mapping = aes(fill = unemp)) + geom_sf() + scale_fill_distiller(palette = "YlGn") ``` <img src="index_files/figure-html/unnamed-chunk-41-1.png" width="864" /> --- # `viridis` <img src="index_files/figure-html/unnamed-chunk-42-1.png" width="864" /> --- # Comparison of palettes <img src="index_files/figure-html/unnamed-chunk-43-1.png" width="864" /> --- # Green-Blind (Deuteranopia) <img src="index_files/figure-html/unnamed-chunk-44-1.png" width="864" /> --- # Desaturated <img src="index_files/figure-html/unnamed-chunk-45-1.png" width="864" /> --- # `viridis` - continuous ```r ggplot(data = unemp_20, mapping = aes(fill = unemp)) + geom_sf() + scale_fill_viridis_c() ``` <img src="index_files/figure-html/unnamed-chunk-46-1.png" width="864" /> --- # `viridis` - continuous ```r ggplot(data = unemp_20, mapping = aes(fill = unemp)) + geom_sf() + scale_fill_viridis_c(option = "magma") ``` <img src="index_files/figure-html/unnamed-chunk-47-1.png" width="864" /> --- # `viridis` - discrete ```r ggplot(data = gss_polviews, mapping = aes(x = polviews, fill = polviews)) + geom_bar() + scale_fill_viridis_d(guide = FALSE) ``` <img src="index_files/figure-html/unnamed-chunk-48-1.png" width="864" /> --- class: middle, center, inverse # Exercise on implementing palettes
08
:
00
--- # When to use sequential or diverging color scales? <img src="images/seq-div.png" width="512" /> --- # Except when you shouldn't! - Meaningful middle point - Emphasize extremes - See more differences --- # Meaningful middle point <img src="images/div-palette.png" width="683" /> - Zero - 50% - Average - Agreed threshold - A target --- # WTF? <img src="images/pepmusic.png" width="683" /> --- # Emphasize highest values <img src="index_files/figure-html/unnamed-chunk-54-1.png" width="864" /> --- # Emphasize extremes <img src="index_files/figure-html/unnamed-chunk-55-1.png" width="864" /> --- # Increased range in scale <img src="images/births-div.png" width="683" /> --- # Increased range in scale <img src="images/births-seq.png" width="683" /> --- # Implementing diverging palettes ```r ggplot(data = gss_polviews, mapping = aes(x = polviews, fill = polviews)) + geom_bar() + scale_fill_brewer(type = "div", guide = FALSE) ``` <img src="index_files/figure-html/unnamed-chunk-58-1.png" width="864" /> --- # Implementing diverging palettes ```r ggplot(data = unemp_20, mapping = aes(fill = unemp)) + geom_sf() + scale_fill_distiller(type = "div") ``` <img src="index_files/figure-html/unnamed-chunk-59-1.png" width="864" /> --- # Implementing diverging palettes ```r ggplot(data = unemp_20, mapping = aes(fill = unemp)) + geom_sf() + scale_fill_viridis_c(option = "turbo") ``` <img src="index_files/figure-html/unnamed-chunk-60-1.png" width="864" /> --- class: center, middle, inverse # Exercise on diverging palettes
08
:
00
--- # When to use classed or unclassed color scales? <img src="images/class-scale.png" width="683" /> --- # Use a classed scale if the data is classed <img src="images/class-continuous.png" width="683" /> --- # Communicating statistical brackets <img src="index_files/figure-html/unnamed-chunk-65-1.png" width="864" /> --- # Communicating general patterns <img src="index_files/figure-html/unnamed-chunk-66-1.png" width="864" /> --- # Increased classes for more nuance <img src="index_files/figure-html/unnamed-chunk-67-1.png" width="864" /> --- # Assisting with interpretations <img src="index_files/figure-html/unnamed-chunk-68-1.png" width="864" /> --- # Directly encoding values <img src="index_files/figure-html/unnamed-chunk-69-1.png" width="864" /> --- # Choosing an interpolation - Linear - Quartiles, quantiles, deciles --- # Linear <img src="index_files/figure-html/unnamed-chunk-70-1.png" width="864" /> --- # Linear <img src="index_files/figure-html/unnamed-chunk-71-1.png" width="864" /> --- # Quartiles <img src="index_files/figure-html/unnamed-chunk-72-1.png" width="864" /> --- # Quintiles <img src="index_files/figure-html/unnamed-chunk-73-1.png" width="864" /> --- # Deciles <img src="index_files/figure-html/unnamed-chunk-74-1.png" width="864" /> --- # Natural breaks <img src="index_files/figure-html/unnamed-chunk-75-1.png" width="864" /> --- # Implementing breaks - Automatically with `scale_*_viridis_b()` - Manually with `cut_number()` --- # Quartiles .pull-left[ ```r ggplot(data = unemp_oct21, mapping = aes(fill = unemp)) + geom_sf(color = "white", size = .1) + scale_fill_viridis_b(n.breaks = 3, nice.breaks = FALSE) ``` ] .pull-right[ <img src="index_files/figure-html/quart-out-1.png" width="432" /> ] --- # Quintiles .pull-left[ ```r ggplot(data = unemp_oct21, mapping = aes(fill = unemp)) + geom_sf(color = "white", size = .1) + scale_fill_viridis_b(n.breaks = 4, nice.breaks = FALSE) ``` ] .pull-right[ <img src="index_files/figure-html/quint-out-1.png" width="432" /> ] --- # Deciles .pull-left[ ```r ggplot(data = unemp_oct21, mapping = aes(fill = unemp)) + geom_sf(color = "white", size = .1) + scale_fill_viridis_b(n.breaks = 9, nice.breaks = FALSE) ``` ] .pull-right[ <img src="index_files/figure-html/dec-out-1.png" width="432" /> ] --- # Manually with `cut_number()` .pull-left[ ```r unemp_oct21 %>% mutate(unemp = cut_number(unemp, n = 4)) %>% ggplot(mapping = aes(fill = unemp)) + geom_sf(color = "white", size = .1) + scale_fill_brewer(type = "seq") ``` ] .pull-right[ <img src="index_files/figure-html/quart-man-out-1.png" width="432" /> ] --- # Manually with `cut_number()` .pull-left[ ```r unemp_oct21 %>% mutate(unemp = cut_number(unemp, n = 5)) %>% ggplot(mapping = aes(fill = unemp)) + geom_sf(color = "white", size = .1) + scale_fill_brewer(type = "seq") ``` ] .pull-right[ <img src="index_files/figure-html/quint-man-out-1.png" width="432" /> ] --- # Manually with `cut_number()` .pull-left[ ```r unemp_oct21 %>% mutate(unemp = cut_number(unemp, n = 10)) %>% ggplot(mapping = aes(fill = unemp)) + geom_sf(color = "white", size = .1) + scale_fill_brewer(type = "seq") ``` ] .pull-right[ <img src="index_files/figure-html/dec-man-out-1.png" width="432" /> ] --- # Natural breaks .pull-left[ ```r library(classInt) # calculate intervals unemp_classes <- classIntervals(unemp_oct21$unemp, n = 5, style = "jenks") unemp_oct21 %>% # apply to variable mutate(unemp_cat = kimisc::cut_format( x = unemp, breaks = unemp_classes$brks, include.lowest = TRUE, format_fun = scales::percent )) %>% ggplot(mapping = aes(fill = unemp_cat)) + geom_sf(color = "white", size = .1) ``` ] .pull-right[ <img src="index_files/figure-html/nat-break-out-1.png" width="432" /> ] --- class: middle, center, inverse # Exercises on interpolating continuous variables
07
:
00