Color

Matteo Ceccarello

The visual system

The retina of the eye has two kinds of receptors

  • rods: black and white vision in low light. Little role in the preception of colors.
  • cones: color vision in normal light. Concentrated around the visual axis.

Responsivity of human cone cells

The visual system

Images from Ware (2008)

How does this impact our work?

This effect is due to the low sensitivity of cones to blue wavelengths

How does this impact our work?

Yellow wavelengths excite two different types of cones, making it almost as light as pure white.

Opponent process theory

The brain combines signals from different cones to build three channels:

  • Red-Green
  • Yellow-Blue
  • Black-White

Contrast

The effect of contrast is distortion of the appearance of a patch of color in a way that increases the difference between a color and its surroundings.

We talk about luminance contrast when it occurs on the black-white channel, and chromatic when it occurs on the other two channels

This phenomenon is called simultaneous contrast, where the background interpheres with our perception of a patch of color. It can create problems when reading values from a graphic.

Unique hues

When there is a strong positive or negative signal on one of the three channels, and a neutral one on the other two, we have “special” colors

In most languages, these six colors are identified as the basic ones [Brent Berlin and Paul Kay, 1969. Basic Color Terms: Their Universality and Evolution]

Color blindness

A considerable number of people is missing one or more color channels. Most commonly, the missing channel is the red-green one.

As we shall see, when designing a color scale we need to take this into account in order to be inclusive.

Saturation

Colors inducing a strong response on the chromatic channels are more “vivid”, and are said to be more saturated.

The maximum saturation for a given hue varies with luminance, because when colors are dark the difference between cone signals on chromatic channels is smaller.

Color segmentation

Remember the discriminability issue? Here is it at play!

Spatial detail

The luminance channel is more effective at conveying spatial details.

Recovering shapes from shades

We perceive three dimensional surfaces through changes of luminance, rather than through chromatic changes.

Color spaces

To work with colors, we need to agree on a representation. Such representations of colors are called color spaces

The RGB color space

\((red, green, blue)\)

In computer representations, each component goes from 0 to 255

Why red, green and blue? This is the set of colors with the widest gamut, that is the set of all colors that can be defined by means of combining the three primary colors.

( 235, 91, 52 ) xxxx #eb5b34

Color spaces

RGB is computationally convenient, but is a poor fit for how our eyes work: it is not perceptually accurate.

In a perceptually uniform color space, colors with the same perceptual distance are at the same distance in the space.

HCL color space

HCL - Hue

What we intuitively think of as pure colors

HCL - Chroma

The “colorfulness” or intensity of the color. From “vivid” to “muted”

HCL - Luminance

Intuitively, the brightness of the color, or the amount of black mixed into the color. From “dark” to “light”

Interacting with the HSL color space

HCL - mapping data types


  • Qualitative



  • Sequential



  • Sequential

Sequential mapping pitfalls:

Source: https://socviz.co/lookatdata.html#perception-and-data-visualization

Sequential mapping pitfalls:

Source: https://socviz.co/lookatdata.html#perception-and-data-visualization

Sequential mapping with Chroma and Luminance

Because of the effects above, it is best not to encode more than 3 to 5 levels using the Chroma or Luminance channel, if we want our readers to be able to distinguish the levels (discriminability)

Colormaps

A colormap specifies a mapping between colors and data values

  • Categorical
  • Ordered
    • Sequential
    • Diverging

  • Continuous vs. discrete

Encoding with color, a summary

Encoding with color, a summary

Encoding with color, a summary

Encoding with color, a summary

Encoding with color, a summary

Encoding with color, a summary

Encoding with color, a summary

Categorical color maps

  • Use mainly hue to encode different categories

There are mainly two things to pay attention to

  • We can distinguish just about 12 bins of color, better to stick to at most 6

  • Luminance contrast: we need our colored marks to “stand out” from the background.

Categorical color maps - a bad example

Source: Munzner, ch.10, fig 10.8.

Ordered colormaps: sequential

Ordered colormaps: diverging

The rainbow color map

It’s often used to encode ordered data, why is it confusing?

The rainbow color map

The rainbow color map

The rainbow color map

An overview of R colormaps

You don’t need to create your colormaps from scratch. R sports a rich collection of colormaps ready for use

library(ggplot2)
library(RColorBrewer) # Qualitative. Visit https://colorbrewer2.org
library(viridis)      # Continuous
library(colorspace)   # General color-related utilities

Selecting a color palette

Install some additional libraries

# In the console
install.packages(c("colorspace", "shiny", "shinyjs"))

Call the wizard!

colorspace::hcl_wizard()

The specplot

The wizard shows, among other things, the specplot which reports how the HCL values change in the palette

# You can pass any list of colors
colormap <- c("#3C1B18","#612E32","#854452","#A75E79","#C47BA5","#DA9DD5")
specplot(colormap)

# Color blindness simulation: deutan, protan, tritan
colormap <- c("#3C1B18","#612E32","#854452","#A75E79","#C47BA5","#DA9DD5")
specplot(deutan(colormap))

The contrast ratio

The contrast ratio, as defined by the World Wide Web Consortium, is a number quantifying the contrast with the background. It should be higher than 4 for text, as a general guideline

colormap <- brewer.pal(5, "Pastel1")
contrast_ratio(colormap, "white", plot=T)

colormap <- sequential_hcl(5)
contrast_ratio(colormap, "white", plot=T)

Bivariate color palettes

Can be used to encode two different variables with color: use with extreme care!

pal1 <- tibble(c1 = c("#f5f5f5","#EE744B","#9F1401"), 
               dim1 = c("low", "mid", "high"))
pal2 <- tibble(c2 = c("#f5f5f5","#878FD3","#07489C"), 
               dim2 = c("low", "mid", "high"))
crossing(pal1, pal2) %>%
  mutate(
    color = hex(mixcolor(0.5, hex2RGB(c1), hex2RGB(c2))),
    across(starts_with("dim"), ~ factor(.x, 
                                        levels = c("low", "mid", "high"), 
                                        ordered=T))
  ) %>%
  ggplot(aes(x=dim1, y=dim2, fill=color)) +
  geom_tile() +
  scale_fill_identity() +
  theme_classic() +
  theme(axis.line = element_blank())

Source: Timo Grossenbacher

Case study

Solution

bg_color <- "gray5"

mortality <- 
  read_csv('death_rates_ITA.csv') |>
  #read_csv('Topics/Color/death_rates_ITA.csv') |>
  mutate(Percentile = ntile(Mortality, 100))

ggplot(mortality, aes(Year, Age, fill=Percentile)) +
  geom_tile() +
  scale_fill_viridis_c(
      option='magma', 
      direction=-1,
      breaks = seq(20, 100, by=20) 
  ) +
  scale_x_continuous( breaks=seq(1850, 2010, by=20) ) +
  scale_y_continuous( breaks=seq(0, 100, by=10) ) +
  facet_wrap(vars(Sex), ncol=1) +
  labs(
    caption = "Source: mortality.org"
  ) +
  theme_void() +
  theme(
    text = element_text(color = "gray90"),
    strip.text = element_text(hjust=0),
    axis.text.x = element_text(),
    axis.text.y = element_text(),
    panel.background = element_rect(fill = bg_color),
    plot.background = element_rect(fill = bg_color),
    legend.position = "top",
    legend.key.width = unit(0.1, "npc")
  )

Solution