Applied Metaphors: Learning TRIZ, Complexity, Data/Stats/ML using Metaphors
  1. Teaching
  2. R for Artists and Managers
  3. Lab-7: The Lobster Quadrille
  • Teaching
    • Data Analytics for Managers and Creators
      • Tools
        • Introduction to R and RStudio
        • Introduction to Radiant
        • Introduction to Orange
      • Descriptive Analytics
        • Data
        • Summaries
        • Counts
        • Quantities
        • Groups
        • Densities
        • Groups and Densities
        • Change
        • Proportions
        • Parts of a Whole
        • Evolution and Flow
        • Ratings and Rankings
        • Surveys
        • Time
        • Space
        • Networks
        • Experiments
        • Miscellaneous Graphing Tools, and References
      • Statistical Inference
        • 🧭 Basics of Statistical Inference
        • 🎲 Samples, Populations, Statistics and Inference
        • Basics of Randomization Tests
        • 🃏 Inference for a Single Mean
        • 🃏 Inference for Two Independent Means
        • 🃏 Inference for Comparing Two Paired Means
        • Comparing Multiple Means with ANOVA
        • Inference for Correlation
        • 🃏 Testing a Single Proportion
        • 🃏 Inference Test for Two Proportions
      • Inferential Modelling
        • Modelling with Linear Regression
        • Modelling with Logistic Regression
        • 🕔 Modelling and Predicting Time Series
      • Predictive Modelling
        • 🐉 Intro to Orange
        • ML - Regression
        • ML - Classification
        • ML - Clustering
      • Prescriptive Modelling
        • 📐 Intro to Linear Programming
        • 💭 The Simplex Method - Intuitively
        • 📅 The Simplex Method - In Excel
      • Workflow
        • Facing the Abyss
        • I Publish, therefore I Am
      • Case Studies
        • Demo:Product Packaging and Elderly People
        • Ikea Furniture
        • Movie Profits
        • Gender at the Work Place
        • Heptathlon
        • School Scores
        • Children's Games
        • Valentine’s Day Spending
        • Women Live Longer?
        • Hearing Loss in Children
        • California Transit Payments
        • Seaweed Nutrients
        • Coffee Flavours
        • Legionnaire’s Disease in the USA
        • Antarctic Sea ice
        • William Farr's Observations on Cholera in London
    • R for Artists and Managers
      • 🕶 Lab-1: Science, Human Experience, Experiments, and Data
      • Lab-2: Down the R-abbit Hole…
      • Lab-3: Drink Me!
      • Lab-4: I say what I mean and I mean what I say
      • Lab-5: Twas brillig, and the slithy toves…
      • Lab-6: These Roses have been Painted !!
      • Lab-7: The Lobster Quadrille
      • Lab-8: Did you ever see such a thing as a drawing of a muchness?
      • Lab-9: If you please sir…which way to the Secret Garden?
      • Lab-10: An Invitation from the Queen…to play Croquet
      • Lab-11: The Queen of Hearts, She Made some Tarts
      • Lab-12: Time is a Him!!
      • Iteration: Learning to purrr
      • Lab-13: Old Tortoise Taught Us
      • Lab-14: You’re are Nothing but a Pack of Cards!!
    • ML for Artists and Managers
      • 🐉 Intro to Orange
      • ML - Regression
      • ML - Classification
      • ML - Clustering
      • 🕔 Modelling Time Series
    • TRIZ for Problem Solvers
      • I am Water
      • I am What I yam
      • Birds of Different Feathers
      • I Connect therefore I am
      • I Think, Therefore I am
      • The Art of Parallel Thinking
      • A Year of Metaphoric Thinking
      • TRIZ - Problems and Contradictions
      • TRIZ - The Unreasonable Effectiveness of Available Resources
      • TRIZ - The Ideal Final Result
      • TRIZ - A Contradictory Language
      • TRIZ - The Contradiction Matrix Workflow
      • TRIZ - The Laws of Evolution
      • TRIZ - Substance Field Analysis, and ARIZ
    • Math Models for Creative Coders
      • Maths Basics
        • Vectors
        • Matrix Algebra Whirlwind Tour
        • content/courses/MathModelsDesign/Modules/05-Maths/70-MultiDimensionGeometry/index.qmd
      • Tech
        • Tools and Installation
        • Adding Libraries to p5.js
        • Using Constructor Objects in p5.js
      • Geometry
        • Circles
        • Complex Numbers
        • Fractals
        • Affine Transformation Fractals
        • L-Systems
        • Kolams and Lusona
      • Media
        • Fourier Series
        • Additive Sound Synthesis
        • Making Noise Predictably
        • The Karplus-Strong Guitar Algorithm
      • AI
        • Working with Neural Nets
        • The Perceptron
        • The Multilayer Perceptron
        • MLPs and Backpropagation
        • Gradient Descent
      • Projects
        • Projects
    • Data Science with No Code
      • Data
      • Orange
      • Summaries
      • Counts
      • Quantity
      • 🕶 Happy Data are all Alike
      • Groups
      • Change
      • Rhythm
      • Proportions
      • Flow
      • Structure
      • Ranking
      • Space
      • Time
      • Networks
      • Surveys
      • Experiments
    • Tech for Creative Education
      • 🧭 Using Idyll
      • 🧭 Using Apparatus
      • 🧭 Using g9.js
    • Literary Jukebox: In Short, the World
      • Italy - Dino Buzzati
      • France - Guy de Maupassant
      • Japan - Hisaye Yamamoto
      • Peru - Ventura Garcia Calderon
      • Russia - Maxim Gorky
      • Egypt - Alifa Rifaat
      • Brazil - Clarice Lispector
      • England - V S Pritchett
      • Russia - Ivan Bunin
      • Czechia - Milan Kundera
      • Sweden - Lars Gustaffsson
      • Canada - John Cheever
      • Ireland - William Trevor
      • USA - Raymond Carver
      • Italy - Primo Levi
      • India - Ruth Prawer Jhabvala
      • USA - Carson McCullers
      • Zimbabwe - Petina Gappah
      • India - Bharati Mukherjee
      • USA - Lucia Berlin
      • USA - Grace Paley
      • England - Angela Carter
      • USA - Kurt Vonnegut
      • Spain-Merce Rodoreda
      • Israel - Ruth Calderon
      • Israel - Etgar Keret
  • Posts
  • Blogs and Talks

