---
title: "Colors and color functions"
author: "SPDS, uni.kn"
date: "2023 07 28"
output: 
  rmarkdown::html_vignette: 
    fig_caption: yes
vignette: > 
  %\VignetteIndexEntry{Colors and color functions}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
editor_options: 
  chunk_output_type: console
---

```{r setup, include = FALSE}
options(max.print = "75")

knitr::opts_chunk$set(echo = TRUE,
                      cache = FALSE,
                      collapse = TRUE, 
                      comment = "#>",
                      prompt = FALSE,
                      tidy = FALSE,
                      message = FALSE,
                      warning = FALSE,
                      # Default figure options:
                      fig.align = "center",
                      # fig.width = 6, 
                      # fig.asp = .8 # .618, # golden ratio
                      out.width = "60%")
```

<!-- unikn pkg logo and link: -->
<a href = "https://CRAN.R-project.org/package=unikn">
<img src = "../inst/pix/unikn.png" alt = "unikn::" align = "right" width = "150px" style = "width: 150px; float: right; border:0;"/>
</a>

This vignette explains the colors, color palettes, and color-related functions provided by the **unikn** package. 
(See the vignettes on [color recipes](color_recipes.html) and [institutional colors](inst_colors.html) for more specialized tasks 
and the vignette on [text](text_decorations.html) for information on text boxes and decorations.) 

Please install and/or load the **unikn** package to get started: 

```{r load-pkg-colors, message = FALSE, warning = FALSE}
# install.packages('unikn')  # install unikn from CRAN client
library('unikn')             # loads the package
```

## Overview 

The **unikn** package provides some colors (e.g., `Seeblau`) and color palettes (e.g., `pal_unikn`). 
However, its functionality is mainly based on color-related functions that are useful beyond the colors and palettes of this package. 

<!-- A. Primary functions: Seeing and using colors -->

The package provides two main functions for interacting with color palettes: `seecol()` and `usecol()`. 

1. `seecol()` is a general-purpose tool for **seeing (inspecting or visualizing) colors or color palettes**. 
The `seecol()` function takes two main arguments:

    - `pal` provides either one or multiple color palettes (with a default of `pal = "unikn_all"`);  
    - `n` specifies the number of desired colors (with a default of `n = "all"`).  

Based on the input of `pal`, the `seecol()` function distinguishes between two modes:

  - A. _viewing the details_ of a _single_ color palette (when providing only one color palette); 
  - B. _comparing multiple_ color palettes (when providing a keyword or `list`-object).   
   

2. `usecol()` allows **using colors or color palettes** (e.g., when creating visualizations) without showing its details. 
The `usecol()` function also takes arguments for conveniently manipulating color palettes:

    - `pal` provides either one or multiple color palettes (with a default of `pal = pal_unikn`);  
    - `n` specifies the number of desired colors (with a default of `n = "all"`); 
    - `alpha` adjusts the opacity of all colors in `pal` (e.g., `alpha = .50` for medium transparency). 


<!-- B. Secondary functions: Finding colors and defining color palettes -->

Two additional functions allow **finding colors** by similarity or name:

1. `simcol()` allows **finding similar colors** (given a target color, a set of candidate colors, and some tolerance threshold(s));  

2. `grepal()` allows **finding colors with particular names** (i.e., colors whose names match some `pattern` or regular expression);  


<!-- C. Auxiliary color functions: -->

Finally, some **auxiliary functions** support specific color functions:

- `ac()` adjusts **color transparency**; 

- `shades_of()` allows creating **linear color gradients**; 

- `newpal()` allows **defining new color palettes** (as vectors or data frames with dedicated color names); and 

- `demopal()` allows **illustrating color palettes** for different types of visualizations. 

 
<!-- Transition: -->

The rest of this vignette provides examples of and some details on using these functions. 
(See the [Color recipes](color_recipes.html) vignette for more examples of solving color-related tasks.)


## Viewing colors and color palettes with `seecol()`

The behavior of the `seecol()` function distinguishes between two modes and depends on the input to its initial `pal` argument. 
It either shows (A)\ the details of an individual color palette, or (B)\ allows comparing multiple color palettes. 
The next two sections will address both modes in turn. 

