R一页多图

  发表文章一般都要求将多个相关的图组合成单个图,并标上A,B,C等标签。所以总结一下R语言绘图的一页多图,以及多图的拼接,子母图等的各种实现方法,!

R一页多图

cowplot:基于ggplot的可视化系统

简介

  cowplot是一个ggplot2包的简单补充,意味着其可以为ggplot2提供出版物级的主题等。更重要的是,这个包可以组合多个”ggplot2”绘制的图为一个图,并且为每个图加上例如A,B,C等标签, 这在具体的出版物上通常是要求的。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
library(ggplot2)
require(cowplot)
plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() + facet_grid(. ~ Species) +
stat_smooth(method = "lm") +
background_grid(major = 'y', minor = "none") +
panel_border() +
labs(title = "dot-line plot")
plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) +
geom_point(size=2.5) +
labs(title = "dot plot")
plot.diamonds <- ggplot(diamonds, aes(clarity, fill = cut)) +
geom_bar() +
theme(axis.text.x = element_text(angle=70, vjust=0.5)) +
labs(title = "bar plot")
ggdraw() +
draw_plot(plot.iris, 0, .5, 1, .5) +
draw_plot(plot.mpg, 0, 0, .5, .5) +
draw_plot(plot.diamonds, .5, 0, .5, .5) +
draw_plot_label(c("A", "B", "C"), c(0, 0, 0.5), c(1, 0.5, 0.5), size = 15)

结果

注意:其中draw_plot(plot, x = 0, y = 0, width = 1, height = 1, scale = 1),坐标参数范围为0-1,相当于每幅图占画布长宽的百分比

rmisc包中的multiplot函数实现上述相同效果

简单高效,一句话搞定!可以实现上述同样的结果。

代码

1
2
3
4
5
library("Rmisc")
library("lattice")
library("plyr")
multiplot(plot.iris,plot.mpg,plot.diamonds, layout = matrix(c(1,1,2,3), nrow=2, byrow=TRUE))

下面看看源码中multiplot函数,本质是grid包!!

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
library(grid)
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# 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 {
###新建图表版面
grid.newpage()
####将版面分成nrow(layout)*ncol(layout)的矩阵
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain 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))
}
}
}

grid包实现上述相同效果

代码

1
2
3
4
5
6
7
8
grid.newpage() ###新建图表版面
grid.text("title of this panel", vp = viewport(layout.pos.row = 1, layout.pos.col = 1:2))
pushViewport(viewport(layout = grid.layout(2,2))) ####将版面分成2*2矩阵
vplayout <- function(x,y){viewport(layout.pos.row = x, layout.pos.col = y)}
print(plot.iris, vp = vplayout(1,1:2)) ###将(1,1)和(1,2)的位置画图plot.iris
print(plot.mpg, vp = vplayout(2,1)) ###将(2,1)的位置画图plot.mpg
print(plot.diamonds , vp = vplayout(2,2)) ###将(2,2)的位置画图plot.diamonds

使用gridExtra包实现上述相同效果

1
2
3
grid.arrange( arrangeGrob(plot.iris,left="A"), arrangeGrob(plot.mpg, left="B"), arrangeGrob(plot.diamonds, left="C"),
layout_matrix = matrix(c(1,1,2,3), ncol=2, byrow=TRUE),
top = "Title",left = "This is my global Y-axis title")

结果

单个图的标签(A,B,C)位置和属性不是很方便调整

使用gridExtra包实现多图的轴向组合

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hist_top <- ggplot()+geom_histogram(aes(mtcars$mpg)) #绘制上方条形图
empty <- ggplot()+geom_point(aes(1,1), colour="white")+
theme(axis.ticks=element_blank(),
panel.background=element_blank(),
axis.line =element_blank(),
axis.text.x=element_blank(), axis.text.y=element_blank(),
axis.title.x=element_blank(), axis.title.y=element_blank())
scatter <- ggplot()+geom_point(aes(mtcars$mpg, mtcars$qsec)) #绘制主图散点图
hist_right <- ggplot()+geom_histogram(aes(mtcars$qsec))+coord_flip() #绘制右侧条形图
#最终组合,由四个图拼图而成,只是右上角的图已经将各种标注去除了
grid.arrange(hist_top, empty, scatter, hist_right, ncol=2, nrow=2,
widths=c(4, 1), heights=c(1, 4))

结果

其实绘制这种组合图已经有相应的R包了–ggExtra

代码

1
2
3
4
5
library(ggplot2)
df <- data.frame(x = mtcars$mpg, y = mtcars$qsec)
p <- ggplot(df, aes(x, y)) + geom_point() + theme_classic()
ggExtra::ggMarginal(p, type = "histogram")

ggExtra包中最主要的函数ggMarginal - Add marginal histograms/boxplots/density plots to ggplot2 scatterplots

子母图

适用场景

  当做分组条形图时,有时碰到一组数据特北大,其他组数据特别小,这时候就不太美观了。可能你想到的第一个办法是截断,但其实还可以用字母图,形成局部放大的效果,既可以从整体上对比,又兼顾特别小的数据组可以轻松查看,而没必要单独做两张图。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 载入需要的包
