[关闭]
@K1999 2016-07-05T05:28:38.000000Z 字数 7764 阅读 11613

数据可视化ggplot2系列——标尺(scale)设置

R 数据可视化


1 标尺设定函数

ggplot2修改标尺的函数有一大堆:

  1. > library(ggplot2)
  2. > scalex <- ls("package:ggplot2", pattern = "^scale.+")
  3. > length(scalex)
  4. [1] 75

提取函数名的第二个字段,对这些函数的作用进行分类:

  1. > scalex <- scalex[grep("([^_]+_){2}.+", scalex)]
  2. > unique(gsub("(([^_]+_){2}).+", "\\1***", scalex))
  3. [1] "scale_alpha_***" "scale_color_***" "scale_colour_***"
  4. [4] "scale_fill_***" "scale_linetype_***" "scale_shape_***"
  5. [7] "scale_size_***" "scale_x_***" "scale_y_***"

可以看到标尺设置的内容有8种(颜色color/colour算一种):线条颜色、填充色、透明度、线型、形状、大小,x和y轴。标尺设置的内容都有对应的映射设置类型,但映射比标尺多了xmin, xmax, ymin, ymax, xend, yend,group和string等(请参看映射一节)。
虽然设置函数很多,但不管是函数用法还是函数名称上都是很有规律的:

  1. ### 线条颜色
  2. > scalexx <- scalex[grepl("scale_color.+", scalex)]
  3. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  4. [1] "brewer" "continuous" "discrete" "distiller" "gradient" "gradient2"
  5. [7] "gradientn" "grey" "hue" "identity" "manual"
  6. ### 填充色
  7. > scalexx <- scalex[grepl("scale_fill.+", scalex)]
  8. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  9. [1] "brewer" "continuous" "date" "datetime" "discrete" "distiller"
  10. [7] "gradient" "gradient2" "gradientn" "grey" "hue" "identity"
  11. [13] "manual"
  12. ### 大小
  13. > scalexx <- scalex[grepl("scale_size.+", scalex)]
  14. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  15. [1] "area" "continuous" "date" "datetime" "discrete" "identity"
  16. [7] "manual"
  17. ### 透明度
  18. > scalexx <- scalex[grepl("scale_alpha.+", scalex)]
  19. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  20. [1] "continuous" "discrete" "identity" "manual"
  21. ### 线型
  22. > scalexx <- scalex[grepl("scale_linetype.+", scalex)]
  23. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  24. [1] "continuous" "discrete" "identity" "manual"
  25. ### 形状
  26. > scalexx <- scalex[grepl("scale_shape.+", scalex)]
  27. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  28. [1] "continuous" "discrete" "identity" "manual"
  29. ### x轴
  30. > scalexx <- scalex[grepl("scale_x.+", scalex)]
  31. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  32. [1] "continuous" "date" "datetime" "discrete" "log10" "reverse"
  33. [7] "sqrt"
  34. ### y轴
  35. > scalexx <- scalex[grepl("scale_y.+", scalex)]
  36. > unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
  37. [1] "continuous" "date" "datetime" "discrete" "log10" "reverse"
  38. [7] "sqrt"

除坐标轴外,其它标尺都有四种基本设置函数: "continuous","discrete","identity"和"manual"。结合标尺的作用和设定方法两个标准,H.W把它们分为4种类型的标尺:位置、颜色、无变换和人工设置类型(说实话,他的分类思维有点乱)。颜色设置相关的函数较多,线条颜色和填充色设置的函数类型一样,而x轴和y轴设置的函数类型也一样。
由于标尺函数的命名和用法很有规律,下面仅介绍颜色和坐标轴设置函数的一些用法。

2 颜色标尺设置

2.1 连续型颜色标尺

当前版本的ggplot2提供了13个填充色设置的标尺函数(线条颜色也一样):

  1. > ls("package:ggplot2", pattern = "^scale_fill.+")
  2. [1] "scale_fill_brewer" "scale_fill_continuous" "scale_fill_date"
  3. [4] "scale_fill_datetime" "scale_fill_discrete" "scale_fill_distiller"
  4. [7] "scale_fill_gradient" "scale_fill_gradient2" "scale_fill_gradientn"
  5. [10] "scale_fill_grey" "scale_fill_hue" "scale_fill_identity"
  6. [13] "scale_fill_manual"

先看看“continuous”的用法。对于数据为非因子型的填充色映射,ggplot2自动使用“continuous”类型颜色标尺表示连续颜色空间。如果要修改默认颜色就要使用scale_fill_continuous函数进行修改,这个函数最有用的参数是low和high,分别表示低端和高端数据的颜色,中间颜色根据颜色空间space自动计算:

  1. theme_set(theme_bw())
  2. df <- expand.grid(1:30, 1:30)
  3. colnames(df) <- c("x", "y")
  4. df$z <- rnorm(900)
  5. p <- ggplot(data = df, aes(x = x, y = y, fill = z))
  6. p + geom_raster()
  7. p + geom_raster() + scale_fill_continuous(low = "darkgreen", high = "orangered", space = "rgb")

