Martin Krzywinski / Canada's Michael Smith Genome Sciences Centre / mkweb.bcgsc.ca Martin Krzywinski / Canada's Michael Smith Genome Sciences Centre / mkweb.bcgsc.ca - contact me Martin Krzywinski / Canada's Michael Smith Genome Sciences Centre / mkweb.bcgsc.ca on Twitter Martin Krzywinski / Canada's Michael Smith Genome Sciences Centre / mkweb.bcgsc.ca - Lumondo Photography Martin Krzywinski / Canada's Michael Smith Genome Sciences Centre / mkweb.bcgsc.ca - Pi Art Martin Krzywinski / Canada's Michael Smith Genome Sciences Centre / mkweb.bcgsc.ca - Hilbertonians - Creatures on the Hilbert CurveMartin Krzywinski / Canada's Michael Smith Genome Sciences Centre / mkweb.bcgsc.ca - Pi Day 2020 - Piku
Feel the vibe, feel the terror, feel the painHooverphonicMad about you, orchestrally.more quotes

red: color


Scientific graphical abstracts — design guidelines


visualization + design
If you are interested in color, explore my other color tools, Brewer palettes resources, color blindness palettes and math and an exhausting list of 10,000 color names for all those times you couldn't distinguish between tan hide, sea buckthorn, orange peel, west side, sunshade, california and pizzaz.

Designing for Color Blindess

Color choices and transformations for deuteranopia and other afflictions

Here, I help you understand color blindness and describe a process by which you can make good color choices when designing for accessibility. You can also delve into the mathematics behind the color blindness simulations.

Different color blindness simulations don't all agree on the luminance of the simulated color. See methods for details.

color blindness RGB transformations

The transformations described here will allow you to simulate color blindness and apply conversions of the kind shown in the images below to your own work.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
An HSV Granger rainbow. Colors progress in hue along the horizontal dimension. The top half of the image has `V=100` with saturation progression `S=0-100`. The bottom half has `V=100-0` and `S=100`. When created at 360 × 200 pixels, each pixel takes on unique integer value of H, S and V. This rainbow is based on a perceptually non-uniform space and this accounts for the bands of brightness across the center and in some columns. (zoom)
Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
An HSV Granger rainbow transformed for protanopia, the second most common type of red-green color blindness in which the long wavelength color receptors are either missing or defective (protanomaly). (zoom)

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
An HSV Granger rainbow transformed for deuternaopia, the most common type of red-green color blindness in which the medium wavelength color receptors are either missing or defective (protanomaly). (zoom)
Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
An HSV Granger rainbow transformed for tritanopia, a rare type of red-blue color blindness in which the short wavelength color receptors are either missing or defective (tritanomaly). (zoom)

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
An HSV Granger rainbow transformed for achromatopsia, a very rare type of color blindness in which all color receptors are either missing (as in rod monochromats) or defective (dyschromatopsia) or only one kind of cone is functioning (e.g. red monochromats, blue monochromats, etc). (zoom)