On this page

  • Introduction
  • Goals
  • Pedagogical Note
    • Setting up R Packages
    • Setting up Plot Theme
    • Using Google Fonts
  • Data
  • Basic Plot
  • Customized Plot
  • Using {ggtext}
    • Using element_markdown()
    • element_markdown() in combination with HTML
    • Adding images to ggplot
    • Annotations with geom_richtext() and geom_textbox()
    • Formatted Text boxes on plots
    • Using geom_texbox() for formatted text boxes with word wrapping
    • Using {ggforce}
    • ggplot tricks
    • Add Images
    • Using {patchwork}
  • References
  1. Teaching
  2. R for Artists and Managers
  3. Lab-7: The Lobster Quadrille

Lab-7: The Lobster Quadrille

Fonts and other Wizardy in ggplot

Published

July 21, 2021

Modified

January 21, 2025

Introduction

We will add icing and froth to our vanilla ggplots: fonts, annotations, highlights and even pictures!!

Goals

  • Appreciate that a publication-worth graphic takes a lot of work!!
  • Adding annotations, pictures and references to graphs is necessary for good understanding
  • Judicious use of colour and scales can enhance comprehension.

Pedagogical Note

The method followed will be based on PRIMM:

  • PREDICT Inspect the code and guess at what the code might do, write predictions
  • RUN the code provided and check what happens
  • INFER what the parameters of the code do and write comments to explain. What bells and whistles can you see?
  • MODIFY the parameters code provided to understand the options available. Write comments to show what you have aimed for and achieved.
  • MAKE : take an idea/concept of your own, and graph it.

Setting up R Packages

Let’s load up a few packages that we need to start:

## packages
library(tidyverse) ## data science package collection (incl. the ggplot2 package)
library(systemfonts) ## use custom fonts (need to be installed on your OS)
library(paletteer) ## scico  and many other colour palettes palettes(http://www.fabiocrameri.ch/colourmaps.php) in R
library(ggtext) ## add improved text rendering to ggplot2
library(ggforce) ## add missing functionality to ggplot2
library(concaveman) ## Needed by ggforce for plot annotation hulls
library(ggdist) ## add uncertainty visualizations to ggplot2
library(ggformula) ## Formula interface to ggplot
library(magick) ## load images into R
library(patchwork) ## combine outputs from ggplot2
library(palmerpenguins)

library(showtext) ## add google fonts to plots

