9.9 分面

9.9.1 问题

你想要根据一个或多个变量对数据进行分割并且绘制出该数据所有的子图。

9.9.2 方案

9.9.2.1 样本数据

以下例子将使用 reshape2 包中的 tips 数据集

  1. library(reshape2)
  2. # 查看头几行数据
  3. head(tips)
  4. #> total_bill tip sex smoker day time size
  5. #> 1 16.99 1.01 Female No Sun Dinner 2
  6. #> 2 10.34 1.66 Male No Sun Dinner 3
  7. #> 3 21.01 3.50 Male No Sun Dinner 3
  8. #> 4 23.68 3.31 Male No Sun Dinner 2
  9. #> 5 24.59 3.61 Female No Sun Dinner 4
  10. #> 6 25.29 4.71 Male No Sun Dinner 4

根据小费 (tip) 占总账单 (total_bill) 的百分比绘制散点图

  1. library(ggplot2)
  2. sp <- ggplot(tips, aes(x = total_bill, y = tip/total_bill)) +
  3. geom_point(shape = 1)
  4. sp

9.9 分面 - 图1

9.9.2.2 facet_grid

根据一个或多个变量对数据进行分割,生成的子图按照水平或垂直的方向进行排列。这一功能是通过赋予 facet_grid() 函数一个 vertical ~ horizontal 公式来实现的(这里所说的「公式」是 R 中的一种数据结构,而不是数学意义上的公式)。

  1. # 根据 'sex' 按垂直方向分割
  2. sp + facet_grid(sex ~ .)

9.9 分面 - 图2

  1. # 根据 'sex' 按水平方向分割。
  2. sp + facet_grid(. ~ sex)

9.9 分面 - 图3

  1. # 垂直方向以 'sex' 分割,水平方向以 'day' 分割。
  2. sp + facet_grid(sex ~ day)

9.9 分面 - 图4

9.9.2.3 facet_wrap

除了能够根据单个变量在水平或垂直方向上对图进行分面,facet_wrap() 函数可以通过设置特定的行数或列数,让子图排列到一起。此时每个图像的上方都会有标签。

  1. # 以变量 `day` 进行水平分面,分面的行数为2。
  2. sp + facet_wrap(~day, ncol = 2)

9.9 分面 - 图5

9.9.2.4 修改分面标签的外观

  1. sp + facet_grid(sex ~ day) + theme(strip.text.x = element_text(size = 8,
  2. angle = 75), strip.text.y = element_text(size = 12,
  3. face = "bold"), strip.background = element_rect(colour = "red",
  4. fill = "#CCCCFF"))

9.9 分面 - 图6

9.9.2.5 修改分面标签的文本

修改分面标签内容有两种方法。最简单的方法是为原来的名字匹配一个新的名字向量。例如,对数据中 sex 的类别进行重新定义 Female==>Women 和 Male==>Men:

  1. labels <- c(Female = "Women", Male = "Men")
  2. sp + facet_grid(. ~ sex, labeller = labeller(sex = labels))

9.9 分面 - 图7

另一个方法就是直接在数据框中修改,将你想要显示的标签赋值给相应的数据:

  1. tips2 <- tips
  2. levels(tips2$sex)[levels(tips2$sex) == "Female"] <- "Women"
  3. levels(tips2$sex)[levels(tips2$sex) == "Male"] <- "Men"
  4. head(tips2, 3)
  5. #> total_bill tip sex smoker day time size
  6. #> 1 16.99 1.01 Women No Sun Dinner 2
  7. #> 2 10.34 1.66 Men No Sun Dinner 3
  8. #> 3 21.01 3.50 Men No Sun Dinner 3
  9. sp2 <- ggplot(tips2, aes(x = total_bill, y = tip/total_bill)) +
  10. geom_point(shape = 1)
  11. sp2 + facet_grid(. ~ sex)

9.9 分面 - 图8

两种方法都能得到相同的结果。

labeller() 可以通过设定不同的 函数 来处理输入的字符向量。比方说 Hmisc 包里的 capitalize 函数可以将字符串的首字母变成大写。我们也可以这样来自定义函数,如下所示,将字符串中的字母倒序:

  1. # 对每个字符向量进行倒序:
  2. reverse <- function(strings) {
  3. strings <- strsplit(strings, "")
  4. vapply(strings, function(x) {
  5. paste(rev(x), collapse = "")
  6. }, FUN.VALUE = character(1))
  7. }
  8. sp + facet_grid(. ~ sex, labeller = labeller(sex = reverse))

9.9 分面 - 图9

9.9.2.6 设置标度

一般而言,每幅图的坐标轴范围都是固定不变的,也就是说每幅图都拥有相同的尺寸和范围。你可以通过将 scales 设置为 freefree_xfree_y 来改变坐标轴范围。

  1. # 描绘一个 total_bill 的柱状图
  2. hp <- ggplot(tips, aes(x = total_bill)) + geom_histogram(binwidth = 2,
  3. colour = "white")
  4. # 根据性别和是否吸烟进行分面
  5. hp + facet_grid(sex ~ smoker)

9.9 分面 - 图10

  1. # 在同样的情况下设定 scales='free_y' (y 轴自由标度)
  2. hp + facet_grid(sex ~ smoker, scales = "free_y")

9.9 分面 - 图11

  1. # 画布的缩放比例不变,但各分面的范围有所改变,因此每个分面的物理大小都不一致
  2. hp + facet_grid(sex ~ smoker, scales = "free", space = "free")

9.9 分面 - 图12