《R数据科学》第1章-ggplot2图层与绘图大法-全

  • 1. 简介

  • 2. 第一步

    • 2.1 mpg数据框

    • 2.2 创建ggplot图形:ggplot()函数和geom_point()函数

    • 2.3 绘图模板

  • 3. 添加变量之——图形属性映射

    • 3.1 将变量 class映射为点的图形属性

    • 3.2 手动为几何对象设置图形属性

  • 4. 添加变量之——分面

    • 4.1 facet_wrap()函数

    • 4.2 facet_grid()函数

  • 5. 几何对象

  • 6. 统计变换(stat)

    • 6.1 diamonds 数据集

    • 6.2 geom_bar()函数

    • 6.3 统计变换

  • 7 位置调整(position)

    • 7.1 position = "stack" (默认):分块堆叠

    • 7.2 position = "identity":覆盖重叠

    • 7.3 position = "fill":百分比堆叠

    • 7.4 position = "dodge":并列放置

    • 7.5 position = "jitter":随机抖动

  • 8. 坐标系

    • 8.1 coord_flip() 函数可以交换 x 轴和 y 轴

    • 8.2 coord_quickmap() 函数为地图设置合适的纵横比

    • 8.3 coord_polar() 函数使用极坐标系

  • 9. 图形分层语法

    • 9.1 绘图模板

    • 9.2 如何从头开始构建一个基本图形?

1. 简介

R 有好几种绘图工具,但 ggplot2 是其中最优雅、功能最全面的一个。

本章重点讨论 tidyverse 的一个核心 R 包——ggplot2。关于tidyverse的介绍详见

往期推荐

初学《R数据科学》之——tidyverse是什么
首先,运行以下代码来加载 tidyverse,以访问其包含的数据集、帮助页面和函数。

library(tidyverse)

# # 这一行代码加载了 tidyverse 的核心 R 包。在几乎所有的数据分析任务中,都会用到这些 R 包。
-- Attaching packages ----------------------------------------------------------------- tidyverse 1.3.1 --
√ ggplot2 3.3.5 √ purrr 0.3.4
√ tibble 3.1.3 √ dplyr 1.0.7
√ tidyr 1.1.3 √ stringr 1.4.0
√ readr 2.0.0 √ forcats 0.5.1

# 这行代码还会告诉你 tidyverse 中的哪些函数与基础 R 包(或者已加载的其他 R 包)中的函数有冲突。
-- Conflicts -------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()

# 如果运时出现错误消息“there is no package called'tidyverse’”,需要先安装 tidyverse,再运行 library() 函数:
install.packages("tidyverse") # 安装,即告诉R你需要这个工具
library(tidyverse) # 加载,即告诉R你要用(调用)这个工具,但前提是你得有这个工具,所以要先安装。

# R 包只需安装一次,但每次开始新会话时都要重新加载。

# 如果想要明确指出某个函数(或数据集)的来源,那么可以使用特殊语法形式. package::function()。
# 例如, ggplot2::ggplot()明确指出了我们使用的是ggplot2包中的1ggplot()函数。

2. 第一步

2.1 mpg数据框

数据框是变量(列)和观测(行)的矩形集合。

mpg 包含了由美国环境保护协会收集的 38 种车型的观测数据。

> mpg
# A tibble: 234 x 11
manufacturer model displ year cyl trans drv cty hwy fl class
<chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
3 audi a4 2 2008 4 manual(m6) f 20 31 p compact
4 audi a4 2 2008 4 auto(av) f 21 30 p compact
5 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
6 audi a4 2.8 1999 6 manual(m5) f 18 26 p compact
7 audi a4 3.1 2008 6 auto(av) f 18 27 p compact
8 audi a4 quattro 1.8 1999 4 manual(m5) 4 18 26 p compact
9 audi a4 quattro 1.8 1999 4 auto(l5) 4 16 25 p compact
10 audi a4 quattro 2 2008 4 manual(m6) 4 20 28 p compact
# ... with 224 more rows

