Exploring colour blind and colour weak plotting options in ggplot2
On my ‘over breakfast’ Twitter scroll I cam across
this interesting series of blogposts on the Chartable blog (hosted by Datawrapper) that discusses how we can make our plots and visuals more friendly for colour blind and colour weak readers. They raised some interesting points and options to use and I thought it would be a ‘constructive’ way to spend my Friday trying to implement these ideas in R, specifically using ggplot2
.
In the second blogpost they have a long discussion about different ways to make your figures more inclusive (I highly recommend reading the full article - it has some awesome visuals as well) and along with the standard recommendation to avoid green and trying to go with complimentary colours such as blue and orange some other points they raised that I thought were interesting include:
- Playing with the lightness of your colours
- Even if you end up using non-ideal colours you can use darker and lighter shades to offset the similarity
- Using fewer colours
- Maybe only use colour to highlight differences or pull out the main points of the figure
- Play with shapes and patterns
- This can include using symbols (such as ticks and crosses) to emphasise a point or show different groups in scatterplots, or use patterns for line plots or even for fill colours on geom-type plots
So at first glance most of these options seem very do-able and easy to integrate into the ggplot2
workflow, with the exception of specifying patterns for fills of geom objects (think barplots) but I came across the ggpattern
package which solves that problem with what seems to be a huge degree of customisability - see the package website
here. At time of writing this package isn’t available on CRAN yet but can be downloaded and installed via GitHub.
With that out of the way let’s get to the actual plotting. Also I thought this would be a good opportunity to play with the penguins
dataset that was
recently released as an iris
alternative.
Playing with lightness
This is theoretically a very simple example to execute as we can just specify our colour choices to be of varying shades. For this example I decided to plot body mass vs. flipper length for the different penguin species as well as for males and females. I used [Adobe Color][https://color.adobe.com/create/color-wheel] to pick my colours but that just personal preference.
library(ggplot2)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(palmerpenguins)
#import data
penguins <- penguins %>%
#removing NAs for ease
na.omit()
#specify colours manually
AdeMale <- "#1C1DAD"
AdeFem <- "#A0A0FA"
ChiMale <- "#AD400B"
ChiFem <- "#FA9966"
GenMale <- "#445748"
GenFem <- "#6AD674"
#create plot
P1 <- ggplot() +
geom_point(data = penguins,
aes(x = body_mass_g,
y = flipper_length_mm,
#make new grouping variable with the species sex combos
colour = paste(penguins$species,
penguins$sex)),
#for simplicity removing legend
show.legend = FALSE) +
#set colours
scale_colour_manual(values = c(AdeMale,
AdeFem,
ChiMale,
ChiFem,
GenMale,
GenFem)) +
theme_bw()
So we can see that using the different shades of the same colour for the different sexes works really well - although arguably there is some issue distinguishing between the species so lets add some shapes…
Adding shapes
P2 <- ggplot() +
geom_point(data = penguins,
aes(x = body_mass_g,
y = flipper_length_mm,
#make new grouping variable with the species sex combos
colour = paste(penguins$species,
penguins$sex),
#specify grouping var for shape
shape = species),
#for simplicity removing legend
show.legend = FALSE) +
#set colours
scale_colour_manual(values = c(AdeMale,
AdeFem,
ChiMale,
ChiFem,
GenMale,
GenFem)) +
theme_bw()
Nice! As we can see just adding one line to our code can make all the difference.
Playing with patterns
This is where it gets fun - time to play with a new package. If we want to call patterns for our geoms instead of using the standard geom_*
function from ggplot2
we will be using the geom_*_pattern
function from the ggpattern
package. But first we can have a look at our original colour palette using a standard boxplot - let’s stick to flipper length.
Here we can see how the different shades pop out really nicely - arguably we can still distinguish between the Chinstraps and the Gentoos but I think we can play with the aesthetics a bit more and make the plot pretty - not just functional!
#To download package from GitHub
#remotes::install_github("coolbutuseless/ggpattern")
library(ggpattern)
#Summarised the dataset for plotting
P4 <- ggplot() +
geom_col_pattern(data = penguins_summary,
aes(y = flipper_length_mm,
x = species,
group = sex,
#make new grouping variable with the species sex combos
fill = paste(penguins_summary$species,
penguins_summary$sex),
#specify pattern type
pattern = sex),
#specify the fill for the pattern
pattern_fill = "black",
#specify box colour
colour = 'black',
#for simplicity removing legend
show.legend = FALSE,
position = "dodge") +
#set colours
scale_fill_manual(values = c(AdeMale,
AdeFem,
ChiMale,
ChiFem,
GenMale,
GenFem)) +
theme_bw()
Neat! We can see that the patterns add a new ‘level’ to our plots and if you look at the syntax of the ggpatterns functions we see that it mirrors that of ggplot - it just has a few more _pattern
thrown in! This package allows a large degree of freedom with regards to what and how you want your patterns to look like. You can even import images or make your own patterns. Combine this with the somewhat intuitive syntax (if you’re comfortable with ggplot) it is something I can see myself trying to use more often when making figures.
🐾 Tanya
Footnote
If you want a better look at all of the code feel free to have a peek on GitHub