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.
One can use the simple plot_grid()
function from the cowplot
.
library(cowplot)
plot_grid(p1, p2)
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"))
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)
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))
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))
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)
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")
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))
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.
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)
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
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
.
sessionInfo()
## R version 4.1.3 (2022-03-10)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 22.04.3 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.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-10 ggpubr_0.6.0
## [4] cowplot_1.1.3 ggthemes_5.0.0 scales_1.3.0
## [7] ggrepel_0.9.5 wesanderson_0.3.7 forcats_1.0.0
## [10] stringr_1.5.1 purrr_1.0.2 readr_2.1.5
## [13] tidyr_1.3.1 tibble_3.2.1 tidyverse_2.0.0
## [16] reshape2_1.4.4 ggplot2_3.4.4 formattable_0.2.1
## [19] kableExtra_1.4.0 dplyr_1.1.4 lubridate_1.9.3
## [22] leaflet_2.2.1 yaml_2.3.8 fontawesome_0.5.2.9000
## [25] captioner_2.2.3 bookdown_0.37 knitr_1.45
##
## loaded via a namespace (and not attached):
## [1] sass_0.4.8 jsonlite_1.8.8 viridisLite_0.4.2 splines_4.1.3
## [5] carData_3.0-5 bslib_0.6.1 highr_0.10 pillar_1.9.0
## [9] backports_1.4.1 lattice_0.20-45 glue_1.7.0 digest_0.6.34
## [13] ggsignif_0.6.4 colorspace_2.1-0 htmltools_0.5.7 Matrix_1.6-5
## [17] plyr_1.8.9 pkgconfig_2.0.3 broom_1.0.5 svglite_2.1.3
## [21] tzdb_0.4.0 timechange_0.3.0 mgcv_1.8-39 generics_0.1.3
## [25] farver_2.1.1 car_3.1-2 ellipsis_0.3.2 cachem_1.0.8
## [29] withr_3.0.0 cli_3.6.2 magrittr_2.0.3 evaluate_0.23
## [33] fansi_1.0.6 nlme_3.1-155 rstatix_0.7.2 xml2_1.3.6
## [37] tools_4.1.3 hms_1.1.3 lifecycle_1.0.4 munsell_0.5.0
## [41] compiler_4.1.3 jquerylib_0.1.4 systemfonts_1.0.5 rlang_1.1.3
## [45] rstudioapi_0.15.0 htmlwidgets_1.6.4 crosstalk_1.2.1 labeling_0.4.3
## [49] rmarkdown_2.25 gtable_0.3.4 abind_1.4-5 R6_2.5.1
## [53] fastmap_1.1.1 utf8_1.2.4 stringi_1.8.3 Rcpp_1.0.12
## [57] vctrs_0.6.5 tidyselect_1.2.0 xfun_0.41