---
title: "Visualize Colors"
---

```{r}
#| echo: false
suppressPackageStartupMessages(library(`lessR`))
style(suggest=FALSE, quiet=TRUE)
```

```{css, echo=FALSE}
.setoff {
  background-color: rgb(245,245,245);
  border: 1px none rgb(100,100,100);
  border-radius: .45em;
  padding-top: .5em;
  padding-left: .5em;
  padding-bottom: -.5em;
}
```

We use the employee data set for examples throughout this section.

```{r}
d <- Read("Employee")
```

# Describe Colors

Colors are organized according to Sir Isaac Newton’s 1666 creation of the color wheel. The lessR function `getColors()` generates the version of the color wheel in @fig-clrwheel for mixing light, such as for computer screens. Generate 360 different colors based on the parameter `n` to approximate the smooth transition between adjacent colors. Set the border parameter to `"transparent"` to disable the border between colors.

::: column-margin
From `lessR` version `r packageVersion("lessR")`.
:::

``` r
getColors(n=360, border="transparent", labels=FALSE, shape="wheel")
```

```{r}
#| echo: FALSE
#| fig.height: 4.25
#| label: fig-clrwheel
#| fig.cap: "The color wheel for mixing light."
getColors(n=360, border="transparent", labels=FALSE, shape="wheel", l=70,
          quiet=TRUE, output=TRUE, main="")
```

## Color Parameters

Colors are defined by their position on the color wheel. To personalize the colors in our data visualizations, we assign chosen colors from this color wheel to specific objects. What are the plotted objects that we wish to colorize? Figures such as circles, bars, triangles, and a state on a map of the United States are *polygons*.

::: {.callout-note title="Polygon"}
A closed geometric figure with straight sides.
:::

We visualize a polygon’s color according to its interior and exterior. As such, we need matching parameter names for their references. Unfortunately, we encounter a complication.

::: {.callout-warning title="No standardization of named color parameters"}
There is no standardized vocabulary for assigning colors across data visualization systems such as those in R, Python, and Tableau.
:::
  
 R and Python each have multiple visualization systems, and even systems within the same language lack a general agreement on color vocabulary.

The commercial standard drawing app, Adobe Illustrator, uses the parameter `fill` to assign the interior color of a polygon. The standard R programming data visualization app from the RStudio people, `ggplot2,` also uses the `fill` parameter, as does `lessR` to maintain compatibility.

::: {.callout-note title="Parameter: fill"}
*[ggplot2, lessR]* Describes the color of the inside of a polygon.
:::

One use of the parameter `color` describes an object's color when viewed from the outside. This is the `ggplot2` system, which uses the parameter `color`, as does `lessR`. The parameter `color` refers to the color of a line segment, either by itself or as an edge of a polygon.

::: {.callout-note title="Parameter: color"}
*[ggplot2, lessR]* Describes the perception of color viewed from the exterior of a polygon, or a line, its appearance from the outside.
:::

Tableau, however, uses the parameter `color` to specify the interior color of a polygon and the parameter `border` to specify the exterior color.

## Color Names

R identifies its 657 color names with the `colors()` function. Some of the more intriguing color names include "chocolate", thistle, "lavenderblush", and "peachpuff". The color names also include shades of gray, ranging from black ("gray00") to white ("gray100"). However, the listed color names do not show the corresponding colors.

To compensate for this shortcoming, the `lessR` function `showColors()` generates a PDF containing all color names and a sample of each color, along with its corresponding red, green, and blue components. @fig-colornames displays a small excerpt from the PDF file from `showColors()`.