library(plyr)
library(Rmisc)
library(ggplot2)
library(grid)
#创建数据
A <- rnorm(10,75,10)
B <- rnorm(10,12,5)
C <- rnorm(10,4,3)
Group <- c(rep('A',10),rep('B',10),rep('C',10))
Value <- c(A,B,C)
D <- data.frame(Group,Value)
# 求标准差,后面画误差要用
DSe <- summarySE(D,measurevar = 'Value',groupvars = 'Group')
# 把组别转化成因子
D$Group <- factor(D$Group)
# 挑三种颜色
C <- c('#55a0fb','#ff8080','#c5944e')
#画大图
p1 <- ggplot(DSe,aes(Group,Value)) + # 定义环境
geom_bar(aes(Group,Value,fill = Group),stat = 'identity',width = 0.5,show.legend = T) + # 画条形图
geom_errorbar(aes(ymin = Value-se, ymax = Value+se),width = .2) + #加误差线
scale_fill_manual(values = C) + # 配色
labs(x='修改X轴为Group',y='修改Y轴为Value',title = '添加标题')+
theme(axis.title = element_text(face = 'bold'),# 定义主題,如坐标轴,标题样式、背景等
axis.text = element_text(face = 'bold',colour = 'black'),
plot.title = element_text(face = 'bold',colour = 'black',hjust = 0.5,size = 20),
legend.background = element_rect(I(0),linetype = 1))
p1 # 看下效果
# 选择小数据集、小颜色集
DSe2 <- DSe[2:3,]
C2 <- C[2:3]
# 画小图,基本和大图一樣,后面要背景透明、显示坐标轴
p2 <- ggplot(DSe2,aes(Group,Value)) +
geom_bar(aes(Group,Value,fill = Group), stat = 'identity',width = 0.5) +
geom_errorbar(aes(ymin = Value-se, ymax = Value+se),width = .2)+
scale_fill_manual(values = C2)+
guides(fill = F)+
theme(axis.text = element_text(face = 'bold',colour = 'black'),
axis.title.y = element_blank(),
axis.line = element_line(linetype = 1,colour = 'black'), # 显示坐标轴
plot.background = element_rect(I(0),linetype = 0), # 背景透明
panel.background = element_rect(I(0)),
panel.grid.major = element_line(colour = NA),
panel.grid.minor = element_line(colour = NA))
p2 # 看下效果
# 嵌套
sub <- viewport(width = 0.5,height = 0.4,x = 0.64,y = 0.6)
# 配置环境。前兩個是子图的大小比例,后两个是位置,可自行调整到好看位置。
p1 # 上大图
print(p2,vp = sub) # 加小图

结果

关键代码就是利用了grid包的viewport函数,viewport简单说就是图形中一块矩形区域(类似于图层),是在这个区域中进一步绘图的基础。所以我们可以利用viewport函数在任意指定位置将两个或者多个图进行拼接~


ggplot2之分组和分面

  以上是不同数据来源的图,以不同展现形式组合成一个图,另外ggplot2对一个数据集合进行分组,通过分面绘图,也算是实现一页多图的效果吧~

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
setwd("F:/R working directory/GO enrichment")
data<-read.csv("GO.csv",header=TRUE,check.names = FALSE)
data_new<-subset(data,data$FDR<0.5)
library("ggplot2")
ggplot(data=data_new)+
theme(plot.margin=unit(c(1,1,1,3),"cm"))+ #调整作图边距,上,右,下,左
geom_bar(aes(x=Term,y=Count,fill=-log10(Pvalue)),stat="identity")+ #指定横纵变量,stat指定统计变换
scale_fill_gradient(low='red',high='blue')+xlab('')+ylab('')+ #指定注释条带
#指定横纵标签的大小,角度,距离等细节
theme(axis.text.x = element_text(color='black',size = 5,angle=90, hjust=1),
axis.text.y = element_text(color='black',size=10))+
facet_grid(.~Type) #根据Type划分作图区块

结果

可以看到结果并不是很好,横轴标签每个分组(BP,CC,MF)均含有13个通路,这是三个分组富集到的GO通路的交集,空值显示出来并不太美观

解决

1
2
3
4
5
6
7
8
9
10
11
setwd("F:/R working directory/GO enrichment")
data<-read.csv("GO.csv",header=TRUE,check.names = FALSE)
data_new<-subset(data,data$FDR<0.5) #过滤数据
Order <-1:dim(data_new)[1] #生成横坐标输出顺序
data_order<-cbind(data_new,Order) #数据框添加一列
library("ggplot2")
ggplot(data=data_order,aes(x=reorder(Term,data_order$Order),y=-log10(Pvalue),fill=Type))+
coord_flip()+ #将图横向
xlab('')+ #覆盖横坐标
theme(plot.margin=unit(c(1,1,1,1),"cm"))+ #调整作图边距,上,右,下,左
geom_bar(stat="identity")

结果

主要通过给数据框加一列来对每一组进行排序输出

参考

(1)【R:ggplot2】同时绘制多个图

(2)cowplot:基于ggplot的可视化系统

(3)R语言可视化——图表排版之一页多图

(4)Add labels to a plot made by grid.arrange from multiple plots

(5)R语言grid包使用笔记——viewport

(6)利用ggplot将多个图形组合在一起(推荐-置信椭圆)

(7)Scatterplot with marginal histograms in ggplot2(推荐)

(8)你終於會做截斷圖了,可審稿人說不讓做,怎麼破?

(9)ggplot2之分组和分面

-------------本文结束感谢您的阅读-------------