Visualising data for patients

Create accessible charts

Dr Rita Giordano

Visual Data Studio / Clarum

June 10, 2025

Introduction

Introduction to patients’data

Patient data: an example

Pain location of a patient with arthritis

How patients can perceive colours?

Normal vision

Protanopia (red colour blindness)

How patients can perceive colours?

Normal vision

Deuteranopia (green colour blindness)

Autism-friendly palette

Calming colours feeling of security: Pink and lilac

Blue and greens

Neutral colours: Beige, greys, creams

High legibility fonts

Example of Google Fonts that are easy to read:

  • Roboto

  • Opens Sans

  • Lato

  • Montserrat

  • Atkinson Hyperlegible

  • Lexend

Packages

{cols4all}

install.packages("cols4all", dependencies = TRUE)

{coloratio}

remotes::install_github("matt-dray/coloratio")

{colorblindr}

remotes::install_github("wilkelab/cowplot")
install.packages("colorspace", repos = "http://R-Forge.R-project.org")
remotes::install_github("clauswilke/colorblindr")

Other packages:

  • {RColorBrewer}

  • {recolorize}

  • {sysfonts}

  • {savonliquide}

How to import Google fonts

library(sysfonts)
library(showtext)
font_add_google("Lexend", family = "lexend")  
showtext_auto()
font_families()

Check if the font is installed

[1] "sans"         "serif"        "mono"         "wqy-microhei" "lexend"      

Colours accessibility

Colourblind friendly palette and useful package

  • {RColorBrewer}
  • {viridis}
  • {cols4all}
  • {colorblindr}

{RColorBrewer} colourblind friendly palette

library(RColorBrewer)
display.brewer.all(colorblindFriendly = TRUE)

Change colours with {RColorBrewer} and font

datasets::penguins %>%
  filter(island == "Dream") %>%
  ggplot(aes(x = flipper_len, y = body_mass, colour = species)) +
  geom_point() +
  scale_colour_brewer(palette = "Set2") +
  theme_minimal(base_family = "lexend", base_size = 14) +
  ggtitle("Penguins on Dream Island")

{cols4all} package

library(cols4all)
c4a_gui()

Create a colourblind friendly palette

## brand colours
library(colorblindr)
brand <- c("red", "darkgreen", "blue", "purple")
palette_plot(brand, xmargin = 0.2, ymargin = 0.8)
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead

Create a colourblind friendly palette

cvd_grid(palette_plot(brand, xmargin = 0.2, ymargin = 0.8, 
label_size = 7, label_family = "roboto"))

Adjust the colours with {recolorize}

library(recolorize)
brand_rgb <- t(col2rgb(brand)/ 255 )
brand_sat <- adjust_color(brand_rgb, 
                          which_colors = c(2, 3),
                          saturation = 0.3,
                          brightness = 0.9,
                          plotting = TRUE)

Adjust the colours with {recolorize}

## convert RGB colours into HEX code
brand_hex <- rgb(brand_sat)
cvd_grid(palette_plot(brand_hex, xmargin = 0.2, ymargin = 0.8, 
label_size = 6, label_family = "roboto"))

Colour contrast

Difference between colours, measured as the ratio of the relative luminance of the lighter colour to that of the darker colour.

  • acceptable ratio \(> 4.5\)

How to check colour contrast?

  • {coloratio}

  • {savonliquide}

Colour contrast {coloratio}

library(coloratio)
cr_get_ratio("lightgreen", "black",
              view = TRUE)

[1] 14.8

Colour contrast {coloratio}

bw <- cr_choose_bw("skyblue")
cr_get_ratio("skyblue", bw, view = TRUE)

[1] 12.1

Colour contrast {savonliquide}

library(savonliquide)
check_contrast("#222222", #f5ebe0")

* The Contrast Ratio is 13.5

* The result for the AA check is : PASS

* The result for the AALarge check is : PASS

* The result for the AAA check is : PASS

* The result for the AAALarge check is : PASS
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead

Colour contrast {savonliquide}

library(savonliquide)
check_contrast("#BFA6DE", "#f5ebe0")

* The Contrast Ratio is 1.83

* The result for the AA check is : FAIL

* The result for the AALarge check is : FAIL

* The result for the AAA check is : FAIL

* The result for the AAALarge check is : FAIL
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
font family 'roboto' not found, will use 'sans' instead

Further resources

  • https://analysisfunction.civilservice.gov.uk/policy-store/data-visualisation-colours-in-charts/

  • https://cols4all.github.io/cols4all-R/index.html

  • https://cran.r-project.org/web/packages/recolorize/vignettes/Introduction.html

Thank you for your attention