前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >可视化绘制技巧|对多图合理排版布局

可视化绘制技巧|对多图合理排版布局

作者头像
DataCharm
发布2021-02-22 11:53:18
2.4K0
发布2021-02-22 11:53:18
举报

通常而言,在绘制图形的时候都是绘制某一种类型的一张图形,例如绘制一张散点图,绘制直方图。但有的时候我们希望同时展示多幅图形,可能是因为这些图形有某种联系,需要共同展示才能够更好的表达数据中蕴含的信息。之前介绍的边际图形就是这样的一个例子。本章节会介绍,当我们绘制了好了多幅图形之后,如何将多幅图形合并起来。

一、 合并多幅图形到一张图中

如果使用的是R的基础绘图形,则可以使用par和layout函数来将多幅图形放到一张图中。但是,如果是使用ggplot绘图系统,则要使用其他的方法来合并图形。包括:

  • gridExtra包中的grid.arrange()。
  • cowplot包中的plot_grid()。

cowplot包是由Claus O.Wilke开发的,它是ggplot2的一个扩展包,可以将多幅图形合并到同一张图形当中。cowplot包中有几个函数可以用来合并图形:

  • plot_grid():可以轻松地组合多个绘图。
  • ggdraw() + draw_plot() + draw_plot_label(): 将图形放置在具有特定大小的局部位置。

下面的代码首先绘制几幅图形,然后将图形合并到同一张图形之中,如图1所示。

代码语言:javascript
复制
require(ggplot2)
## Loading required package: ggplot2
# install.packages("gridExtra") 
# install.packages("cowplot")
library("gridExtra") 
library("cowplot")
## 
## ********************************************************
## Note: As of version 1.0.0, cowplot does not change the
##   default ggplot2 theme anymore. To recover the previous
##   behavior, execute:
##   theme_set(theme_cowplot())
## ********************************************************
# 使用的数据集是ToothGrowth 
ToothGrowth$dose <- as.factor(ToothGrowth$dose)
data("economics") #加载数据集

# 设置颜色
my3cols <- c("red", "black", "yellow")

require(cowplot)
p <- ggplot(ToothGrowth, aes(x = dose, y = len))
# 绘制图形
bxp <- p + geom_boxplot(aes(color = dose)) + scale_color_manual(values = my3cols)
 
# 绘制点图
dp <- p + geom_dotplot(aes(color = dose, fill = dose), binaxis='y',stackdir='center') +
scale_color_manual(values = my3cols) +
scale_fill_manual(values = my3cols) 
 
lp <- ggplot(economics, aes(x = date, y = psavert)) + geom_line(color = "#E46726")
 
plot_grid(bxp, dp, lp, labels = c("A", "B", "C"), ncol = 2, nrow = 2)
## `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

图1 合并多幅图形

上面的代码中,首先绘制了三幅图形,箱线图,点图和时间序列图。然后使用cowplot包中的plot_grid函数将三幅图形合并到一幅图当中。代码‘plot_grid(bxp, dp, lp, labels = c(“Box plot”, “Jitter plot”, “time series”), ncol = 2, nrow = 2)’表示的是将box,dp,lp这三幅图形合并,labels参数用于指定标签名称,nrow用于设定图形中子图的行数,ncol用于设置图中子图的列数。从图中可以看到,三幅图形被放到了同一幅图形中,图形包含两行两列,第四幅图形是空白的。

另外,使用ggdraw()函数、draw_plot()函数和draw_plot_label()函数的组合可用于将图形和标签放置在具有特定大小的特定位置。ggdraw():初始化一个空的绘图画布;draw_plot():在绘图画布上的某个位置放置一个绘图。draw_plot_label():在图的左上角添加一个plot标签。draw_plot()函数的格式如下:

代码语言:javascript
复制
draw_plot(plot, x = 0, y = 0, width = 1, height = 1)

参数含义如下:

  • plot:要放置的plot (ggplot2图形或gtable图形)。
  • x,y: 用于指定图形的位置。
  • width,height:图形的宽度和高度。

draw_plot_label()函数的格式如下:

代码语言:javascript
复制
draw_plot_label(label, x = 0, y = 1, size = 16, ...)

函数的参数含义是:

  • plot:要放置的plot (ggplot2图形或gtable图形)。
  • x,y::用于指定标签的位置。
  • size :要绘制的标签的字体大小。

需要注意的是,默认情况下,x,y位置的表示是 从0到1,点(0,0)位于画布的左下角。下面的代码使用这种方式将上文的图形合并成为同一幅图形,如图2所示。

代码语言:javascript
复制
ggdraw() +
draw_plot(bxp, x = 0, y = .5, width = .5, height = .5) + 
  draw_plot(dp, x = .5, y = .5, width = .5, height = .5) + 
  draw_plot(lp, x = 0, y = 0, width = 1, height = 0.5) + 
  draw_plot_label(label = c("Box plot", "Jitter plot", "Time series"),
x = c(0.1, 0.5, 0), y = c(1, 1, 0.5), size = 15)

图2 合并多幅图形