mpg 中共包括11个变量

- manufacturer 生产厂商
- model 品牌
- displ 引擎大小,单位为升
- year 出厂年份
- cyl 气缸数
- trans 变压器类型
- drv 驱动类型,其中f =前轮驱动,r =后轮驱动,4 = 4wd
- cty 城市燃油效率,单位为英里/加仑
- hwy 公路燃油效率,单位为英里 / 加仑(mpg)。与燃油效率高的汽车相比,燃油效率低的汽车在行驶相同距离时要消耗更多燃油。
- fl 燃油类型
- class 车种

那么我们是如何了解到关于 mpg 的这些信息呢?

# 直接运行这条代码,会在控制台窗格(左下角)中显示部分数据信息(部分行,部分列)
mpg

# 用view()函数,会在新的窗口中显示全部数据信息(全部行,全部列),类似于Excel数据表。
view(mpg)

# 运行这条代码,会在输出结果窗格(右下角)的Help页面中显示关于mpg 的详细介绍。
# 或者,选中mpg,按F1键也可以得到同样的效果。
?mpg

2.2 创建ggplot图形:ggplot()函数和geom_point()函数

提出问题:大引擎汽车比小引擎汽车更耗油吗?

需要数据:displ 引擎大小;cty(城市燃油效率) 或 hwy(高速公路燃油效率)

设想图形:散点图,x为displ,y为 cty 或 hwy。

那么如何用ggplot2来绘制这一图形呢?

ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy))

运行结果如下:

可见,引擎大小(displ)和燃油效率(hwy)之间是负相关关系。也就是说,大引擎汽车更耗油。

ggplot()函数

函数1:ggplot()
- 功能:创建一个新的ggplot(或坐标系),可以在它上面添加图层。
- 用法:ggplot(data = NULL, mapping = aes(), ..., environment = parent.frame())
- 参数data:要在图中使用的数据集。
- 参数mapping:用于绘图的默认映射列表。如果没有指定,则必须在添加的图层中提供。函数aes()用于构建映射。

geom_point()函数

函数2:geom_point()
- 功能:向图中添加一个点层
- 用法:geom_point(mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., na.rm = FALSE, show.legend = NA, inherit.aes = TRUE)
- 参数mapping:由aes()或aes_()创建的映射集。定义了如何将数据集中的变量映射为图形属性。mapping 参数总是与 aes() 函数成对出现, aes() 函数的 x 参数和 y 参数分别指定了映射到 x 轴的变量与映射到 y 轴的变量。
- 参数data:要在这一层显示的数据。有三种选择:① NULL(即默认值),用ggplot()中指定的绘图数据;② 用data.frame或其他对象覆盖绘图数据;③ 用函数创建,如~ head(.x, 10)
- 参数stat:要在此层的数据上使用的统计转换,为字符串。
- 参数position:位置调整,可以是字符串,也可以是调用位置调整函数的结果。
- 参数na.rm:默认为FALSE,删除NA(缺失值)并发出警告;如果为TRUE,删除NA(缺失值)但不显示警告。二者的区别仅在于是否显示警告。
- 参数show.legend:是否显示图例。为逻辑值,也可以是一个逻辑向量。① 默认NA,包括是否有任何美学映射:② FALSE 从不包含;③ TRUE 总是包含图例。

2.3 绘图模板

要想生成一张图,将以下代码中的尖括号部分替换为数据集、几何对象函数、映射集合即可。

ggplot(data = <DATA>) + # 数据集
<GEOM_FUNCTION>( # 几何对象
mapping = aes(<MAPPINGS>)) # 映射集合

3. 添加变量之——图形属性映射

可以向二维散点图中添加第三个变量,比如 class,方式是将它映射为图形属性。

图形属性是图中对象的可视化属性,其中包括数据点的大小、形状和颜色。

