前言
ggforce 是 ggplot2 的一个扩展包,提供了许多自定义的工具函数,可以更方便地为图形添加不同的形状、线条等注释,更灵活的分面图形绘制
使用
安装使用
# 从 CRAN 安装
install.packages("ggforce")
# 从 GitHub 安装
# install.packages("devtools")
devtools::install_github("thomasp85/ggforce")
# 导入
library(ggforce)
1. 形状
形状,本质上是任何有体积的东西。通过设置不同的参数就可以绘制不同类型的几何体。
在 ggplot2 中,大部分用于绘制形状的 geom 函数,其底层都是 geom_polygon。
而在 ggforce 中的所有形状函数都是基于 geom_shape,一个比 geom_polygon 功能更强的函数。并且可以在任何使用 geom_polygon 地方,用 geom_shape 来代替。
geom_polygon 与 geom_polygon 最大的不同在于,它可以对图形的每个角进行设置,还可以使用绝对长度来扩张和收缩。所有基于 geom_polygon 的函数都继承了这些特性
举个例子
data <- data.frame(
labels = rep(LETTERS[1:6], each = 4),
values = rep(c(3, 3.1, 3.1, 3.2, 3.15, 3.5), each = 4),
x = c(2, 1, 1.1, 2.2, 1, 0, 0.3, 1.1, 2.2, 1.1, 1.2, 2.5, 1.1, 0.3,
0.5, 1.2, 2.5, 1.2, 1.3, 2.7, 1.2, 0.5, 0.6, 1.3),
y = c(-0.5, 0, 1, 0.5, 0, 0.5, 1.5, 1, 0.5, 1, 2.1, 1.7, 1, 1.5,
2.2, 2.1, 1.7, 2.1, 3.2, 2.8, 2.1, 2.2, 3.3, 3.2)
)
ggplot(data, aes(x, y)) +
geom_shape(aes(fill = values, group = labels))
其中 x 和 y 坐标是用于标识图中的各个顶点,使用 group 来对点进行分组,对分组的点填充颜色之后看起来就是 6 个不同的形状连接在一起。
我们可以设置每个图形之间的绝对长度间隔,将图形分隔开。注意 expand 设置为负值
ggplot(data, aes(x, y)) +
geom_shape(aes(fill = values, group = labels),
expand = unit(-2, 'mm')
)
也可以将每个角设置为圆角,通过 radius 设置圆角的半径
ggplot(data, aes(x, y)) +
geom_shape(aes(fill = values, group = labels),
expand = unit(-2, 'mm'),
radius = unit(3, "mm")
)
将 expand 设置为正值会让图形重叠,再设置透明度,看看图形长啥样
ggplot(data, aes(x, y)) +
geom_shape(aes(fill = values, group = labels), expand = unit(2, 'mm'),
radius = unit(3, "mm"), alpha = 0.5)
说实话,还有点像地图
下面我们具体看几种常用的形状
1.1 扇形
扇形是通过圆心、圆半径以及起始和终止角度来固定的。ggforce 提供了 geom_arc_bar 函数,可用于绘制扇形柱状图。
主要通过设置内半径和外半径,最常见的形式就是甜甜圈图,如果内半径为 0 则变成饼图。
绘制一个扇形
ggplot(pie) +
geom_arc_bar(
aes(x0 = 0, y0 = 0, r0 = 0,
r = 1, start = start,
end = end, fill = state)
) +
theme_no_axes() + coord_fixed()
但是饼图通常是根据每个分类的值的大小来分配扇形的角度的,例如
ggplot(pie) +
geom_arc_bar(
aes(x0 = 0, y0 = 0, r0 = 0, r = 1,
amount = amount, fill = state), stat = "pie"
) +
theme_no_axes() + coord_fixed()
使用 amount 参数来控制分类的值,注意要设置 stat = "pie"
。
有时,我们还想着重强调某一个分类,使用 explode 参数可以把它抽出来
ggplot(pie) +
geom_arc_bar(
aes(x0 = 0, y0 = 0, r0 = 0, r = 1,
amount = amount, fill = state,
explode = focus), stat = "pie",
) +
theme_no_axes() + coord_fixed()
如果要绘制甜甜圈图,只要把 r0 设置为大于 0 的值
ggplot(pie) +
geom_arc_bar(
aes(x0 = 0, y0 = 0, r0 = 0.6, r = 1,
amount = amount, fill = state,
explode = focus), stat = "pie",
) +
theme_no_axes() + coord_fixed()
1.2 圆形
geom_circle 函数绘制的圆圈与 geom_point 有所不同,圆圈的大小与坐标系统相关而不是标度。
可以通过圆心坐标与半径来确定圆圈的位置,需要与 coord_fixed 搭配使用才能绘制成圆形。
circles <- data.frame(
x0 = rep(1:3, 2),
y0 = rep(1:2, each=3),
r = seq(0.1, 1, length.out = 6)
)
ggplot(circles) +
geom_circle(aes(x0=x0, y0=y0, r=r, fill=r)) +
coord_fixed()
使用参数 n 来设置圆的平滑
ggplot(circles) +
geom_circle(aes(x0=x0, y0=y0, r=r, fill=r),
n = 12) +
coord_fixed()
1.3 椭圆
geom_ellipse 可以绘制相对于坐标轴的椭圆,需要传递的参数比较多,要圆心坐标,长轴和短轴的长度,以及相对于坐标轴的角度
例如
ggplot() +
geom_ellipse(aes(x0 = 0, y0 = 0, a = 10, b = 3, angle = 0)) +
coord_fixed()
增加角度,pi/6 也就是 30 度
ggplot() +
geom_ellipse(aes(x0 = 0, y0 = 0, a = 10, b = 3, angle = pi/6)) +
coord_fixed()
1.4 多边形
geom_regon 用于绘制任意多边形,需要指定中心点坐标、边的数量、以及多边形绘制的圆圈半径(相当于在圆内绘制多边形),以及放置的角度
ggplot() +
geom_regon(aes(x0 = runif(8), y0 = runif(8),
sides = sample(3:10, 8),
angle = 0, r = runif(8) / 10)) +
coord_fixed()
geom_regon 继承于 geom_shape,所以可以设置间距及圆角
ggplot() +
geom_regon(aes(x0 = runif(8), y0 = runif(8),
sides = sample(3:10, 8),
angle = 0, r = runif(8) / 10),
expand = unit(1, 'cm'), radius = unit(1, 'cm')) +
coord_fixed()
1.5 宽对角线
geom_diagonal_wide 用于绘制宽对角线形状,更像是流量图。每个对角线通过 4 个顶点来确定位置,默认的流向是 x 轴方向
data <- data.frame(
x = c(1, 2, 2, 1, 2, 3, 3, 2),
y = c(1, 2, 3, 2, 3, 1, 2, 5),
group = c(1, 1, 1, 1, 2, 2, 2, 2)
)
ggplot(data) +
geom_diagonal_wide(
aes(x, y, group = group),
colour = 'black', fill = 'steelblue',
radius = 0.01
)
strength 参数可以控制对角线的陡峭程度
ggplot(data, aes(x, y, group = group)) +
geom_diagonal_wide(strength = 0.75, alpha = 0.5, fill = 'green') +
geom_diagonal_wide(strength = 0.25, alpha = 0.5, fill = 'red')
设置圆角
ggplot(data) +
geom_diagonal_wide(
aes(x, y, group = group),
colour = 'black', fill = 'steelblue',
radius = unit(5, 'mm')
)
1.6 平行集合图
平行集合图用于可视化多个分类变量之间的相互关系,以平行坐标轴之间的宽对角线图来衡量变量之间的交叠情况。
要将每个变量映射为一个轴,需要用到 ggforce 提供的工具函数先对数据进行转换
> data <- as.data.frame(Titanic)
> head(data)
Class Sex Age Survived Freq
1 1st Male Child No 0
2 2nd Male Child No 0
3 3rd Male Child No 35
4 Crew Male Child No 0
5 1st Female Child No 0
6 2nd Female Child No 0
> data <- gather_set_data(data, 1:4)
> head(data)
Class Sex Age Survived Freq id x y
1 1st Male Child No 0 1 Class 1st
2 2nd Male Child No 0 2 Class 2nd
3 3rd Male Child No 35 3 Class 3rd
4 Crew Male Child No 0 4 Class Crew
5 1st Female Child No 0 5 Class 1st
6 2nd Female Child No 0 6 Class 2nd
ggplot(data, aes(x, id = id, split = y, value = Freq)) +
geom_parallel_sets(aes(fill = Sex), alpha = 0.3, axis.width = 0.1) +
# 轴样式设置
geom_parallel_sets_axes(axis.width = 0.1, colour = "lightgrey", fill = "steelblue") +
# 轴标签设置
geom_parallel_sets_labels() +
theme_no_axes()
1.7 Voronoi 图和 delaunay 三角化
1.7.1 Voronoi 图
Voronoi 图,又叫泰森多边形或 Dirichlet 图,它是一组由连接两邻点直线的垂直平分线组成的连续多边形组成
ggplot(iris, aes(Sepal.Length, Sepal.Width, group = -1L)) +
geom_voronoi_tile(aes(fill = Species)) +
geom_voronoi_segment() +
geom_text(aes(label = stat(nsides), size = stat(vorarea)),
stat = 'delvor_summary', switch.centroid = TRUE
)
对形状和线条都标准化
ggplot(iris, aes(Sepal.Length, Sepal.Width, group = -1L)) +
geom_voronoi_tile(aes(fill = Species), normalize = TRUE) +
geom_voronoi_segment(normalize = TRUE)
控制最大半径
ggplot(iris, aes(Sepal.Length, Sepal.Width, group = -1L)) +
geom_voronoi_tile(aes(fill = Species), colour = 'black', max.radius = 0.25)
使用 bound 参数可以自定义边界形状,比如,设置成三角形
triangle <- cbind(c(3, 9, 6), c(1, 1, 6))
ggplot(iris, aes(Sepal.Length, Sepal.Width, group = -1L)) +
geom_voronoi_tile(aes(fill = Species), colour = 'black', bound = triangle)
也可以设置 geom_shape 属性
ggplot(iris, aes(Sepal.Length, Sepal.Width, group = -1L)) +
geom_voronoi_tile(aes(fill = Species), colour = 'black',
expand = unit(-.5, 'mm'), radius = unit(2, 'mm'))
1.7.2 Delaunay 三角化
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_delaunay_tile(alpha = 0.3, colour = 'black')
使用 geom_delauney_segment2 可以设置线段大小和终点连接处的形状
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_delaunay_segment2(aes(colour = Species, group = -1), size = 2,
lineend = 'round')