9.6 坐标轴

9.6.1 问题

你想要改变轴的顺序或方向。

9.6.2 方案

注意:下面的例子中提到的 scale_y_continuous()ylim() 等函数名中,y 都可以替换为 x

下面使用内置的 PlantGrowth 数据集绘制一个基本的箱线图。

  1. library(ggplot2)
  2. bp <- ggplot(PlantGrowth, aes(x = group, y = weight)) +
  3. geom_boxplot()
  4. bp

9.6 坐标轴 - 图1

9.6.2.1 交换 x 和 y 轴

交换 x 和 y 轴(让 x 垂直、y 水平)。

  1. bp + coord_flip()

9.6 坐标轴 - 图2

9.6.2.2 离散轴

9.6.2.2.1 改变条目的顺序
  1. # 手动设定离散轴条目的顺序
  2. bp + scale_x_discrete(limits = c("trt1", "trt2", "ctrl"))

9.6 坐标轴 - 图3

  1. ## 逆转轴条目顺序 获取因子水平
  2. flevels <- levels(PlantGrowth$group)
  3. flevels
  4. #> [1] "ctrl" "trt1" "trt2"
  5. # 逆转顺序
  6. flevels <- rev(flevels)
  7. flevels
  8. #> [1] "trt2" "trt1" "ctrl"
  9. bp + scale_x_discrete(limits = flevels)

9.6 坐标轴 - 图4

  1. # 或者一行搞定
  2. bp + scale_x_discrete(limits = rev(levels(PlantGrowth$group)))

9.6 坐标轴 - 图5

9.6.2.2.2 设定标签

对于离散变量,标签来自于因子水平。然而,有时候短的因子水平名字并不适合展示。

  1. bp + scale_x_discrete(breaks = c("ctrl", "trt1", "trt2"),
  2. labels = c("Control", "Treat 1", "Treat 2"))

9.6 坐标轴 - 图6

  1. # 隐藏 x 刻度、标签和网格线
  2. bp + scale_x_discrete(breaks = NULL)

9.6 坐标轴 - 图7

  1. # 隐藏所有的刻度和标签(X 轴),保留网格线
  2. bp + theme(axis.ticks = element_blank(), axis.text.x = element_blank())

9.6 坐标轴 - 图8

9.6.2.3 连续轴

9.6.2.3.1 设定范围和反转轴方向

如果你仅想简单地让轴包含某个值,可以使用 expand_limits(),它会进行拓展而不是拉伸。

  1. # 确保 y 轴包含 0
  2. bp + expand_limits(y = 0)

9.6 坐标轴 - 图9

  1. # 确保 y 轴包含 0 和 8
  2. bp + expand_limits(y = c(0, 8))

9.6 坐标轴 - 图10

当然你也可以通过 y 刻度显式地指定。注意如果使用任何 scale_y_continuous 命令,它会覆盖任何 ylim 命令,而且 ylim 会被忽略。

  1. # 设定连续值轴的范围 下面是相同的操作
  2. bp + ylim(0, 8)

9.6 坐标轴 - 图11

  1. # bp + scale_y_continuous(limits=c(0, 8))

如果使用上述方法让 y 轴的范围变小,任何超出范围的数据都会被忽略。有时候这会产生一些问题,读者需要注意。

为了避免产生问题,你可以使用 coord_cartesian(),相比于设定轴的范围,它设定数据可视化的区域。

  1. # 这两个操作一致,超出范围的数据被删除了,导致产生一个误导的箱线图
  2. bp + ylim(5, 7.5)
  3. #> Warning: Removed 13 rows containing non-finite values
  4. #> (stat_boxplot).

9.6 坐标轴 - 图12

  1. # bp + scale_y_continuous(limits=c(5, 7.5))
  2. # 使用 coord_cartesian 'zooms' 区域
  3. bp + coord_cartesian(ylim = c(5, 7.5))

9.6 坐标轴 - 图13

  1. # 直接指定刻度
  2. bp + coord_cartesian(ylim = c(5, 7.5)) + scale_y_continuous(breaks = seq(0,
  3. 10, 0.25)) # Ticks from 0-10, every .25

9.6 坐标轴 - 图14

9.6.2.3.2 反转轴方向
  1. # 反转一个连续值轴的方向
  2. bp + scale_y_reverse()

9.6 坐标轴 - 图15

9.6.2.3.3 设置和隐藏刻度标记
  1. # Setting the tick marks on an axis This will show tick
  2. # marks on every 0.25 from 1 to 10 The scale will show
  3. # only the ones that are within range (3.50-6.25 in this
  4. # case)
  5. bp + scale_y_continuous(breaks = seq(1, 10, 1/4))

9.6 坐标轴 - 图16

  1. # 刻度不平等变化
  2. bp + scale_y_continuous(breaks = c(4, 4.25, 4.5, 5, 6, 8))

9.6 坐标轴 - 图17

  1. # 抑制标签和网格线
  2. bp + scale_y_continuous(breaks = NULL)

9.6 坐标轴 - 图18

  1. # Hide tick marks and labels (on Y axis), but keep the
  2. # gridlines
  3. bp + theme(axis.ticks = element_blank(), axis.text.y = element_blank())

9.6 坐标轴 - 图19

9.6.2.3.4 轴刻度 log、sqrt 等转换

默认轴是线性坐标,我们也可以将它转换为 log、幂、根等等。

