Knowledge base

How to draw multiple images into one image in R language

Introduction

Sometimes we need to arrange multiple images on a picture. For the functions of the R language basic package, such as plot, barplot, hist, etc., it can be typeset through par, layout, but for ggplot images, we need Use another method

Several methods to achieve
Several methods to achieve
par method

The method only applies to the functions of the basic package (plot, barplot, hist, etc.), not to ggplot.

par(mfrow = c(1,2))
plot(mtcars[,1:2],pch =19)
plot(iris[,1:2],pch = 19)
layout method
layout(matrix(c(2,0,1,3),2,2,byrow=TRUE), widths=c(3,1), heights=c(1,3), respect=TRUE)

Set the layout, the layout matrix is

2  0 
1  3

It means that the lower left is the first painting, the upper left is the second, the lower right is the third, and the upper right is not drawn. widths = c(3,1) means that the width ratio from left to right is 3 to 1, heights=c(1,3) means that the height is 1 to three from top to bottom, respect=True unit column width and unit row height The same physical measurement on the device

The example is as follows

#Read in data
air<-read.csv("airpollution.csv")

#First set the layout
layout(matrix(c(2,0,1,3),2,2,byrow=TRUE), widths=c(3,1), heights=c(1,3), TRUE)

#Draw a scatter plot
par(mar=c(5.1,4.1,0.1,0))
plot(air$Respirable.Particles~air$Nitrogen.Oxides,pch=19,
col="black",xlim=c(0,600),ylim=c(0,80),xlab="Nitrogen Oxides Concentrations",ylab="Respirable Particle Concentrations")

#Draw the histogram of X, above the scatter plot
par(mar=c(0,4.1,3,0))
hist(air$Nitrogen.Oxides,breaks=seq(0,600,100),ann=FALSE,axes=FALSE,
col="black",border="white")

#Draw a histogram of Y, to the right of the scatter plot
yhist <- hist(air$Respirable.Particles,breaks=seq(0,80,10),plot=FALSE)
par(mar=c(5.1,0,0.1,1))
barplot(yhist$density,horiz=TRUE,space=0,axes=FALSE,col="black",border="white")
ggplot can use the function ggarange of the ggpubr package

Use install.packages("ggpubr") to install the ggpubr package.

ggarrange(..., 
    plotlist = NULL, 
    ncol = NULL, 
    nrow = NULL, 
    labels = NULL,
    label.x = 0, 
    label.y = 1, 
    hjust = -0.5, 
    vjust = 1.5,
    font.label = list(size = 14, color = "black", face = "bold", family = NULL),
    align = c("none", "h", "v", "hv"), 
    widths = 1, 
    heights = 1,
    legend = NULL,
    common.legend = FALSE)

  …:The figure object that needs to be drawn can be directly placed in multiple ggplot objects
  plotlist,You can also put the ggplot object in the list and give this plotlist parameter
  ncol and nrow are arranged in several rows and columns
  labelsThe label of each figure, label.x label.y hjust vjust font.label is the position parameter of adjusting labels,
  alignThe arrangement of each figure, is it vertical (v) or horizontal (h),
  widths and heights adjust the aspect ratio of each image
  legend is the legend of each figure,
  common.legend common legend

The example is as follows

cols <- brewer.pal(n=5, name='Set1')  #Configure color palette
# Use plist to store ggplot objects, and then use ggarrange for typesetting and drawing
plist <- list()
plist[[1]] <- ggplot(df1,aes(x=sample,y=count,fill=group))+theme_classic()+geom_bar(stat='identity')+
  theme(legend.position = "none", 
        axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) + 
  ylab('HMR#')+
  scale_fill_manual(values=c('darkgray',cols))
plist[[2]] <- ggplot(df3,aes(x=sample,y=count,fill=group))+theme_classic()+geom_bar(stat='identity')+
  theme(axis.title.x=element_blank(),axis.text.x=element_blank(),axis.ticks.x=element_blank(),legend.position = "none")+
  scale_fill_brewer(palette='Dark2')+ylab('CpG#')
plist[[3]] <- ggplot(df5,aes(x=sample,y=percent.copy.altered,fill=namecn))+theme_classic()+geom_bar(stat='identity')+
  theme(axis.title.x=element_blank(),axis.text.x=element_blank(),axis.ticks.x=element_blank(),legend.position = "none")+
  scale_fill_manual(values='darkgrey')+ylab('% CN Altered')