### A. Viewing details of a single color palette 

When the `pal` argument of the `seecol()` function specifies a _single_ color palette, the function plots a more detailed view of this particular color palette: 

```{r unikn-palette, fig.width = 5, fig.asp = .8, fig.align = 'center'}
seecol(pal_unikn)  # view details of pal_unikn 
```

The detailed overview of a color palette provides us with 

- the color names (where available),  
- their numeric indices (within the color palette),     
- the HEX values for each color,   
- the RGB values for each color.  

When a color palette contains too many colors, the HEX and RGB values are no longer printed. 
However, setting `hex` and `rgb` to\ TRUE will force them to be shown. 

<!-- Seeing and saving a color palette: -->

Note that `seecol()` also returns the color palette that is being shown. 
Thus, a typical workflow comprises both _seeing_ a particular color palette and _saving_ it (for storing and applying it later):   

```{r save-seecol, fig.width = 5, fig.asp = .8, fig.align = 'center'}
my_pal <- seecol(pal_unikn_light)  # view details of AND save a color palette  
```

Due to saving the color palette (here to `my_pal`) we can later use it in a visualization: 

```{r my-pal-example, fig.width = 5, fig.asp = .65, fig.align = 'center'}
barplot(1/sqrt(1:10), col = my_pal)  # use my_pal in a plot
```

Note that `seecol()` _invisibly_ returns the color palette.  
Thus, the following will plot the palette `pal_bordeaux` without doing anything else with it:

```{r invisible-seecol, fig.width = 5, fig.asp = .8, fig.align = 'center'}
seecol(pal_bordeaux)
```

but the following would both plot and assign the palette to `my_pal`:

```{r invisible-seecol-assign, eval = FALSE}
my_pal <- seecol(pal_bordeaux)
```


### B. Viewing and comparing multiple color palettes

The second mode of `seecol()` is invoked by providing (a list of) _multiple_ color palettes to its `pal` argument.  
In this case, the function allows comparing these palettes by plotting a color vector for each palette. 
Some special keywords within the **unikn** package denote sets of color palettes: 