有两种办法可以转换一个轴,一是使用 scale 进行转换,另外是使用 coordinate 进行转换。使用前者需要在先弄好刻度和轴的范围之前转换,而使用后者则相反,需要在弄好刻度和轴范围之后转换。这将产生不太一样的显示效果,如下所示。

  1. # 创建指数分布数据
  2. set.seed(201)
  3. n <- 100
  4. dat <- data.frame(xval = (1:n + rnorm(n, sd = 5))/20, yval = 2 *
  5. 2^((1:n + rnorm(n, sd = 5))/20))
  6. # 创建常规的散点图
  7. sp <- ggplot(dat, aes(xval, yval)) + geom_point()
  8. sp

9.6 坐标轴 - 图20

  1. # log2 比例化(间隔相等)
  2. library(scales) # 需要 scales 包
  3. sp + scale_y_continuous(trans = log2_trans())

9.6 坐标轴 - 图21

  1. # log2 坐标转换,空间间隔不同
  2. sp + coord_trans(y = "log2")

9.6 坐标轴 - 图22

在标度转换中,我们还可以指定刻度值,让它们显示指数。

  1. sp + scale_y_continuous(trans = log2_trans(), breaks = trans_breaks("log2",
  2. function(x) 2^x), labels = trans_format("log2", math_format(2^.x)))

9.6 坐标轴 - 图23

可以使用非常多的转换,参见 ?trans_new 查看所有可用转换的列表。如果你所需要的转换不在该列表上,可以自己写一个转换函数。

有一些非常便捷的函数:scale_y_log10()scale_y_sqrt() (有对应的 x 版本)。

  1. set.seed(205)
  2. n <- 100
  3. dat10 <- data.frame(xval = (1:n + rnorm(n, sd = 5))/20,
  4. yval = 10 * 10^((1:n + rnorm(n, sd = 5))/20))
  5. sp10 <- ggplot(dat10, aes(xval, yval)) + geom_point()
  6. # log10
  7. sp10 + scale_y_log10()

9.6 坐标轴 - 图24

  1. # log10 转换,并设定指数标签
  2. sp10 + scale_y_log10(breaks = trans_breaks("log10", function(x) 10^x),
  3. labels = trans_format("log10", math_format(10^.x)))

9.6 坐标轴 - 图25

9.6.2.3.5 x 与 y 轴固定的比例

设置 x 与 y 轴比例宽度也是可以的。

  1. # x 范围 0-10, y 范围 0-30
  2. set.seed(202)
  3. dat <- data.frame(xval = runif(40, 0, 10), yval = runif(40,
  4. 0, 30))
  5. sp <- ggplot(dat, aes(xval, yval)) + geom_point()
  6. # 强制比例相等
  7. sp + coord_fixed()

9.6 坐标轴 - 图26

  1. # 相等的标度变化,让 x 的 1 个单位等同 y 的 3 个单位
  2. sp + coord_fixed(ratio = 1/3)

9.6 坐标轴 - 图27

9.6.2.4 轴标签和文字格式化

设置和隐藏轴标签:

  1. bp + theme(axis.title.x = element_blank()) + # 移除 x 轴标签
  2. ylab("Weight (Kg)") # 设置 y 轴标签

9.6 坐标轴 - 图28

  1. # 也可以通过标度设置
  2. # 注意这里 x 轴标签的空间仍然保留
  3. bp + scale_x_discrete(name="") +
  4. scale_y_continuous(name="Weight (Kg)")

9.6 坐标轴 - 图29

改变字体、颜色、旋转刻度标签:

  1. # 改变字体选项: X-axis label: bold, red, and 20 points
  2. # X-axis tick marks: rotate 90 degrees CCW, move to the
  3. # left a bit (using vjust, since the labels are
  4. # rotated), and 16 points
  5. bp + theme(axis.title.x = element_text(face = "bold", colour = "#990000",
  6. size = 20), axis.text.x = element_text(angle = 90, vjust = 0.5,
  7. size = 16))

9.6 坐标轴 - 图30

9.6.2.5 刻度标签

你可能想将值显示为百分比、或美元、或科学计数法。这里可以使用格式器,它是一个可以改变文本的函数。

  1. # 标签格式器
  2. library(scales) # 需要 scales 包
  3. bp + scale_y_continuous(labels = percent) + scale_x_discrete(labels = abbreviate) # 在这个例子中它没作用

9.6 坐标轴 - 图31

连续标度格式器有 commapercentdollar 以及 scientific。离散标度格式器有 abbreviatedate_format 等。

有时你需要自己创建格式化函数。下面的函数可以显示时间格式为 HH:MM:SS。

  1. # 自定义时间格式化函数
  2. timeHMS_formatter <- function(x) {
  3. h <- floor(x/60)
  4. m <- floor(x%%60)
  5. s <- round(60 * (x%%1)) # Round to nearest second
  6. lab <- sprintf("%02d:%02d:%02d", h, m, s) # Format the strings as HH:MM:SS
  7. lab <- gsub("^00:", "", lab) # Remove leading 00: if present
  8. lab <- gsub("^0", "", lab) # Remove leading 0 if present
  9. }
  10. bp + scale_y_continuous(label = timeHMS_formatter)

9.6 坐标轴 - 图32

9.6.2.6 隐藏网格线

隐藏网格线:

  1. # 隐藏所有网格线
  2. bp + theme(panel.grid.minor = element_blank(), panel.grid.major = element_blank())

9.6 坐标轴 - 图33

  1. # 仅隐藏次级网格线
  2. bp + theme(panel.grid.minor = element_blank())

9.6 坐标轴 - 图34

也可以仅隐藏水平或垂直网格线:

  1. # 隐藏所有垂直网格线
  2. bp + theme(panel.grid.minor.x = element_blank(), panel.grid.major.x = element_blank())

9.6 坐标轴 - 图35

  1. # 隐藏所有水平网格线
  2. bp + theme(panel.grid.minor.y = element_blank(), panel.grid.major.y = element_blank())

9.6 坐标轴 - 图36