颜色可以使用预设颜色名称,也可以使用十六进制表示。颜色空间可以是rgb或Lab,两者差别还比较大(rgb已经弃用):

  1. p + geom_raster() + scale_fill_continuous(low = "#000099", high = "#FF0000", space = "rgb")
  2. p + geom_raster() + scale_fill_continuous(low = "#000099", high = "#FF0000", space = "Lab")

连续填充色设置函数还有scale_fill_gradient,scale_fill_gradient2和 scale_fill_gradientn,其中scale_fill_gradient的用法和作用和scale_fill_continuous完全相同(其实ggplot2早期版本连续颜色标尺默认使用scale_fill_gradient,没有scale_fill_continuous函数;后者可能是H.W头脑清楚以后加进去的,相当于前者的别名)。scale_fill_gradient2增加了中间点和中间颜色的设置,效果相当不错:

  1. p + geom_raster() + scale_fill_gradient2(low = "darkgreen", high = "red", mid = "yellow")
  2. p + geom_raster() + scale_fill_gradient2(low = "darkgreen", high = "red", mid = "yellow", midpoint = 1)

而scale_fill_gradientn可以使用colours参数设置多个中间颜色,配合其它颜色参数函数使用也很不错:

  1. p + geom_raster() + scale_fill_gradientn(colours = c("blue", "green", "yellow", "red"))
  2. p + geom_raster() + scale_fill_gradientn(colours = terrain.colors(100))

注意参数名称为colours,不是colors,米国人民可能不习惯,不过问题不大。

2.2 离散(间断)型颜色标尺

如果数据是因子型的颜色映射,颜色标尺则是离散型的,修改标尺需要使用相应的离散型颜色标尺如scale_color_discrete或scale_color_hue。这两个函数只是别名函数,早期版本只有scale_color_hue。它们通过设置色调范围(h)、饱和度(c)和亮 度(l)获取颜色,不太容易掌握:

  1. set.seed(100)
  2. dt <- diamonds[sample(nrow(diamonds), 500), ]
  3. p <- ggplot(data = dt, aes(x = carat, y = price, color = cut))
  4. p + geom_point() + scale_color_discrete()
  5. p + geom_point() + scale_color_discrete(h = c(150, 350), c = 100, l = 60)

注意:因为映射是color,所以标尺设置也得相应用scale_color而不是scale_fill。
scale_color_discrete或scale_color_hue设置颜色不是很直观,如果想要啥来啥,那就用manual类型函数:

  1. p + geom_point() + scale_color_manual(values = c("blue", "cyan", "yellow", "orange", "red"))
  2. p + geom_point() + scale_color_manual(values = rainbow(5))

grey灰度标尺函数是设置离散型颜色的另外一类函数,用法很简单。

  1. p + geom_point() + scale_color_grey(start = 0, end = 0.8)

brewer类型函数则可以直接使用RColorBrewer包预定义的一些调色板,那些调色板最多能设置8-11种颜色不等,如果超过最大颜色数就不合适了。

  1. x <- sample(LETTERS, 13)
  2. y <- 1:13 qplot(x = x, y = y, fill = x, geom = "bar") + scale_fill_brewer(palette = "YlOrRd")
  3. x <- x[1:8] y = y[1:8] qplot(x = x, y = y, fill = x, geom = "bar") + scale_fill_brewer(palette = "YlOrRd")

与其去记那些调色板名称,还不如用manual可以设置自己需要的颜色(可参考本博客的文章《R语言进阶之一:颜色设置》)。
查看scale_fill_gradientn等函数的说明发现很多用于连续颜色设置的函数都有palette参数选项,似乎连续型和离散型颜色在函数上没有严格区别,但实际使用时会出错,或许这些功能只是H.W做的TODO list。

2.3 identity标尺

如果数据本身就是可以用作标尺的取值,那当然可以直接使用:

  1. > set.seed(2)
  2. > (col <- sample(colors(), 4))
  3. "deepskyblue1" "mediumblue" "indianred4" "darkslategray2"
  4. val <- abs(rnorm(4)) * 10
  5. qplot(x = col, y = val, fill = col, geom = "bar") + scale_fill_identity()
  6. qplot(x = carat, y = price, data = dt, size = x) + scale_size_identity()

设置identity标尺后不再产生对应的图例。

3. 坐标轴标尺设置

ggplot2为x或y轴标尺的设置分别提供了7个函数:

  1. > ls("package:ggplot2", pattern = "^scale_x.+")
  2. "scale_x_continuous" "scale_x_date" "scale_x_datetime" "scale_x_discrete" "scale_x_log10" "scale_x_reverse" "scale_x_sqrt"

