6  Appendix

6.1 Point shapes

Type ?tidyplots::add_data_points in R console, you can view the help information of the function.

shape An integer between 0 and 24, representing the shape of the plot symbol.

Let’s see: which point shapes in tidyplots allow simultaneous use of color and fill aesthetics?

library(tidyplots)

# Set a df for point plotting
df <- tibble::tibble(
  x = rep(1:20, length.out = 200),
  y = rep(letters[1:10], each = 20),
  shape = seq(0, 199)) # testing more numbers here

# View top 10 rows
df |> 
  dplyr::slice_head(n = 10)
# A tibble: 10 × 3
       x y     shape
   <int> <chr> <int>
 1     1 a         0
 2     2 a         1
 3     3 a         2
 4     4 a         3
 5     5 a         4
 6     6 a         5
 7     7 a         6
 8     8 a         7
 9     9 a         8
10    10 a         9
# Plot
df |> tidyplot(
    x = x, 
    y = y) |> 
  add_data_points(
    shape = df$shape, 
    size = 3, 
    color = "#000000", 
    fill = "#bb5566") |> 
  add_annotation_text(
    text = df$shape, 
    x = df$x, 
    y = df$y, 
    vjust = 2.5, 
    color = "#004488") |> 
  adjust_size(
    width = 150, 
    height = 100) |> 
  adjust_y_axis(
    limits = c(0.3, NA)) |>  
  remove_x_axis_labels() |> 
  remove_y_axis_labels() |> 
  remove_x_axis_title() |> 
  remove_y_axis_title() |> 
  add_title(
    title = "Just shapes 21 - 25 in tidyplots use both 'color' and 'fill' aesthetics") |> 
  save_plot(
    filename = "images/point-shape-color-fill.png",
    view_plot = FALSE)

Point shapes in tidyplots.

6.2 Point white borders and width

library(tidyplots)

df <- tibble::tibble(x = 1, y = 1)

# View
df
# A tibble: 1 × 2
      x     y
  <dbl> <dbl>
1     1     1
# Define a style
my_style <- function(x) {
  x |> 
  adjust_size(width = 10, height = 10) |> 
  remove_x_axis_labels() |> remove_x_axis_title() |> remove_x_axis_ticks() |> 
  remove_y_axis_labels() |> remove_y_axis_title() |> remove_y_axis_ticks() |> 
  adjust_theme_details(
    panel.background = ggplot2::element_rect(fill = "#bb55664d"))}

# Set a function to plot
generate_plot <- function(point_shape, white_border_width) {
  df |> tidyplot(x = x, y = y) |> 
    my_style() |> 
    add_data_points(
      white_border = TRUE, 
      size = 3, 
      stroke = white_border_width, # border width
      color = "#000000", 
      shape = point_shape) |> # point shape
  add_title(title = as.character(point_shape))}

# Plots with point shapes 0 - 25 (white_border width: 1)
plots_width1 <- purrr::set_names(
  purrr::map(0:25, generate_plot, white_border_width = 1),
  paste0("p", 0:25))

# Plots with point shapes 0 - 25 (white_border width: 2)
plots_width2 <- purrr::set_names(
  purrr::map(0:25, generate_plot, white_border_width = 2),
  paste0("p", 0:25))

# Wrap plots together and save
(patchwork::wrap_plots(plots_width1, ncol = 10) +
  patchwork::plot_annotation(
    title = "plots_width1",
    subtitle = "some shapes with white borders (width = 1)")) |> 
  save_plot("images/point-white-borders1.png",
    view_plot = FALSE, width = 140, height = 70)

(patchwork::wrap_plots(plots_width2, ncol = 10) +
  patchwork::plot_annotation(
    title = "plots_width2",
    subtitle = "some shapes with white borders (width = 2)")) |> 
  save_plot("images/point-white-borders2.png",
    view_plot = FALSE, width = 140, height = 70)

Some shapes can be with white borders.
Note

Some shapes become visually identical under this condition (i.e. when white_border = TRUE), such as shapes 0, 15, and 22.

6.3 xy coordinates in ImageJ/Fiji

Here it uses Fiji.

Fiji is a distribution of ImageJ which includes many useful plugins contributed by the community. https://imagej.net/software/fiji/downloads

library(tidyplots)

img <- "images/fiji.png" |> magick::image_read()
# View image information
img_info <- img |> magick::image_info()
img_width <- img_info$width; img_height <- img_info$height
# Change to graphical object
img_grob <- img |> grid::rasterGrob()

# Create a data frame relevant to img_grob
df <- tibble::tibble(x = seq(0, img_width, length.out = 100),
  y = seq(0, img_height, length.out = 100))
# View the 1st row of df
df |> dplyr::slice_head(n = 1)
# A tibble: 1 × 2
      x     y
  <dbl> <dbl>
1     0     0
# The intended width of image
img_intend_width = 100 # unit: mm
# Tailor relative extra spaces of plot
top_extra = 0 # 0 (0%) - 1 (100%)
right_extra = 0.2; bottom_extra = 0; left_extra = 0

# The width and height of plot
plot_width = img_intend_width * (1 + left_extra + right_extra) # unit: mm
plot_height = img_intend_width * (img_height/img_width) * (1 + top_extra + bottom_extra)