knitr::opts_chunk$set(
  error = TRUE,
  comment = NA,
  warning = FALSE,
  errors = FALSE,
  message = FALSE,
  tidy = FALSE,
  cache = FALSE,
  echo = TRUE,
  warning = FALSE,
  # from the vignette for the showtext package
  fig.showtext = TRUE,
  fig.retina = 1,
  fig.path = "figs/"
  # fig.height = 3.09,
  # fig.width = 5
)

Setting up Plot Theme

Using Google Fonts

We will want to add a few new fonts to our graphs. The best way (currently) is to use the showtext package (which we loaded above) to bring into our work fonts from Google. To view and select the fonts you might want to work with, spend some time looking over:

  1. Google Webfonts Helper App

  2. Google Fonts

We will work with a familiar dataset, so that we can concentrate on the chart aesthetics, without having to spend time getting used to the data: the penguins dataset again, from the palmerpenguins package.

Tipggformula and ggplot worlds do intersect!

It seems we can mix `ggformula` code with `ggtext` code, using the `+` sign!! What joy !!! Need to find out if this works for other `ggplot` extensions as well !!!

Data

Always start your work with a table of the data:

penguins <- penguins %>% drop_na()
# remove data containing missing data
penguins
ABCDEFGHIJ0123456789
species
<fct>
island
<fct>
bill_length_mm
<dbl>
bill_depth_mm
<dbl>
flipper_length_mm
<int>
body_mass_g
<int>
sex
<fct>
year
<int>
AdelieTorgersen39.118.71813750male2007
AdelieTorgersen39.517.41863800female2007
AdelieTorgersen40.318.01953250female2007
AdelieTorgersen36.719.31933450female2007
AdelieTorgersen39.320.61903650male2007
AdelieTorgersen38.917.81813625female2007
AdelieTorgersen39.219.61954675male2007
AdelieTorgersen41.117.61823200female2007
AdelieTorgersen38.621.21913800male2007
AdelieTorgersen34.621.11984400male2007
Next
123456
...
34
Previous
1-10 of 333 rows

Basic Plot

A basic scatter plot, which we will progressively dress up.

  • Using ggformula
  • Using ggplot
## simple plot: data + mappings + geometry
## no colour or fill yet
gf <- gf_point(bill_depth_mm ~ bill_length_mm,
  data = penguins,
  alpha = 0.6, size = 3.5
)
gf

## simple plot: data + mappings + geometry
## no colour or fill yet
gg <- ggplot(penguins, aes(
  x = bill_length_mm,
  y = bill_depth_mm
)) +
  geom_point(alpha = .6, size = 3.5)
gg

Customized Plot

Let us set some ggplot theme aspects now!! Here is a handy picture showing (most of) the theme-able aspects of a ggplot plot.

Ggplot theme elements

Rosana Ferrero (@RosanaFerrero) on Twitter Sept 11, 2022

For more info, type ?theme in your console.

## change global theme settings (for all following plots)
my_theme <- theme_set(theme_classic(
  base_size = 12,
  base_family = "roboto"
)) +

  ## modify plot elements globally (for all following plots)
  theme_update(
    text = element_text(family = "roboto"),
    axis.ticks = element_line(color = "grey92"),
    axis.ticks.length = unit(.5, "lines"),
    panel.grid.minor = element_blank(),
    legend.title = element_text(size = 12),
    legend.text = element_text(color = "grey30"),
    plot.title = element_text(size = 18, face = "bold"),
    plot.subtitle = element_text(size = 12, color = "grey30"),
    plot.caption = element_text(size = 9, margin = margin(t = 15))
  )

Since we know what the basic plot looks like, let’s add titles, labels and colours. We will also set limits and scales.

  • Using ggformula
  • Using ggplot
theme_set(my_theme)

gf1 <- penguins %>%
  gf_point(bill_depth_mm ~ bill_length_mm,

    # colour by continuous variable
    color = ~body_mass_g,
    alpha = .6, size = 3.5
  ) %>%
  ## custom axes scaling
  gf_refine(
    scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)),
    scale_y_continuous(
      breaks = seq(12.5, 22.5, by = 2.5),
      limits = c(12.5, 22.5)
    ),

    ## custom colors from the scico package
    ## using the paletteer super package
    paletteer::scale_color_paletteer_c(`"scico::bamako"`,
      direction = -1
    ),

    ## custom labels
    labs(
      title = "Bill Dimensions of Brush-Tailed Penguins (Pygoscelis)",
      subtitle = "A scatter plot of bill depth versus bill length.",
      caption = "Data: Gorman, Williams & Fraser (2014) PLoS ONE",
      x = "Bill Length (mm)",
      y = "Bill Depth (mm)",
      ## See this!
      color = "Body mass (g)"
    )
  )