- The keywords `"unikn_all"`, `"unikn_basic"`, `pair_all"`, `"pref_all"` and `"grad_all"` refer to [University of Konstanz](https://www.uni-konstanz.de/) color palettes.

<!-- - The keywords `"all"` and `"add"` allow comparing all or only the additional color palettes, respectively.  -->

Calling `seecol` with `pal` set to these keywords allows comparing pre-defined sets of the color palettes:   

Viewing the [uni.kn](https://www.uni-konstanz.de/) color palettes:

```{r seecol-unikn-all, fig.width = 6, fig.height = 5, fig.align = 'center'}
seecol("unikn_all")  # all uni.kn color palettes
```

1. three _basic_ color palettes:

```{r seecol-unikn-basic-2, fig.width = 6, fig.height = 2, fig.align = 'center'}
seecol("unikn_basic")
```

Note, that `pal_unikn_web` and `pal_unikn_ppt` are almost identical, but differ in how vibrant their colors are.  

2. three _paired_ color palettes:

```{r seecol-pair-all, fig.width = 6, fig.height = 2.5, fig.align = 'center'}
seecol("pair_all")
```

3. all _preferred_ colors from the spectrum and their respective _gradients_:

```{r seecol-pref-all, fig.width = 6, fig.height = 3.5, fig.align = 'center', out.width="500"}
seecol("pref_all")
```

4. only the pre-defined color _gradients_:

```{r seecol-grad-all-2, fig.width = 5, fig.asp = .8, fig.align = 'center', out.width="400"}
seecol("grad_all")
```

<!-- All _additional_ color palettes (from other institutions): -->

```{r seecol-add, echo = FALSE, eval = FALSE, fig.width = 7.2, fig.asp = .9, fig.align = 'center', out.width="500"}
seecol("add")
```

See the vignette on [Institutional colors](inst_colors.html) for creating color palettes for other institutions. 


### Other `seecol()` arguments 

The `seecol()` function provides some aesthetic parameters for adjusting how color palettes are plotted:

- `col_brd` allows specifying the color of box borders (if shown. Default: `col_brd = NULL`);  
- `lwd_brd` allows specifying the line width of box borders (if shown. Default: `lwd_brd = NULL`);   
- `main` and `sub` allow replacing the default titles with custom titles.  

Examples:

```{r seecol-aesthetic-parameters, fig.width = 5, out.width = "60%", fig.asp = .8, fig.align = 'center', out.width="400"}
seecol("grad_all", col_brd = "black", lwd_brd = .5, main = "Color gradients (with black borders)")
seecol(pal_seegruen, col_brd = "white", lwd_brd = 5, main = "A color palette (with white borders)")
```


## Using a color palette with `usecol()`

The `usecol()` function allows directly using a color palette in a plot (i.e., without first viewing it).
`usecol()` corresponds to `seecol()` by taking the same main arguments (`pal` and `n`). 
However, as its purpose is _using_ the colors specified by `pal`, rather than plotting (or _seeing_) them, its `pal`\ argument typically contains only one color palette: 

```{r usecol-default-use, fig.width = 5, out.width = "60%", fig.asp = .65, fig.align = 'center'}
# Using a color palette:
barplot(1/sqrt(1:11), col = usecol(pal_unikn))
```

<!-- Flexibility in providing color palette pal: -->

Note that the `seecol()` and `usecol()` functions are both quite permissive with respect to specifying their `pal` argument: 
A particular color palette (e.g., `pal_seegruen`) can not only be displayed by providing it (as an object) but also by providing its name (i.e., `"pal_seegruen"`) or even an incomplete object name or name (i.e., `"seegruen"` or `seegruen`). 
Hence, the following expressions all yield the same result: 

```{r free-pal-args, fig.width = 5, fig.asp = .75, eval = FALSE}
seecol(pal_seegruen)
seecol("pal_seegruen")
seecol("seegruen")
seecol(seegruen)  # issues a warning, but works 
```


## Customizing color palettes

Both the `seecol()` and the `usecol()` functions allow a flexible on-the-fly customization of color palettes. 

Specifying a value for the `n` argument of `seecol()` an `usecol()` allows:  

- specifying subsets of colors and comparing these subsets for different palettes for `n` _smaller_ than the length of the color palette;  
- extending color palettes and comparing different palettes for `n` _greater_ than the length of the color palette. 

Passing a vector of colors and/or color palettes allows users to create and view their own color palettes. 

Finally, specifying a value for `alpha` (in a range from 0 to 1) allows controlling the transparency of the color palette(s), with higher values for `alpha` corresponding to higher transparency (i.e., lower opacity). 


### Selecting subsets

Using only a subset of colors:

```{r use-subset, fig.width = 5, fig.height = 4, fig.align = 'center', collapse = TRUE}
seecol("unikn_all", n = 4)
seecol(pal_unikn, 4)
```

Importantly, when using pre-defined color palettes of **unikn** but a value of `n` that is smaller than the length of the current color palette, `usecol` and `seecol` select a predefined subset of colors:

```{r use-col-small-n, fig.width = 3, out.width = c('35%', '35%'), fig.height = 2.5, fig.align = 'center', collapse = TRUE, fig.show = 'hold'}
barplot(1/sqrt(1:2), col = usecol(pal_seeblau, n = 2))
barplot(1/sqrt(1:3), col = usecol(pal_seeblau, n = 3))
```

### Extending color palettes

For values of `n` that are larger than the number of available colors in `pal`, the specified color palette is extended using `ColorRampPalette`:

```{r use-superset-all, fig.width = 5, fig.asp = .8, fig.align = 'center', collapse = TRUE}
seecol("unikn_all", n = 12)
```

Both `seecol()` and `usecol()` allow extending or truncating color palettes to a desired number `n` of colors. 
For instance:

- Inspecting an extended version of `pal_seeblau` (with `n = 8` colors):

```{r use-superset, eval = FALSE, fig.width = 5, fig.asp = .8, fig.align = 'center', collapse = TRUE}
seecol(pal_seeblau, n = 8)
```

- Using a truncated version of `pal_bordeaux` (with `n = 3` colors):

```{r use-col-big-n, eval = FALSE, fig.width = 5, fig.asp = .65, fig.align = 'center'}
barplot(1/sqrt(1:9), col = usecol(pal_bordeaux, n = 3))
```


### Mixing colors and color palettes

By passing a vector to `pal`, we can concatenate 2 color palettes and connect them with a color (here: `"white"`) as the midpoint of a new color palette:  

```{r combine-pals, fig.width = 5, out.width = "60%", fig.asp = .8, fig.align = 'center'}
seecol(pal = c(rev(pal_petrol), "white", pal_bordeaux))
```

We can combine a set of colors and extend this palette by specifying an `n` argument that is larger than the length of the specified palette: 

```{r combine-pals-n, fig.width = 5, out.width = "60%", fig.asp = .8, fig.align = 'center'}
seecol(pal = usecol(c(Karpfenblau, Seeblau, "gold"), n = 10))
```

These custom palettes can easily be used in a plot. For instance, we can define and use a subset of the `pal_unikn_pair` palette as follows: 

```{r use-my-pair, fig.width = 5, fig.height = 4, fig.align = 'center'}
my_pair <- seecol(pal_unikn_pair, n = 10)

# Create data: 
dat <- matrix(sample(5:10, size = 10, replace = TRUE), ncol = 5)

# Plot in my_pair colors:
barplot(dat, beside = TRUE, col = my_pair)
```

Creating linear color gradients is also supported by the `shades_of()` function (see below).


### Controlling transparency

Both `seecol()` and `usecol()` accept an `alpha` argument (in a range from\ 0 to\ 1) for controlling the transparency of color palettes, with higher values for `alpha` corresponding to lower transparency (i.e., higher opacity). 

Displaying a specific color palette at a medium opacity/transparency:

```{r transparency1-pal, fig.width = 5, fig.asp = .8, fig.align = 'center', collapse = TRUE}
seecol(pal_unikn, alpha = 0.5)
```

Setting opacity for a custom color palette: 

```{r transparency-four, fig.width = 5, fig.asp = .8, fig.align = 'center'}
four_cols <- usecol(c("steelblue", "gold", "firebrick", "forestgreen"), alpha = 2/3)

seecol(four_cols, main = "Four named colors with added transparency")
```

Setting opacity for comparing of multiple color palettes: 

```{r transparency-all, fig.width = 5, fig.height = 4, fig.align = 'center'}
seecol("grad", alpha = 0.67, main = "Seeing transparent color palettes")
```


### Creating and comparing custom palettes 

Suppose we want to compare a newly created color palette to existing color palettes. To achieve this, advanced users can use the `seecol()` function for displaying and comparing different custom palettes. When provided with a list of color palettes as the input to its `pal` argument, `seecol()` will show a _comparison_ of the inputs:

```{r compare-custom-palettes, fig.width = 5, fig.height = 3, fig.align = 'center'}
# Define 2 palettes: 
pal1 <- c(rev(pal_seeblau), "white", pal_bordeaux)
pal2 <- usecol(c(Karpfenblau, Seeblau, "gold"), n = 10)

# Show the my_pair palette from above, the 2 palettes just defined, and 2 pre-defined palettes:  
seecol(list(my_pair, pal1, pal2, pal_unikn, pal_unikn_pair))
```

Note that unknown color palettes are named `pal_`$n$, in increasing order. 
Palettes known to `seecol()` are labeled by their respective names. 
Labeling only custom palettes works by setting the `pal_names` argument to a character vector of appropriate length: 

```{r set-custom-palette-names, eval = FALSE, fig.width = 5, fig.height = 3, fig.align = 'center'}
seecol(list(my_pair, pal1, pal2, pal_unikn, pal_unikn_pair), 
       pal_names = c("my_pair", "blue_bord", "blue_yell"),
       main = "Labeling custom color palettes")
```

If the `pal_names` argument is specified and corresponds to the length of _all_ color palettes, the default names of all color palettes are overwritten by `pal_names`:

```{r set-all-palette-names, eval = FALSE, fig.width = 5, fig.height = 3, fig.align = 'center'}
seecol(list(my_pair, pal1, pal2, pal_unikn, pal_unikn_pair), 
       pal_names = c("my_pair", "blue_bord", "blue_yell", "blue_black", "mix_pair"),
       main = "Comparing and labeling custom color palettes")
```

As before, we can use lower values of `n`\ for truncating/obtaining shorter subsets of color palettes: 

```{r subset-compare, fig.width = 5, fig.height = 3, fig.align = 'center'}
seecol(list(my_pair, pal1, pal2, pal_unikn, pal_unikn_pair), n = 5)
```

or higher values of\ `n` for extending color palettes: 

```{r superset-compare, fig.width = 5, fig.height = 3, fig.align = 'center'}
seecol(list(my_pair, pal1, pal2, pal_unikn, pal_unikn_pair), n = 15)
```


## Finding colors

Two familiar color search tasks are addressed by the `simcol()` and `grepal()` functions:

- `simcol()` allows searching for colors that are similar to a given target color
- `grepal()` allows searching for colors whose names match some pattern 

### Finding similar colors with `simcol()` 

Assuming that our favorite color is `"deeppink"`, a good question is: How can we find similar colors? 
Given some target color, the `simcol()` function searches through a set of colors to find and return visually similar ones: 

```{r simcol-1, fig.width = 5, fig.asp = .8, fig.align = 'center', fig.show = 'hold'}
simcol("deeppink", plot = FALSE)
```

By default, `simcol()` searches though all named R\ colors of `colors()` (of the **grDevices** package), but adjusting the `col_candidates` and `tol` arguments allows for more fine-grained searches:

```{r simcol-2, fig.width = 5, out.width = "60%", fig.asp = .8, fig.align = 'center', fig.show = 'hold'}
simcol("deepskyblue", col_candidates = pal_seeblau, tol = c(50, 50, 100))
```

### Finding color names with `grepal()` 

We often search for some particular color hue (e.g., some sort of purple), but also know that the particular color named "purple" is _not_ the one we want. 
Instead, we would like to see all colors that contain the keyword "purple" in its name. 
The `grepal()` function addresses this need:

```{r grepal-1, fig.width = 6, out.width = "60%", fig.height = 4, fig.align = 'center'}
grepal("purple")  # get & see 10 names of colors() with "purple" in their name
```

Note that the `grepal()` function allows searching color names by regular expressions:

```{r grepal-2}
length(grepal("gr(a|e)y", plot = FALSE))    # shades of "gray" or "grey"
length(grepal("^gr(a|e)y", plot = FALSE))   # shades starting with "gray" or "grey"
length(grepal("^gr(a|e)y$", plot = FALSE))  # shades starting and ending with "gray" or "grey"
```

By default, `grepal()` searches the vector of named colors `x = colors()` (of the **grDevices** package) and plots its results (as a side effect). 
However, it also allows for searching color palettes provided as data frames (with color names) and for suppressing the visualization (by setting `plot = FALSE`): 

```{r grepal-3, fig.width = 5, out.width = "60%", fig.asp = .8, fig.align = 'center'}
grepal("see", pal_unikn)   # finding "see" in (the names of) pal_unikn (as df)
grepal("blau", pal_unikn_pref, plot = FALSE)  # finding "blau" in pal_unikn_pref
```


## Auxiliary color functions 

### Adjusting transparency with `ac()` 

The `ac()` function provides a flexible wrapper around the `adjustcolor()` function of the **grDevices** package. 
Its key functionality is that it allows for _vectorized_\ `col` and\ `alpha` arguments:

```{r transparency-ac, fig.width = 5, fig.asp = .8, fig.align = 'center'}
my_cols <- c("black", "firebrick", "forestgreen", "gold", "steelblue")
seecol(ac(my_cols, alpha = c(rep(.25, 5), rep(.75, 5))))
```

The name `ac` is an abbreviation of "adjust color", but also a mnemonic aid for providing "air conditioning".


### Creating color gradients with `shades_of()`

We have seen that the main `usecol()` function allows stretching and squeezing color palettes and thus creating complex color gradients. 
An even simpler way for creating linear color gradients is provided by the `shades_of()` function:

```{r shades-of-1, fig.width = 4.5, fig.asp = .8, fig.align = 'center'}
seecol(shades_of(n = 5, col_1 = Karpfenblau), main = "5 shades of Karpfenblau")
```

Internally, `shades_of()` is just a convenient wrapper for a special `usecol()` function.
The limitation of `shades_of()` is that it only allows creating bi-polar color palettes (i.e., gradients between two colors). 
When the final color `col_n` is unspecified, its default of "white" is used (as in the example). 
By contrast, the `usecol()` function allows creating color gradients between an arbitrary number of colors. 
Thus, the following two expressions define the same bi-polar color palette: 

```{r shades-of-2, fig.width = 5, fig.asp = .8, fig.align = 'center'}
pg_1 <- usecol(c("deeppink", "gold"), 5)
pg_2 <- shades_of(5, "deeppink", "gold")
all.equal(pg_1, pg_2)

seecol(pg_2, main = "A bi-polar color gradient")
```


### Defining color palettes with `newpal()`

Having created, combined or found all those beautiful colors, we may wish to define a new color palette. 
Defining a new named color palette allows to consistently access and apply colors (e.g., to a series of visualizations in a report or publication). 
The `newpal()` function makes it easy to define color palettes: 

```{r newpal-1, fig.width = 5, fig.asp = .8, fig.align = 'center'}
col_flag <- c("#000000", "#dd0000", "#ffce00")  # source: www.schemecolor.com

flag_de  <- newpal(col = col_flag,
                   names = c("black", "red", "gold"))

seecol(flag_de, main = "Defining a flag_de color palette")
```

By default, `newpal()` returns the new color palette as a (named) vector. Setting `as_df = TRUE` returns a data frame. 


### Illustrating color palettes with `demopal()` 

After choosing, creating or modifying a color palette, we usually inspect the result with `seecol()`. 
Alternatively, we can use the `demopal()` function to use a color palette\ `pal` in a visualization. 
Currently, the `type` argument supports the following visualizations:

1. "bar": A bar plot
2. "curve": A plot of normal distribution curves (with transparency) 
3. "mosaic": A mosaic/table plot
4. "polygon": An area/polygon plot 
5. "scatter": A scatter plot of points (with transparency)

All types of `demopal()` invisibly return their (randomly generated) data and accept some graphical arguments (e.g., `col_par` and `alpha`), a scaling `n` and a `seed` value (for reproducible results), as well as `main` and `sub` arguments (for setting plot titles). 
Some functions additionally accept type-specific arguments (e.g., logical `beside`, `horiz`, and `as_prop` arguments for plot `type = "bar"`).

```{r demopal, fig.width = 5, fig.asp = .8, fig.align = 'center'}
demopal(pal = pg_2, type = 3)
```

<!-- Conclusion: -->

This concludes our quick tour through the colors and color functions of the **unikn** package. 
We hope that they enable you to find, design, and use beautiful color palettes ---\ and spice up your visualizations by vivid and flamboyant colors! 


## Resources

The following versions of **unikn** and corresponding resources are currently available: 

Type:                    | Version:           | URL:                           |         
:------------------------|:-------------------|:-------------------------------| 
A. **unikn** (R package): | [Release version](https://CRAN.R-project.org/package=unikn) | <https://CRAN.R-project.org/package=unikn> |
    &nbsp;                | [Development version](https://github.com/hneth/unikn/)      | <https://github.com/hneth/unikn/> | 
B. Online documentation:  | [Release version](https://hneth.github.io/unikn/)           | <https://hneth.github.io/unikn/> | 
    &nbsp;                | [Development version](https://hneth.github.io/unikn/dev/)   | <https://hneth.github.io/unikn/dev/> | 


## Vignettes

The following vignettes provide instructions and examples for using the **unikn** colors, color palettes, and functions: 

<!-- unikn pkg logo and link: -->
<a href = "https://CRAN.R-project.org/package=unikn">
<img src = "../inst/pix/unikn.png" alt = "unikn::" align = "right" width = "150px" style = "width: 150px; float: right; border:0;"/>
</a> 

<!-- Table of vignettes: -->

| Nr.  | Vignette | Content    |        
| ---: |:---------|:-----------|
| 1. | [Colors](color_functions.html)           | Colors and color functions                     |
| 2. | [Color recipes](color_recipes.html)      | Recipes for color-related tasks                |
| 3. | [Institutional colors](inst_colors.html) | Creating color palettes for other institutions |
| 4. | [Text](text_decorations.html)            | Text boxes and decorations                     | 

<!-- eof. -->