3.1 将变量 class映射为点的图形属性

  • 需要在函数 aes() 中将图形属性名称和变量名称关联起来。

  • ggplot2 还会添加一个图例,以表示图形属性水平和变量值之间的对应关系。

  • ggplot2 不会为 x 和 y 这两个图形属性创建图例,而会创建带有刻度标记和标签的坐标轴。坐标轴就相当于图例,可以体现出位置和变量值之间的映射关系。

# 将class映射为点的颜色。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy,color=class))

# 将class映射为点的大小。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy,size=class))

# 将class映射为点的透明度。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy,alpha=class))

# 将class映射为点的形状。ggplot2 只能同时使用 6 种形状。默认情况下,当使用这种图形属性时,多出的变量值将不会出现在图中。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy,shape=class))

3.2 手动为几何对象设置图形属性

  • 需要将其作为几何对象函数(如geom_point())的一个参数,即在函数 aes() 的外部进行设置。

  • 此外,还需要为这个图形属性选择一个有意义的值。

  • 颜色名称是一个字符串(如color="blue");点的大小用毫米表示(如size=1);点的形状是一个数值(如shape=4)。

# 例如,可以让图中的所有点都为蓝色:
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy),color="blue")

4. 添加变量之——分面

添加额外变量的另一种方法是将图分割成多个分面,即可以显示数据子集的子图。这种方法特别适合添加分类变量。

4.1 facet_wrap()函数

- 功能:通过单个变量对图进行分面。
- 用法:facet_wrap( facets, nrow = NULL, ncol = NULL, scales = "fixed", shrink = TRUE, labeller ="label_value", as.table = TRUE, switch = NULL, drop = TRUE, dir = "h", strip.position = "top")
- 参数 facets:是一个公式,创建公式的方式是在 ~ 符号后面加一个变量名。
- 参数 nrow 和 ncol :分面行数和列数。
- 与facet_grid()函数不同,facet_wrap()函数是按一个变量进行分面,即使手动设置 nrow = 2 分成2行,也是按同一个变量分的,只是为了好看,并无实际意义;而facet_grid()函数是按两个变量,行和列维度有不同的意义。
- 传递给 facet_wrap() 的变量应该是离散型的。
# 按 class 进行分面,分成2行。
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_wrap(~ class, nrow = 2)

4.2 facet_grid()函数

  • 功能:通过两个变量对图进行分面。

  • 第一个参数也是一个公式,但该公式包含由 ~ 隔开的两个变量名。

  • ~左边表示在行的维度进行分面,右边表示在列的维度进行分面。

# 在行的维度按drv(驱动类型)分面,在列的维度按cyl(气缸数)分面。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy))+
facet_grid(drv~cyl)

  • 如果不想在行或列的维度进行分面,你可以使用 . 来代替变量名。

# 仅在列的维度按cyl(气缸数)进行分面。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy))+
facet_grid(.~cyl)

5. 几何对象

几何对象是图中用来表示数据的几何图形对象。

  • 条形图:使用了条形几何对象;

  • 折线图:使用了直线几何对象;

  • 箱线图:使用了矩形和直线几何对象。

  • 散点图:使用点几何对象。

要想改变图中的几何对象,需要修改添加在 ggplot() 函数中的几何对象函数。

  • 条形图:geom_bar()函数;

  • 折线图:geom_line()函数;

  • 箱线图:geom_boxplot()函数;

  • 散点图:geom_point()函数;

  • 平滑曲线:geom_smooth()函数;

  • 直方图:geom_histogram()函数;

ggplot2 中的每个几何对象函数都有一个 mapping 参数。

不是每种图形属性都适合每种几何对象。比如,可以设置点的形状,但不能设置线的“形状”,而可以设置线的线型。

分组

# 未分组
ggplot(data=mpg)+
geom_smooth(mapping=aes(x=displ,y=hwy))