The conversion from RGB values to their color blindness equivalents for protanopia, deuteranopia and tritanopia consists of the following steps

  1. convert from sRGB to linear RGB
  2. convert from linear RGB to XYZ
  3. convert from XYZ to LMS
  4. apply color blindness transformation in LMS space
  5. convert from LMS to XYZ (inverse of #3)
  6. convert from XYZ to linear RGB (inverse of #2)
  7. convert from linear RGB to sRGB (clip and inverse of #1)
Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
The steps of simulating color blindness by transforming an sRGB color `(R,G,B)` to its color blind equivalent `(R',G',B')`. For each of the color blindness types (protanopia, deuteranopia, tritanopia) all the transformation matrices can be combined into a single matrix `\mathbf{T}`. (zoom)

The greyscale conversion for achromatopsia does not require the XYZ and LMS steps. We can go straight to `Y`.

  1. convert from sRGB to linear RGB
  2. `Y = 0.02126r + 0.7152g + 0.0722b`
  3. convert from linear RGB to sRGB (inverse of #1)

The details of each of the steps are shown below. If you just want the `\mathbf{T}` matrices, scroll down to the bottom or download the code.

Depending on the implementation, this process may have an additional step that reduces the color domain (e.g. step 2 in Viénot, Brettel & Mollon, 1999). This makes sure that none of the transformed colors are outside of the sRGB domain. Here, I instead of doing this I just clip the transformed colors at the end. This simplifies the process and (my sense is that) the difference is negligible.

Different simulators will yield slightly different results, too.

sRGB to linear RGB

The RGB input color is `\{R,G,B\} = \{ V \in [0,255] \}` and assumed to be sRGB. This is first linearized with `\gamma = 2.4` to obtain `\{r,g,b\} = \{ v \in [0,1] \}`. $$v = \begin{cases} \dfrac{V/255}{12.92} & \text{if $V/255 \le 0.04045$} \\[2ex] \left({\dfrac{V/255+0.055}{1.055}}\right)^\gamma & \text{otherwise} \end{cases} $$

linear RGB to XYZ

Next, convert the linearized `(r,g,b)` to XYZ by multiplying by `\mathbf{M}_\textrm{XYZ}`. $$ \left[ \begin{matrix} X \\Y \\Z \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 0.4124564 & 0.3575761 & 0.1804375 \\0.2126729 & 0.7151522 & 0.0721750 \\0.0193339 & 0.1191920 & 0.9503041 \end{matrix} \right] }_{\mathbf{M}_\textrm{XYZ}} \left[ \begin{matrix} r \\g \\b \end{matrix} \right] $$

XYZ to LMS

Multiply by `\mathbf{M}_\textrm{LMS,D65}` to convert XYZ to LMS. This matrix is normalized to the D65 illuminant, which will ensure that greys will be preserved.

The LMS (long, medium, short) is a color space which represents the response of the three types of cones of the human eye, named for their sensitivity peaks at long (560 nm, red) medium (530 nm, green), and short (420 nm, blue) wavelengths. $$ \left[ \begin{matrix} L \\ M \\ S \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 0.4002 & 0.7076 & -0.0808 \\ -0.2263 & 1.1653 & 0.0457 \\ 0 & 0 & 0.9182 \end{matrix} \right] }_{\mathbf{M}_\textrm{LMS,D65}} \left[ \begin{matrix} X \\ Y \\ Z \end{matrix} \right] $$

If for some reason you don't want to normalize to D65, you would use `\mathbf{M}_\textrm{LMS}` below but whites will now appear pinkish. $$ \left[ \begin{matrix} L \\ M \\ S \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 0.0.38971 & 0.68898 & -0.07868 \\ -0.22981 & 1.18340 & 0.04641 \\ 0 & 0 & 1 \end{matrix} \right] }_{\mathbf{M}_\textrm{LMS}} \left[ \begin{matrix} X \\ Y \\ Z \end{matrix} \right] $$

There are other XYZ to LMS matrices and the R code lists them all.

apply daltonism correction

Now that we have the RGB color represented in LMS space, we can correct for color receptor dysfunction in this space, since color blindness affects one of the L, M or S receptors.

I show the calculations here in a lot of detail—they're not as complicated as things look. Once you understand what's happening for one of the color blindness types, the other two are analogously treated.

Each of the color blindness types will have its own correction matrix `\mathbf{S}`. $$ \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] = \mathbf{S} \left[ \begin{matrix} L \\ M \\ S \\ \end{matrix} \right] $$

This matrix is the identity matrix with the row for the malfunctioning receptor (e.g. S for protanopia) replaced by two free parameters `a` and `b`. $$ \begin{align} \mathbf{S}_\textrm{protanopia} & = \left[ \begin{matrix} 0 & a & b \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] \\ \mathbf{S}_\textrm{deuteranopia} & = \left[ \begin{matrix} 1 & 0 & 0 \\ a & 0 & b \\ 0 & 0 & 1 \end{matrix} \right] \\ \mathbf{S}_\textrm{tritanopia} & = \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ a & b & 0 \end{matrix} \right] \end{align} $$

