In this chapter, we will mainly focus on making a “publication-type” figure, with sub-plots and such using different tools in R. There are many different ways/packages to do this, but we will mainly focus on 2 packages: cowplot and ggpubr.

Now let us consider some of the plots we have made so far in the previous exercises. From the picture below, A and B are the figures that was made from the gene counts dataset and the figures C and D are using the Sepal.Length and Sepal.Width from the iris data. Now let us look into how we can combine each of the figures like it is shown here.

Now, let us go step by step. First let us make these plots into R objects. This will make things a lot easier.

p1 <- gc_long %>% 
  group_by(Time, Replicate) %>% 
  summarise(mean=mean(log10(count +1)),se=se(log10(count +1))) %>%
  ggplot(aes(x= Time, y= mean, fill = Replicate)) + 
  geom_col(position = position_dodge2()) +
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), position = position_dodge2(.9, padding = .6)) +
  ylab("mean(log10(count+1))") +
  theme(axis.ticks = element_blank()) +
  theme_bw(base_size = 10)

p2 <- ggplot(data = gc_long) +
  geom_boxplot(mapping = aes(x = Sample_Name, y = log10(count + 1), fill = Replicate)) +
  facet_grid(~Time , scales = "free", space = "free") +
  xlab("Time") +
  theme_bw(base_size = 10) +
  theme(axis.ticks.x = element_blank(), axis.text.x = element_blank())

p3 <- ggplot(data=iris,mapping=aes(x=Sepal.Length))+
  geom_density(aes(fill = Species), alpha = 0.6) +
  theme_light(base_size = 10)