# 仅分组:可以将这些几何对象的 group 图形属性设置为一个分类变量, ggplot2 就会为这个分类变量的每个唯一值绘制一个独立的几何对象,即进行分组。
ggplot(data=mpg)+
geom_smooth(mapping=aes(x=displ,y=hwy,group=drv))

# 分组且分颜色:只要将一个图形属性(如 color )映射为一个离散变量(drv), ggplot2 就会自动对数据进行分组来绘制多个几何对象
# 添加参数 show.legend=FALSE:不显示图例。
ggplot(data=mpg)+
geom_smooth(mapping=aes(x=displ,y=hwy,color=drv),show.legend=FALSE)

要想在同一张图中显示多个几何对象,可以向 ggplot() 函数中添加多个几何对象函数

# 代码有重复,不易修改。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy))+
geom_smooth(mapping=aes(x=displ,y=hwy))

# 避免重复(全局映射):将一组映射传递给 ggplot() 函数。ggplot2 会将这些映射应用到图中的每个几何对象中。
ggplot(data=mpg,mapping=aes(x=displ,y=hwy))+
geom_point()+
geom_smooth()

# 局部映射:如果将映射放在几何对象函数中,ggplot2 将使用这些映射扩展或覆盖全局映射,但仅对该图层有效。

# 可以在不同的图层中显示不同的图形属性。
ggplot(data=mpg,mapping=aes(x=displ,y=hwy))+
geom_point(mapping=aes(color=class))+ # 散点图按class进行颜色分类
geom_smooth()

# 也可以为不同的图层指定不同的数据。
ggplot(data=mpg,mapping=aes(x=displ,y=hwy))+
geom_point(mapping=aes(color=class))+
geom_smooth(data=filter(mpg,class=="subcompact"),se=FALSE) # 平滑曲线表示的只是 mpg 数据集的一个子集,即微型车。其中 se=FALSE 表示去掉平滑时的灰色区域。

6. 统计变换(stat)

6.1 diamonds 数据集

  • 是 ggplot2 的内置数据集,包含大约 54 000 颗钻石的信息。

  • 共包含10个变量。每颗钻石具有 price、 carat、 color、clarity 和 cut 等变量。

- price:价格,单位为美元(\$326–\$18,823)
- carat:钻石质量(克拉数)(0.2–5.01)
- cut:切割质量(Fair, Good, Very Good, Premium, Ideal)
- color:钻石颜色,从D (best) 到 J (worst)
- clarity:钻石清晰度 (I1 (worst), SI2, SI1, VS2, VS1, VVS2, VVS1, IF (best))
- x:长度,单位 mm (0–10.74)
- y:宽度,单位 mm (0–58.9)
- z:深度,单位 mm (0–31.8)
- depth:全深比 = z / mean(x, y) = 2 * z / (x + y) (43–79)
- table:钻石顶部相对于最宽点的宽度(43–95)

6.2 geom_bar()函数

- 功能:绘制条形图
- 用法:geom_bar(mapping = NULL, data = NULL, stat = "count", position = "stack", ..., width = NULL, na.rm = FALSE, orientation = NA, show.legend = NA, inherit.aes = TRUE)
- 参数stat:统计变换,默认值是count,说明geom_bar()使用stat_count() 函数进行统计变换。stat_count()会计算出两个变量:count 和 prop。

# 不同切割质量的钻石数量。
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut))

该图 x 轴显示的是 cut,这是 diamonds 数据集中的一个变量。y 轴显示的是 count,但 count 不是 diamonds 中的变量!

很多图形绘制的是数据集的原始数据,比如散点图。另外一些图形则可以绘制那些计算出的新数据,比如条形图。

  • 条形图、直方图和频率多边形图可以对数据进行分箱,然后绘制出分箱数量和落在每个分箱的数据点的数量。

  • 平滑曲线会为数据拟合一个模型,然后绘制出模型预测值。

  • 箱线图可以计算出数据分布的多种摘要统计量,并显示一个特殊形式的箱体。