The reason why these matrices have this format is so that we can satisfy two conditions. First, this matrix should not affect how white appears—if one of the rows was just zero then white would be altered. Second, we expect that one of the primaries won't be affected, depending on the color blindness type. For protanopia and deuteranopia this is blue and for tritanopia this is red.

If we set `\mathbf{M} = \mathbf{M}_\textrm{LMS,D65} \mathbf{M}_\textrm{XYZ}` then these conditions (using the blue case for protanopia) can be expressed as $$ \mathbf{S}_\textrm{protanopia} \mathbf{M} \left[ \begin{matrix} 1 \\ 1 \\ 1 \end{matrix} \right] = \mathbf{M} \left[ \begin{matrix} 1 \\ 1 \\ 1 \end{matrix} \right] = \left[ \begin{matrix} L_0 \\ M_0 \\ S_0 \end{matrix} \right] $$ $$ \mathbf{S}_\textrm{protanopia} \mathbf{M} \left[ \begin{matrix} 0 \\ 0 \\ 1 \end{matrix} \right] = \mathbf{M} \left[ \begin{matrix} 0 \\ 0 \\ 1 \end{matrix} \right] = \left[ \begin{matrix} L \\ M \\ S \end{matrix} \right] $$

where `(L_0,M_0,S_0)` are the LMS coordinates of white and `(L_b,M_b,S_b)` of the primary that is not affected (e.g. blue). Using the form for `\mathbf{S}_\textrm{protanopia}`, these lead to the following equations $$ \begin{align} a M_b + b S_b & = L_b \\a M_0 + b S_0 & = L_0 \end{align} $$

which can be written as $$ \left[ \begin{matrix} a \\b \end{matrix} \right]_\textrm{protanopia} = { \left[ \begin{matrix} M_b & S_b \\M_0 & S_0 \end{matrix} \right] }^{-1} \left[ \begin{matrix} L_b \\L_0 \end{matrix} \right] $$

For deuteranopia and tritanopia the calculation of `a` and `b` is analogous, except that because now `a` and `b` change position in `\mathbf{S}`, the equations are slightly different. $$ \left[ \begin{matrix} a \\b \end{matrix} \right]_\textrm{deuteranopia} = { \left[ \begin{matrix} L_b & S_b \\L_0 & S_0 \end{matrix} \right] }^{-1} \left[ \begin{matrix} M_b \\M_0 \end{matrix} \right] $$

and for tritanopia (here `(L_r,M_r,S_r)` refers to the coordinates of red). $$ \left[ \begin{matrix} a \\b \end{matrix} \right]_\textrm{tritanopia} = { \left[ \begin{matrix} L_r & M_r \\L_0 & M_0 \end{matrix} \right] }^{-1} \left[ \begin{matrix} S_r \\S_0 \end{matrix} \right] $$

Using the following LMS coordinates (calculated by linearizing the corresponding RGB values and then muptiplying by `\mathbf{M}`) $$ \begin{align} \left[ \begin{matrix} L_0 \\ M_0 \\ S_0 \end{matrix} \right] & = \left[ \begin{matrix} 1 \\ 0.999683 \\ 0.9997637 \end{matrix} \right] \\ \left[ \begin{matrix} L_b \\ M_b \\ S_b \end{matrix} \right] & = \left[ \begin{matrix} 0.04649755 \\ 0.08670142 \\ 0.87256922 \end{matrix} \right] \\ \left[ \begin{matrix} L_r \\ M_r \\ S_r \end{matrix} \right] & = \left[ \begin{matrix} 0.31399022 \\ 0.15537241 \\ 0.01775239 \end{matrix} \right] \end{align} $$

Using protanopia as the example $$ \begin{align} \left[ \begin{matrix} a \\b \end{matrix} \right]_\textrm{protanopia} & = { \left[ \begin{matrix} 0.08670142 & 0.87256922 \\0.999683 & 0.9997637 \end{matrix} \right] }^{-1} \left[ \begin{matrix} 0.04649755 \\1 \end{matrix} \right] \\ & = \left[ \begin{matrix} -1.27219 & 1.1103359 \\1.27245 & -0.1103267 \end{matrix} \right] \left[ \begin{matrix} 0.04649755 \\1 \end{matrix} \right] \\ & = \left[ \begin{matrix} 1.05118294 \\-0.05116099 \end{matrix} \right] \end{align} $$