gf1

Note this neat way of naming a scale and the legend in the labs command above!

theme_set(my_theme)


gg1 <- penguins %>%
  ggplot(aes(y = bill_depth_mm, x = bill_length_mm),
    alpha = .6
  ) +
  geom_point(aes(colour = body_mass_g), size = 3.5) +


  ## custom axes scaling
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(
    breaks = seq(12.5, 22.5, by = 2.5),
    limits = c(12.5, 22.5)
  ) +

  ## custom colors from the scico package
  paletteer::scale_color_paletteer_c(`"scico::bamako"`,
    direction = -1
  ) +

  ## custom labels
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (Pygoscelis)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) PLoS ONE",
    x = "Bill Length (mm)",
    y = "Bill Depth (mm)",
    color = "Body mass (g)"
  )
gg1

Using {ggtext}

From Claus Wilke’s website → www.wilkelab.org/ggtext

The ggtext package provides simple Markdown and HTML rendering for ggplot2. Under the hood, the package uses the gridtext package for the actual rendering, and consequently it is limited to the feature set provided by gridtext.
Support is provided for Markdown both in theme elements (plot titles, subtitles, captions, axis labels, legends, etc.) and in geoms (similar to geom_text()). In both cases, there are two alternatives, one for creating simple text labels and one for creating text boxes with word wrapping.

CautionWorking with ggtext

NOTE: on some machines, the ggtext package may not work as expected. In this case, please do as follows, using your Console:

  • remove gridtext: remove.packages(gridtext).
  • Install development version of gridtext: install.packages(remotes) remotes::install_github("wilkelab/gridtext")

Using element_markdown()

We can use our familiar markdown syntax right inside the titles and captions of the plot. element_markdown() is a theme-ing command made available by the ggtext package.

element_markdown() → formatted text elements, e.g. titles, caption, axis text, striptext.

  • Using ggformula
  • Using ggplot
theme_set(my_theme)

gf2 <- penguins %>%
  gf_point(bill_depth_mm ~ bill_length_mm,
    color = ~body_mass_g,
    alpha = 0.6, size = 3.5
  ) %>%
  gf_refine(
    scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)),
    scale_y_continuous(
      breaks = seq(12.5, 22.5, by = 2.5),
      limits = c(12.5, 22.5)
    ),

    ## custom colors from the scico package
    paletteer::scale_color_paletteer_c("scico::bamako",
      direction = -1
    ),

    ## custom labels using element_markdown()
    labs(
      title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
      subtitle = "A scatter plot of bill depth versus bill length.",
      caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
      x = "**Bill Length** (mm)",
      y = "**Bill Depth** (mm)",
      color = "Body mass (g)"
    )
  ) %>%
  # New code from here
  # Enables markdown titles, captions and labels
  gf_theme(theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown()
  ))

gf2

theme_set(my_theme)

gg2 <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) +
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(
    breaks = seq(12.5, 22.5, by = 2.5),
    limits = c(12.5, 22.5)
  ) +
  paletteer::scale_color_paletteer_c(`"scico::bamako"`,
    direction = -1
  ) +

  ## New code starts here: Two Step Procedure with ggtext
  ## 1. Markdown formatting of labels and title, using asterisks
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)"
  ) +

  ## 2. Add theme related commands from ggtext
  ## render respective text elements
  theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown()
  )
gg2

element_markdown() in combination with HTML

This allows us to change fonts in titles, labels, and captions.

  • Using ggformula
  • Using ggplot
theme_set(my_theme)

## use HTML syntax to change text color