代码中,首先使用了ggdraw()函数添加了一张空白的画布。然后使用draw_plot函数添加了第一幅图形bxp,位置在(0,0.5),宽度为0.5,高度为0.5。

然后使用draw_plot函数添加了第二幅图形dp,位置在(0.5,0.5)宽度为0.5,高度为0.5。然后使用draw_plot函数绘制了第三幅图形,lp,位置是(0,0),宽度为1,长度高度为0.5.最后使用draw_plot_label函数为图形添加标签label参数用于指定标签的名称。代码x = c(0.1, 0.5, 0), y = c(1, 1, 0.5),指定了三个标签的位置。例如第一个标签的位置是(0,1),size参数调整的标签的大小。

另外,如果需要保存图形的话,可以使用ggsave()函数或者save_plot()函数。ggsave函数是ggplot2自带的函数。如果合并了图形,则最好使用save_plot()函数。下面的代码可以储存合并之后的图形。

代码语言:javascript
复制
p <- ggdraw() +
draw_plot(bxp, x = 0, y = .5, width = .5, height = .5) + 
  draw_plot(dp, x = .5, y = .5, width = .5, height = .5) + 
  draw_plot(lp, x = 0, y = 0, width = 1, height = 0.5) + 
  draw_plot_label(label = c("Box plot", "Jitter plot", "Time series"),
x = c(0.1, 0.5, 0), y = c(1, 1, 0.5), size = 15)
save_plot("plot2by2.pdf", plot2by2,
ncol = 2, # we're saving a grid plot of 2 columns
nrow = 2, # and 2 rows
# each individual subplot should have an aspect ratio of 1.3 base_aspect_ratio = 1.3
)

二、 gridExtra 包

使用gridExtra包同样可以将多幅图形合并起来。关键函数则是:grid.arrange()。下面的代码使用了grid.arrange函数来合并上文的三幅函数加上下面的代码新绘制的一幅直方图,如图3所示。

代码语言:javascript
复制
# 定义一组5种颜色
my5cols <- c("#6D9EC1", "#646567", "#A29B32", "#E46726", "#F3BF94")
# 绘制图形
data("diamonds")
brp <- ggplot(diamonds, aes(x = x)) +
geom_bar(aes(fill = cut)) + scale_fill_manual(values = my5cols)
require(gridExtra)
grid.arrange(bxp, dp, lp ,brp, ncol = 2, nrow =2)

图3 合并多幅图形

gridExtra包中有一个函数很好用,arangeGrop()函数。可以在图形中将图形分块。例如,如果希望首先将图形分成两块,在左边放一幅子图。然后在右边分两块,绘制两幅子图。则可以使用arangeGrop()函数轻松的实现,下面的代码在图形的左侧放置了一幅点图,在右侧放置了两幅图形,箱线图的直方图,如图4所示。

代码语言:javascript
复制
grid.arrange(dp, arrangeGrob(bxp, brp), ncol = 2)

图4 合并多幅图形

上面的代码在使用grid.arrange函数合并图形的时候,使用arrangeGrob函数首先将dp和brp这两幅图合并在一起,然后再和bxp图形合并在一起。

从图中可以看到,左边只有一幅图形,而右边有两幅图形。另外你,使用grid.arrange函数的layout_matrix参数同样可以进行这样的设置,如图5所示。

代码语言:javascript
复制
grid.arrange(brp, bxp, dp,lp, ncol = 2, nrow = 2, layout_matrix = rbind(c(1,1), c(2,3,4)))

图5 合并多幅图形

上面的代码将使用了grid.arrange函数合并四幅图形。参数ncol=2和nrow =2 表示将整个图形分成四个部分。代码

