--- title: "Bivariate Palettes" author: "Christopher Prener, Ph.D. and Branson Fox" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Bivariate Palettes} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` One of the important aspects of cartography and data visualization is color choice. This vignette illustrates the palettes included with `biscale`, provides an overview of palette manipulation tools, and describes the revised approach to utilizing custom palettes. ## Included Palettes *As of v1.0.0, `biscale` supports a dozen built-in palettes and expanded ability to utilize custom palettes. For five of these palettes, there are both "primary" versions and "legacy versions."* ### Primary Palettes All of the primary palettes listed here can be used with two-by-two (`dim = 2`), three-by-three (`dim = 3`), and four-by-four (`dim = 4`) maps. The palettes that contain a `2` at the end of their name are visually similar to the original, "legacy" palettes (see below) but utilize slightly different hex values for colors. ```{r echo=FALSE, out.width='100%'} knitr::include_graphics('../man/figures/pals_primary.jpeg') ``` Most of the newly added palettes not based on legacy designs were adapted from earlier work by Branson Fox. ### Legacy Palettes To ensure compatibility with scripts written with older versions of `biscale`, the original five palettes included in the package are still available. They can be used only for two-by-two (`dim = 2`) and three-by-three (`dim = 3`) maps. ```{r echo=FALSE, out.width='100%'} knitr::include_graphics('../man/figures/pals_legacy.jpeg') ``` The `"DkViolet"` palette was created by [Timo Grossenbacher and Angelo Zehr](https://timogrossenbacher.ch/2019/04/bivariate-maps-with-ggplot2-and-sf/), and the other four palettes were created by [Joshua Stevens](https://www.joshuastevens.net/cartography/make-a-bivariate-choropleth-map/). ## Palette Manipulations In order to facilitate even greater flexibility with palettes, `biscale` functions include two additional arguments to manipulate their arrangement. "Flipping axes" will invert the colors assigned to the x and y axes. Flipping axes is accomplished with the `flip_axes` argument: ```r bi_pal(pal = "PurpleOr", dim = 3, flip_axes = TRUE) ``` "Rotating" the palette (with the `rotate_pal` argument) will rotate the colors 180 degrees, resulting in a palette that highlights low values as opposed to high values. Rotating the palette rotates the entire color scale 180 degrees. For example: ```r bi_pal(pal = "PurpleOr", dim = 3, rotate_pal = TRUE) ``` These manipulations can be combined as well, producing a palette that has been both flipped and rotated: ```r bi_pal(pal = "PurpleOr", dim = 3, flip_axes = TRUE, rotate_pal = TRUE) ``` Together, these changes to `bi_pal()` result in the following shifts to the `"PurpleOr"` palette: ```{r echo=FALSE, out.width='100%'} knitr::include_graphics('../man/figures/manipulated_pal.jpeg') ``` When applied to real world data, these transformations result in subtle (in the case of flipping) or more dramatic (in the case of rotating) differences in maps: ```{r echo=FALSE, out.width='100%'} knitr::include_graphics('../man/figures/biscale.005.jpeg') ``` Utilizing both flipping axes and palette rotations also yields a considerable change from the original: ```{r echo=FALSE, out.width='100%'} knitr::include_graphics('../man/figures/biscale.006.jpeg') ``` Be careful to ensure that your use of `flip_axes` and/or `rotate_pal` is consistent across `bi_scale_fill()`/`bi_scale_color()` as well as `bi_legend()`. ## Custom Palettes In addition the built-in palettes described above, `biscale` supports custom palettes. *As of v1.0.0, the workflow for using custom palettes is different than prior releases and the old approach, using `bi_pal_manual()`, has been deprecated. We plan to remove `bi_pal_manual()` in late 2022. Please update your workflows accordingly.* To create a custom palette, users must create a named vector and supply associated hex values. We recommend checking out [Benjamin Brooke's](https://bvgsoftware.com) [Bivariate Choropleth Color Generator](https://observablehq.com/@benjaminadk/bivariate-choropleth-color-generator) if you want to experiment with creating your own palettes. [Joshua Steves' blogpost from 2015](https://www.joshuastevens.net/cartography/make-a-bivariate-choropleth-map/) also contains tips for creating palettes. The first example below is a named vector for a two-by-two (`dim = 2`) map. The pairs correspond to `x,y` coordinates on the legend where the first value is the `x` value and the second is the `y` value. The `1-1` pair is therefore the lower left corner of the legend and, in the example, the `2-2` pair is the upper right corner. The named vector should have 4 values in total. ```r custom_pal2 <- c( "1-1" = "#d3d3d3", # low x, low y "2-1" = "#9e3547", # high x, low y "1-2" = "#4279b0", # low x, high y "2-2" = "#311e3b" # high x, high y ) ``` If you are creating a custom palette for a three-by-three (`dim = 3`) map, you need to extend each row and column by 1 so that `3-1` and `3-2` are included in the vector along with `1-3`, `2-3`, and `3-3`. The named vector should have 9 values in total. ```r custom_pal3 <- c( "1-1" = "#d3d3d3", # low x, low y "2-1" = "#ba8890", "3-1" = "#9e3547", # high x, low y "1-2" = "#8aa6c2", "2-2" = "#7a6b84", # medium x, medium y "3-2" = "#682a41", "1-3" = "#4279b0", # low x, high y "2-3" = "#3a4e78", "3-3" = "#311e3b" # high x, high y ) ``` Finally, for a four-by-four (`dim = 4`), should be further extended by 1 so that `4-1`, `4-2`, and `4-3` are included in the vector along with `1-4`, `2-4`, `3-4`, and `4-4`. The named vector should have 16 values in total. ```r custom_pal4 <- c( "1-1" = "#d3d3d3", # low x, low y "2-1" = "#c2a0a6", "3-1" = "#b16d79", "4-1" = "#9e3547", # high x, low y "1-2" = "#a3b5c7", "2-2" = "#96899d", "3-2" = "#895e72", "4-2" = "#7a2d43", "1-3" = "#7397bb", "2-3" = "#697394", "3-3" = "#604e6b", "4-3" = "#56263f", "1-4" = "#4279b0", # low x, high y "2-4" = "#3c5c8b", "3-4" = "#373f65", "4-4" = "#311e3b" # high x, high y ) ``` You can preview and validate your named vector using `bi_pal()`. For example, we can preview the `custom_pal3` vector created above: ```r # load dependencies library(biscale) # preview palette bi_pal(pal = custom_pal3, dim = 3) ``` Once you have created your named vector, you can use it any place where you would ordinarily provide a quoted palette name in `biscale` functions. In this example, the `custom_pal3` vector created above is passed to `bi_scale_fill()` and `bi_legend()`: ```r # prep data data <- stl_race_income data <- bi_class(data, x = pctWhite, y = medInc, dim = 3, style = "quantile", keep_factors = TRUE) # draw map map <- ggplot() + geom_sf(data = data, aes(fill = bi_class), color = "white", size = 0.1, show.legend = FALSE) + bi_scale_fill(pal = custom_pal3, dim = 3) + labs( title = "Race and Income in St. Louis, MO", subtitle = "Custom Palette" ) + bi_theme() # draw legend legend <- bi_legend(pal = custom_pal3, xlab = "Higher % White ", ylab = "Higher Income ", size = 12) ``` When custom palettes are passed to `biscale` functions, they will be validated to ensure they have the correct number of entries, have the correct names, and have properly formatted hex values. For custom palettes that are two-by-two (`dim = 2`), three-by-three (`dim = 3`), or four-by-four (`dim = 4`), the palette manipulations described above can also be applied: ```r bi_pal(pal = custom_pal3, dim = 3, flip_axes = TRUE, rotate_pal = TRUE) ``` ## High Dimensional Palettes The custom palette workflow not only enables users to bring whatever color scheme they wish to `biscale`, but it provides support for higher dimensional maps (`dim = 5` and beyond). Users should carefully consider the readability of these maps, however, and a warning to this effect will be generated when using `bi_class()`. Users creating high dimensional maps should also note that flipping and rotating palettes is not supported beyond `dim = 5`, and any modifications to the palette must be made manually. To create a named vector for a five-by-five (`dim = 5`) map, for example, the following named vector could be used: ```r custom_pal <- c( "1-1" = "#d3d3d3", # low x, low y "2-1" = "#b6cdcd", "3-1" = "#97c5c5", "4-1" = "#75bebe", "5-1" = "#52b6b6", # high x, low y "1-2" = "#cab6c5", "2-2" = "#aeb0bf", "3-2" = "#91aab9", "4-2" = "#70a4b2", "5-2" = "#4e9daa", "1-3" = "#c098b9", "2-3" = "#a593b3", "3-3" = "#898ead", "4-3" = "#6b89a6", "5-3" = "#4a839f", "1-4" = "#b77aab", "2-4" = "#9e76a6", "3-4" = "#8372a0", "4-4" = "#666e9a", "5-4" = "#476993", "1-5" = "#ad5b9c", # low x, high y "2-5" = "#955898", "3-5" = "#7c5592", "4-5" = "#60528d", "5-5" = "#434e87" # high x, high y ) ```