这些函数最基本的是continuous和discrete两个,通过设置它们的参数可以实现其它函数的效果。

3.1 breaks, labels, limits参数

continuous和discrete坐标轴标尺设定函数中最常用的参数是breaks、labels和limits,分别用于设置刻度位置、刻度标签和坐标轴范围。先看看前两个参数:

  1. p <- ggplot(data = dt, aes(x = carat, y = price)) + geom_point()
  2. bks <- pretty(range(dt$price), 10)
  3. p + scale_y_continuous(breaks = bks)
  4. bks <- c(0, 2000, 10000, 15500, 18000)
  5. p + scale_y_continuous("Price (*1000)", breaks = bks, labels = bks/1000)

如果xy轴都是非因子数据,limits的设置比较顺利,但另外一个坐标轴还不能自动调整,可能需要改进:

  1. p + scale_x_continuous(limits = c(0.5, 1.5))
  2. p + scale_y_continuous(limits = c(500, 1000))

用limits参数设置因子型数据轴还有意外的效果:既能选择要显示的数据子集,还能调整它们在图形上的显示顺序:

  1. qplot(x = x, y = y, geom = "bar") + scale_x_discrete(limits = c("W", "D", "F"))

3.2 trans参数
连续数据的坐标轴可以设置trans参数,它应该是通过调用scales包的相应trans类型实现的,比如scales中有log10_trans,ggplot2中可以直接设置trans='log10',它其实就是scale_x_log10函数的效果:

  1. p + scale_y_continuous(trans = "log10") + ggtitle("scale_y_continuous(trans='log10')")
  2. p + scale_y_log10() + ggtitle("scale_y_log10()")

同样reverse_trans和sqrt_trans也等价于scale_x_reverse和scale_x_sqrt,它们分别对坐标轴反转和求平方根。日期相关的转换函数scale_x_date和scale_x_datetime我没用过,就不说来。scales包中还有其它一些转换函数,但在 ggplot中没有对应的设置函数,如果数据合适,有些可以直接用:

  1. p + scale_y_continuous(trans = "reciprocal") + ggtitle("reciprocal_trans")
  2. p + scale_x_continuous(trans = "log1p") + ggtitle("log1p_trans")

3.3 坐标轴标尺转换与数据映射

如果你认为坐标轴标尺只是改变了坐标轴的外观那就错了,它还影响到用于建立映射的数据。下面我们分别用坐标轴标尺应用之前和之后的数据获得拟合直线:

  1. lmx <- lm(dt$price ~ dt$carat)
  2. gs1 <- geom_line(aes(y = lmx$fitted.values), size = 3, color = "red")
  3. gs2 <- geom_smooth(aes(group = 1), method = "lm", se = FALSE, size = 1.5)
  4. p + gs1 + gs2 p + gs1 + gs2 + scale_x_log10()

第一个图没改变坐标轴标尺,所以两个拟合直线是完全重合的;而第二个图中两条先就差别很大,原来红色的直线变成了曲线,而geom_smooth获得的仍然是直线。改变坐标轴范围也是同样的效果:

  1. p + gs1 + gs2 + scale_y_continuous(limits = c(1000, 10000))
  2. p + gs1 + gs2 + ylim(limits = c(1000, 10000))

也就是说人工设置坐标轴标尺后改变了用于建立映射的数据,或作变换,或取子集(设置limits),这个过程发生在建立映射之前。如果想在ggplot2建立映射后改变坐标轴,应该用coord_xxx类型函数:

  1. p + gs1 + gs2 + coord_cartesian(ylim = c(1000, 10000))
  2. p + gs1 + gs2 + coord_trans(xtrans = "log10")

前面用到了ylim函数,同样也有xlim,它们只是辅助函数,实质调用了坐标轴标尺设置函数。在映射一文我们还提到柱形图不能用scale类函数调整坐标轴刻度范围,主要原因是:柱形图即直方图,不能改变y轴起始为非0;另外scale设置导致取数据子集,随之直方图坐标轴范围改变,这些改变多数情况下会和scale的设置冲突。用scale设置柱形图保险不出错的情况是设置的范围比数据范围要大,但没有什么实际意义:

  1. qplot(x = x, y = y, geom = "bar") qplot(x = x, y = y, geom = "bar") + ylim(limits = c(-10, 10))

4 标尺函数的通用参数

除前面提到的breaks和labels外,常用的还有name,用于改变所设scale的名称,具体表现是改变坐标轴标题或图例标题。放在第一个参数的位置可以不用写参数名称。

  1. qplot(x = carat, y = price, color = cut, data = dt) + scale_color_hue("Diamond Cut")
  2. qplot(x = carat, y = price, color = cut, data = dt) + scale_y_continuous("Diamond Cut")
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注