本节将介绍使用grid Extra、cowplot等R包合并多个独立图表的操作。
一、grid.arrange
我们可以用grid Extra包中的grid.arrange方便地把多个并列图表合并起来。
# install.packages("grid Extra")
library(grid Extra)
library(ggplot2)
library(grid) # 使用grid.rect、grid.text
library(cowplot) # 使用ggdraw、draw_grob、draw_plot、plot_grid
# 先生成多个独立图表
basic=ggplot()+geom_point(aes(1: 5, 1: 5))
# 修改背景的填充色和轮廓p1=basic+theme(plot.background=element_rect(fill="lightgreen", color="lightgreen"))
# 只修改背景填充色,而不修改轮廓,会导致图表周围有白边
p2=basic+theme(plot.background=element_rect(fill="lightgreen"))
# 设置coord_fixed()
p3=basic+coord_fixed()+theme(plot.background=element_rect (fill="lightgreen", color="lightgreen"))
# 当去掉背景和面板时,整个图表的背景会显露出来
p4=basic+labs(y="Very Long Title")+theme(plot.background=element_blank(), panel.background=element_blank(), axis.title.y=element_text(angle=0, vjust=0.5))
## 用grid.arrange合并并调整放置方式
grid.arrange(p1, p2, p3) # 亦可用grobs=list(p1, p2, p3)的形式选择图表
# 像生成矩阵一样用nrow或ncol设置行数和列数
grid.arrange(p1, p2, p3, ncol=2)
# 以矩阵的形式明确放置方式并调整图表大小。矩阵中的数字代表放置顺序,NA代表不放置任何东西
pos=matrix(c(
1, 1, 1,
2, NA, NA), nrow=2, byrow=TRUE)
grid.arrange(p1, p2, layout_matrix=pos)
## 如果不希望每个子图表的面积相同,可使用widths和heights调节大小,这两个参数的值,要么是用unit设置的绝对尺寸,要么是相对数值(例如,widths= c(1, 3)表示第二列的宽度是第一列的三倍)。这两个参数的长度由实际行数和列数决定。本例中的图表有两行两列,所以此处要给出两个宽度值、两个高度值
grid.arrange(p1, p2, p3, ncol=2, widths=c(1, 3), heights=unit(c(8,4), "cm"))
要强调的是,在保存由grid.arrange生成的图表时,我们必须明确为ggsave指定要保存的图表。
# 生成图表并赋值:p=grid.arrange(...)
# 保存:ggsave("文件名", plot=p)
grid包可用于为合并后的图表添加元素(我们已经在第五章介绍了用grid包添加文字和线条的方法)。
# 第一步:用rect Grob函数添加矩形可用于修改整个图表的背景
bottom=rect Grob(gp=gpar(fill="khaki", col="khaki"))
# 第二步:排列图表
p=grid.arrange(p1, p2, p3, p4, ncol=2)
# 第三步:用text Grob添加文字
cha=text Grob(label="Combine Plots", x=0.5, y=0.5, gp=gpar (col="darkred", alpha=0.7, fontsize=30))
# 第四步:合并。我们先把图表的各部分放在列表中,再用g List将它们合并,以便生成可以保存的图表
final=do.call(g List, list(bottom, p, cha))
grid.newpage() # 使用grid包显示图表时需删除前边的图表
grid.draw(final) # 查看图表
# 保存:ggsave("文件名", plot=final)
我们亦可使用cowplot包中的函数为合并后的图表添加背景。
## 方法一:由于bottom、p和cha均为grob对象,所以可使用draw_grob函数添加
ggdraw()+draw_grob(bottom)+draw_grob(p)+draw_grob(cha)
## 方法二:用ggplot添加背景和文字,并用draw_plot添加
bottom_gg=ggplot()+theme_void()+
annotation_raster(matrix("khaki"), xmin=-Inf, xmax=Inf, ymin=Inf, ymax=Inf)
cha_gg=ggplot()+theme_void()+
geom_text(aes(0, 0, label="Combine Plots"), color="darkred", alpha=0.7, size=15)
ggdraw()+draw_plot(bottom_gg)+draw_grob(p)+draw_plot(cha_gg)
二、plot_grid
如果我们要确保各子图表的坐标轴自动对齐的话,可使用egg包中的ggarrange函数。它的使用方法和grid.arrange相似,读者可自行尝试。
接下来我们学习cowplot包中的plot_grid函数,它不但可以自动对齐坐标轴,而且还会输出ggplot图表,方便我们添加其他元素并保存图表。
# 排列图表时,为了让p2和p4的纵坐标轴能够对齐,我们使用了align参数,它的选项为"none"(默认,不对齐)、"h"(水平对齐)、"v"(垂直对齐)或"hv"(两个方向都对齐)。在本例中,p3没有跟其他图表对齐,是因为它设置了coord_fixed()。rel_widths和rel_heights用于指定相对宽度和相对高度。
p=plot_grid(p1, p2, p3, p4, # 亦可写成plotlist=list(p1, p2, p3, p4)
ncol=2, align="v",
rel_widths=1, rel_heights=c(2, 1)
)
# 如不添加其他元素,此处可直接用ggsave("文件名")保存
# 由于plot_grid生成的对象本身是一个ggplot图表,所以我们只要往上添加图层即可。注意:由于ggdraw生成的图表坐标轴范围是从0至1,所以,为了把文字放在中间,x和y均应设为0.5
ggdraw()+draw_plot(p)+geom_text(aes(x=0.5, y=0.5, label="Combine Plots"), color="darkred", alpha=0.7, size=20)
plot_grid还有两个跟坐标轴对齐有关的参数:
●scale:子图表缩放比例。取值为单一数值,或者依次与每个图表相对应的多个数值。当其小于默认值1时,图表之间的缝隙会增大。显然,如果修改了缩放比例,图表之间就可能无法对齐了。
●axis:在对齐子图表时,我们还可使用axis参数,它的取值为"t"、"b"、"l"、"r"(分别代表上、下、左、右),以及"tb"、"lr"(分别代表上下、左右)或"tblr"(四个方向同时对齐)。
三、多个图表共用一个图例
在多个并列图表使用相同图例的情况下,我们只须添加一个图例即可(图7-4-1)。
# install.packages("ggpubr")
library(ggpubr) # 使用get_legend
library(magick) # 用于读取图片
library(reshape2) # 使用melt
library(dplyr)
# 第一步:绘制不带图例的图表
p1=ggplot()+geom_bar(show.legend=FALSE, aes(x=1: 5, y=1: 5, fill=factor(1: 5)), stat="identity")(www.xing528.com)
p2=ggplot()+geom_segment(show.legend=FALSE, aes(x=0, xend=5, y=1: 5, yend=1: 5, color=factor(1: 5)), size=2)
p3=ggplot()+geom_point(show.legend=FALSE, aes(1: 5, 1: 5, color=factor(1: 5)), size=5)
# 第二步:任选一个带图例的图表并完成对图例的修改,用ggpubr包中的get_legend函数提取图例的grob对象
p1_fake=ggplot()+geom_bar(aes(x=1: 5, y=1: 5, fill=factor(1: 5)), stat="identity")+
scale_fill_discrete(name="使用单一图例", guide=guide_legend(ncol=2)) leg=ggpubr::get_legend(p1_fake)
# 第三步:把图例当成图表进行合并
grid.arrange(p1, p2, p3, leg, ncol=2)
当使用plot_grid时,我们同样可使用上述方法添加图例。我们以军费数据为例进行示范(图7-4-1)。
图7-4-1 使用单一图例
dat=read.csv("military expd.csv", row.names=1) # 课件中的文件
dat=dat[, c(4, 5, 9)] # 只选取伊朗、以色列和沙特阿拉伯的数据
# 整理数据
dat=round(dat/(10^6), 4) # 图表以百万美元为单位
dat=data.frame(dat, Year=as.numeric(rownames(dat)))
dat=melt(dat, id.vars="Year", measure.vars=c("Iran", "Israel","Saudi.Arabia"))
colnames(dat)=c("Year", "Country", "Value")
dat$Country=gsub("\\.", "\n", dat$Country)
# 计算增长率
dat=group_by(dat, Country)
increase_fun=function(x) c(NA, diff(x)/x[-length(x)]) # 注意:增长率的第一个数字应是缺失值
dat=mutate(dat, Increase=increase_fun(Value))
dat=as.data.frame(dat)
# 第一步:添加背景图片
img=image_read("jet.jpg") # 课件中的图片
bg=ggplot()+annotation_raster(img, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)+theme_void()
# 第二步:绘制不带图例的图表
p1=ggplot(dat)+geom_line(show.legend=FALSE, aes(Year, Value, color=Country), size=1.1)+
geom_point(show.legend=FALSE, aes(Year, Value, color=Country), size=2.2)+
scale_color_manual(values=c("darkred", "coral", "khaki1"))+
scale_x_continuous(breaks=dat$Year)+
labs(title="MIlitary Expenditure (million current $)")
p2=ggplot(dat)+geom_line(show.legend=FALSE, na.rm=TRUE, aes(Year, Increase, color=Country), size=1.1)+
geom_point(show.legend=FALSE, na.rm=TRUE, aes(Year, Increase,color=Country), size=2.2)+
scale_color_manual(values=c("darkred", "coral", "khaki1"))+
scale_x_continuous(limits=range(dat$Year), breaks=dat$Year)+
labs(title="Increase Ratio (%)")
same_theme=theme_minimal(base_size=13, base_family="serif")+
theme(
axis.text.x=element_text(angle=20),
axis.title=element_blank(),
panel.grid.minor=element_blank(),
panel.grid.major=element_line(color="#133150"),
plot.background=element_rect(fill=scales::alpha("white", 0.3), color=NA)
)
p1=p1+same_theme
p2=p2+same_theme
p=plot_grid(p1, p2, ncol=1, align="v")
# 第三步:生成带图例的图表并从中提取图例
leg=ggplot(dat)+
geom_line(na.rm=TRUE, aes(Year, Value, color=Country))+
scale_color_manual(values=c("darkred", "coral", "khaki1"), guide=guide_legend(override.aes=list(size=1.5)))+
theme_minimal(base_size=13, base_family="serif")+
theme(legend.background=element_rect(fill=scales::alpha("white", 0.5), color=NA))
leg=ggpubr::get_legend(leg)
# 第四步:合并。有时,为防止使用draw_plot添加的图表交叠,可以在它们占据的区域之间留出间隙
ggdraw()+draw_plot(bg)+draw_plot(p, x=0.025, y=0.025, width=0.7,height=0.95)+draw_grob(leg, x=0.8, width=0.2)
#==========
# 练习:使用patchwork包
#==========
# patchwork包提供了涉及合并图表的更多操作,以下示例对其功能进行了简单展示,感兴趣的读者可以进一步学习
# install.packages("patchwork")
library(patchwork)
dat=data.frame(x=1: 3, y=1: 3)
p=ggplot(dat, aes(x, y))
p1=p+geom_point()
p2=p+geom_point(shape=15)
p3=p+geom_bar(stat="identity")
# 斜线表示上下并置,竖线表示左右并置
(p1/p2)|p3
# 用plot_annotation为整个图表添加标题
((p1/p2)|p3)+plot_annotation(title="Title", subtitle="Subtitle", theme=theme(plot.title=element_text(color="blue"), plot. background=element_rect(fill="green")))
# 用加号把多个图表(而不是多个图层)连结起来,用plot_spacer生成空白图表
p1+plot_spacer()+p2+p3+plot_layout(nrow=2, ncol=3, byrow=TRUE, width=c(2, 1, 2), height=c(2, 1))
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。