gf2 %>%
  # html in labels
  gf_labs(title = 'Bill Dimensions of Brush-Tailed Penguins
          <i style = "color:#28A87D;">Pygoscelis </i>')
## use HTML syntax to change font and text size
gf2 %>%
  gf_labs(title = 'Bill Dimensions of Brush-Tailed Penguins <b style="font-size:32pt;font-family:tangerine;">Pygoscelis</b>')

theme_set(my_theme)

## use HTML syntax to change text color
gg2 +
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <i style="color:#28A87D;">Pygoscelis</i>') +
  theme(plot.margin = margin(t = 15))
## use HTML syntax to change font and text size
gg2 +
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <b style="font-size:32pt;font-family:tangerine;">Pygoscelis</b>')

Adding images to ggplot

Save an image from the web in the same folder as your RMarkdown. Use html tags to include it, say as part of your plot title, as shown below.

  • Using ggformula
  • Using ggplot
theme_set(my_theme)

## use HTML syntax to add images to text elements
gf2 %>%
  gf_labs(title = 'Bill Dimensions of Brush-Tailed Penguins &nbsp;&nbsp;&nbsp; < img src="images/culmen_depth.png"‚ width="480"/>')

theme_set(my_theme)

## use HTML syntax to add images to text elements
gg2 +
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins &nbsp;&nbsp;&nbsp; <img src="images/culmen_depth.png"‚ width="480"/>')

Annotations with geom_richtext() and geom_textbox()

Further ggplot annotations can be achieved using geom_richtext() and geom_textbox(). geom_richtext() also allows formatted text labels with 360° rotation. One needs to pass a tibble to geom_richtext() giving the location, colour, rotation etc of the label annotation.

  • Design the labels
  • Using ggformula
  • Using ggplot
# Create a label tibble
# Three rich text labels,
# so three sets of locations x and y, and angle of rotation

labels <- tibble(
  x = c(34, 56, 54),
  y = c(20, 18.5, 14.5),
  angle = c(12, 20, 335),
  species = c("Adelie", "Chinstrap", "Gentoo"),
  lab = c(
    "<b style='font-family:anton;font-size:24pt;'>Adélie</b><br><i style='color:darkgrey;'>P. adéliae</i>",
    "<b style='font-family:anton;font-size:24pt;'>Chinstrap</b><br><i style='color:darkgrey;'>P. antarctica</i>",
    "<b style='font-family:anton;font-size:24pt;'>Gentoo</b><br><i style='color:darkgrey;'>P. papua</i>"
  )
)
labels
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
angle
<dbl>
species
<chr>
3420.012Adelie
5618.520Chinstrap
5414.5335Gentoo
3 rows | 1-4 of 5 columns
theme_set(my_theme)

gf_rich <- penguins %>%
  gf_point(bill_depth_mm ~ bill_length_mm,
    color = ~species,
    alpha = 0.6, size = 3.5, data = penguins
  ) +


  ## add text annotations for each species
  ggtext::geom_richtext(
    data = labels,
    # Now pass the data variables as aesthetics
    aes(x, y, label = lab, color = species, angle = angle),
    size = 4, fill = NA, label.color = NA,
    lineheight = .3
  ) +
  # show.legend = FALSE else we get some unusual legends!
  # fill = NA makes the labels' fill transparent


  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(
    breaks = seq(12.5, 22.5, by = 2.5),
    limits = c(12.5, 22.5)
  ) +
  scale_colour_paletteer_d(
    palette = `"rcartocolor::Bold"`,
    guide = "none"
  ) +

  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)"
  ) +

  # Use theme and element_markdown() to format axes and titles as usual
  theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
    plot.margin = margin(25, 6, 15, 6)
  )


gf_rich

Important

Note the plus sign usage here!!We are combining the ggformula and ggplot syntax, and it works!

theme_set(my_theme)


gg_rich <- ggplot(penguins, aes(
  x = bill_length_mm,
  y = bill_depth_mm
)) +
  geom_point(aes(color = species), alpha = .6, size = 3.5) +

  ## add text annotations for each species
  ggtext::geom_richtext(
    data = labels,
    # Now pass the data variables as aesthetics
    aes(x, y, label = lab, color = species, angle = angle),
    size = 4, fill = NA, label.color = NA,
    lineheight = .3
  ) +
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(
    breaks = seq(12.5, 22.5, by = 2.5),
    limits = c(12.5, 22.5)
  ) +
  scale_colour_paletteer_d(`"rcartocolor::Bold"`, guide = "none") +
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)"
  ) +

  # Use theme and element_markdown() to format axes and titles as usual
  theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
    plot.margin = margin(25, 6, 15, 6)
  )

gg_rich

Formatted Text boxes on plots

element_textbox() and element_textbox_simple() → formatted text boxes with word wrapping.

  • Using ggformula
  • Using ggplot
theme_set(my_theme)

