colorjam
provides visually distinct categorical colors of arbitrary
length, using an optimized pattern of chroma/luminance values.
-
Scalable. Visually distinct categorical colors of arbitrary length.
rainbowJam(n)
- ggplot2 functions:
scale_color_jam()
,scale_fill_jam()
-
Color-blindness friendly. Optimized for three kinds of color blindness.
- Flexible.
"dichromat"
,"ryb"
,"rgb"
color wheels are available.
- Optimized for statistical design. First color gold assigned to control groups:
- Interactive R-shiny app.
launchColorjamShiny()
Install colorjam using the remotes
package:
remotes::install_github("jmw86069/colorjam");
OR, use pacman
to keep the package updated:
### if necessary, install pacman:
# install.packages("pacman")
library(pacman)
p_load_current_gh("jmw86069/colorjam")
The colorjam
package is being prepared for CRAN in the “near”
future.
The full command reference is available here:
For the examples below, two packages are loaded:
library(colorjam);
library(jamba);
Let’s generate n=5
categorical colors, displayed by
jamba::showColors()
.
showColors(rainbowJam(5));
Alternatively, color_pie()
displays colors in a pie circle.
color_pie(rainbowJam(5));
Categorical colors are scalable.
color_pie(rainbowJam(15));
Label the colors using the 4994 named_colors
:
color_pie(rainbowJam(15, nameStyle="closest_named_color"));
Gradually increase the number of colors, then use color_pie()
to plot
them in concentric circles.
colorList <- lapply(nameVector(c(36, 24, 12)), function(n){
rainbowJam(n, nameStyle="n");
});
color_pie(colorList,
main="preset='dichromat2' (default)");
Every color system has a “color wheel” - something like red-green-blue (RGB) or red-yellow-blue (RYB).
We defined a new color wheel "dichromat"
to maximize the visual
distinction between color hues for people with color blindness. The
process was driven by R package dichromat
, so we gave it that name out
of respect.
The "dichromat"
color wheel allocates approximately equal halves of
the color wheel to be visually distinct for "deutan"
, "protan"
, and
"tritan"
forms of color blindness. Roughly akin to using “cool”/“warm”
colors for each half the color wheel, for each simulated color. The
wheel avoids colors which are the most difficult to distinguish in the
color wheel.
It isn’t perfect.
However colorjam
does provide the first scalable method (we have seen)
to produce categorical colors optimized for the three major forms of
color-blindness. Other excellent resources that provide color-blindness
friendly colors, which are not scalable. However to be fair, fixed
colors may be the best realistic approach, so colorjam
may not be the
ideal solution.
The “full rainbow” color wheel “red-yellow-blue” is recommended over default RGB to provide the best full rainbow. It performs particularly well for color blending (see Color-blending) for additive paint-like mixing.
preset="ryb"
for red-yellow-blue
colorList1 <- lapply(nameVector(c(12)), function(n){
rainbowJam(n, preset="ryb");
});
color_pie(colorList1,
main="Red-Yellow-Blue\npreset='ryb' (starting at red)");
preset="ryb2"
(recommended) for yellow-red-blue, starting with yellow
colorList1 <- lapply(nameVector(c(16)), function(n){
rainbowJam(n, preset="ryb2");
});
color_pie(colorList1,
main="Yellow-Red-Blue\npreset='ryb2' (starting at yellow)");
The reason to start with yellow is noticed when the first category in a set is the reference or control group in a scientific experiment. It is intuitive for the reference/control to have a neutral color, instead of being bright red.
Previous versions (<= 0.0.23.900) of colorjam used a red-yellow-blue color wheel starting with red.
Similarly, the R default “red-green-blue” color wheel:
preset="rgb"
the R default RGB color wheel
color_pie(
rainbowJam(16, preset="rgb"),
main="Red-Green-Blue\npreset='rgb' (starting at red)");
(Look how much of this color wheel is blue-green. This style is not for me, haha.)
preset="rgb2"
the R default RGB color wheel, starting with yellow
color_pie(
rainbowJam(16, preset="rgb2"),
main="Red-Green-Blue\npreset='rgb2' (starting at yellow)");
The 4994 colors provided in named_colors
(see next section) are
collated from numerous sources, and ultimately represent colors that
people were motivated to name. Look how many named colors include
red/orange/yellow as compared to green/blue/purple! Then compare to the
RGB color wheel above, which disproportionately represents blue/green,
to the detriment of red/yellow.
Here, named_colors
are filtered for at least Chroma 40 using
subset_colors(named_colors, C > 40)
color_pie(unname(
subset_colors(named_colors, C > 40)))
Clearly people can see many more red-orange-yellow, and comparatively very few green/blue colors. This bias is partly from lower sensitivity of colors such as “cyan”, and partly due to RGB color monitors being unable to produce high saturation colors with that hue. Color theory is fascinating, and endlessly complex, in part because each person is slightly different.
Two functions are provided to match colors to a reference set, which is a convenient way to assign color names.
-
closestRcolor()
- matches colors to the 657 colors in
grDevices::colors()
, custom reference colors can be supplied.
- matches colors to the 657 colors in
-
closest_named_color()
- matches colors to 4883
named_colors
, which adds 4447 colors from meodai/named-colors (amazing!) and 436 colors not already represented fromgrDevices::colors()
.
- matches colors to 4883
The argument showPalette=TRUE
will plot the original colors and the
closest matched color for comparison.
cnc <- closest_named_color(c(rainbowJam(12), "grey"),
showPalette=TRUE,
main="closest_named_color() using `named_colors`");
crc <- closestRcolor(c(rainbowJam(12), "grey"),
showPalette=TRUE,
main="closestRcolor() using `colors()`");
There are two underlying methods:
"HCL"
(default) matches color hue by angle, with custom weights to channels H, C, and L."LUV"
matches colors using non-polar coordinates and Euclidean distance across the channels L, U, and V.
Greyscale colors are matches separately to a subset of grayscale reference colors, to avoid using hue in unsaturated colors.
blend_colors()
has some useful features:
- Paint-style blending. blue + yellow = green. (For default RGB: blue + yellow = grey)
- Scalable number of colors. Able to mix more than two colors.
- Transparency-aware. Accounts for color transparency during mixing.
The argument do_plot=TRUE
will plot a visual summary of the mixing
results.
blent1 <- blend_colors(c("red", "blue"), do_plot=TRUE);
blent2 <- blend_colors(c("gold", "blue"), do_plot=TRUE);
blent3 <- blend_colors(c("gold", "red"), do_plot=TRUE);
blent8 <- blend_colors(c("red1", "red3", "blue"), do_plot=TRUE);
blent9 <- blend_colors(c("red1", "blue1", "blue4"), do_plot=TRUE);
blent10 <- blend_colors(c("red", "blue", "ivory"), do_plot=TRUE);
color2gradient()
can split colors using a light-dark gradient.
colorSet <- rainbowJam(5);
colorSet4 <- color2gradient(colorSet, n=4);
color_pie(list(
colorSet4=unname(colorSet4),
colorSet=rep(colorSet, each=4)),
main="Color split into 4 additional subsets.");
The intensity of the gradient is adjusted with dex
, “darkness
expansion factor”.
colorSet <- rainbowJam(5);
colorSet4a <- color2gradient(colorSet,
n=4,
dex=1/2);
colorSet4c <- color2gradient(colorSet,
n=4,
dex=3);
colorSet4b <- color2gradient(colorSet,
n=4,
dex=10);
colorSet <- rep(colorSet, each=4)
names(colorSet4c) <- names(colorSet4b) <- names(colorSet4a) <- names(colorSet4) <- "";
names(colorSet4b)[5:8] <- c(" 10", " |", " |", " v")
names(colorSet4c)[5:8] <- c(" 3", " |", " |", " v")
names(colorSet4)[5:8] <- c(" 1", " |", " |", " v")
names(colorSet4a)[5:8] <- c("1/2", " |", " |", " v")
color_pie(list(
`dex=10`=(colorSet4b),
`dex=3`=(colorSet4c),
`dex=1\n(default)`=(colorSet4),
`dex=1/2`=(colorSet4a),
colorSet=colorSet),
main=paste0("Intensity of the gradient is adjusted with 'dex'\n",
"(darkness expansion factor)"));
scale_color_jam()
categorical colors for ggplot2colour
scale_fill_jam()
categorical colors for ggplot2fill
if (suppressPackageStartupMessages(require(ggplot2))) {
dsamp <- ggplot2::diamonds[sample(nrow(ggplot2::diamonds), 1000),];
d <- ggplot2::ggplot(dsamp, ggplot2::aes(carat, price)) +
ggplot2::geom_point(ggplot2::aes(colour=cut, fill=cut), size=4, shape=21);
d +
scale_color_jam() +
scale_fill_jam() +
ggplot2::ggtitle("scale_color_jam()");
}
Colors can be adjusted for darkness, saturation, to make interesting point shapes:
if (suppressPackageStartupMessages(require(ggplot2))) {
d +
scale_color_jam(darkFactor=1.5) +
scale_fill_jam(darkFactor=-1.2) +
ggplot2::ggtitle("Adjustment using 'darkFactor'");
}
An alternative ggplot2 theme is provided.
if (suppressPackageStartupMessages(require(ggplot2))) {
d +
scale_color_jam(darkFactor=1.5) +
scale_fill_jam(darkFactor=-1.2) +
ggplot2::ggtitle("theme_jam()") +
theme_jam()
}
This function provides some common arguments to customize:
base_size
:numeric
default font size in points.blankGrid
:logical
to remove all background grid lines.
if (suppressPackageStartupMessages(require(ggplot2))) {
d +
scale_color_jam(darkFactor=1.5) +
scale_fill_jam(darkFactor=-1.2) +
ggplot2::ggtitle("theme_jam()") +
theme_jam(base_size=24)
}
jam_linear
: linear (sequential) gradients with white baseline color
jamba::showColors(jam_linear)
jam_divergent
: divergent color gradients with black baseline color
jamba::showColors(jam_divergent)
The driving use case was to display genome sequence coverage heatmaps
with slightly different colors for each type of signal. We wanted linear
and divergent color gradients to use in tandem, for example
"jam_linear$firebrick"
and "jam_divergent$firebrick_skyblue"
.
twostep_gradient()
combines two linear gradients into one linear
gradient.
Two linear gradients are combined, using orange and red:
ts1 <- twostep_gradient("orange2", "firebrick", n=11, debug=TRUE)
#> w1 w2
#> 1 1.000 0.000
#> 2 1.000 0.000
#> 3 0.838 0.162
#> 4 0.686 0.314
#> 5 0.544 0.456
#> 6 0.414 0.586
#> 7 0.296 0.704
#> 8 0.192 0.808
#> 9 0.105 0.895
#> 10 0.037 0.963
#> 11 0.000 1.000
title("orange2 + firebrick");
Two linear gradients are combined, using aquamarine and blue:
ts2 <- twostep_gradient("aquamarine", "dodgerblue", n=11, debug=TRUE)
#> w1 w2
#> 1 1.000 0.000
#> 2 1.000 0.000
#> 3 0.838 0.162
#> 4 0.686 0.314
#> 5 0.544 0.456
#> 6 0.414 0.586
#> 7 0.296 0.704
#> 8 0.192 0.808
#> 9 0.105 0.895
#> 10 0.037 0.963
#> 11 0.000 1.000
title("aquamarine + dodgerblue");
make_jam_divergent()
combines two linear gradients.
ts1ts2 <- make_jam_divergent(list(ts2=ts2),
list(ts1=ts1),
n=21)
jamba::showColors(ts1ts2)