6.3 统计变换

统计变换(statistical transformation,stat):是指绘图时用来计算新数据的算法。

geom_bar() 函数的统计变换过程如下:

  • geom_bar() 的默认统计变换(stat)是count,说明geom_bar() 使用 stat_count() 函数进行统计变换。

  • stat_count() 会计算出两个新变量:count 和 prop。

  • 但geom_bar() 的默认统计变换(stat)是count,所以条形图的y轴是count。

通常,几何对象函数(如 geom_bar())和统计变换函数(如stat_count())可以互换使用。

# 可以使用 stat_count() 替换 geom_bar() 来重新生成前面那张图
ggplot(data=diamonds)+
stat_count(mapping=aes(x=cut))

显式使用统计变换的情况如下:

  1. 覆盖默认的统计变换。设置参数 stat = "identity",使条形的高度映射为 y 轴变量的初始值(即y值),这样得到的就是我们通常见到的条形图。

demo <- tribble(
~a, ~b,
"bar_1", 20,
"bar_2", 30,
"bar_3", 40
)

ggplot(data = demo) +
geom_bar(
mapping = aes(x = a, y = b), stat = "identity"
)

  1. 覆盖从统计变换生成的变量到图形属性的默认映射。

# 显示一张表示比例(而不是计数)的条形图
# 帮助文件中的“Computed variables”可以查看由统计变换计算出的变量。
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut,y=..prop..,group=1))

  1. 在代码中强调统计变换。如用stat_summary() 函数做摘要统计量,这里统计变换是summary 而非 count。

ggplot(data=diamonds)+
stat_summary(mapping=aes(x=cut,y=depth),
fun.min = min,
fun.max = max,
fun = median
)

ggplot(data=diamonds)+
geom_pointrange(
mapping=aes(x=cut,y=depth),
stat = "summary", # geom_pointrange()的默认stat是identity,故要特别指出。
fun.min=min, # Stat_summary()用平均值和sd来计算直线的中点和端点,而上图端点用的是最小值和最大值,故要重新计算。
fun.max=max, # ggplot2 v 3.3.0.已弃用fun.ymin、fun.ymax和fun.y,替换为fun.min、fun.max和fun
fun=median
)

7 位置调整(position)

条形图还可以使用 color(边界色) 或者 fill(填充色)图形属性来为条形图上色:

# 未填充
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut))

# 填充 color 边界色
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut,color=cut))

# 填充 fill 填充色
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut,fill=cut))

7.1 position = "stack" (默认):分块堆叠

如果将 fill 图形属性映射到另一个变量(如 clarity),那么条形会自动分块堆叠起来。

# 每个彩色矩形表示 cut 和 clarity 的一种组合。
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut,fill=clarity))

自动分块堆叠是由 position 参数设定的位置调整功能自动完成的。如果不想生成堆叠式条形图,还可以使用以下 3 种选项之一: "identity"、 "fill" 和 "dodge"。

7.2 position = "identity":覆盖重叠

# ① position="identity":柱子彼此间会覆盖重叠(纵坐标最高为5000,分块堆叠时最高为20000),不太适合条形图
ggplot(data=diamonds,mapping=aes(x=cut,fill=clarity))+
geom_bar()

7.3 position = "fill":百分比堆叠

# ② position="fill":与堆叠相似,但每组条形的高度一致。用途:比较各组间比例。
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut,fill=clarity),position="fill")

7.4 position = "dodge":并列放置

# ③ position="dodge"(躲开):将每组中的条形依次并列放置。用途:比较具体数值。
ggplot(data=diamonds)+
geom_bar(mapping=aes(x=cut,fill=clarity),position="dodge")

7.5 position = "jitter":随机抖动

# 默认位置调整(position=“identity”),对值都进行了舍入取整,导致很多点彼此重叠(过绘制)。234个观测值,散点图中只显示了126个点。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy))

