查看原文
其他

圈圈 2018-06-01

一点碎碎念:今天开始看第三章Toolbox, 主要讲的是图层的用法,在图像的基础上,图层可以让plot的信息更加丰富和完整,于是就有了怎样加标签,加注释等等。这些内容虽然不难但是很琐碎,由于R基础薄弱,有些代码理解起来需要时间。所以,在这里我想先以读书笔记和翻译的形式,记录为主,尽量去逐字逐句理解。除了添加注释、标签等之外,使用图层还可以完成箱线图、多边形等等多种群组几何对象类型的图,还可以绘制曲面图等。下面是第三章的主要内容:

使用图层的三个主要目的:

  1. 展示数据:绘制原始数据时唯一的一层(数据层)

  2. 展示数据的统计摘要:在数据背景下展示模型的统计预测效果,模型层通常绘制在数据层之上

  3. 添加额外的元数据(metadata)、上下文信息和注释:也称背景层,了解数据的背景信息或强调数据中的某些特征,一般在最后绘制。

1. 基本图形类型

几何对象是ggplot2的基本组成部分,可以独立构建图形。他们都是二维的,主要函数有 geom_area()geom_bar()geom_linegeom_point()geom_polygon()geom_tile()等等。这些函数包括x,y两个主要属性,另外也可以接受 colorsize两个图形属性,他们构成了基本的数据层。

我们可以通过使用 +添加图层

  1. df <- data.frame(

  2.  x = c(3, 1, 5),

  3.  y = c(2, 4, 6),

  4.  label = c("a","b","c")

  5. )

  6. df

  7. p <- ggplot(df, aes(x, y, label = label)) +

  8.  labs(x = NULL, y = NULL) + # Hide axis label

  9.  theme(plot.title = element_text(size = 12)) # Shrink plot title

  10. p + geom_point() + ggtitle("point")

  11. p + geom_text() + ggtitle("text")

  12. p + geom_bar(stat = "identity") + ggtitle("bar")

  13. p + geom_tile() + ggtitle("raster")

  14. p + geom_line() + ggtitle("line")

  15. p + geom_area() + ggtitle("area")

  16. p + geom_path() + ggtitle("path")

  17. p + geom_polygon() + ggtitle("polygon")

以上命令运行后可依次生成散点图、含标签的散点图、条形图、色深图、线条图、面积图、路径图和多边形图等八个图,其中 ggtitle()是给各个图片添加注释/命名


2. 添加标签(label)

主要函数 geom_text():和散点类似,就是将point换成了文字。它包括以下几种参数:

  • size:设置字体大小


  • angle:设置倾斜角度


  • family:可设置字体,下面代码中的 "sans", "serif", "mono"代表三种字体, "sans"是默认字体。


  1. df <- data.frame(x = 1, y = 3:1, family = c("sans", "serif", "mono"))

  2. ggplot(df, aes(x, y)) +

  3.  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”斜体。

  1. df <- data.frame(x = 1, y = 3:1, face = c("plain", "bold", "italic"))

  2. ggplot(df, aes(x, y)) +

  3.  geom_text(aes(label = face, fontface = face))

  • vjust 和 hjust 可以设置字体对齐方式。 vjust (“bottom”, “middle”, “top”, “inward”, “outward”); hjust (“left”, “center”, “right”, “inward”, “outward”)。最常用的路线之一是 “inward”:它将文本对齐到主画面的中间:

  1. df <- data.frame(

  2.  x = c(1, 1, 2, 2, 1.5),

  3.  y = c(1, 2, 1, 2, 1.5),

  4.  text = c(

  5.    "bottom-left", "bottom-right",

  6.    "top-left", "top-right", "center"

  7.  )

  8. )

  9. ggplot(df, aes(x, y)) +

  10.  geom_text(aes(label = text))  # 字母不能全部在画面中

  11. ggplot(df, aes(x, y)) +

  12.  geom_text(aes(label = text), vjust = "inward", hjust = "inward")  # 字母全部在画面中

  • nudge()参数可以设置文字距原坐标点的距离,在散点和文字同时存在时很有必要,这是文字是一个注释的作用,如果不添加该参数,点和文字就会重合。

  1. df <- data.frame(trt = c("a", "b", "c"), resp = c(1.2, 3.4, 2.5))

  2. ggplot(df, aes(resp, trt)) +

  3.  geom_point() +

  4.  geom_text(aes(label = paste0("(", resp, ")")), nudge_y = -0.25) +         # y轴负方向下移0.25

  5.  xlim(1, 3.6)               # 设定x轴取值区间

  • check_overlap:查找重复值。当注释中有大量重复时,设置 check_overlap=TRUE可以自动删除重复标签。