gf_box <- penguins %>%
  gf_point(bill_depth_mm ~ bill_length_mm,
    color = ~species,
    alpha = 0.6, size = 3.5, data = penguins
  ) +


  ## add text annotations for each species
  ggtext::geom_richtext(
    data = labels,
    # Now pass the data variables as aesthetics
    aes(x, y, label = lab, color = species, angle = angle),
    size = 4, fill = NA, label.color = NA,
    lineheight = .3
  ) +
  # show.legend = FALSE else we get some unusual legends!
  # fill = NA makes the labels' fill transparent


  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(
    breaks = seq(12.5, 22.5, by = 2.5),
    limits = c(12.5, 22.5)
  ) +
  scale_colour_paletteer_d(
    palette = `"rcartocolor::Bold"`,
    guide = "none"
  ) +


  # Now for the Plot Titles and Labels, as before
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)"
  ) +

  # Add the ggtext theme related commands
  theme(
    ## turn title into filled textbox
    plot.title = ggtext::element_textbox_simple(
      color = "white",
      fill = "#28A78D",
      size = 28,
      padding = margin(8, 4, 8, 4),
      margin = margin(b = 5),
      lineheight = .9
    ),
    plot.subtitle = ggtext::element_textbox_simple(
      size = 10,
      padding = margin(5.5, 5.5, 5.5, 5.5),
      margin = margin(0, 0, 5.5, 0),
      fill = "orange1"
    ),

    ## add round outline to caption
    plot.caption = ggtext::element_textbox_simple(
      width = NULL,
      linetype = 1,
      fill = "grey",
      padding = margin(4, 8, 4, 8),
      margin = margin(t = 15),
      r = grid::unit(8, "pt")
    ),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
    plot.margin = margin(25, 6, 15, 6)
  )

gf_box

theme_set(my_theme)

gg_box <- ggplot(
  penguins,
  aes(x = bill_length_mm, y = bill_depth_mm)
) +
  geom_point(aes(color = species),
    alpha = .6, size = 3.5
  ) +

  ## add text annotations for each species
  ggtext::geom_richtext(
    data = labels,
    # Now pass the data variables as aesthetics
    aes(x, y, label = lab, color = species, angle = angle),
    size = 4, fill = NA, label.color = NA,
    lineheight = .3
  ) +
  # show.legend = FALSE else we get some unusual legends!
  # fill = NA makes the labels' fill transparent


  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(
    breaks = seq(12.5, 22.5, by = 2.5),
    limits = c(12.5, 22.5)
  ) +
  scale_colour_paletteer_d(
    palette = `"rcartocolor::Bold"`,
    guide = "none"
  ) +


  # Now for the Plot Titles and Labels, as before
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)"
  ) +

  # Add the ggtext theme related commands
  theme(
    ## turn title into filled textbox
    plot.title = ggtext::element_textbox_simple(
      color = "white",
      fill = "#28A78D",
      size = 28,
      padding = margin(8, 4, 8, 4),
      margin = margin(b = 5),
      lineheight = .9
    ),
    plot.subtitle = ggtext::element_textbox_simple(
      size = 10,
      padding = margin(5.5, 5.5, 5.5, 5.5),
      margin = margin(0, 0, 5.5, 0),
      fill = "orange1"
    ),

    ## add round outline to caption
    plot.caption = ggtext::element_textbox_simple(
      width = NULL,
      linetype = 1,
      fill = "grey",
      padding = margin(4, 8, 4, 8),
      margin = margin(t = 15),
      r = grid::unit(8, "pt")
    ),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
    plot.margin = margin(25, 6, 15, 6)
  )

gg_box

Using geom_texbox() for formatted text boxes with word wrapping

  • Using ggformula
  • Using ggplot
theme_set(my_theme)

text_box <- tibble(x = 34, y = 13.7, label = "<span style='font-size:12pt;font-family:anton;'>Lorem Ipsum Dolor Sit Amet</span><br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")


gf_box +
  ## add textbox with long paragraphs
  ggtext::geom_textbox(
    data = text_box,
    aes(x, y,
      label = label
    ),
    size = 2.2, family = "sans",
    fill = "cornsilk",
    colour = "black",
    # This is ESSENTIAL !!!
    # It appears that the original colour aesthetic mapping in `gf_box` and a possible colour aesthetic with `geom_textbox` have a clash, *only* with ggformula. No such issues below with the ggplot.
    # So declaring a colour here is essential

    box.color = "cornsilk3",
    # box.padding = c(2,2,2,2),
    width = unit(11, "lines")
  ) +
  coord_cartesian(clip = "off") # ensure no clipping of labels near the edge