# ④ position="jitter":抖动,即为每个数据点添加一个很小的随机扰动,这样就可以将重叠的点分散开来。适合于散点图,可以避免网格化排列。
ggplot(data=mpg)+
geom_point(mapping=aes(x=displ,y=hwy),position="jitter")

8. 坐标系

ggplot2 默认的坐标系是笛卡儿直角坐标系。偶尔也会用到一些其他类型的坐标系。

8.1 coord_flip() 函数可以交换 x 轴和 y 轴

当想要绘制水平箱线图时,这非常有用。它也非常适合使用长标签。

# 默认
ggplot(data=mpg,mapping=aes(x=class,y=hwy))+
geom_boxplot()

# 用coord_flip() 函数交换 x 轴和 y 轴
ggplot(data=mpg,mapping=aes(x=class,y=hwy))+
geom_boxplot()+
coord_flip()

8.2 coord_quickmap() 函数为地图设置合适的纵横比

当使用 ggplot2 绘制空间数据时, 这个函数特别重要。

nz <- map_data("nz")

# 默认纵横比
ggplot(nz,aes(long,lat,group=group))+
geom_polygon(fill="white",color="black")

# 用coord_quickmap() 函数为地图设置合适的纵横比
ggplot(nz,aes(long,lat,group=group))+
geom_polygon(fill="white",color="black")+
coord_quickmap()

8.3 coord_polar() 函数使用极坐标系

极坐标系可以揭示出条形图和鸡冠花图间的一种有趣联系

bar <- ggplot(data=diamonds)+
geom_bar(
mapping=aes(x=cut,fill=cut),
show.legend = FALSE,
width = 1)+
theme(aspect.ratio = 1)+
labs(x=NULL,y=NULL)
bar+coord_flip() # 交换x轴和y轴(条形图)
bar+coord_polar() # 极坐标系(鸡冠花图)

9. 图形分层语法

9.1 绘图模板

向前面的代码模板中添加位置调整、统计变换、坐标系和分面:

# 要想生成一张图,将以下代码中的尖括号部分替换即可:
ggplot(data = <DATA>) + # 数据集
<GEOM_FUNCTION>( # 几何对象
mapping = aes(<MAPPINGS>), # 映射集合
stat = <STAT>, # 统计变换
position = <POSITION> # 位置调整
) +
<COORDINATE_FUNCTION> + # 坐标系
<FACET_FUNCTION> # 分面

9.2 如何从头开始构建一个基本图形?

  • 首先,需要有一个数据集(如diamonds),然后(通过统计变换(如stat_count()))将其转换为想要显示的信息。

  • 接下来,可以选择一个几何对象(如条形图)来表示转换后的数据中的每个观测值。

  • 然后,选择几何对象的图形属性(如fill)来表示数据中的变量,这会将每个变量的值映射为图形属性的水平。

  • 下一步,选择放置几何对象的坐标系。

这样就生成了一张完整的图。但还可以进行进一步调整。

  • 可以进一步调整几何对象在坐标系中的位置(位置调整)

  • 或者将图划分为多个子图(分面)

  • 还可以通过添加一个或多个附加图层对图进行扩展,其中每个附加图层都使用一个数据集、一个几何对象、一个映射集合、一个统计变换和一个位置调整。

根际互作生物学研究室 简介

根际互作生物学研究室是沈其荣教授土壤微生物与有机肥团队下的一个关注于根际互作的研究小组。本小组由袁军副教授带领,主要关注:1.植物和微生物互作在抗病过程中的作用;2 环境微生物大数据整合研究;3 环境代谢组及其与微生物过程研究体系开发和应用。团队在过去三年中在 isme J, Microbiome, PCE,SBB,Horticulture Research等期刊上发表了多篇文章。欢迎关注 微生信生物 公众号对本研究小组进行了解。

(0)

相关推荐