![Excerpt from output of `showColors()`.](images/colorNamesEg.png){#fig-colornames width="74%"}

@fig-colnames shows two customized bar charts. @fig-colnames(a) shows that specifying one color name for `fill` yields a bar chart with all the bars of that same color. By default, the bars have no borders other than the end of the `fill` color. The bars in @fig-colnames(a) have added black borders. @fig-colnames(b) shows that to separately customize the color of each bar, specify a vector of colors for the `fill` parameter, one for each bar, with the vector function `c()`.

::: {#fig-colnames layout-ncol="2" layout-valign="bottom"}
```{r}
#| fig.cap: "(a) All bars the same color with black borders."
Chart(Gender, fill="slategray3", color="black")
```

```{r}
#| fig.cap: "(b) Each bar separately custom colorized with no border."
Chart(Gender, fill=c("plum3", "seagreen3"))
```

Two bar charts with custom colors according to R color names.
:::

@fig-rosy shows how to customize the color of each bar in a bar chart to highlight a specific bar. In this example, highlight the bar with the highest average salary, the administration department.

```{r}
#| label: fig-rosy
#| fig.width: 5.5
#| fig.cap: "Explicitly highlight one of the bars in the bar chart relative to the others."
Chart(Dept, y=Salary, stat="mean", 
      fill=c("gray66", "rosybrown3", "gray66", "gray66", "gray66"))
```

::: column-margin
Use the Base R repetition function `rep()` to replace the last three "gray66" instances for the `fill` parameter with `rep("gray66",3)`.
:::

The same `fill` and `color` parameters apply to histograms and scatterplots. For histograms, `fill` also applies to the bars. For scatterplots, `fill` applies to the interior of the plotted points and `color` to their borders.

@fig-sp highlights the data points for the administration department in the scatterplot of years employed by the company vs. salary. Because of the relatively small number of plotted points, the point size was enlarged from the default value of 1.0 to the value of 1.3.

```{r}
#| label: fig-sp
#| fig.width: 5.5
#| fig.cap: "Explicitly highlight employees who work in administration in the scatterplot of years employed with salary."
XY(Years, Salary, by=Dept, pt_size=1.3,
     fill=c("gray66", "red3", "gray66", "gray66", "gray66"))
```

This scatterplot straightforwardly demonstrates that two of the highest paid and most senior officials in the company work in administration, but the remaining four employees in that department are newer employees with much lower salaries.

Color names can work well for color customization, but we often need more control over the specific colors used in a visualization.

## Color Spaces

A color space enables the description of far more colors than does a limited set of color names. Instead of identifying a color by a name such as *red*, *blue*, or *dark gray*, a color space defines a color by a set of numerical values. These values locate the color within a coordinate system, much as the values of two variables locate a point on a scatterplot.

::: {.callout-note title="Color space"}
A color space describes a color in terms of its coordinates across a set of color dimensions.
:::

Different color spaces organize these dimensions in different ways.  Following is a description of two color spaces important to data visualization: the RGB color space and the HCL color space. RGB describes color according to the red, green, and blue light emitted by computer displays. HCL describes color according to hue, chroma, and luminance, dimensions that more closely correspond to how people perceive color.

### RGB Color Space

One essential color space, one set of dimensions, is the RGB color space, the language of electronic screens such as TVs and computer monitors.

::: {.aside}
The R package `colorspace` provides many functions for exploring various color spaces and converting color coordinates between them.
:::

::: {.callout-note title="RGB color space"}
The RGB color space describes a color in terms of the combination of primary colors, its red, green, and blue components.
:::

Each of the many thousands of tiny dots on a TV or computer monitor, the pixels, is colored according to its specific red, green, and blue constituent colors in various combinations. Together, a screen full of pixels can generate all the colors on the color wheel in @fig-clrwheel.

The Base R `rgb()` function specifies colors in the RGB color space with parameters `red`, `green`, and `blue`. By default, the three or four values of the `rgb()` function are proportions ranging from 0 to 1. For example, `rgb(0,0,0)` is equivalent to the named color "black", `rgb(1,1,1)` is equivalent to the named color "white", and `rgb(1,0,0)` is equivalent to the named color "red".

An optional fourth parameter, `alpha`, specifies the degree of transparency. The default alpha value of 1 results in a fully opaque color, that is, no transparency.

::: column-margin
Most applications for color manipulation in the RGB color space typically specify colors with values that range from 0 to 255 to align more closely with how color information is stored in digital memory. To accommodate this larger, more common range of numbers, add the parameter and value `maxColorValue=255` to the `rgb()` function call.
:::

@fig-rgb repeats the bar charts from @fig-colnames but specifies the colors in the RGB color space. For @fig-rgb(a), the bar chart colors from `rgb()` are scaled with the `maxColorValue` parameter set to 255. For @fig-rgb(b), the bar chart colors use the native `rgb()` parameter values, proportions from 0 to 1.

::: {#fig-rgb layout-ncol="2" layout-valign="bottom"}
```{r}
#| fig.cap: "(a) All bars the same color with black borders."
Chart(Gender, fill=rgb(159, 182, 205, maxColorValue=255),
                 color=rgb(0,0,0))
```

```{r}
#| fig.cap: "(b) Each bar separately custom colorized with no border."
Chart(Gender, fill=c(rgb(.804,.588,.804), rgb(.263,.804,.502)))
```

Two bar charts with custom colors specified according to RGB values.
:::

A second way to represent RGB colors closely follows the structure of computer memory. Internally, computers store and process information with binary digits, 0 and 1, which represent *off* and *on* states for an electronic switch, the transistor. Describing long strings of zeros and ones to map colors from computer memory to a computer monitor is tedious and takes up a lot of space. Computer memory is more efficiently described in hexadecimal (HEX) notation.

::: {.callout-note title="Hexadecimal digit"}
Digits that vary from 0 through 9, then A through F to span 16 digits, where our usual Base 10 number 15 is represented with an F for the hexadecimal Base 16.
:::

As illustrated in @fig-HEX, hexadecimal notation is much more compact than binary notation. Express our usual number 15 with a single hexadecimal digit F in place of the four binary digits 1111.

![Binary, decimal, and hexadecimal digits.](images/HEX.png){#fig-HEX fig-align="center" width="650"}

Because RGB colors map to pixels on a computer screen, HEX notation provides an alternate description of RGB colors. Find these color descriptions in web applications, R, Tableau, and other visualization systems. The first two digits of a color’s hexadecimal representation indicate the amount of red, the second two digits indicate green, and the last two digits indicate blue.

For example, specify pure blue with no red and green components using the R `rgb()` function, which evaluates to a hexadecimal number.

```{r}
#| fig.cap: "Hexadecimal output of the base R rgb() function."
rgb(0,0,1)
```

In this example, the red and green components of the `rgb()` function call are both 0, while the blue component is at the maximum value of 1. This translates to 00 for red, 00 for green, and the largest hexadecimal value, FF, for blue, equal to our Base 10 value of 255. That is why most graphics design and visualization systems specify RGB colors as 0 to 255, which corresponds to the hexadecimal range 00 to FF.

The next example illustrates the HEX notation as the argument to the `fill` parameter in a call to the `Chart()` function. If only one color is specified for the `fill` parameter in `lessR` data visualizations, then all of the corresponding plotted objects, such as bars, are plotted in that specified color. @fig-tableau shows the default blue color obtained within Tableau from its `Color` parameter setting (mark) and then plots the bars in Tableau's default blue color.

::: {#fig-tableau layout-ncol="2" layout-valign="bottom"}
![(a) Tableau color chart for its default blue color.](images/TableauBlue.png){fig-align="center" width="208"}

```{r}
#| fig.cap: "(b) Default Tableau fill color for the bars of a bar chart."
Chart(Dept, fill="#4E79A7")
```

Default Tableau blue color and corresponding bar chart.
:::

The RGB color space follows from the physical characteristics of how a computer screen displays color. But computer screens are not people. Engineering specifications of physical hardware do not directly translate into uniform human perception of color. For example, there is no straightforward way to systematically vary RGB colors while maintaining the same perceived brightness. How people perceive color and how computer monitors display color are distinct processes, which suggests the need for another color space.

### HCL Color Space

#### HCL Coordinates

The generally preferred specification of colors for data visualization is the HCL color space,[^1] defined by three values that correspond more closely to how people perceive color:

[^1]: More technically, HCL represents the polar coordinates of the CIE-LUV color space.

1. *Hue* - the color name, positioned around a color wheel
2. *Chroma* - the intensity of color, ranging from gray to saturated
3. *Luminance* - perceived brightness

Within R, directly express HCL colors with the Base R function `hcl()`, or more conveniently with the `lessR` color function `getColors()` that relies upon `hcl()`. The parameter names for the three `hcl()` coordinates are `h`, `c`, and `l`. Chroma and luminance each scale from 0 to 100. Increasing `c` toward 100 yields more saturated, more vivid colors. Regardless of the value of `h`, a value of 0 for `c` removes hue and produces a grayscale, from dark gray for values of `l` close to 0 to lighter gray as `l` approaches 100.

#### Perceptual Biases

The primary advantage of the HCL color space is that colors can vary systematically in hue, chroma, and luminance. Different regions of a visualization can be plotted in different hues while maintaining approximately the same chroma and luminance. When all plotted objects, such as bars, have the same chroma and luminance, no object receives unintended emphasis merely because its color appears brighter or more intense. Presenting colors with comparable perceptual weight helps the viewer focus on the data values rather than on accidental differences in color intensity.

Brighter, more intense colors can exaggerate the perceived size or importance of a plotted region relative to more subdued colors. As a result, brighter regions can bias interpretation because they attract more visual attention than darker regions.

::: {.callout-note title="Irradiation illusion"}
Lighter, brighter areas of a visualization can appear to spread into adjoining darker areas, making the lighter areas seem larger or more visually prominent.
:::

The visualizations in @fig-HCLcolors compare two pre-existing color sequences available through the `lessR` `getColors()` function: `rainbow` from Base R and `rainbow_hcl` from the `colorspace` package. @fig-HCLcolors(a) illustrates the irradiation illusion. The red bar appears more vivid and visually dominant than the light green bar. @fig-HCLcolors(b) demonstrates the greater visual consistency of HCL colors, which vary hue while maintaining approximately the same chroma and luminance. These HCL colors reduce the irradiation illusion and minimize unintended emphasis on one part of the visualization at the expense of the rest.

``` r
getColors("rainbow")
getColors("rainbow_hcl")
```

::: {#fig-HCLcolors layout-ncol="2" layout-valign="bottom"}
```{r}
#| echo: FALSE
#| fig.height: 2
#| fig.cap: "(a) Non-HCL color spectrum."
getColors("rainbow", output=TRUE, main="")
```

```{r}
#| echo: FALSE
#| fig.height: 2
#| fig.cap: "(b) HCL color spectrum."
getColors("rainbow_hcl", c=65, l=60, output=TRUE, main="")
```

Non-HCL color spectrum compared to HCL colors, all with chroma of 65 and a luminosity of 60.
:::

::: column-margin
See the manual by entering `?getColors`into the R console to identify other available pre-defined sequences, such as `heat_hcl` and `terrain_hcl`, plus others, some of which are discussed later.
:::

A perceptual bias that applies to an ordered categorical variable or a continuous variable is *perceptual non-uniformity*. Here, define the concept in terms of the corresponding goal, to avoid the non-uniformity.

::: {.callout-note title="Perceptual uniformity"}
Plotted colors change appropriately to the amount of change in the corresponding data values.
:::

The colors in a perceptually uniform palette change in proportion to changes in the magnitude of the data values. A palette is perceptually non-uniform if a small change in data values produces a large apparent change in color, or if a large change in data values produces only a small apparent change in color. Such a mapping distorts the perception of corresponding changes in the underlying data.

@fig-hclEgs shows three examples of perceptual uniformity achieved with the `lessR` function `getColors()` applied to two predefined sets of colors. All three examples keep chroma high at 95 but vary luminance from 35 to 75. A high value of chroma combined with lower luminance, as in @fig-hcl_a, produces vibrant, rich hues. A high value of chroma combined with higher luminance, as in @fig-hcl_c, produces light, airy pastels.

``` r
getColors("rainbow_hcl", c=95, l=35)
getColors("rainbow_hcl", c=95, l=55)
getColors("rainbow_hcl", c=95, l=75)
```

::: {#fig-hclEgs layout-ncol="3" layout-valign="bottom"}
```{r}
#| label: fig-hcl_a
#| echo: FALSE
#| fig.cap: "chroma=95, luminance=35"
getColors("rainbow_hcl", c=95, l=35, output=TRUE, main=NULL)
```

```{r}
#| label: fig-hcl_b
#| echo: FALSE
#| fig.cap: "chroma=95, luminance=55"
getColors("rainbow_hcl", c=95, l=55, output=TRUE, main=NULL)
```

```{r}
#| label: fig-hcl_c
#| echo: FALSE
#| fig.cap: "chroma=95, luminance=70"
getColors("rainbow_hcl", c=95, l=75, output=TRUE, main=NULL)
```

Three examples of perceptual uniformity across the rainbow of hues achieved with HCL colors with chroma at 95 and varying luminosity.
:::

::: {.callout-tip title="Avoid overly bright colors"}
Most visualizations, especially composites such as dashboards, should generally avoid overly bright, intense, or harsh colors. Generally, use somewhat muted colors or add some transparency to the displayed colors.
:::

As shown in the next section (see @fig-deep and @fig-alt), you can access these color sequences directly in visualization function calls, such as `Chart()`, via the `fill` parameter.


#### An HCL Display Problem

Unfortunately, there is a problem displaying HCL colors: Translating human perceptual colors to the screens of color monitors is not straightforward.

::: {.callout-warning title="Insufficient HCL to RGB translation"}
Not all colors in the HCL color space of human perception map to the RGB color space of computer monitors.
:::

Displaying all HCL colors requires approximating some colors when translated to the RGB color space of color monitors. Only moderate values of chroma and luminance render all hues as precise HCL colors.

If using R to obtain HCL colors, set the parameter `fixup` to `FALSE` to show only precise HCL colors among the generated colors. Colors that fall outside of the RGB color space of computer monitors are displayed as `NA`, that is, missing. By default, `fixup` is set to `TRUE`.

# Color Palettes

## Introduction

Visualizations apply combinations of related colors, including shades of gray for grayscale.

::: {.callout-note title="Color palette"}
A set of related colors, usually to provide a consistent design, such as data visualizations.
:::

All visualization systems feature built-in color palettes. Users are also free to define any palette they choose, either generated by specialized functions or manually entered.

::: {.callout-tip title="Types of color palettes"}
Three basic types of color palettes appear in visualizations offered by any visualization system: qualitative, sequential, and divergent.
:::

Discussions of these three types of palettes follow. Any of these palettes can be used with any data visualization system that allows color customization.

::: {.callout-note title="General applicability of color specifications"}
A standard color name, such as the hexadecimal representation of an RGB color, is applicable to any data visualization system that displays colors on a computer screen.
:::

To store colors generated by `getColors()`, store the result in a vector. In this example, the vector of stored colors is named *clr*. The parameter output is set to false because there is no need to view the palette here.

```{r}
clr <- getColors(output=FALSE)
```

``` r
clr
```

```{r}
#| echo: FALSE
print(clr, width=80)
```

Apply this `getColors()` palette, defined by hexadecimal color specifications, to any visualization system that supports custom colors displayed on a computer screen.

## Qualitative Palettes

[Nominal data](https://web.pdx.edu/~gerbing/0Viz/CatCont/CatContDV.html) are unordered data values of a categorical variable. Examples include State of Residence and Gender. To plot resulting data values, such as the count of each data value, one option is to display all levels as bars in a bar chart, with the same color. To apply a color palette, however, the appropriate scale for the display of the levels of nominal data is a *qualitative palette*.

::: {.callout-note title="Qualitative scale"}
Color palette of mixed hues applied to nominal data.
:::

Preferably, different values of hues across the different bars, pie slices, or points should generally have the same chroma and luminance.

### HCL Palettes

The `lessR` function `getColors()` generates and displays colors for a wide variety of palettes. The parameter list begins with `pal`, short for `palette`. In addition to the predefined palettes shown in @fig-hclEgs, `getColors()` can also generate custom palettes.

The default value of `pal` is `"hues"`, which generates the specified number of hues around the HCL color wheel. This palette is the default qualitative palette for `lessR` visualizations. The number of colors in the generated palette is set by `n`, with a default value of 12. By default, `getColors()` displays the palette as a rectangle. To display the colors around the color wheel, specify `shape="wheel"`.

The resulting palette is divided into hue intervals in the order the colors are used in subsequent visualizations. Adjacent values are chosen to maximize hue separation. The hue value, `h`, is shown in the plot. The text output also provides the hexadecimal and RGB specifications for each color.

@fig-default indicates the `getColors()` text and visualization output for all default parameter values.

``` r
getColors()
```

```{r}
#| echo: FALSE
#| label: fig-default
#| fig.height: 2.75
#| fig.cap: "Default output of getColors()."
getColors(output=TRUE, quiet=FALSE)
```

The ordering of the hues was chosen to maximize differences between adjacent hues, with the first five hues arbitrarily set to blue (240), brown (60), green (120), red (0), and purple (275).

The default `"hues"` qualitative palette is implicitly generated by `getColors()` for each bar chart, assuming the default value of the `fill` parameter. Also, a slight transparency is added to further soften the bars in the bar chart shown in @fig-defaultBars.

``` r
Chart(Dept)    or   Chart(Dept, fill=getColors())
```

```{r}
#| echo: FALSE
#| label: fig-defaultBars
#| fig.cap: "Default output of getColors()."
Chart(Dept)
```

Explicitly override the default by providing any qualitative palette for `fill`, including having `getColors()` generate an alternative with different chroma and luminance values. @fig-alt shows deeper, bolder colors than the default, by lowering luminance to `l=30`.

```{r}
#| label: fig-alt
#| fig.cap: "A bar chart with high saturation, chroma set at 95, and little brightness, luminance at 30."
Chart(Dept, fill=getColors(c=95, l=30))
```

Or minimize the color differences between the bars by dropping chroma to `c=25`, as shown in @fig-deep, almost desaturating the colors.

```{r}
#| label: fig-deep
#| fig.cap: "A bar chart with low saturation, chroma set at 25, and low brightness, luminance at 35."
Chart(Dept, fill=getColors(c=25, l=35))
```

### Manual Palettes

#### Complete Customization

One possibility creates a palette color-by-color. Enter multiple colors, then use `getColors()` to experiment with different color combinations and choose the palette. One inspiration for creating your custom palette is working with complementary colors or other related color patterns.

::: {.callout-note title="Complementary colors"}
For a given color, the color on the opposite side of the color wheel.
:::

Complementary colors, when paired, often form pleasing combinations in graphic design and data visualization. Many free online sources are available from which to choose complementary and related colors; here are some from [canva.com](https://www.canva.com/colors/color-wheel/), illustrated in @fig-comp.

![Color wheel to derive complementary and other related colors, here from canva.com.](images/complementary.png){#fig-comp fig-align="center" width="300"}

Specify the palette of multiple colors as a single unit with the vector function `c()` when calling `getColors()`. Usually, each color would be specified with the same notation. However, to demonstrate, this example uses multiple ways to specify colors. Store the resulting five colors in a vector, here named *clr*, as shown in the function call that created @fig-manual.

``` r
clr <- getColors(c("#63B99F", rgb(.35,.53,.71), hcl(40,60,70),
                   "palevioletred2", "gray60"))
```

```{r}
#| echo: FALSE
#| label: fig-manual
#| fig.height: 1.5
#| fig.cap: "Manually constructed color palette with getColors()."
clr <- getColors(c("#63B99F", rgb(.35,.53,.71), hcl(40,60,70), "palevioletred2", "gray60"), output=TRUE)
```

@fig-man2 shows the bar cart constructed from this manually constructed palette, directly references the *clr* vector.

```{r}
#| label: fig-man2
#| fig.cap: "A bar chart with a manually created qualitative palette."
Chart(Dept, fill=clr)
```

#### From an Image

Another possibility creates a palette from an image. For example, there could be official corporate logos or photographs from which a palette could be extracted using one of many free online services, then incorporated into subsequent data visualizations. Find the image picker illustrated in @fig-candle at [coolors.co](https://coolors.co/image-picker). Upload the image, then drag the circles on the picture around to obtain different colors. Drag a color to a different spot on the palette to rearrange the colors.

![A palette derived from the colors of a burning candle.](images/CandleLightPic.png){#fig-candle fig-align="center" width="410"}

In this example, click on `Export palette` and choose `Code`, from which the following five colors were copied and the bar chart created as shown in @fig-firecolors.

```{r}
#| label: fig-firecolors
#| fig.cap: "Bar chart from the burning candle palette."
Chart(Dept, fill=c("#69503A","#A86E47","#F2C66F","#4A5967","#CA4A18"))
```

Other possibilities, such as @fig-firecolors, can also be considered to achieve specific effects, including the palette discussed next.

### CVD Palettes

Many people are susceptible to various forms of color vision deficiency (CVD). The eye contains three types of cone receptor cells, each most sensitive to a different range of wavelengths: long, medium, and short. These sensitivities roughly correspond to red, green, and blue light. The most common forms of CVD involve difficulty distinguishing red from green, usually because the long- or medium-wavelength cone response is missing or shifted. Accordingly, red and green are often confused, making it problematic to rely on both colors as the primary distinction within the same palette. Less frequently, the short-wavelength cone response is affected, making it difficult to distinguish between blue and yellow.

::: column-margin
About 8% of men and 0.5% of women experience some degree of CVD, though the inability to visualize any color is rare.
:::

A qualitative scale for addressing these forms of color vision deficiency is the eight-color Okabe-Ito palette [@OI], shown in @fig-OIscale. This palette is directly accessible via `lessR`.

``` r
getColors("Okabe-Ito", n=8)
```

```{r}
#| label: fig-OIscale
#| echo: FALSE
#| fig.height: 1.5
#| fig.cap: "Okabe-Ito color palette."
getColors("Okabe-Ito", n=8, main="", output=TRUE)
```

An illustrative bar chart that applies the first five colors of this palette appears in @fig-OI.

```{r}
#| label: fig-OI
#| fig.cap: "Bar chart based on the Okae-Ito CVD qualitative color palette."
Chart(Dept, fill="Okabe-Ito")
```

The R package `colorBlindness` provides a variety of CVD palettes. It also provides functions that emulate how different palettes are perceived with different types of CVD.

## Sequential Palettes

### Definition

A sequential palette applies to a variable with ordered values, an ordinal categorical variable or a continuous variable.

::: {.callout-note title="Sequential palette"}
Systematically vary chroma or luminance at the same hue to generate a palette of colors.
:::

Examples of creating a sequential palette appear in @fig-two, where the hue is kept constant at `h=0` for red and either chroma or luminance is varied.

``` r
getColors(h=0, l=60, c=c(0,100))
getColors(h=0, c=80, l=c(90,20))
```

::: {#fig-two layout-ncol="2" layout-valign="bottom"}
```{r}
#| echo: FALSE
#| fig.height: 2
#| fig.cap: "(a) Variable chroma."
getColors(h=0, l=60, c=c(0,100), main="", output=TRUE)
```

```{r}
#| echo: FALSE
#| fig.height: 2
#| fig.cap: "(b) Variable luminance."
getColors(h=0, c=80, l=c(90,20), main="", output=TRUE)
```

Two sequential palettes with constant hue but variable chroma or luminance.
:::

### Pre-defined Palettes

Express the hues of the HCL color space in degrees from 0 to 360, with values wrapping around the circle for multiples beyond that range. Set red, associated with the longest visible wavelengths of light, to 0 degrees. Green and blue, the other two reference hues, appear at 120-degree increments, 120 and 240 degrees, respectively. @fig-colorwheel depicts the hues around the color wheel in 30-degree increments. Color names are also provided; some are standard R color names, but all are recognized by the lessR color management system.

The following call to `getColors()` generates the color wheel in @fig-colorwheel, without the color names. The default values for chroma and luminance are `c=65` and `l=60`.

``` r
getColors(n=12, shape="wheel")
```

![HCL color wheel with annotated color names.](images/ColorWheelHCL.png){#fig-colorwheel fig-align="center" width="420"}

For convenience, `getColors()` provides a predefined sequential palette for each corresponding hue name. The names of these palettes are the hue names from the color wheel in @fig-colorwheel, expressed as the plural of the color name. For example, the hue at 240 degrees, `"blue"`, defines the corresponding sequential palette named `"blues"`. Also included is a grayscale sequential palette named `"grays"`.

The `getColors()` function generates a sequential palette for the specified value of `n`. It also adjusts the luminance range according to the number of intervals generated, so fewer intervals produce a narrower range of luminance. Custom starting and ending luminance values can also be specified with the `l` parameter.

Substitute `"rusts"`, `"emeralds"`, `"purples"`, or any other plural version of the HCL color-wheel names from @fig-colorwheel to access the corresponding predefined sequential color scale. Use `"grays"` to access the corresponding grayscale palette. @fig-seq shows three examples of these sequential scales.

``` r
getColors("rusts")
getColors("aquas")
getColors("grays")
```

::: {#fig-seq layout-ncol="3" layout-valign="bottom"}
```{r}
#| echo: FALSE
#| fig.height: 2
#| fig.cap: "(a) \"rusts\" sequential palatte."
getColors("rusts", main="", output=TRUE)
```

```{r}
#| echo: FALSE
#| fig.height: 2
#| fig.cap: "(b) \"aquas\" sequential palatte."
getColors("aquas", main="", output=TRUE)
```

```{r}
#| echo: FALSE
#| fig.height: 2
#| fig.cap: "(c) \"grays\" sequential palatte."
getColors("grays", main="", output=TRUE)
```

Two `lessR` pre-defined sequential palettes.
:::

Predefined palettes, such as `"blues"`, preselect the hue, chroma, and luminance. Include custom values for `c` and `l` in the call to `getColors()` to override the provided defaults. The default chroma level for each predefined palette ranges from 35 to 75. The default luminance range depends on the number of intervals generated.

Consider the variable *JobSat* in the employee data set, which has three levels: Low, Med, and High. As with any categorical variable, the first step in its analysis is to formally declare it as a factor, which in R is done with the `factor()` function. Here, set the optional parameter `ordered` to `TRUE`, defining *JobSat* as an ordinal categorical variable.

```{r}
d$JobSat <- factor(d$JobSat, level=c("low", "med", "high"),
                             ordered=TRUE)
```

@fig-jobsat shows the resulting bar graph. Because JobSat is ordinal, `lessR`automatically applies a sequential palette to color the bars.

```{r}
#| label: fig-jobsat
#| fig.cap: Bar chart of an ordinal variable.
Chart(JobSat)
```

Of course, use the `fill` parameter to indicate a sequential palette with hues other than the default blue (for the existing color theme, explained later).

### CVD Viridis Palette

The most commonly applied sequential palette for color vision deficiency (CVD) is named `viridis` [@viridisExp]. The `viridis` palette avoids red hues, directly addressing the common difficulty of distinguishing red from green.

The `viridis` palette was developed according to the following principles.

- Perceptual uniformity, so that similar data values have similar-appearing colors and discrepant data values have more different-appearing colors, consistently across the range of values

- A wide color range, so differences among adjacent colors are easier to detect and extreme values are visually apparent

- Robustness to color vision deficiency, so that the above properties remain useful for people who do not perceive the full color spectrum

The `lessR` function `getColors()` can display the `viridis` palette directly. The default value for `n`, the number of intervals, is 12. A large value such as `n=100` approximates continuity, resulting in @fig-vpal.

``` r
getColors("viridis", n=100, border="transparent")
```

```{r}
#| label: fig-vpal
#| echo: FALSE
#| fig.height: 1.5
#| fig.cap: "The viridis palette."
getColors("viridis", n=100, border="transparent", main="", output=TRUE)
```

The `viridis` palette spans a wide color gamut, from dark blue to bright yellow. As a result, extreme data values, whether large or small, are visually differentiated from the remaining values by appearing near one end of the palette. Regarding perceptual uniformity, no large color steps interrupt adjacent color values. Instead, dark blue smoothly transitions to blue, then to blue-green, then to green, and finally to yellow.

As a sequential palette, the `viridis` palette is best applied to variables with ordered levels of magnitude, including ordinal variables and especially numerical variables measured on a continuum. The default palette for producing choropleth maps with the `mapview()` function is the `viridis` palette. An example is the Gini distribution map shown in @fig-map.

![Viridis is the default palette for the mapview() function.](images/US_gini.png){#fig-map fig-align="center"}

As indicated, `viridis` excels at detecting extreme values. In @fig-map, the state with the largest Gini coefficient, New York, is clearly distinguished from the remaining states with its yellow color.

## Divergent Palettes

Another form of a color palette diverges from two colors toward the neutral middle.

::: {.callout-note title="Divergent color palette"}
Each side of the palette is anchored by a different color, which fades to a central neutral toward the middle.
:::

For `lessR`, the most straightforward way to define a divergent scale is to use predefined sequential palettes such as "reds" and "blues" based on the HCL color names from @fig-colorwheel. The first parameter, `pal`, names the hue to be generated. If the scale is to be divergent, it names the left side of the scale. The second parameter, `end_pal`, indicates divergent. If present, it names the hue of the right side. An example of a divergent palette appears in @fig-redsblues.

``` r
getColors("reds", "blues", n=100, border="transparent")
```

```{r}
#| label: fig-redsblues
#| echo: FALSE
#| fig.height: 1.5
#| fig.cap: "Red-Blue divergent palette."
getColors("reds", "blues", n=100, border="transparent", output=TRUE, main="")
```

To apply the data visualization, we return to a different data set: the results of an attitude survey with 20 items, labeled from m01 to m20. The Survey response to each item was on a six-point scale from *strongly disagree* to *strongly agree*. The data table is included with \`lessR\`, called `*Mach4*`.

```{r}
d <- Read("Mach4")
```

The data are recorded numerically, with each response ranging from 0 (strongly disagree) to 5 (strongly agree). Label the numerical responses with the corresponding category name using the `lessR` `factors()` function, which can assign the factor levels and labels simultaneously to multiple variables, here in the *d* data frame.

```{r}
LikertCats <- c("Strongly Disagree", "Disagree", "Slightly Disagree",
                "Slightly Agree", "Agree", "Strongly Agree")
d <- factors(m01:m20, levels=0:5, labels=LikertCats, ordered=TRUE)
```

Set the `fill` parameter with a call to `getColors()` to define a divergent scale. According to the specification in @fig-m05, red indicates Disagree and blue indicates Agree. Given six possible response categories, there is no single value exactly in the middle, so there is no single gray bar.

```{r}
#| label: fig-m05
#| fig.cap: "Created divergent scale anchored by red and blue."
Chart(m05, fill=getColors("reds", "blues"))
```

We can view the responses to all 20 items on the default divergent scale by simply listing all 20 items as the data values to create the bar chart shown in @fig-mscale.

```{r}
#| label: fig-mscale
#| fig.width: 6.5
#| fig.height: 5
#| fig.cap: "A divergent scale for each of the 20 variables with similar responses."
Chart(m01:m20)
```

As an option, remove the labels displayed within each bar segment, shown in @fig-mscale2. Also, change from the default divergent scale Brown-Blue to Green-Violet.


```{r}
#| label: fig-mscale2
#| fig.width: 6.5
#| fig.height: 5
#| fig.cap: "A divergent scale for each of the 20 variables with similar responses."
Chart(m01:m20, fill=getColors("greens", "violets"), labels="off")
```


When listing multiple one-column bar charts, `Chart()` sorts the items by their mean response by default. The average score for *m09* is the highest of all 20 items. The average score for *m20* is the lowest.

# Other Customizations

## Themes

The values for each visual aesthetic, color or style option, can be pre-set as a group to define a theme, a presumably harmonious blend of visual aesthetics. `lessR` offers a variety of pre-defined themes, including their default themes.

The default `lessR` theme, `"colors"`, displays a relatively colorful palette. The `lessR` themes present different color combinations called *themes*.

::: {.callout-note title="theme"}
Pre-defined values for all visual aesthetics that apply to all visualizations when activated.
:::

Change or tweak a `lessR` theme with the `style()` function. The theme argument is the first argument in the parameter list for the function, so the first unnamed argument to `style()` specifies the theme. The `lessR` theme names correspond to the predominant theme color. Beyond the default of `"colors"`, `lessR` themes include "lightbronze", "dodgerblue", "darkred", "gold", "darkgreen", "blue", "red", "rose", "slatered", "green", "purple", "sienna", "brown", "orange", "white", "light", and "gray" for grayscale, set with `style("gray")`.

For additional flexibility, `lessR` also provides the `sub_theme` parameter. The `sub_theme` "black" sets a black background for any of the primary themes, as shown in @fig-subtheme.

```{r}
#| echo: FALSE
d <- Read("Employee")
```

```{r}
#| label: fig-subtheme
#| fig.cap: "Application of new style setting for a \"slatered\" theme and a  \"black\" sub_theme."
style("slatered", sub_theme="black", quiet=TRUE)
Chart(Dept)
```

Once the style has been set, it remains active until changed. So, the histogram in @fig-subhist continues the same style settings set for @fig-subtheme.

```{r}
#| label: fig-subhist
#| fig.cap: "Continuation of previous style settings."
X(Salary)
```

Now reset the style to the default for subsequent visualizations.

```
style()
```

If a theme is only to be applied to a single visualization, invoke the `theme` parameter to specify a theme different from the current theme.

## Individual Characteristics

Many characteristics of a data visualization do not depend directly on the data values. Want green axis labels, extra large? A purple background? Want to customize almost any aspect of your visualization? View the available `lessR` color and style options with a call to `style()`, setting the `show` parameter to `TRUE`.

```{r}
style(show=TRUE)
```

To illustrate, specify a new background color for the plot area of a panel, the rectangle defined by the *x* and *y* coordinate axes with the `panel_fill` parameter. According to the listed parameter values, set the color of the labels for each axis to "royalblue1" with the `lab_color` parameter. The result is @fig-individ.

```{r}
#| label: fig-individ
#| fig.cap: "Customization of the visualization for non-data based characteristics, panel color, and axis label color."
style(panel_fill="slategray1", lab_color="royalblue1") 
XY(Years, Salary)
```

The most straightforward function call to re-initialize the style settings is `style()`, which resets all parameters to the default theme, the equivalent of `style("colors")`.

## Drawing Editor

Another possibility for editing that offers the most flexibility is to leave the data visualization app entirely and complete editing in a standalone drawing editor, a vector graphics editor. Since the 1990's, the expensive and commercial standard for vector graphics is [Adobe Illustrator](https://www.adobe.com/products/illustrator/free-trial-download.html), rented on a monthly basis, \$38 per month until the next price increase. Much more affordable is [Affinity Designer](https://affinity.serif.com/en-us/designer/) \$70 for Windows and Mac, and \$18.49 for iPad, for a one-time purchase. [Inkscape](https://affinity.serif.com/en-us/designer/) offers the ultimate in affordability, providing an open-source, free, and capable alternative with more than 20 years of development and an extensive developer and support community. Other alternatives are available as well.

::: column-margin
The Affinity company has  been acquired by Canva, which operates an extensive, partially free [website](https://www.canva.com) for data visualization and graphic design.
:::

The key to using these drawing editors is to save the data visualization as a vector graphics file, such as a PDF. In the drawing application, each object in a PDF file is selectable and editable.

To demonstrate, consider the `lessR` bar chart saved as a PDF file from RStudio with the following menu sequence:\
    `Plots` –\> `Export` -\> `Save as PDF...`\
The bar chart was opened in Affinity Designer, as shown in @fig-edit1.

![lessR bar chart in Affinity Designer.](images/edit1.png){#fig-edit1 fig-align="center" width="600"}

Double-click on the desired bar to select it. Once selected, move to the color picker at the top right and choose the color for the bar's interior, as shown in @fig-edit2.

![Change a bar color.](images/edit2.png){#fig-edit2 fig-align="center" width="600"}

All objects are selectable. @fig-edit3 shows the selection of the axis labels. After selecting, open the color picker and choose a blue color.

![Change the axis labels color.](images/edit3.png){#fig-edit3 width="600"}

Editing a visualization in a drawing application offers a wider range of options than available in any data visualization application. The updated visualization can be saved in a variety of formats and used in presentation software ranging from MS Word and PowerPoint to RStudio's Quarto.