theme_set(my_theme)

gg_box +
  ## add textbox with long paragraphs
  ggtext::geom_textbox(
    data = text_box,
    aes(x, y, label = label),
    size = 2.2, family = "sans",
    fill = "cornsilk", box.color = "cornsilk3",
    width = unit(11, "lines")
  ) +
  coord_cartesian(clip = "off") # ensure no clipping of labels near the edge

Using {ggforce}

From Thomas Lin Pedersen’s website → www.ggforce.data-imaginist.com

ggforce is a package aimed at providing missing functionality to ggplot2 through the extension system introduced with ggplot2 v2.0.0. Broadly speaking ggplot2 has been aimed primarily at explorative data visualization in order to investigate the data at hand, and less at providing utilities for composing custom plots a la D3.js. ggforce is mainly an attempt to address these “shortcomings” (design choices might be a better description). The goal is to provide a repository of geoms, stats, etc. that are as well documented and implemented as the official ones found in ggplot2.

We will start with the basic plot, with the ggtext related work done up to now:

## use ggtext rendering for the following plots
theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)
  • Using ggformula and ggforce
  • Using ggplot and ggforce
theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)

## plot that we will annotate with ggforce afterwards
gf3 <- penguins %>%
  gf_point(bill_depth_mm ~ bill_length_mm,
    color = ~body_mass_g,
    alpha = .6,
    size = 3.5
  ) +

  coord_cartesian(xlim = c(25, 65), ylim = c(10, 25)) +

  # Add Colour scales
  scale_color_paletteer_c(`"grDevices::Lajolla"`,
    direction = -1
  ) +

  # Add labels
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)",
    fill = "Species"
  )



## ellipsoids for all groups
gf3 +
  ggforce::geom_mark_ellipse(
    aes(
      fill = species,
      label = species
    ),
    color = "black",
    # This is good to include
    # Else ellipses get coloured too

    alpha = .15,
    show.legend = FALSE
  )

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)

## plot that we will annotate with ggforce afterwards
gg3 <- ggplot(
  penguins,
  aes(x = bill_length_mm, y = bill_depth_mm)
) +
  geom_point(aes(color = body_mass_g),
    alpha = .6,
    size = 3.5
  ) +
  coord_cartesian(xlim = c(25, 65), ylim = c(10, 25)) +

  # Add Colour scales
  scale_color_paletteer_c(`"grDevices::Lajolla"`,
    direction = -1
  ) +


  # Add labels
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)",
    fill = "Species"
  )


## ellipsoids for all groups
gg3 +
  ggforce::geom_mark_ellipse(
    aes(
      fill = species,
      label = species
    ),
    alpha = .15,
    show.legend = FALSE
  )

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)

## ellipsoids for specific subset
gg3 +
  ggforce::geom_mark_ellipse(
    aes(
      fill = species, label = species,
      filter = species == "Gentoo"
    ),
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)

## circles
gg3 +
  ggforce::geom_mark_circle(
    aes(
      fill = species, label = species,
      filter = species == "Gentoo"
    ),
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)

## rectangles
gg3 +
  ggforce::geom_mark_rect(
    aes(
      fill = species, label = species,
      filter = species == "Gentoo"
    ),
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)

## hull
gg3 +
  ggforce::geom_mark_hull(
    aes(
      fill = species, label = species,
      filter = species == "Gentoo"
    ),
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)

ggplot tricks

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

gg0 <-
  ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  ggforce::geom_mark_ellipse(
    aes(
      fill = species,
      label = species
    ),
    alpha = .15,
    show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) +
  scale_x_continuous(
    breaks = seq(25, 65, by = 5),
    limits = c(25, 65)
  ) +
  scale_y_continuous(
    breaks = seq(12, 24, by = 2),
    limits = c(12, 24)
  ) +
  scico::scale_color_scico(palette = "bamako", direction = -1) +
  labs(
    title = "**Bill Dimensions of Brush-Tailed Penguins** (*Pygoscelis*)",
    subtitle = "A scatter plot of bill depth versus bill length.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)",
    y = "**Bill Depth** (mm)",
    color = "**Body mass** (g)"
  )
gg0

Left-Aligned Title

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

(gg1 <- gg0 + theme(plot.title.position = "plot"))

Right-Aligned Caption

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

gg1b <- gg1 + theme(plot.caption.position = "plot")
gg1b

Legend Design

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