p4 <- ggplot(data=iris,mapping=aes(x=Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point(size = 3, alpha = 0.6) +
  theme_light(base_size = 10)

The objects p1, p2, p3 and p4 as intuitively represent the plots A, B, C and D repectively.

1 Cowplot

1.1 plot_grid

One can use the simple plot_grid() function from the cowplot.

library(cowplot)
plot_grid(p1, p2)

plot

You can also do some simple customizations using nrow or ncol to specify the number of rows and columns and provide labels to those plots as well.

plot_grid(p1, p2, nrow = 2, labels = c("A", "B"))

plot

1.2 ggdraw and draw_plot

In cowplot, you can also customize the dimentions of the plots in a much more controlled fashion. For this one starts with ggdraw() which initiates the drawing “canvas” followed by draw_plot() that you use to draw the different plots on to the canvas.

Here is how the dimentions of the empty canvas looks like:

From here, you can draw your plots in the way you want using these dimensions. AN example is shown below, where we plot C and D similar to the plot above:

ggdraw() +
  draw_plot(p3, x = 0, y = 0, width = 1, height = .5) +
  draw_plot(p4, x = 0, y = .5, width = 1, height = .5) 

plot

You can also add “labels” to these figures using draw_plot_label() with the same dimensions.

ggdraw() +
  draw_plot(p3, x = 0, y = 0.5, width = 1, height = .5) +
  draw_plot(p4, x = 0, y = 0, width = 1, height = .5) +
  draw_plot_label(label = c("A", "B"), size = 15, x = c(0,0), y = c(1, 0.5))

plot

It is easier to draw three (or any odd number) plots in a neat way using this function compared to plot_grid()

ggdraw() +
  draw_plot(p3, x = 0, y = 0.5, width = 0.5, height = 0.5) +
  draw_plot(p4, x = 0.5, y = 0.5, width = 0.5, height = 0.5) +
  draw_plot(p2, x = 0, y = 0, width = 1, height = 0.5) +
  draw_plot_label(label = c("A", "B", "C"), size = 15, x = c(0,0.5,0), y = c(1, 1,0.5))

plot

2 ggpubr

2.1 ggarrange

The package ggpubr comes with quite a few functions that can be very useful to make comprehensive figures. To start with the simple function, let’s start with ggarrange() that is used to put plots together.

library(ggpubr)
ggarrange(p3, p4, labels = c("A", "B"), nrow = 2)

plot

One of the nicer things with ggarrange() is that you can automatically have common legends that are shared between the figures.

ggarrange(p3, p4, labels = c("A", "B"), nrow = 2, common.legend = TRUE, legend = "right")

plot

2.2 Mixing text and table with Figures

You can include tables and even normal texts to any figure using ggtexttable() and ggparagraph(). Let us look into adding a table that we saw in the previous exercise with the gene counts dataset.

gc_table <- gc_long %>% 
  group_by(Time) %>% 
  summarise(mean=mean(log10(count +1)),se=se(log10(count +1)))

tab1 <- ggtexttable(gc_table, rows = NULL, 
                        theme = ttheme("mOrange"))
gc_text <- paste("In the experiment, RNA was extracted at four time points:", 
                 "before the gefinitib treatment (t=0), and two, six and twenty-four hours",
                 "after treatment (t=2, t=6, t=24, respectively).", sep = " ")

tex1 <- ggparagraph(text = gc_text, face = "italic", size = 11, color = "black")

Note   Here, for the text part, paste() has been used just to make it a bit easier to show here in the code. It could be used without the paste() command as well.

ggarrange(ggarrange(p1, p2, nrow = 2, labels = c("A", "B"), common.legend = TRUE, legend = "top"),
          ggarrange(tab1, tex1, nrow = 2),
          ncol = 2,
          widths = c(2, 1))

plot

2.3 Multiple-page

With ggarrange() it is also possible to make multiple-page plots. If you are for example making a report of many different figures this can come quite handy. Then you can use ggexport() to export these figures in a multi-page pdf.

multi.page <- ggarrange(p1, p2, p3, p4,
                        nrow = 1, ncol = 1)
ggexport(multi.page, filename = "multi.page.ggplot2.pdf")

Note   From this multi.page R object (which is of class list) , you can get the indivdual plots by multi.page[[1]], multi.page[[2]] and so on.

3 Adding images to plots

Let us you have a microscopic image in jpeg or png that you want to add to a normal ggplot plot that you have made from the data.

Let’s take for example the RBC cluster from a SEM that is in data/Blood_Cells_Image.jpeg:

Let us take the following plot that you want to add the image to:

x <- 1:10
y <- x*abs(rnorm(10))
p1 <- ggplot(data.frame(x,y), mapping=aes(x=x,y=y)) + geom_point() + geom_smooth() + ggtitle("The Title") + theme(title=element_text(size=14, hjust=0.5), axis.title=element_text(size=10), axis.text = element_text(size=6))
p1

For this first you need to convert the image into a grid object (grob). For this we need a couple of packages grid and jpeg to be able to convert the image into a grid object! We will use the functions readJPEG and rasterGrob from these packages.

library(grid)
library(jpeg)
cells_jpg=readJPEG("data/Blood_Cells_Image.jpeg")
p2 <- rasterGrob(cells_jpg)

Now, we can use the grid.arrange() function to plot the grob objects and the ggplot objects.

library(gridExtra)
grid.arrange(p1,p2,nrow=1)

plot

We can also use the annotation_custom to place the image in a particular position of the plot!

p3 <- p1 + annotation_custom(rasterGrob(cells_jpg, width = 0.2),
                    ymin = 10)
p3

plot

4 Exercise

Task   For the exercise in this session, let us look into way of using the tools available for combining plots to make one plot that could be very comprehensive. Try to code the figure below:

Tip: 1   Within ggarrange(), it is possible to adjust the dimension of each plot with widths and heights options.

Tip: 2   You can plot an empty plot with NULL.

5 Session info

sessionInfo()
## R version 4.1.3 (2022-03-10)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.6 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so
## 
## locale:
##  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
##  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
##  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
## [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] gridExtra_2.3          jpeg_0.1-9             ggpubr_0.4.0          
##  [4] cowplot_1.1.1          ggthemes_4.2.4         scales_1.2.0          
##  [7] ggrepel_0.9.1          wesanderson_0.3.6      forcats_0.5.1         
## [10] stringr_1.4.0          purrr_0.3.4            readr_2.1.2           
## [13] tidyr_1.2.0            tibble_3.1.6           tidyverse_1.3.1       
## [16] reshape2_1.4.4         ggplot2_3.3.5          formattable_0.2.1     
## [19] kableExtra_1.3.4       dplyr_1.0.8            lubridate_1.8.0       
## [22] leaflet_2.1.1          yaml_2.3.5             fontawesome_0.2.2.9000
## [25] captioner_2.2.3        bookdown_0.26          knitr_1.39            
## 
## loaded via a namespace (and not attached):
##  [1] nlme_3.1-155      fs_1.5.2          webshot_0.5.3     httr_1.4.2       
##  [5] tools_4.1.3       backports_1.4.1   bslib_0.3.1       utf8_1.2.2       
##  [9] R6_2.5.1          DBI_1.1.2         mgcv_1.8-39       colorspace_2.0-3 
## [13] withr_2.5.0       tidyselect_1.1.2  compiler_4.1.3    cli_3.3.0        
## [17] rvest_1.0.2       xml2_1.3.3        labeling_0.4.2    sass_0.4.1       
## [21] systemfonts_1.0.4 digest_0.6.29     rmarkdown_2.14    svglite_2.1.0    
## [25] pkgconfig_2.0.3   htmltools_0.5.2   dbplyr_2.1.1      fastmap_1.1.0    
## [29] highr_0.9         htmlwidgets_1.5.4 rlang_1.0.2       readxl_1.4.0     
## [33] rstudioapi_0.13   jquerylib_0.1.4   farver_2.1.0      generics_0.1.2   
## [37] jsonlite_1.8.0    crosstalk_1.2.0   car_3.0-12        magrittr_2.0.3   
## [41] Matrix_1.4-0      Rcpp_1.0.8.3      munsell_0.5.0     fansi_1.0.3      
## [45] abind_1.4-5       lifecycle_1.0.1   stringi_1.7.6     carData_3.0-5    
## [49] plyr_1.8.7        crayon_1.5.1      lattice_0.20-45   haven_2.5.0      
## [53] splines_4.1.3     hms_1.1.1         pillar_1.7.0      ggsignif_0.6.3   
## [57] reprex_2.0.1      glue_1.6.2        evaluate_0.15     modelr_0.1.8     
## [61] vctrs_0.4.1       tzdb_0.3.0        cellranger_1.1.0  gtable_0.3.0     
## [65] assertthat_0.2.1  xfun_0.30         broom_0.8.0       rstatix_0.7.0    
## [69] viridisLite_0.4.0 ellipsis_0.3.2