之前零零散散写了几篇ggplot2
绘图系统的推文,反响还不错。目前基础绘图系统已经基本介绍完毕,从本篇开始制表与可视化专辑就集中介绍ggplot2
绘图系统。
ggplot2
系统与基础绘图系统的语法结构很不一样,它更希望使用者能够专注于原始数据,而不必纠结从原始数据到绘图数据的转换。
例如,在基础绘图系统里,如果想对连续变量进行分段配色,需要先对原始数据进行分段,而在ggplot2
绘图系统中可以使用颜色标度函数直接进行分箱映射,具体见前不久的推文:颜色标度函数。
统计变换函数也有类似的功能,它执行的是原始数据到图形类别以及y轴变量的映射。
library(ggplot2)
library(patchwork)
从柱状图说起
柱状图是常见的统计图形。基础绘图系统中专门绘制柱状图的函数是barplot()
,而在ggplot2
系统中对应的几何图形函数是geom_bar()
。
示例1
生成随机离散值作为示例数据df01
:
set.seed(12)
df01 <- data.frame(x = rpois(20, 5))
df01$x
## [1] 2 7 9 4 3 1 3 6 1 1 4 7 4 4 3 4 5 5 6 2
分别使用两个函数直接进行绘图:
barplot(df01$x)
ggplot(df01, aes(x)) +
geom_bar()
可以看到,上面两个函数绘制出的图形完全不同,其中ggplot2
系统绘制出的才是我们想要的柱状图。
这是因为使用原始数据绘制柱状图前需要先进行频数统计,这个过程就是统计变换。
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
参数就是统计变换参数,stat = "count"
表示geom_bar()
函数默认执行的是频数统计转换,因此在默认情况下geom_bar()
函数就能使用原始数据绘制出我们需要的柱状图,而基础绘图系统中的barplot()
函数则不行。
示例2
使用dplyr
工具包的count()
函数对示例1中的df01
数据框进行频数统计,作为示例数据df02
:
library(dplyr)
df02 <- count(df01, x)
df02
## x n
## 1 1 3
## 2 2 2
## 3 3 3
## 4 4 5
## 5 5 2
## 6 6 2
## 7 7 2
## 8 9 1
再分别使用两个函数绘制柱状图:
barplot(df02$n)
ggplot(df02, aes(n)) +
geom_bar()
可以看到,两个函数绘制出的结果仍然不一样,其中barplot()
函数绘制出的图形与示例1中的geom_bar()
函数绘制出的结果比较类似,是我们想要的柱状图。
这是由于geom_bar()
函数依然默认执行了频数统计变换,而在本例中原始数据df02
中已经包含了频数变量,因此不再需要进行统计变换。
解决办法是设置stat = "identity"
,该语句表示直接使用原始数据进行绘图。
ggplot(df02, aes(x = x, y = n)) +
geom_bar(stat = "identity")
- 需要注意的是count变换只需要一个绘图变量(示例1中的
x
),而identity变换需要两个绘图变量(示例2中的x
和n
)。
到这里,就介绍了count和identity两种类型的变换了。
从柱状图到直方图、密度图
示例3
在基础绘图系统中,柱状图和直方图有着明显的界限:柱状图应用于离散变量的频数统计,直方图应用于连续变量的频数统计。
在ggplot2
绘图系统中,直方图对应的几何图形函数是geom_histogram()
,但是通过设置统计变换参数stat
,geom_bar()
函数也能绘制出直方图。
直方图的绘制原理是先将连续变量分段、统计频数,然后再绘制成“柱状图”,这就是分箱统计变换,即stat = bin
。geom_histogram()
函数默认的就是分箱变换:
geom_histogram(
mapping = NULL,
data = NULL,
stat = "bin",
position = "stack",
...,
binwidth = NULL,
bins = NULL,
na.rm = FALSE,
orientation = NA,
show.legend = NA,
inherit.aes = TRUE
)
生成连续变量作为示例数据df03
:
set.seed(34)
df03 <- data.frame(x = rnorm(200, 5))
分别使用geom_histogram()
和geom_bar()
函数绘制直方图:
ggplot(df03, aes(x)) +
geom_histogram(binwidth = 0.25, color = "white") -> p1
ggplot(df03, aes(x)) +
geom_bar(stat = "bin", binwidth = 0.25, color = "white") -> p2
p1 + p2
可以看出,两个函数绘制出的结果一致。
示例4
密度图相当于将柱状图的频数统计变换变为频率统计变换(离散变量),或者对直方图进行无限分割后再进行频率统计变换(连续变量)。
尽管有专门的密度函数geom_density()
,但是通过设置统计变换参数,仍然可以使用geom_bar()
绘制出密度图。
## 离散变量
ggplot(df01, aes(x)) +
geom_bar(stat = "density") -> p3
## 连续变量
ggplot(df03, aes(x)) +
geom_bar(stat = "density") -> p4
p3 + p4
至此,又介绍了bin和density两种统计变换。
统计变换函数
进行统计变换不仅可以通过设置几何图形函数的stat
参数,还可以直接使用统计变换函数,这些函数以stat_
开头进行命名。
示例5
频数统计变换函数的语法结构如下:
stat_count(
mapping = NULL,
data = NULL,
geom = "bar",
position = "stack",
...,
width = NULL,
na.rm = FALSE,
orientation = NA,
show.legend = NA,
inherit.aes = TRUE
)
geom
参数表示统计变换后绘制的图形类型,geom = "bar"
表示stat_count()
函数在进行频数统计后默认绘制柱状图。
ggplot(df01, aes(x)) +
stat_count() -> p5
ggplot(df03, aes(x)) +
stat_bin(binwidth = 0.25) -> p6
p5 + p6
示例6
stat_identity()
函数的语法结构如下:
stat_identity(
mapping = NULL,
data = NULL,
geom = "point",
position = "identity",
...,
show.legend = NA,
inherit.aes = TRUE
)
该函数默认绘制的几何图形是散点图:
ggplot(df02, aes(x = x, y = n)) +
stat_identity() -> p7
ggplot(df02, aes(x = x, y = n)) +
stat_identity(geom = "bar") -> p8
p7 + p8
其他统计变换
ggplot2
绘图系统中内置了许多类型的统计变换,还支持使用stat_function()
函数进行自定义统计变换。下面简单列举几种,详细可查看官方帮助文档。
- 概率累积变换
ggplot(df02, aes(x)) +
stat_ecdf() -> p9
ggplot(df03, aes(x)) +
stat_ecdf() -> p10
p9 + p10
- 方向分布变换(标准差椭圆)
ggplot(df02, aes(x, n)) +
geom_point() +
stat_ellipse()
- 正态QQ检验
ggplot(df03, aes(sample = x)) +
stat_qq() +
stat_qq_line()
- 平滑变换
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
stat_smooth(span = 0.3)
- 汇总变换
ggplot(mtcars, aes(cyl, mpg)) +
geom_point()+
stat_summary(fun.data = "mean_cl_boot", colour = "red", size = 2)