plist[[4]] <- ggplot(df5,aes(x=sample,y=mutation_count,fill=namemut))+theme_classic()+geom_bar(stat='identity')+
  theme(axis.title.x=element_blank(),axis.text.x=element_blank(),axis.ticks.x=element_blank(),legend.position = "none")+
  scale_fill_manual(values='darkgrey')+ylab('Mut/Mb')+scale_y_log10() 

plist[[5]] <- ggplot(df6,aes(x=sample,y=count,fill=group))+theme_classic()+geom_bar(stat='identity')+
  theme(axis.title.x=element_blank(),
        axis.text.x=element_text(angle=90,hjust=1,vjust=0.5,colour=df6$color),
        axis.ticks.x=element_blank(),
        legend.position = "none")+ 
  scale_fill_brewer(palette='Set2')+ylab('# SV')

ggarrange(plotlist=plist,
          ncol=1,
          nrow=length(plist),
          heights=c(3,1,1,1,2) ,
          align="v")
ggsave(fn_fig1a, height=8, width=14)
ggplot can also use grid typesetting

The grid package is the underlying drawing system that comes with the R language, which can finely lay out graphs, lines, points, etc. We wrap it as a function here, and its usage is very similar to ggarrange.
Example:

# Multiple plot function
#
# ggplot objects can be passed in ..., or to plotlist (as a list of ggplot
# objects)
# - cols:   Number of columns in layout
# - layout: A matrix specifying the layout. If present, 'cols' is ignored.
#
# If the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE),
# then plot 1 will go in the upper left, 2 will go in the upper right, and
# 3 will go all the way across the bottom.
# e=0.15, # extra height needed for last plot (vertical layout),
# or extra width for first plot (horizontal layout)
multiplot <- function(..., plotlist=NULL, file, cols=1,
                      layout=NULL, horizontal=FALSE, e=0.15) {
  require(grid)

  # Make a list from the ... arguments and plotlist
  plots = c(list(...), plotlist)

  numPlots = length(plots)
  #message(paste0('>>>>>>>INFO: num plots 2 = ', numPlots), '\n')

  # If layout is NULL, then use 'cols' to determine layout
  if (is.null(layout)) {
    # Make the panel
    # ncol: Number of columns of plots
    # nrow: Number of rows needed, calculated from # of cols
    layout = matrix(seq(1, cols * ceiling(numPlots/cols)),
                    ncol = cols, nrow = ceiling(numPlots/cols))
  }

  if (numPlots==1) {
    print(plots[[1]])

  } else {

    ## set up heights/widths of plots

    # extra height needed for last plot (vertical layout),
    # or extra width for first plot (horizontal layout)
    hei = rep(1, numPlots)
    # bottom plot is taller
    hei[numPlots] = hei[numPlots]*(1+e)
    wid = rep(1, numPlots)
    # first left plot is wider
    wid[1] = wid[1]*(1+e)
    # Set up the page
    grid.newpage()
    if(horizontal){
      pushViewport(viewport(layout = grid.layout(nrow(layout),
                                                 ncol(layout), widths=wid)))
    }else{
      pushViewport(viewport(layout = grid.layout(nrow(layout),
                                                 ncol(layout), heights=hei)))

    }

    # Make each plot, in the correct location
    for (i in 1:numPlots) {
      # Get i,j matrix positions of the regions containing this subplot
      matchidx = as.data.frame(which(layout == i, arr.ind = TRUE))
      print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
                                      layout.pos.col = matchidx$col))
    }
  }
}

library(ggplot2)
p1 <- ggplot(iris, aes(x = Sepal.Length)) + geom_histogram() + theme_bw()
p2 <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Width)) + geom_point() + theme_bw()

# Use ggplot object to draw directly
multiplot(p1,p2)

# 将ggplot对象放入列表中,再用列表画图, 并设置两列的排列方式
plot_lst <- list()
plot_lst[[1]] <- p1
plot_lst[[2]] <- p2
multiplot(plotlist = plot_lst, cols = 2)

Reference

Hrishi V.Mittal, R Graphs Cookbook
Zhao S G , Chen W S , Li H , et al. The DNA methylation landscape of advanced prostate cancer[J]. Nature Genetics, 2020.
https://github.com/DavidQuigley/WCDT_WGBS/blob/master/scripts/2019_05_15_WGBS_figure_1A.R
Dang H X , White B S , Foltz S M , et al. ClonEvol: clonal ordering and visualization in cancer sequencing[J]. Annals of Oncology, 2017.
ywliao blog: https://www.cnblogs.com/ywliao/p/12419025.html

Leave a Reply

Your email address will not be published. Required fields are marked *