以耗油量数据为例:

  1. library(ggplot2)

  2. mpg

  3. ggplot(mpg, aes(displ, hwy)) +

  4.  geom_text(aes(label = model)) +

  5.  xlim(1, 8)

  6. ggplot(mpg, aes(displ, hwy)) +

  7.  geom_text(aes(label = model), check_overlap = TRUE) +

  8.  xlim(1, 8)

另外,与 geom_text() 类似的是 geom_label(),它与geom_text的区别自动在文字后方绘制一个圆角矩形标签,当需要在复杂的背景上标注文字时可以使用。

  1. label <- data.frame(

  2.  waiting = c(55, 80),

  3.  eruptions = c(2, 4.3),

  4.  label = c("peak one", "peak two")

  5. )

  6. ggplot(faithfuld, aes(waiting, eruptions)) +

  7.  geom_tile(aes(fill = density)) +

  8.  geom_label(data = label, aes(label = label))

学会了在图中添加标签,可以替代图例


3. 注释(Annotations)

注释可以在你的图上添加一些额外的元数据,可以使用以下函数:

  • geom_text():在指定点添加标签(见上文)

  • geom_rect():可强调图形中感兴趣的矩形区域。包括 xminxmaxyminymax

  • geom_line()geom_path()geom_segment():在图形中添加线条; arrow()可以用来添加箭头

  • geom_vline()geom_hline():向图形添加垂直线或水平线

  • geom_abline():向图形添加任意斜率和截距地直线

然后我们用“失业率数据集”来举例:

  1. ggplot(economics, aes(date, unemploy)) +

  2. geom_line()

下面我们想在图中展现一下不同政党执政时期失业率的高低情况:

  1. presidential <- subset(presidential, start > economics$date[1])          ## 设置数据集,economics$date[1]是指定了数据集中data一列的第一行数据

  2. ggplot(economics) +

  3.  geom_rect(

  4.    aes(xmin = start, xmax = end, fill = party),

  5.    ymin = -Inf, ymax = Inf, alpha = 0.2,

  6.    data = presidential

  7.  ) +

  8.  geom_vline(

  9.    aes(xintercept = as.numeric(start)),

  10.    data = presidential,

  11.    colour = "grey50", alpha = 0.5

  12.  ) +

  13.  geom_text(

  14.    aes(x = start, y = 2500, label = name),data = presidential,

  15.    size = 3, vjust = 0, hjust = 0, nudge_x = 50

  16.  ) +

  17.  geom_line(aes(date, unemploy)) +                ## 数据集中的两列数据来源

  18.  scale_fill_manual(values = c("blue", "red"))    ## scale是标度函数

(疑问: party这个对象的数据不知道从哪里来的)

生成图片:

如果我们想使用同样的方法在图片中添加一个单独的注释,方法有点复杂,因为首先要创建一个数据框:

  1. library(ggplot2)

  2. economics

  3. yrng <- range(economics$unemploy)

  4. xrng <- range(economics$date)   ## range 是取提取范围的子集,最大值和最小值

  5. caption <- paste(strwrap("Unemployment rates in the US have

  6. +  varied a lot over the years", 40), collapse = "\n")      ## 设置题目内容

  7. ggplot(economics, aes(date, unemploy)) +

  8. geom_line() +

  9. geom_text(

  10. aes(x, y, label = caption),

  11. data = data.frame(x = xrng[1], y = yrng[2], caption = caption),                

  12. hjust = 0, vjust = 1, size = 4

  13. )

上述代码可以用 annotate()来简化 geom_text()部分:

  1. ggplot(economics, aes(date, unemploy)) +

  2. geom_line() +

  3. annotate("text", x = xrng[1], y = yrng[2], label = caption,

  4. hjust = 0, vjust = 1, size = 4)

生成图片:

注释,在分面状态下的组间比较的时也非常有用。下面要做一组关于钻石质量(carat)和价格(price)比较的2d热图,按照切割品质(cut)进行分面:

  1. ggplot(diamonds, aes(log10(carat), log10(price))) +

  2.  geom_bin2d() +

  3.  facet_wrap(~cut, nrow = 1)

4. 群组几何对象(Collective Geoms)

在ggplot2中,几何对象大致可以分为个体(individual)几何对象和群组(collective)两种类型。群组几何对象可以多角度的展现数据结果。

group(分组)这种图形属性可以用来设置:哪些观测值控制哪种图形元素

举例:纵向数据集Oxboys(nlme包)记录了26个男生(subject)在9个不同时期(occasion)中测定的身高(height)和中心化年龄(age)。

  1. data(Oxboys, package = "nlme")

  2. > head(Oxboys)

  3. #>  Subject   age  height Occasion    ## 以下是输出结果

  4. #> 1  1    -1.0000  140    1

  5. #> 2  1    -0.7479  143    2

  6. #> 3  1    -0.4630  145    3

  7. #> 4  1    -0.1643  147    4

  8. #> 5  1    -0.0027  148    5

  9. #> 6  1     0.2466  150    6

多个分组+单个图形属性

当我们想从总体上查看数据,将数据中的每个个体区分开,然后用同样的方式映射。这在含有多个个体的纵向数据中很常见,叫“细面图”(spaghetti plot)。

例如,我们想在整体上观察26个男生的成长轨迹(并不区分哪条线是那个男生),就可以在映射 aes()中添加参数 group=Subject

  1. ggplot(Oxboys, aes(age, height, group = Subject)) +

  2.  geom_point() +

  3.  geom_line()

如果不加 group这个参数,我们只会得到一条将所有点连起来的奇怪的折线,这就毫无疑义了

在不同图层进行分组

如果我们想要将不同水平下的数据加以整合得到一个汇总信息,这时,基本的数据图层上是每个个体的数据,我们可以在第二个数据层上展示整体组群的信息。

例如在上面的例子中,我们想根据所有男孩的年龄和身高在图中添加一个平滑线条,如果按照上面的方式,在第一层函数中直接添加 group=Subject就会给每个男孩的线条上加一个平滑曲线,这不能得到我们想要的结果:

  1. ggplot(Oxboys, aes(age, height, group = Subject)) +

  2. geom_line() +

  3. geom_smooth(method = "lm", se = FALSE)

这时我们应该把分组参数放到另一个图层中,正确的代码如下:

  1. ggplot(Oxboys, aes(age, height)) +

  2. geom_line(aes(group = Subject)) +

  3. geom_smooth(method = "lm", size = 2, se = FALSE)

修改默认分组

在这里首先补充说明一下变量的分类:变量按其数值表现是否连续,分为连续变量和离散变量。

离散变量:指变量值可以按一定顺序一一列举,通常以整数位取值的变量。如职工人数、工厂数、机器台数等。

连续变量:在一定区间内可以任意取值的变量叫连续变量,其数值是连续不断的,相邻两个数值可作无限分割,即可取无限个数值

当离散变量存在时,一般就会将其认为是默认分组变量。

如果图像中含有离散型变量,而你却想绘制连接所有分组的线条。这时就要修改默认分组。或者在新图层中设定一个新的分组,就能将二者结合起来。

在上个例子中,绘制各个时期(Occasion)和身高(height)的箱线图,离散型变量Occasion默认为分组变量:

  1. ggplot(Oxboys, aes(Occasion, height)) +

  2.  geom_boxplot()

然后要在此基础上添加个体轨迹,这时只添加 geom line()函数不能达到预期效果,因为它还会默认Occasion为分组变量,这时应该将 aes(group=Subject)添加在 geom line()函数中,另外添加颜色属性 colour将第二个图层区分开:

  1. ggplot(Oxboys, aes(Occasion, height)) +

  2. geom_boxplot() +

  3. geom_line(aes(group = Subject), colour = "#3366FF", alpha = 0.5)

匹配图形属性和图形对象

如何将个体的图形属性映射给整体图形属性。

  • 线段和路径类

例如建立一个数据框,包括三个数据点,两条连接三点的线段。数据点比线段条数多一,线段的图形属性是由起始点的图形属性决定的,所以第一条线段使用第一个数据点的图形属性,第二条线段使用第二个数据点的图形属性,而第三个点的图形属性将不会被用到。下面代码生成图片的颜色是随着数据点,呈现离散状态。

  1. library(ggplot2)

  2. df <- data.frame(x = 1:3, y = 1:3, colourname = c(1,3,5))

  3. ggplot(df, aes(x, y, colour = factor(colourname))) +

  4.  geom_line(aes(group = 1), size = 2) +    ## group = 1 默认分组设置

  5.  geom_point(size = 5)

下面修改可以将颜色属性设置为渐变状态,但是数据点还是突出的:

  1. ggplot(df, aes(x, y, colour = colourname)) +

  2.  geom_line(aes(group = 1), size = 2) +

  3.  geom_point(size = 5)

在复杂一些,利用“线性插值法”可以将线段平稳地在图形属性间变化:

啥是“线性插值法”:已知坐标 (x0, y0) 与 (x1, y1),要得到 [x0, x1] 区间内某一位置 x 在直线上的值。

  1. library(ggplot2)

  2. df <- data.frame(x = 1:3, y = 1:3, colour = c(1,3,5))

  3. xgrid <- with(df, seq(min(x), max(x), length = 50))   ## seq()是生成一组数字

  4. interp <- data.frame(

  5.  x = xgrid,

  6.  y = approx(df$x, df$y, xout = xgrid)$y,   ##approx()是排序

  7.  colour = approx(df$x, df$colour, xout = xgrid)$y

  8. )

  9. ggplot(interp, aes(x, y, colour = colour)) +

  10.  geom_line(size = 2) +

  11.  geom_point(data = df, size = 5)

  • 多边形等

对于多边形这类几何图像,当所有个体的图形属性都相同时,可以使用 fill()参数。

当图形映射对象是离散型对象时,默认将群组几何对象分解成更小的部分。

如下例,耗油量数据集(mpg)中,用柱状图表示不同类别的汽车数量:

  1. library(ggplot2)

  2. mpg

  3. ggplot(mpg, aes(class)) +

  4.  geom_bar()

进一步,通过 fill()参数,用不同颜色表示drv(动力传动系统:前轮f,后轮r,四轮4),填充每个class:

  1. library(ggplot2)

  2. mpg

  3. ggplot(mpg, aes(class, fill = drv)) +

  4.  geom_bar()

drv是离散型变量,所以可以用不同的颜色区分

如果根据连续型变量hwy(高速公路行驶记录每加仑行驶的英里数)填充class,如果不添加分组信息,则不会有不同颜色填充。

  1. ggplot(mpg, aes(class, fill = hwy)) +

  2. geom_bar()

如果在 fill()后面添加 group()参数,设置按 hwy分组:

  1. ggplot(mpg, aes(class, fill = hwy, group = hwy)) +

  2. geom_bar()

就可以形成按照hwy数量大小,渐变填充的状态。

5. 曲面图(Surface Plots)

ggplot2包不能绘制3D曲面图像,但是可绘制能表示3D图的2D图像,比如等高线图、着色瓦片图、气泡图等

geom_contour() 等高线图:

  1. library(ggplot2)

  2. faithfuld

  3. # A tibble: 5,625 x 3

  4.   eruptions waiting density

  5.       <dbl>   <dbl>   <dbl>

  6. 1      1.60    43.0 0.00322

  7. 2      1.65    43.0 0.00384

  8. 3      1.69    43.0 0.00444

  9. 4      1.74    43.0 0.00498

  10. 5      1.79    43.0 0.00542

  11. 6      1.84    43.0 0.00574

  12. 7      1.88    43.0 0.00592

  13. 8      1.93    43.0 0.00594

  14. 9      1.98    43.0 0.00581

  15. 10      2.03    43.0 0.00554

  16. # ... with 5,615 more rows

  17. ggplot(faithfuld, aes(eruptions, waiting)) +

  18.  geom_contour(aes(z = density, colour = ..level..))

geom_raster() 着色瓦片图:

  1. ggplot(faithfuld, aes(eruptions, waiting)) +

  2. geom_raster(aes(fill = density))

气泡图:

  1. library(ggplot2)

  2. faithfuld

  3. # Bubble plots work better with fewer observations

  4. small <- faithfuld[seq(1, nrow(faithfuld), by = 10), ]

  5. ggplot(small, aes(eruptions, waiting)) +

  6.  geom_point(aes(size = density), alpha = 1/3) +

  7.  scale_size_area()

参考资料:

  1. Hadley Wickham(2016). ggplot2. Springer International Publishing. doi: 10.1007/978-3-319-24277-4

  2. 《R语言应用系列丛书·ggplot2:数据分析与图形艺术》

猜你喜欢

写在后面

为鼓励读者交流、快速解决科研困难,我们建立了“宏基因组”专业讨论群,目前己有国内外150+ PI,1300+ 一线科研人员加入。参与讨论,获得专业解答,欢迎分享此文至朋友圈,并扫码加主编好友带你入群,务必备注“姓名-单位-研究方向-职称/年级”。技术问题寻求帮助,首先阅读《如何优雅的提问》学习解决问题思路,仍末解决群内讨论,问题不私聊,帮助同行。

学习16S扩增子、宏基因组科研思路和分析实战,关注“宏基因组”

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存