The `(a,b)` calculations for deuteranopia and tritanopia are analogous and once they're done we can write the correction matrices as $$ \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 0 & 1.05118294 & -0.05116099 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] }_{\mathbf{S}_\textrm{protanopia}} \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] $$ $$ \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 1 & 0 & 0 \\ 0.9513092 & 0 & 0.04866992 \\ 0 & 0 & 1 \end{matrix} \right] }_{\mathbf{S}_\textrm{deuteranopia}} \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] $$ $$ \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ -0.86744736 & 1.86727089 & 0 \end{matrix} \right] }_{\mathbf{S}_\textrm{tritanopia}} \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] $$

These `(a,b)` values are for the D65-normalized XYZ-to-LMS matrix and will change if you use a different matrix. The R code calculates `(a,b)` for whatever matrix you provide.

Corrected LMS to XYZ

Once the color blindness correction has been applied in LMS space, we convert back to XYZ using the inverse `\mathbf{M}_\text{LMS,D65}^{-1}`. $$ \left[ \begin{matrix} X' \\ Y' \\ Z' \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 1.8600666 & -1.1294801 & 0.2198983 \\ 0.3612229 & 0.6388043 & 0 \\ 0 & 0 & 1.089087 \end{matrix} \right] }_{\mathbf{M}_\textrm{LMS,D65}^{-1}} \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] $$

If you used `\mathbf{M}_\textrm{LMS}` and didn't normalize to D65, then you'd use its inverse `\mathbf{M}_\text{LMS}^{-1}` instead. $$ \left[ \begin{matrix} X' \\ Y' \\ Z' \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 1.9101968 & -1.1121239 & 0.2019080 \\ 0.3709501 & 0.6290543 & 0 \\ 0 & 0 & 1 \end{matrix} \right] }_{\mathbf{M}_\textrm{LMS}^{-1}} \left[ \begin{matrix} L' \\ M' \\ S' \end{matrix} \right] $$

XYZ to linear RGB

Finally, one last matrix multiplication from XYZ back to linear RGB using `\mathbf{M}_\textrm{XYZ}^{-1}`. $$ \left[ \begin{matrix} r' \\ g' \\ b' \end{matrix} \right] = \underbrace{ \left[ \begin{matrix} 3.24045484 & -1.5371389 & -0.49853155 \\ -0.96926639 & 1.8760109 & 0.04155608 \\ 0.05564342 & -0.2040259 & 1.05722516 \end{matrix} \right] }_{\mathbf{M}_\textrm{XYZ}^{-1}} \left[ \begin{matrix} X' \\ Y' \\ Z' \end{matrix} \right] $$

linear RGB to sRGB

The first step is now inverted to obtain the final sRGB values as perceived by someone with color blindness. $$V = \begin{cases} 255(12.92v) & \text{if $v \le 0.0031308$} \\[1ex] 255(1.055 v^{1/\gamma} - 0.055) & \text{otherwise} \end{cases} $$

Make sure to clip `v` to `[0,1]` before applying the final transformation back to sRGB.

Conversion summary

The matrix multiplication steps can be written compactly as $$ \left[ \begin{matrix} r' \\ g' \\ b' \end{matrix} \right] = \mathbf{M}_\textrm{XYZ}^{-1} \mathbf{M}_\textrm{LMS,D65}^{-1} \mathbf{S} \mathbf{M}_\textrm{LMS,D65} \mathbf{M}_\textrm{XYZ} \left[ \begin{matrix} r \\ g \\ b \end{matrix} \right] = \mathbf{T} \left[ \begin{matrix} r \\ g \\ b \end{matrix} \right] $$

where `\mathbf{T}` is the product of all the matrices for a given color blindness correction `\mathbf{S}`, which are $$ \begin{align} \mathbf{T}_\textrm{protanopia} & = \left[ \begin{matrix} 0.170556992 & 0.829443014 & 0 \\ 0.170556991 & 0.829443008 & 0 \\ -0.004517144 & 0.004517144 & 1 \end{matrix} \right] \\ \mathbf{T}_\textrm{deuteranopia} & = \left[ \begin{matrix} 0.33066007 & 0.66933993 & 0 \\ 0.33066007 & 0.66933993 & 0 \\ -0.02785538 & 0.02785538 & 1 \end{matrix} \right] \\ \mathbf{T}_\textrm{tritanopia} & = \left[ \begin{matrix} 1 & 0.1273989 & -0.1273989 \\ 0 & 0.8739093 & 0.1260907 \\ 0 & 0.8739093 & 0.1260907 \end{matrix} \right] \\ \mathbf{T}_\textrm{achromatopsia} & = \left[ \begin{matrix} 0.2126 & 0.7152 & 0.0722 \\ 0.2126 & 0.7152 & 0.0722 \\ 0.2126 & 0.7152 & 0.0722 \end{matrix} \right] \end{align} $$

VIEW ALL

news + thoughts

Graphical Abstract Design Guidelines

Fri 13-11-2020

Clear, concise, legible and compelling.

Making a scientific graphical abstract? Refer to my practical design guidelines and redesign examples to improve organization, design and clarity of your graphical abstracts.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Graphical Abstract Design Guidelines — Clear, concise, legible and compelling.

"This data might give you a migrane"

Tue 06-10-2020

An in-depth look at my process of reacting to a bad figure — how I design a poster and tell data stories.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
A poster of high BMI and obesity prevalence for 185 countries.

He said, he said — a word analysis of the 2020 Presidential Debates

Thu 01-10-2020

Building on the method I used to analyze the 2008, 2012 and 2016 U.S. Presidential and Vice Presidential debates, I explore word usagein the 2020 Debates between Donald Trump and Joe Biden.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Analysis of word usage by parts of speech for Trump and Biden reveals insight into each candidate.

Points of Significance celebrates 50th column

Mon 24-08-2020

We are celebrating the publication of our 50th column!

To all our coauthors — thank you and see you in the next column!

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Nature Methods Points of Significance: Celebrating 50 columns of clear explanations of statistics. (read)

Uncertainty and the management of epidemics

Mon 24-08-2020

When modelling epidemics, some uncertainties matter more than others.

Public health policy is always hampered by uncertainty. During a novel outbreak, nearly everything will be uncertain: the mode of transmission, the duration and population variability of latency, infection and protective immunity and, critically, whether the outbreak will fade out or turn into a major epidemic.

The uncertainty may be structural (which model?), parametric (what is `R_0`?), and/or operational (how well do masks work?).

This month, we continue our exploration of epidemiological models and look at how uncertainty affects forecasts of disease dynamics and optimization of intervention strategies.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Nature Methods Points of Significance column: Uncertainty and the management of epidemics. (read)

We show how the impact of the uncertainty on any choice in strategy can be expressed using the Expected Value of Perfect Information (EVPI), which is the potential improvement in outcomes that could be obtained if the uncertainty is resolved before making a decision on the intervention strategy. In other words, by how much could we potentially increase effectiveness of our choice (e.g. lowering total disease burden) if we knew which model best reflects reality?

This column has an interactive supplemental component (download code) that allows you to explore the impact of uncertainty in `R_0` and immunity duration on timing and size of epidemic waves and the total burden of the outbreak and calculate EVPI for various outbreak models and scenarios.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Nature Methods Points of Significance column: Uncertainty and the management of epidemics. (Interactive supplemental materials)

Bjørnstad, O.N., Shea, K., Krzywinski, M. & Altman, N. (2020) Points of significance: Uncertainty and the management of epidemics. Nature Methods 17.

Background reading

Bjørnstad, O.N., Shea, K., Krzywinski, M. & Altman, N. (2020) Points of significance: Modeling infectious epidemics. Nature Methods 17:455–456.

Bjørnstad, O.N., Shea, K., Krzywinski, M. & Altman, N. (2020) Points of significance: The SEIRS model for infectious disease dynamics. Nature Methods 17:557–558.