R 数据可视化 —— ggforce(注释和分面)
接上一节内容,这一节主要介绍 ggforce
提供的分组注释以及分面功能
3. 分组注释
ggforce
提供了一个很方便的分组注释功能。例如,我们想展示不同种类的鸢尾花在花瓣长度和宽度上的区别,使用 ggplot2
,我们常用的绘制方式是
p <- ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point(show.legend = FALSE)
p
不同种类用颜色来标注
使用 ggforce
可以为不同种类的点添加区域和文本注释,可以更容易的从图中分辨不同类别的点。主要包含 4
种不同形状的注释:
geom_mark_circle()
geom_mark_ellipse()
geom_mark_hull()
geom_mark_rect()
除了形状不同之外,其他都一样。
下面,我们来添加矩形注释
p + geom_mark_rect()
只需添加一个函数,而不用做其他任何操作,就能为每个分组的点添加一个矩形框,简单快捷。
想要添加标签和箭头,也非常方便,直接设置 label
参数即可
p + geom_mark_rect(aes(label = Species))
标签和箭头的位置会自动优化调整,并不需要我们指定。
添加椭圆注释
p + geom_mark_ellipse(aes(label = Species))
圆形
p + geom_mark_circle(aes(label = Species))
添加不同的主题
p + geom_mark_rect(aes(label = Species), show.legend = FALSE) +
theme_void()
但是,在有些情况下,使用矩形或者圆形注释并不好,或者说不够理想。这时就可以使用 geom_mark_hull
函数,来绘制更加复杂的多边形边界,随着分组的边界绘制线条
使用前,先安装依赖包 concaveman
install.packages("concaveman")
更换注释函数
p + geom_mark_hull(aes(label = Species)) +
theme_void()
这样的结果已经很不错了,还可以为每个分组区域添加填充色
p +
geom_mark_hull(aes(label = Species, fill = Species), show.legend = FALSE) +
theme_void()
ggforce
会自动为填充色添加透明度,以防分组的重叠区域被覆盖,也可以手动设置 alpha
参数,来调整透明度
另一个对 hull
函数比较重要的参数就是这是整个区域的大小,就是更改区域周围 padding
的大小。对应的参数是 expand
,可以使用 unit
来指定大小
p +
geom_mark_hull(
aes(label = Species, fill = Species),
show.legend = FALSE, expand = unit(3, "mm")) +
theme_void()
可以看到,区域边界更加紧密了
4. 分面
ggplot2
所提供的分面函数:facet_grid
和 facet_wrap
,基本上可以满足大部分的需求。ggforce
扩展了分面的功能,能够适用于任何布局
4.1 分页
当变量过多时,facet_wrap()
和 facet_grid()
生成的图片中,每个面板都被压缩得很小,例如
ggplot(diamonds) +
geom_point(aes(carat, price), alpha = 0.1) +
facet_wrap(~cut:clarity, ncol = 3)
而 ggforce
为这两个函数提供了一个分页版本,通过设置每一页的行列数,以及页数,可以对变量分页进行绘制,例如
ggplot(diamonds) +
geom_point(aes(carat, price), alpha = 0.1) +
facet_wrap_paginate(~cut:clarity, ncol = 3, nrow = 3, page = 2)
每页包含 3
行 3
列,绘制的是第二页。
对于 facet_grid
也是一样的
ggplot(diamonds) +
geom_point(aes(carat, price), alpha = 0.1) +
facet_grid_paginate(color~cut:clarity, ncol = 3, nrow = 3, page = 4)
可以使用 n_pages
来获取页数
> p <- ggplot(diamonds) +
geom_point(aes(carat, price), alpha = 0.1) +
facet_wrap_paginate(~cut:clarity, ncol = 3, nrow = 3, page = 1)
> n_pages(p)
[1] 5
4.2 内容缩放
ggplot2
的缩放包括:坐标系统的缩放和位置的缩放,而 ggforce
提供了一个更强大的函数:facet_zoom
。
例如,放大 versicolor
类的 x
轴对应的区域
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point() +
facet_zoom(x = Species == "versicolor")
或者 y
坐标轴对应的区域
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point() +
facet_zoom(y = Species == "versicolor")
或者,指定 x
和 y
共同的区域
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point() +
facet_zoom(xy = Species == "versicolor")
为不同的轴指定不同的条件
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point() +
facet_zoom(x = Species != 'setosa', y = Species == 'versicolor')
还可以将每个轴的范围分开绘制
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point() +
facet_zoom(x = Species != 'setosa', y = Species == 'versicolor',
split = TRUE)
使用 xlim
和 ylim
来确定范围
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point() +
facet_zoom(xlim = c(4, 5), ylim = c(1, 2),
split = TRUE)
设置区域的颜色
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point() +
facet_zoom(xlim = c(4, 5), ylim = c(1, 2),
split = TRUE) +
theme(zoom = element_rect(fill = 'orange', colour = NA), validate = FALSE)
与注释一起使用
ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point(show.legend = FALSE) +
geom_mark_hull(
aes(label = Species, fill = Species),
show.legend = FALSE, expand = unit(3, "mm")) +
theme_no_axes() +
facet_zoom(x = Species == "versicolor")
5. 标度
我们的数据一般都会带有相应的单位,比如身高 cm
,体重 kg
等,但是我们在分析的时候一般会忽略数值的单位,而 ggforce
可以让我们在绘图时,加上数值单位
这一功能有 units
包提供
library(units)
定义单位
miles <- as_units('miles')
gallon <- as_units('gallon')
horsepower <- as_units('horsepower')
为数据添加单位,直接与单位相乘即可
> mtcars$consumption <- mtcars$mpg * (miles/gallon)
> mtcars$power <- mtcars$hp * horsepower
> head(mtcars$power)
Units: [horsepower]
[1] 110 110 93 110 175 105
绘制图形
ggplot(mtcars) +
geom_point(aes(power, consumption, colour = factor(cyl)))
在 aes
中的变换会直接反映到图中
ggplot(mtcars) +
geom_point(aes(power, 1/consumption, colour = factor(cyl)))
也可以使用 scale*
函数,设置 unit
参数,会自动变换为新的单位
ggplot(mtcars) +
geom_point(aes(power, consumption, colour = factor(cyl))) +
scale_x_unit(unit = 'W') +
scale_y_unit(unit = 'km/l')
6. 变换
ggplot2
的变换其实使用的是 scales
包,而不是其自身的一部分。ggforce
扩展了 ggplot
的变换功能,包括对坐标轴的变换
6.1 单变量变换
这些变换主要针对 scales
包缺少的功能,如
幂变换
> p3 <- power_trans(3)
> p3$transform(1:5)
[1] 1 8 27 64 125
ggplot(mtcars) + geom_point(aes(mpg, cyl)) + scale_y_continuous(trans = p3)
逆变换
scales
包提供了逆线性变换,但是没有提供其他函数的逆变换,比例 log
的逆变换。
> p3r <- trans_reverser(p3)
> p3r
Transformer: reverse-power of 3
> p3r$transform(1:5)
[1] -1 -8 -27 -64 -125
ggplot(mtcars) + geom_point(aes(mpg, cyl)) + scale_y_continuous(trans = p3r)
6.2 坐标变换
径向变换
radial_trans
可以将半径和角度转换为笛卡尔坐标系下的 x
和 y
轴坐标
line <- data.frame(
x = seq(0, 10, length.out = 100),
y = seq(0, 10, length.out = 100)
)
r_trans <- radial_trans(r.range = c(0, 1), a.range = c(0, 2))
spiral <- r_trans$transform(r = line$x, a = line$y)
ggplot() + geom_path(aes(x, y), data = line, colour = 'red') +
geom_path(aes(x, y), data = spiral, colour = 'blue')
线性变换
线性变换系列涵盖了缩放/拉伸、旋转、剪切、反射和平移,所有的变换都是相对于原始位置进行的。
# 定义旋转、剪切和坐标平移
trans <- linear_trans(rotate(a), shear(1, 0), translate(x1, y1))
square <- data.frame(x = c(0, 0, 1, 1), y = c(0, 1, 1, 0))
# 旋转 60,x + 4, y + 8
square2 <- trans$transform(square$x, square$y, a = pi/3, x1 = 4, y1 = 8)
# 旋转 60,x + 2, y - 6
square3 <- trans$transform(square$x, square$y, a = pi/1.5, x1 = 2, y1 = -6)
square_all <- rbind(square, square2, square3)
square_all$group <- rep(1:3, each = 4)
ggplot(square_all, aes(x, y, group = group)) +
geom_polygon(aes(fill = factor(group)), colour = 'black')