---
title: "An introduction to qualpalr"
author: "Johan Larsson"
date: "`r Sys.Date()`"
bibliography: qualpal.bib
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{An introduction to qualpalr}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

## Overview

`qualpalr` generates qualitative color palettes optimized
for maximally distinct colors. Given `n` (the number of colors to generate), along with a subset
in the [hsl color space](https://en.wikipedia.org/wiki/HSL_and_HSV)[^1] (a
cylindrical representation of the RGB color space) `qualpalr` attempts to find
the `n` colors in the provided color subspace that *maximize the smallest
pairwise color difference*. This is done by computing the pairwise
color differences between all the input colors, and then
selecting the `n` colors that maximize the minimum pairwise color difference.

[^1]: Input can also be a predefined set of colors or a
  subspace of the LCH~ab~ color space.

## Examples

`qualpalr` main workhorse is `qualpal()`, which takes as its input
`n` (the number of colors to generate) and `colorspace`, which can be either

* a list of numeric vectors `h` (hue from -360 to 360), `s` (saturation from
  0 to 1), and `l` (lightness from 0 to 1), all of length 2, specifying a min and
  max,
* a list of numeric vectors `h` (hue from -360 to 360), `c` (chroma from
  0 to 100), and `l` (lightness from 0 to 100), all of length 2, specifying a min and
  max, or
* a character vector specifying a predefined color palette.

```{r}
#| label: basic-usage
library(qualpalr)
pal <- qualpal(5, list(h = c(-200, 120), s = c(0.3, 0.8), l = c(0.4, 0.9)))

# Adapt the color space to deuteranopia of severity 0.7
pal <- qualpal(5, cvd = c(deutan = 0.7))
```

The resulting object, `pal`, is a list with several color tables and a distance
matrix based based on the color difference metric used, by default CIEDE2000 (`metric = ciede2000`).

```{r}
#| label: qualpal-list
pal
```

Methods for `pairs` and `plot` have been written for `qualpal` objects to help
visualize the results.

```{r}
#| fig-show: hold
# Multidimensional scaling plot
plot(pal)

# Pairs plot in the DIN99d color space
pairs(pal, colorspace = "DIN99d")
```

The colors are most easily used in R by accessing `pal$hex`

```{r map}
#| fig-width: 5
#| fig-height: 5
library(maps)
map("france", fill = TRUE, col = pal$hex, mar = c(0, 0, 0, 0))
```

## Details

`qualpal` begins by generating a point cloud out of the HSL color subspace
provided by the user, using a quasi-random Halton sequence. Here is the color
subspace in HSL with settings
`h = c(-200, 120), s = c(0.3, 0.8), l = c(0.4, 0.9)`.

```{r}
#| label: details-input
#| message: false
#| echo: false
options(rgl.useNULL = TRUE)
library(rgl)

# Set up color subspace as in qualpal()
h <- c(-200, 120)
s <- c(0.3, 0.8)
l <- c(0.4, 0.9)

# Generate a quasi-random Halton sequence
rnd <- randtoolbox::halton(1000, dim = 3)

# Convert random sequence to specified color space
scale_runif <- function(x, new_min, new_max) {
  (new_max - new_min) * (x - 1) + new_max
}

rnd[, 2] <- sqrt(rnd[, 2])
H <- scale_runif(rnd[, 1], min(h), max(h))
S <- scale_runif(rnd[, 2], min(s), max(s))
L <- scale_runif(rnd[, 3], min(l), max(l))

HSL <- cbind(H, S, L)
HSL[HSL[, 1] < 0, 1] <- HSL[HSL[, 1] < 0, 1] + 360

# Set up variables to produce the HSL cylinder
x <- S * cos(H * pi / 180)
y <- S * sin(H * pi / 180)

# Convert to RGB to enable coloring
RGB <- qualpalr:::convert_colors(HSL, "hsl", "rgb")

plot3d(cbind(x, y, L), col = rgb(RGB), main = "HSL")
rglwidget()
```

The program then proceeds by projecting these colors into the sRGB space.

```{r}
#| label: rgb-space
#| echo: false
plot3d(RGB, col = rgb(RGB), main = "RGB")
rglwidget()
```

It then continues projecting the colors into the XYZ space. After this,
behavior depends on the metric used. By default, qualpal uses the CIEDE2000
color difference formula [@sharma2005], which is the current state of the art
in color difference metrics and standard as defined by the International
Commission on Illumination (CIE). For illustrative purposes, however, we will
show the procedure when the DIN99d color space [@cui_uniform_2002] is used
instead, which is a perceptually uniform color space that uses the Euclidean
distance as a color difference metric. This makes for a computationally simpler
and faster algorithm, but it is not as accurate as CIEDE2000. 

```{r}
#| label: din-space
#| echo: false
DIN99d <- qualpalr:::convert_colors(RGB, "rgb", "din99d")

plot3d(DIN99d, col = rgb(RGB), main = "DIN99d")
rglwidget()
```

When using the DIN99d color space, we also apply a power transformation
[@huang_power_2015] to fine tune these differences.

To select the `n` colors that the user wanted, we proceed greedily: first, we
find the two most distant points, then we find the third point that maximizes
the minimum distance to the previously selected points. This is repeated until
`n` points are selected. These points are then returned to the user; below is
an example using `n = 5`.

```{r}
#| label: selected-points
#| echo: false
pal <- qualpal(5, list(h = c(-200, 120), s = c(0.3, 0.8), l = c(0.4, 0.9)))
plot3d(DIN99d, col = rgb(RGB), main = "DIN99d", alpha = 0.1)
plot3d(pal$DIN99d, col = pal$hex, main = "DIN99d", add = TRUE, size = 5)
rglwidget()
```

## Thanks

[Bruce Lindbloom's webpage](http://www.brucelindbloom.com/) has
been instrumental in making qualpalr. Thanks also to
[i want hue](https://medialab.github.io/iwanthue/), which inspired me
to make qualpalr.

## References