代码语言:javascript
复制
’layout_matrix = rbind(c(1,1,1), c(2,3,4)’

设置了这四个部分是如何显示图形的.这里表示将第一幅图设置为第一行,将第2,3,4幅图显示在第四行,如图所示,整个图形的上方显示了直方图,下方显示了三幅图形。

需要注意的layout_matrix本质上是要传入一个矩阵,用于描述每一行或者每一列绘制什么图形。

代码语言:javascript
复制
rbind(c(1,1,1), c(2,3,4))
##      [,1] [,2] [,3]
## [1,]    1    1    1
## [2,]    2    3    4

rbind函数本质上是创建了一个二行三列的矩阵矩阵,如果希望图形划分成为一个三行的图形。首先创建一个三行的矩阵。

代码语言:javascript
复制
cbind(c(1,1,1), c(2,3,4))
##      [,1] [,2]
## [1,]    1    2
## [2,]    1    3
## [3,]    1    4

上面的代码创建了一个三行的矩阵,矩阵的第一列都是1.然后传入layout_matrix参数,如图6所示。

代码语言:javascript
复制
grid.arrange(brp, bxp, dp,lp, ncol = 2, nrow = 2, layout_matrix = cbind(c(1,1,1), c(2,3,4)))

图6 合并多幅图形

从图中可以看到,图形的左方变成了直方图,这是因为矩阵的第一列都是1。右边由于三幅图形构成。

三、添加边缘分布图

在绘制散点图的时候,如果希望进一步了解单个变量的分布,可以在散点图中添加边际分布图。使用ggExtra包可以非常轻松的在图形中添加边缘分布图,可以添加的图形包括直方图,箱线图和密度图。

下面的代码首先绘制了一幅散点图,然后添加了边际图形,如图7所示。

代码语言:javascript
复制
library("ggExtra") # 加载包
# 创建数据集
set.seed(1234)
x <- c(rnorm(350, mean = -1), rnorm(350, mean = 1.5),
rnorm(350, mean = 4))
y <- c(rnorm(350, mean = -0.5), rnorm(350, mean = 1.7), rnorm(350, mean = 2.5))

group <- as.factor(rep(c(1, 2, 3), each = 350))
df2 <- data.frame(x, y, group)
scatterPlot <- ggplot(df2, aes(x, y)) +geom_point(aes(color = group)) + scale_color_manual(values = my3cols) +theme(legend.position=c(0,1), legend.justification=c(0,1))
# 添加边际分布图
ggMarginal(scatterPlot)

# 添加边际分布
ggMarginal(scatterPlot, type = "histogram", fill = "#6D9EC1", color = "#BFD5E3")

图7 添加边际图形

上面的代码中使用了ggMarginal函数为散点图添加编辑图形。默认添加的是密度曲线。代码’ggMarginal(scatterPlot)’表示为图形添加密度曲线。代码

代码语言:javascript
复制
’ggMarginal(scatterPlot, type = “histogram”, fill = “#6D9EC1”, color = “#BFD5E3”)’

表示为图形添加边际分布,分别调用多个ggMarginal函数的时候,图形是会叠加的。从图中可以看到,散点图同时添加了密度曲线和直方图。

四、 在ggplot中插入一个外部图形元素

使用annotation_custom()函数,可以在图中添加表,图和其他的元素。函数的格式如下:

代码语言:javascript
复制
annotation_custom(grob, xmin, xmax, ymin, ymax)
  • grob:要显示的外部图形元素。
  • xmin, xmax:数据坐标中的x位置(水平位置)。
  • ymin, ymax:数据坐标中的y位置(垂直位置)。

通过下面的步骤可以在一幅散点图中添加图形元素:

  • 首先创建一幅散点图。
  • 在散点图中添加一个关于x轴的箱线图。

使用annotation_custom()函数函数添加图形元素,由于添加一个箱线图会与原来的图形有一些点重叠,因此可以调整图形的透明度。如下图8所示。

代码语言:javascript
复制
require(hrbrthemes)
## Loading required package: hrbrthemes
## NOTE: Either Arial Narrow or Roboto Condensed fonts are required to use these themes.
##       Please use hrbrthemes::import_roboto_condensed() to install Roboto Condensed and
##       if Arial Narrow is not on your system, please see http://bit.ly/arialnarrow
p1 <- scatterPlot # 散点图
# 绘制箱线图
p2 <- ggplot(df2, aes(factor(1), x))+ geom_boxplot(width=0.3,color = 'black')+coord_flip()+ theme_ipsum()
# 箱线图
p3 <- ggplot(df2, aes(factor(1), y))+ geom_boxplot(width=0.3,color = 'red')+ theme_ipsum()
# 创建图形元素
p2_grob = ggplotGrob(p2)
p3_grob = ggplotGrob(p3)

 # 合并图形
p1 + annotation_custom(grob = p2_grob, xmin = 0, xmax =7,ymin = -4, ymax = 0)

图8 添加图形元素

上面的代码首先使用散点图中x轴对应的数据创建了一幅箱线图,然后使用y轴对应的变量绘制了一幅箱线图。然后将图形使用ggplotGrob函数转换成为一个图形元素(grob对象)。最后使用annotation_custom函数添加创建好的图形元素。代码

代码语言:javascript
复制
’p1 + annotation_custom(grob = p2_grob, xmin = 0, xmax = 5,ymin = -2, ymax = 0)’

表示将p2_grob这个图形元素添加到p1中。通过xmin,xmax,ymin和ymax这几个参数调整了图形元素的位置。从图中可以看到,添加的箱线图被放在图形的右下方,如图9所示。

代码语言:javascript
复制
# 在散点图中插入p3_grob
p1 + annotation_custom(grob = p3_grob,
xmin = -6, xmax = -2,ymin = -3, ymax =2)

图9 添加图形元素

从图可以看到,箱线图被添加到了图形的左下角的位置。使用这种方式可以以任意的方式合并图形。在这种情况下,需要注意的是,图形之间可能存在覆盖的显现,这种情形是需要避免的。

在本章节中,介绍了合并多幅图形的内容,本章节的内容是数据可视化过程中非常重要的一个步骤,将多幅图形合并成一幅图形也是比较多幅的一个重要的方法。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DataCharm 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、 合并多幅图形到一张图中
  • 二、 gridExtra 包
  • 三、添加边缘分布图
  • 四、 在ggplot中插入一个外部图形元素
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档