一点碎碎念:今天开始看第三章Toolbox, 主要讲的是图层的用法,在图像的基础上,图层可以让plot的信息更加丰富和完整,于是就有了怎样加标签,加注释等等。这些内容虽然不难但是很琐碎,由于R基础薄弱,有些代码理解起来需要时间。所以,在这里我想先以读书笔记和翻译的形式,记录为主,尽量去逐字逐句理解。除了添加注释、标签等之外,使用图层还可以完成箱线图、多边形等等多种群组几何对象类型的图,还可以绘制曲面图等。下面是第三章的主要内容:
使用图层的三个主要目的:
展示数据:绘制原始数据时唯一的一层(数据层)
展示数据的统计摘要:在数据背景下展示模型的统计预测效果,模型层通常绘制在数据层之上
添加额外的元数据(metadata)、上下文信息和注释:也称背景层,了解数据的背景信息或强调数据中的某些特征,一般在最后绘制。
1. 基本图形类型
几何对象是ggplot2的基本组成部分,可以独立构建图形。他们都是二维的,主要函数有 geom_area()
, geom_bar()
, geom_line
, geom_point()
, geom_polygon()
, geom_tile()
等等。这些函数包括x,y两个主要属性,另外也可以接受 color
和 size
两个图形属性,他们构成了基本的数据层。
我们可以通过使用 +
来添加图层。
df <- data.frame(
x = c(3, 1, 5),
y = c(2, 4, 6),
label = c("a","b","c")
)
df
p <- ggplot(df, aes(x, y, label = label)) +
labs(x = NULL, y = NULL) + # Hide axis label
theme(plot.title = element_text(size = 12)) # Shrink plot title
p + geom_point() + ggtitle("point")
p + geom_text() + ggtitle("text")
p + geom_bar(stat = "identity") + ggtitle("bar")
p + geom_tile() + ggtitle("raster")
p + geom_line() + ggtitle("line")
p + geom_area() + ggtitle("area")
p + geom_path() + ggtitle("path")
p + geom_polygon() + ggtitle("polygon")
以上命令运行后可依次生成散点图、含标签的散点图、条形图、色深图、线条图、面积图、路径图和多边形图等八个图,其中 ggtitle()
是给各个图片添加注释/命名
2. 添加标签(label)
主要函数 geom_text()
:和散点类似,就是将point换成了文字。它包括以下几种参数:
size
:设置字体大小angle
:设置倾斜角度family
:可设置字体,下面代码中的"sans"
,"serif"
,"mono"
代表三种字体,"sans"
是默认字体。
df <- data.frame(x = 1, y = 3:1, family = c("sans", "serif", "mono"))
ggplot(df, aes(x, y)) +
geom_text(aes(label = family, family = family))
此外还有两个字体安装包
– showtext, https://github.com/yixuan/showtext, by Yixuan Qiu, makes GD-independent plots by rendering all text as polygons.
– extrafont, https://github.com/wch/extrafont, by Winston Chang, converts fonts to a standard format that all devices can use.
fontface
:可设置粗体或斜体,“plain”
默认普通值,“bold”
粗体、“italic”
斜体。
df <- data.frame(x = 1, y = 3:1, face = c("plain", "bold", "italic"))
ggplot(df, aes(x, y)) +
geom_text(aes(label = face, fontface = face))
vjust
和hjust
可以设置字体对齐方式。vjust
(“bottom”, “middle”, “top”, “inward”, “outward”);hjust
(“left”, “center”, “right”, “inward”, “outward”)。最常用的路线之一是“inward”
:它将文本对齐到主画面的中间:
df <- data.frame(
x = c(1, 1, 2, 2, 1.5),
y = c(1, 2, 1, 2, 1.5),
text = c(
"bottom-left", "bottom-right",
"top-left", "top-right", "center"
)
)
ggplot(df, aes(x, y)) +
geom_text(aes(label = text)) # 字母不能全部在画面中
ggplot(df, aes(x, y)) +
geom_text(aes(label = text), vjust = "inward", hjust = "inward") # 字母全部在画面中
nudge()
参数可以设置文字距原坐标点的距离,在散点和文字同时存在时很有必要,这是文字是一个注释的作用,如果不添加该参数,点和文字就会重合。
df <- data.frame(trt = c("a", "b", "c"), resp = c(1.2, 3.4, 2.5))
ggplot(df, aes(resp, trt)) +
geom_point() +
geom_text(aes(label = paste0("(", resp, ")")), nudge_y = -0.25) + # y轴负方向下移0.25
xlim(1, 3.6) # 设定x轴取值区间
check_overlap
:查找重复值。当注释中有大量重复时,设置check_overlap=TRUE
可以自动删除重复标签。
以耗油量数据为例:
library(ggplot2)
mpg
ggplot(mpg, aes(displ, hwy)) +
geom_text(aes(label = model)) +
xlim(1, 8)
ggplot(mpg, aes(displ, hwy)) +
geom_text(aes(label = model), check_overlap = TRUE) +
xlim(1, 8)
另外,与 geom_text()
类似的是 geom_label()
,它与geom_text的区别自动在文字后方绘制一个圆角矩形标签,当需要在复杂的背景上标注文字时可以使用。
label <- data.frame(
waiting = c(55, 80),
eruptions = c(2, 4.3),
label = c("peak one", "peak two")
)
ggplot(faithfuld, aes(waiting, eruptions)) +
geom_tile(aes(fill = density)) +
geom_label(data = label, aes(label = label))
学会了在图中添加标签,可以替代图例
3. 注释(Annotations)
注释可以在你的图上添加一些额外的元数据,可以使用以下函数:
geom_text()
:在指定点添加标签(见上文)geom_rect()
:可强调图形中感兴趣的矩形区域。包括xmin
,xmax
,ymin
,ymax
geom_line()
;geom_path()
;geom_segment()
:在图形中添加线条;arrow()
可以用来添加箭头geom_vline()
;geom_hline()
:向图形添加垂直线或水平线geom_abline()
:向图形添加任意斜率和截距地直线
然后我们用“失业率数据集”来举例:
ggplot(economics, aes(date, unemploy)) +
geom_line()
下面我们想在图中展现一下不同政党执政时期失业率的高低情况:
presidential <- subset(presidential, start > economics$date[1]) ## 设置数据集,economics$date[1]是指定了数据集中data一列的第一行数据
ggplot(economics) +
geom_rect(
aes(xmin = start, xmax = end, fill = party),
ymin = -Inf, ymax = Inf, alpha = 0.2,
data = presidential
) +
geom_vline(
aes(xintercept = as.numeric(start)),
data = presidential,
colour = "grey50", alpha = 0.5
) +
geom_text(
aes(x = start, y = 2500, label = name),data = presidential,
size = 3, vjust = 0, hjust = 0, nudge_x = 50
) +
geom_line(aes(date, unemploy)) + ## 数据集中的两列数据来源
scale_fill_manual(values = c("blue", "red")) ## scale是标度函数
(疑问: party
这个对象的数据不知道从哪里来的)
生成图片:
如果我们想使用同样的方法在图片中添加一个单独的注释,方法有点复杂,因为首先要创建一个数据框:
library(ggplot2)
economics
yrng <- range(economics$unemploy)
xrng <- range(economics$date) ## range 是取提取范围的子集,最大值和最小值
caption <- paste(strwrap("Unemployment rates in the US have
+ varied a lot over the years", 40), collapse = "\n") ## 设置题目内容
ggplot(economics, aes(date, unemploy)) +
geom_line() +
geom_text(
aes(x, y, label = caption),
data = data.frame(x = xrng[1], y = yrng[2], caption = caption),
hjust = 0, vjust = 1, size = 4
)
上述代码可以用 annotate()
来简化 geom_text()
部分:
ggplot(economics, aes(date, unemploy)) +
geom_line() +
annotate("text", x = xrng[1], y = yrng[2], label = caption,
hjust = 0, vjust = 1, size = 4)
生成图片:
注释,在分面状态下的组间比较的时也非常有用。下面要做一组关于钻石质量(carat)和价格(price)比较的2d热图,按照切割品质(cut)进行分面:
ggplot(diamonds, aes(log10(carat), log10(price))) +
geom_bin2d() +
facet_wrap(~cut, nrow = 1)
4. 群组几何对象(Collective Geoms)
在ggplot2中,几何对象大致可以分为个体(individual)几何对象和群组(collective)两种类型。群组几何对象可以多角度的展现数据结果。
group
(分组)这种图形属性可以用来设置:哪些观测值控制哪种图形元素
举例:纵向数据集Oxboys(nlme包)记录了26个男生(subject)在9个不同时期(occasion)中测定的身高(height)和中心化年龄(age)。
data(Oxboys, package = "nlme")
> head(Oxboys)
#> Subject age height Occasion ## 以下是输出结果
#> 1 1 -1.0000 140 1
#> 2 1 -0.7479 143 2
#> 3 1 -0.4630 145 3
#> 4 1 -0.1643 147 4
#> 5 1 -0.0027 148 5
#> 6 1 0.2466 150 6
多个分组+单个图形属性
当我们想从总体上查看数据,将数据中的每个个体区分开,然后用同样的方式映射。这在含有多个个体的纵向数据中很常见,叫“细面图”(spaghetti plot)。
例如,我们想在整体上观察26个男生的成长轨迹(并不区分哪条线是那个男生),就可以在映射 aes()
中添加参数 group=Subject
:
ggplot(Oxboys, aes(age, height, group = Subject)) +
geom_point() +
geom_line()
如果不加 group
这个参数,我们只会得到一条将所有点连起来的奇怪的折线,这就毫无疑义了
在不同图层进行分组
如果我们想要将不同水平下的数据加以整合得到一个汇总信息,这时,基本的数据图层上是每个个体的数据,我们可以在第二个数据层上展示整体组群的信息。
例如在上面的例子中,我们想根据所有男孩的年龄和身高在图中添加一个平滑线条,如果按照上面的方式,在第一层函数中直接添加 group=Subject
就会给每个男孩的线条上加一个平滑曲线,这不能得到我们想要的结果:
ggplot(Oxboys, aes(age, height, group = Subject)) +
geom_line() +
geom_smooth(method = "lm", se = FALSE)
这时我们应该把分组参数放到另一个图层中,正确的代码如下:
ggplot(Oxboys, aes(age, height)) +
geom_line(aes(group = Subject)) +
geom_smooth(method = "lm", size = 2, se = FALSE)
修改默认分组
在这里首先补充说明一下变量的分类:变量按其数值表现是否连续,分为连续变量和离散变量。
离散变量:指变量值可以按一定顺序一一列举,通常以整数位取值的变量。如职工人数、工厂数、机器台数等。
连续变量:在一定区间内可以任意取值的变量叫连续变量,其数值是连续不断的,相邻两个数值可作无限分割,即可取无限个数值。
当离散变量存在时,一般就会将其认为是默认分组变量。
如果图像中含有离散型变量,而你却想绘制连接所有分组的线条。这时就要修改默认分组。或者在新图层中设定一个新的分组,就能将二者结合起来。
在上个例子中,绘制各个时期(Occasion)和身高(height)的箱线图,离散型变量Occasion默认为分组变量:
ggplot(Oxboys, aes(Occasion, height)) +
geom_boxplot()
然后要在此基础上添加个体轨迹,这时只添加 geom line()
函数不能达到预期效果,因为它还会默认Occasion为分组变量,这时应该将 aes(group=Subject)
添加在 geom line()
函数中,另外添加颜色属性 colour
将第二个图层区分开:
ggplot(Oxboys, aes(Occasion, height)) +
geom_boxplot() +
geom_line(aes(group = Subject), colour = "#3366FF", alpha = 0.5)
匹配图形属性和图形对象
如何将个体的图形属性映射给整体图形属性。
线段和路径类
例如建立一个数据框,包括三个数据点,两条连接三点的线段。数据点比线段条数多一,线段的图形属性是由起始点的图形属性决定的,所以第一条线段使用第一个数据点的图形属性,第二条线段使用第二个数据点的图形属性,而第三个点的图形属性将不会被用到。下面代码生成图片的颜色是随着数据点,呈现离散状态。
library(ggplot2)
df <- data.frame(x = 1:3, y = 1:3, colourname = c(1,3,5))
ggplot(df, aes(x, y, colour = factor(colourname))) +
geom_line(aes(group = 1), size = 2) + ## group = 1 默认分组设置
geom_point(size = 5)
下面修改可以将颜色属性设置为渐变状态,但是数据点还是突出的:
ggplot(df, aes(x, y, colour = colourname)) +
geom_line(aes(group = 1), size = 2) +
geom_point(size = 5)
在复杂一些,利用“线性插值法”可以将线段平稳地在图形属性间变化:
啥是“线性插值法”:已知坐标 (x0, y0) 与 (x1, y1),要得到 [x0, x1] 区间内某一位置 x 在直线上的值。
library(ggplot2)
df <- data.frame(x = 1:3, y = 1:3, colour = c(1,3,5))
xgrid <- with(df, seq(min(x), max(x), length = 50)) ## seq()是生成一组数字
interp <- data.frame(
x = xgrid,
y = approx(df$x, df$y, xout = xgrid)$y, ##approx()是排序
colour = approx(df$x, df$colour, xout = xgrid)$y
)
ggplot(interp, aes(x, y, colour = colour)) +
geom_line(size = 2) +
geom_point(data = df, size = 5)
多边形等
对于多边形这类几何图像,当所有个体的图形属性都相同时,可以使用 fill()
参数。
当图形映射对象是离散型对象时,默认将群组几何对象分解成更小的部分。
如下例,耗油量数据集(mpg)中,用柱状图表示不同类别的汽车数量:
library(ggplot2)
mpg
ggplot(mpg, aes(class)) +
geom_bar()
进一步,通过 fill()
参数,用不同颜色表示drv(动力传动系统:前轮f,后轮r,四轮4),填充每个class:
library(ggplot2)
mpg
ggplot(mpg, aes(class, fill = drv)) +
geom_bar()
drv是离散型变量,所以可以用不同的颜色区分
如果根据连续型变量hwy(高速公路行驶记录每加仑行驶的英里数)填充class,如果不添加分组信息,则不会有不同颜色填充。
ggplot(mpg, aes(class, fill = hwy)) +
geom_bar()
如果在 fill()
后面添加 group()
参数,设置按 hwy
分组:
ggplot(mpg, aes(class, fill = hwy, group = hwy)) +
geom_bar()
就可以形成按照hwy数量大小,渐变填充的状态。
5. 曲面图(Surface Plots)
ggplot2包不能绘制3D曲面图像,但是可绘制能表示3D图的2D图像,比如等高线图、着色瓦片图、气泡图等
geom_contour()
等高线图:
library(ggplot2)
faithfuld
# A tibble: 5,625 x 3
eruptions waiting density
<dbl> <dbl> <dbl>
1 1.60 43.0 0.00322
2 1.65 43.0 0.00384
3 1.69 43.0 0.00444
4 1.74 43.0 0.00498
5 1.79 43.0 0.00542
6 1.84 43.0 0.00574
7 1.88 43.0 0.00592
8 1.93 43.0 0.00594
9 1.98 43.0 0.00581
10 2.03 43.0 0.00554
# ... with 5,615 more rows
ggplot(faithfuld, aes(eruptions, waiting)) +
geom_contour(aes(z = density, colour = ..level..))
geom_raster()
着色瓦片图:
ggplot(faithfuld, aes(eruptions, waiting)) +
geom_raster(aes(fill = density))
气泡图:
library(ggplot2)
faithfuld
# Bubble plots work better with fewer observations
small <- faithfuld[seq(1, nrow(faithfuld), by = 10), ]
ggplot(small, aes(eruptions, waiting)) +
geom_point(aes(size = density), alpha = 1/3) +
scale_size_area()
参考资料:
Hadley Wickham(2016). ggplot2. Springer International Publishing. doi: 10.1007/978-3-319-24277-4
《R语言应用系列丛书·ggplot2:数据分析与图形艺术》
猜你喜欢
写在后面
为鼓励读者交流、快速解决科研困难,我们建立了“宏基因组”专业讨论群,目前己有国内外150+ PI,1300+ 一线科研人员加入。参与讨论,获得专业解答,欢迎分享此文至朋友圈,并扫码加主编好友带你入群,务必备注“姓名-单位-研究方向-职称/年级”。技术问题寻求帮助,首先阅读《如何优雅的提问》学习解决问题思路,仍末解决群内讨论,问题不私聊,帮助同行。
学习16S扩增子、宏基因组科研思路和分析实战,关注“宏基因组”