gg1b + theme(legend.position = "top")
# ggsave("06a_legend_position.pdf", width = 9, height = 8, device = cairo_pdf)

gg1b +
  theme(legend.position = "top") +
  guides(
    color = guide_colorbar(
      # title.position = "top",
      # title.hjust = .5,
      legend.key.width = unit(20, "lines"),
      legend.bar.height = unit(.5, "lines")
    )
  )

Add Images

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

## read PNG file from web
png <- magick::image_read("images/culmen_depth.png")

## turn image into `rasterGrob`
img <- grid::rasterGrob(png, interpolate = TRUE)

gg5 <-
  gg1 +
  annotation_custom(img,
    ymin = 22, ymax = 28,
    xmin = 65, xmax = 80
  ) +
  labs(caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* &bull; Illustration: Allison Horst") +
  coord_cartesian(clip = "off") # ensure no clipping of labels near the edge
gg5

Using {patchwork}

The goal of patchwork is to make it ridiculously simple to combine separate ggplots into the same graphic. As such it tries to solve the same problem as gridExtra::grid.arrange() and cowplot::plot_grid but using an API that incites exploration and iteration, and scales to arbitrarily complex layouts.

→ https://patchwork.data-imaginist.com/

Let us make two plots and combine them into a single patchwork plot.

theme_set(new = my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

## calculate bill ratio
penguins_stats <- penguins %>%
  mutate(bill_ratio = bill_length_mm / bill_depth_mm) %>%
  filter(!is.na(bill_ratio))

## create a second chart
gg6 <-
  ggplot(
    penguins_stats,
    aes(
      y = bill_ratio,
      x = species,
      fill = species,
      color = species
    )
  ) +
  geom_violin() +
  labs(
    y = "Bill ratio",
    x = "Species",
    subtitle = "",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* &bull; Illustration: Allison Horst"
  ) +
  theme(
    panel.grid.major.x = element_line(linewidth = .35),
    panel.grid.major.y = element_blank(),
    axis.text.y = element_text(size = 13),
    axis.ticks.length = unit(0, "lines"),
    plot.title.position = "plot",
    plot.subtitle = element_text(margin = margin(t = 5, b = 10)),
    plot.margin = margin(10, 25, 10, 25)
  )

Now to combine both plots into one using simple operators:

For the special case of putting plots besides each other or on top of each other patchwork provides 2 shortcut operators. | will place plots next to each other while / will place them on top of each other.

First we stack up the graphs side by side:

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

## combine both plots
gg5 | (gg6 + labs(
  title = "Bill Ratios of Brush-Tailed Penguins",
  subtitle = "Violin Plots of Bill Ration versus species"
))

We can place them in one column:

theme_set(my_theme)
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown(),
  legend.title = ggtext::element_markdown()
)

gg5 / (gg6 + labs(
  title = "Bill Ratios of Brush-Tailed Penguins",
  subtitle = "Violin Plots of Bill Ration versus species"
)) +
  plot_layout(heights = c(0.4, 0.4))

References


1. Thomas Lin Pedersen, https://www.data-imaginist.com/. The creator of ggforce, and patchwork packages.
2. Claus Wilke, cowplot – Streamlined plot theme and plot annotations for ggplot2, https://wilkelab.org/cowplot/index.html
3. Claus Wilke, Spruce up your ggplot2 visualizations with formatted text, https://clauswilke.com/talk/rstudio_conf_2020/. Slides, Code, and Video !
4. Robert Kabacoff, ggplot theme cheatsheet, https://rkabacoff.github.io/datavis/modifyingthemes.pdf
5. Zuguang Gu, Circular Visualization in R, https://jokergoo.github.io/circlize_book/book/

R Package Citations
Package Version Citation
ggdist 3.3.2 @ggdist2024a; @ggdist2024b
ggforce 0.4.2 @ggforce
ggtext 0.1.2 @ggtext
grid 4.4.2 @grid
magick 2.8.5 @magick
paletteer 1.6.0 @paletteer
patchwork 1.3.0 @patchwork
scico 1.5.0 @scico
showtext 0.9.7 @showtext
sysfonts 0.8.9 @sysfonts
systemfonts 1.2.0 @systemfonts
Back to top
Lab-6: These Roses have been Painted !!
Lab-8: Did you ever see such a thing as a drawing of a muchness?

License: CC BY-SA 2.0

Website made with ❤️ and Quarto, by Arvind V.

Hosted by Netlify .