# Plot
p1 <- df |> tidyplot(x = x, y = y) |> 
  add_data_points(alpha = 0) |> 
  add(ggplot2::annotation_custom(img_grob, xmin = 0, xmax = img_width, 
    ymin = img_height, ymax = 0)) |> 
  add_title(title = "p1: Fiji") |> 
  add_annotation_text(text = "+", x = 626, y = c(img_height - 804), fontsize = 14) |> 
  adjust_size(width = plot_width, height = plot_height) |> 
  adjust_x_axis(limits = c(-img_width*left_extra, img_width*(1 + right_extra))) |> 
  adjust_y_axis(limits = c(-img_height*bottom_extra, img_height*(1+top_extra))) |> 
  remove_x_axis_labels() |> remove_y_axis_labels()

p2 <- p1 |> 
  adjust_title(title = "p2: annotation") |> 
  add_annotation_text(text = "x", x = 125, y = c(img_height - 226), fontsize = 14, 
    color = "#bb5566", fontface = "bold") |> 
  add_annotation_text(text = "y", x = 279, y = c(img_height - 226), fontsize = 14, 
    color = "#bb5566", fontface = "bold") |>
  add_annotation_text(text = "width: 180\nheight: 237", x = 468, 
    y = c(img_height - 334),fontsize = 14, color = "#bb5566", 
    hjust = 0, vjust = 1, fontface = "bold") |>  
  add_annotation_text(text = "(x, y) in Fiji\n(x, (height - y)) in tidyplots", x = 650,
    y = c(img_height - 804), color = "#bb5566", fontsize = 14, 
    hjust = 0, fontface = "bold")

xy coordinates in ImageJ (Fiji).

6.4 Patchwork package for combining multiple plots

Note

Patchwork https://patchwork.data-imaginist.com/ was not initially designed to handle plots with absolute dimensions.

All multi-panel figures throughout this book (except the figure in Section 3.4 and Section 3.39), due to differences in absolute dimensions, are combined using the patchwork package.

In general, patchwork can be used to combine seperate plots into a multi-panel figure and tag each panel, which is a common practice in scientific papers.

library(tidyplots)

# View top 10 rows of the columns used
study |> dplyr::select(treatment, score) |> 
  dplyr::slice_head(n = 10)
# A tibble: 10 × 2
   treatment score
   <chr>     <dbl>
 1 A             2
 2 A             4
 3 A             5
 4 A             4
 5 A             6
 6 B             9
 7 B             8
 8 B            12
 9 B            15
10 B            16
# Plot
p1 <- study |> 
  tidyplot(
    x = treatment, y = score, color = treatment) |> 
  add_median_bar(alpha = 0.3) |> 
  add_data_points_beeswarm(white_border = TRUE) |> 
  add_sd_errorbar() |> 
  add_test_asterisks(ref.group = "A", hide_info = TRUE)

p2 <- p1
multipanel_1 <- patchwork::wrap_plots(p1, p2, ncol = 2) + 
  patchwork::plot_annotation(
    tag_levels = "A", title = "tags in uppercase letters (i.e. A, B)") &
  ggplot2::theme(plot.tag = ggplot2::element_text(size = 12, face = "bold"))
multipanel_1 |> 
  save_plot("images/patchwork_multipanel_1.png",
    view_plot = FALSE, width = 170, height = 80) # width and height should be tailored

multipanel_2 <- patchwork::wrap_plots(p1, p2, ncol = 2) + 
  patchwork::plot_annotation(
    tag_levels = "a", title = "tags in lowercase letters (i.e. a, b)") &
  ggplot2::theme(plot.tag = ggplot2::element_text(size = 12, face = "bold"))  
multipanel_2 |> 
  save_plot("images/patchwork_multipanel_2.png",
    view_plot = FALSE, width = 170, height = 80) # width and height should be tailored

Add panel tags via the patchwork package.

6.5 Packages used across this cookbook

os_version <- paste(Sys.info()[c("sysname", "release")], collapse = " ")
quarto_version <- system2("quarto", "--version", stdout = TRUE)
positron_version <- system2("positron", "--version", stdout = TRUE)
r_version <- R.version.string

r_packages_versions <- tibble::tibble(
  r_package = c(
    "tidyplots", "grid", "scales", "ggplot2", "patchwork",
    "ggtext", "ggridges", "see", "legendry", "gggenes",
    "purrr", "readr", "readxl", "tibble", "dplyr",
    "rphylopic", "fs", "magick")) |> 
  dplyr::mutate(
    version = purrr::map_chr(r_package, \(x) as.character(packageVersion(x))))

os_version
[1] "Windows 10 x64"
paste0("quarto: ", quarto_version)
[1] "quarto: 1.9.38"
paste0("positron: ", positron_version[1])
[1] "positron: Positron: 2026.06.0 build 211"
r_version
[1] "R version 4.5.3 (2026-03-11 ucrt)"
r_packages_versions
# A tibble: 18 × 2
   r_package version
   <chr>     <chr>  
 1 tidyplots 0.4.0  
 2 grid      4.5.3  
 3 scales    1.4.0  
 4 ggplot2   4.0.3  
 5 patchwork 1.3.2  
 6 ggtext    0.1.2  
 7 ggridges  0.5.7  
 8 see       0.13.0 
 9 legendry  0.3.0  
10 gggenes   0.6.0  
11 purrr     1.2.1  
12 readr     2.2.0  
13 readxl    1.4.5  
14 tibble    3.3.1  
15 dplyr     1.2.1  
16 rphylopic 1.6.0  
17 fs        2.1.0  
18 magick    2.9.1